Lekce 8 - Wicket - Validace vstupu a opakovač
V předchozí lekci, Wicket - Databáze, jsme se věnovali propojení Wicketu s databází.
Aktuálně tedy máme funkční verzi webové aplikace a v následujících několika lekcích budeme pracovat na jejím vylepšení. Můžete pokračovat ve stávajícím projektu, nebo si jako já, vytvořit projekt nový. Abychom nemuseli vytvářet vše od začátku, předchozí projekt jednoduše okopírujeme a vložíme do workspace.


Eclipse se nás zeptá, pod jakým názvem chceme kopii projektu uložit. Zvolte např. MujWebPokrocily a klikněte na OK.

V tomto novém projektu je potřeba provést několik drobných změn (všechen výskyt slova MujWebStredni zaměnit za MujWebPokrocily). Kliknete na nově vytvořený projekt, následně zvolíte na liště Search -> File -> do pole "Containing text:" zadáte MujWebStredni, v poli "File name patterns …" necháte * a ve Scope zvolíte "Selected resources" -> Search. V záložce Search se vám zobrazí nalezené výsledky (je jich cca sedm). U nich pozměňte název. Možná budete potřebovat restartovat Eclipse. Když nyní nasadíte aplikaci, měla by být přístupná na url http://localhost:8080/MujWebPokrocily
V minulé lekci jsme přidali stránku s formulářem pro vkládání komentářů. Vstup z formuláře ale není nijak kontrolován, takže je možné vložit prázdný komentář, nebo vynechat email. Toto nyní změníme. Budeme chtít, aby jak email, tak text komentáře byli povinné. Toho dosáhneme ve Wicketu jednoduše.
ContactForm.java
add(new TextField("email").setRequired(true)); add(new TextArea("text").setRequired(true));
Po stisknutí tlačítka "Odeslat" se formulář neodešle, ale uživatel neví proč. Přidáme tedy panel, ve kterém se bude zobrazovat informace pro uživatele.
Wicket Panel je komponenta, která má vlastní .html, a která umožňuje vytvořit vlastní komponentu včetně html a tu používat na více místech v aplikaci. Pro zobrazování chybových informací při odesílání formuláře má Wicket již hotovou komponentu FeedbackPanel.
ContactPage.java
public ContactPage() { FeedbackPanel feedback = new FeedbackPanel("feedback"); add(feedback); Form form = new ContactForm("form"); add(form); }
ContactPage.html
<h2><wicket:message key="text.contact"/></h2> <div wicket:id="feedback"></div> <form wicket:id="form"> …

Upravíme také styly.
style.css
.feedbackPanel { list-style: none; color: red; border: 1px solid red; margin: 10px 0; padding: 5px; } .feedbackPanel li { padding: 2px 0; }

Pokud se vám defaultní hláška nelíbí, je možné ji upravit (název_formuláře.název_pole.Required).
WicketApplication.properties
form.email.Required=Email is required! form.text.Required=Text of the comment is required!
WicketApplication_cs.properties
form.email.Required=Email je povinn\u00FD\! form.text.Required=Text koment\u00E1\u0159e je povinn\u00FD\!

Pole jsou nyní povinná, ale ještě by to chtělo validaci, zda je zadaný email je platný. I na toto má Wicket již připravené řešení. Políčku přidáme EmailAddressValidator.
ContactForm.java
public ContactForm(String id) { super(id); setDefaultModel(new CompoundPropertyModel(this)); TextField<String> emailTF = new TextField<String>("email"); emailTF.setRequired(true); emailTF.add(EmailAddressValidator.getInstance()); add(emailTF); add(new TextArea<String>("text").setRequired(true)); }
Také si všimněte, že jsem u komponenty typu TextField použil generiku (určil jsem, s jakým typem dat budou pracovat - s řetězci).

Defaultní hlášku lze opět změnit.
WicketApplication.properties
EmailAddressValidator=Not valid email address!
WicketApplication_cs.properties
EmailAddressValidator=Zadan\u00E1 hodnota nen\u00ED platn\u00E1 emailov\u00E1 adresa\!

