Разработка повторно-используемых компонентов
Библиотека Wicket предоставляет иерархию классов, на базе которых можно создавать собственные повторно-используемые компоненты. Каждый компонент должен содержать класс-контроллер, а также может иметь собственный файл разметки и собственные ресурсные файлы. Для компонентов, не нуждающихся в файле разметки, достаточно расширить класс WebComponent и перекрыть метод onComponentTag(). Ниже приводится реализация компонента Spacer, позволяющего создать на странице пространство с высотой и шириной, задаваемой при помощи атрибутов width и height в файле разметки.
public class Spacer extends WebComponent { public Spacer(String s) { super(s); setRenderBodyOnly(true); }
protected void onComponentTag(ComponentTag componentTag) { String width = componentTag.getString("width"); String height = componentTag.getString("height");
StringBuffer buffer = new StringBuffer(); buffer.append(MessageFormat.format("<div style=\"width:{0}; height:{1};\">", width, height)); buffer.append(MessageFormat.format("<spacer type=\"block\" width=\"{0}\" height=\"{1}\">", width, height)); buffer.append("</div>");
replaceComponentTagBody(findMarkupStream(), componentTag, buffer.toString()); } } |
Объект componentTag содержит сведения о теге разметки, с которым связан компонент при помощи атрибута wicket:id (это может быть, например, тег вида <div wicket:id=”spacer” width=”10px” height=”1px” />), и позволяет использовать значения его атрибутов width и height при генерации кода, отображающего компонент.
В случае, когда разработчик желает снабдить компонент файлом разметки, в качестве базового класса должен быть использован класс Panel. Для примера создадим компонент, отображающий текущее время. Файл разметки TimePanel.html представлен ниже.
<html xmlns:wicket="http://wicket.sourceforge.net/"> <body> <wicket:panel> <div align="center" style="width:80px;height:20px;border:1px solid #000000"> <span wicket:id="timeLabel">00:00:00</span> </div> </wicket:panel> </body> </html> |
Данный файл является полноценной HTML-страницей с тегами <html> и <body>. Однако для отображения компонента будет использована только та часть разметки, которая находится внутри специального тега <wicket:panel>.
Соответствующий класс-контроллер должен использовать стандартный компонент Label, передающий текущее время в динамически формируемый результат.
public class TimePanel extends Panel { public TimePanel(String s) { super(s); add(new Label("timeLabel", new SimpleDateFormat("HH:mm:ss").format(new Date()))); } } |
Рассмотрим другую задачу: необходимо создать компонент, который отрисовывает рамку с заголовком вокруг формы на странице AddPersonPage из первого примера статьи. Для решения подобных задач лучше всего использовать компоненты-контейнеры. Создадим класс FormBorder, расширяющий класс Border из библиотеки Wicket.
public class FormBorder extends Border { public FormBorder(String s, String title) { super(s); add(new Label("formTitle", title)); } } |
Далее, необходимо создать файл с разметкой FormBorder.html.
<html xmlns:wicket="http://wicket.sourceforge.net/"> <body> <wicket:border> <div align="center" style="border:1px solid #000000"> <span wicket:id="formTitle" style="font-weight: bold">Заголовок формы</span> <wicket:body/> </div> </wicket:border> </body> </html> |
Специальный тег <wicket:border> по смыслу аналогичен тегу <wicket:panel>. Он определяет ту часть HTML-разметки, которая будет использоваться для отображения компонента, остальные теги будут игнорированы. Тег <wicket:body/> указывает место, которое займет код, сгенерированный для отображения компонентов, вложенных в контейнер. Чтобы подключить компонент, необходимо изменить файл AddPersonPage.html таким образом, чтобы форма оказалась внутри блока с меткой wicket:id="border".
<html xmlns:wicket="http://wicket.sourceforge.net/"> <head> <title>Сохранение персональных данных</title> </head> <body> <div wicket:id="border"> <form wicket:id="form"> <span wicket:id="feedback"/> <div>Имя: <input wicket:id="name" type="text" /></div> <div>Адрес: <input wicket:id="email" type="text" /></div> <input type="submit" name="submit" value="Сохранить"/> </form> </div> </body> </html> |
Необходимо также изменить конструктор класса AddPersonPage; в нем должен создаваться экземпляр класса FormBorder.
public class AddPersonPage extends WebPage { … public AddPersonPage() { FormBorder border = new FormBorder("border", "Введите данные"); border.setRenderBodyOnly(true); border.add(new PersonForm("form")); add(border); } } |
Обратите внимание, что вложенность компонентов в точности соответствует вложенности тегов в файле разметки. Подключение компонента закончено. Если запустить приложение, то для страницы AddPersonPage будет сгенерирован примерно следующий HTML-код:
<html> <head> <title>Сохранение персональных данных</title> </head> <body> <div align="center" style="border:1px solid #000000"> <span style="font-weight: bold">Введите данные</span> <form action="/wdemo/app?path=0:border:form&interface=IFormSubmitListener" method="post"> <span></span> <div>Имя: <input value="" type="text" name="name"/></div> <div>Адрес: <input value="" type="text" name="email"/></div> <input type="submit" name="submit" value="Сохранить"/> </form> </div> </body> </html> |
Использование компонентно-ориентированного подхода открывает перед разработчиками грандиозные возможности для организации повторного использования кода. Очевидно, что, например, компонент FormBorder может быть использован при создании других Web-форм приложения. При этом изменения в файле FormBorder.html автоматически приведут к изменению в отображении всех страниц, в которых задействован данный компонент.