Nyní vytvoříme stránku, na níž budeme komentáře zobrazovat. Nejdříve ale budeme potřebovat model, který bude poskytovat stránce data k zobrazení. Metodu pro získání všech komentářů (getAllComments()) už máme připravenu z minulé lekce.
CommentsModel.java
public class CommentsModel implements IModel<List<Comment>> { @Override public void detach() { } @Override public List<Comment> getObject() { CommentDao dao = new CommentDaoImpl(); List<Comment> comments = dao.getAllComments(); return comments; } @Override public void setObject(List<Comment> object) { } }
Pro zobrazení všech komentářů na stránce použijeme komponentu opakovač (repeater). Wicket nabízí několik různých typů opakovačů pro různé příležitosti. My použijeme ListView, který se používá (jak jeho název napovídá) k zobrazení všech položek ze seznamu, které obdrží. V ListView je potřeba implementovat metodu populateItem(), ve které definujeme, jak se má každá položka seznamu zobrazit.
CommentsPage.java
public class CommentsPage extends BasePage { public CommentsPage() { ListView listView = new ListView<Comment>("listView", new CommentsModel()) { @Override protected void populateItem(ListItem<Comment> item) { Comment comment = item.getModelObject(); item.add(new Label("date", comment.getCreatedTime().toString())); item.add(new Label("email", comment.getEmail())); item.add(new Label("text", comment.getTextOfComment())); } }; add(listView); } @Override public void setTitleModelObject() { titleModel.setObject(getString("title.adminPage")); } }
CommentsPage.html
<wicket:extend> <h2><wicket:message key="text.comments"/></h2> <table> <tr> <th><wicket:message key="tableHeader.date"/></th> <th><wicket:message key="tableHeader.email"/></th> <th><wicket:message key="tableHeader.text"/></th> </tr> <tr wicket:id="listView"> <td><span wicket:id="date"></span></td> <td><span wicket:id="email"></span></td> <td><span wicket:id="text"></span></td> </tr> </table> </wicket:extend>
Konstruktor ListView požaduje dva parametry: id a model, který mu poskytuje data (model, jehož getObject() metoda vrací seznam objektů). Metoda populateItem() se volá pro každý objekt v seznamu a jako parametr obsahuje ListItem. Z ní je možné získat objekt ze seznamu. ListView opakuje tag, kterému je přiřazen a všechny tagy, které obsahuje. My jsme ListView přiřadili řádku tabulky <tr> a dovnitř řádku jsme umístili buňky <td>, které obsahují texty. ListView pro každou položku ze seznamu vytvoří řádek tabulky a též jednotlivé buňky. Pokud tyto buňky obsahují další Wicket komponenty, jsou vytvořeny také.
Dále je třeba doplnit stránku do menu.
BasePage.java
Link commentsPageLink = new Link("commentsPage") { @Override public void onClick() { setResponsePage(CommentsPage.class); } }; add(commentsPageLink);
BasePage.html
<li><a href="#" wicket:id="commentsPage"><wicket:message key="menu.comments"/></a></li>
A také doplnit resources.
Pro češtinu:
title.commentsPage=Koment\u00E1\u0159e menu.comments=Koment\u00E1\u0159e text.comments=V\u00FDpis koment\u00E1\u0159\u016F tableHeader.date=Datum tableHeader.email=Email tableHeader.text=Text koment\u00E1\u0159e
Pro angličtinu
title.commentsPage=Comments page menu.comments=Comments text.comments=Comments listing tableHeader.date=Date tableHeader.email=Email tableHeader.text=Text of the comment
Též upravíme styly.
style.css
table, th, td { border: 1px solid black; border-collapse: collapse; } table { width: 100%; margin: 5px 0; } th, td { padding: 5px; }


Ještě by to chtělo jednu drobnou úpravu. Komentáře se řadí sestupně od nejstaršího. Asi by bylo lepší řazení od nejnovějších. Stačí změnit select v CommentDaoImpl.java na
select id_comment, created_time, email, text_of_comment from comment order by created_time desc

To je pro tentokrát vše.
V následujícím kvízu, Kvíz - Internacionalizace a lokalizace, formuláře a databáze, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.