Сообщений 7    Оценка 145        Оценить  
Система Orphus

Разработка Web-приложений с использованием Wicket

Автор: Вячеслав Скорых
Компания Сибиус, Новосибирск

Источник: RSDN Magazine #5-2005
Опубликовано: 19.05.2006
Исправлено: 10.12.2016
Версия текста: 1.0
Введение
Приложения Wicket
Стандартные компоненты
Разработка повторно-используемых компонентов
Наследование при разработке Web-страниц
Разграничение прав доступа
Локализация приложений
Изменение поведения системы
Заключение

Введение

Развитие информационных технологий идет по вполне предсказуемому сценарию: одновременно с ростом сложности программных продуктов ужесточаются требования к срокам и стоимости реализации проектов. Поиск способов повышения рентабельности происходит преимущественно в области новейших технологий разработки программного обеспечения, позволяющих повысить эффективность труда разработчиков. Среди чисто технических решений проблемы особо стоит отметить компонентно-ориентированный подход к разработке программного обеспечения. За последние годы этот подход, заключающийся в разбиении приложения на модули с целью многократного повторного использования, хорошо зарекомендовал себя в области разработки настольных и многоуровневых приложений, а затем и в области разработки Web-приложений. За последние годы Java-программисты получили в свое распоряжение целый арсенал программных продуктов, разобраться в особенностях, преимуществах и недостатках которых не так-то и просто. Данная статья представляет читателям новейшее средство Web-разработки c компонентно-ориентированным подходом для платформы Java, библиотеку Wicket.

Приложения Wicket

Строго говоря, Wicket относится к категории программных каркасов (application framework). Являясь надстройкой над Servlet API, Wicket предоставляет всю необходимую инфраструктуру для функционирования приложений, включая средства для управления жизненным циклом объектов, разграничения прав доступа, локализации, обработки исключительных ситуаций, поддержки сессий пользователей и т.п.

Рассмотрим процесс создания приложения Wicket на конкретном примере. Предположим, необходимо создать Web-форму для ввода имени и электронного адреса пользователя. Результаты ввода будут сохраняться в объекте нижеследующей структуры:

      public
      class Person
{
  private String name;
  private String email;

  public String getName()
  {
    return name;
  }

  publicvoid setName(String name)
  {
    this.name = name;
  }

  public String getEmail()
  {
    return email;
  }

  publicvoid setEmail(String email)
  {
    this.email = email;
  }
}

Каждая страница приложения, реализованного с помощью Wicket, состоит из Java-класса, управляющего поведением страницы, файла с HTML-разметкой, использующейся для генерации страницы и, возможно, ресурсного файла. После сборки проекта все эти файлы должны размещаться в каталоге WEB-INF\classes сервера приложений, с учетом структуры пакетов. Создадим файл AddPersonPage.html, содержащий форму для ввода данных:

<html xmlns:wicket="http://wicket.sourceforge.net/">
<head>
  <title>Сохранение персональных данных</title>
</head>
<body>
  <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>
</body>
</html>

В данном файле у некоторых HTML-тегов присутствуют атрибуты wicket:id. Посредством этих атрибутов производится сопоставление тегов разметки с объектами, создаваемыми при работе приложения на стороне сервера. Теперь создадим класс AddPersonPage, который будет функционировать на сервере при отображении данной страницы.

      public
      class AddPersonPage extends WebPage
{
  publicfinalclass PersonForm extends Form
  {
    public PersonForm(String s)
    {
      super(s, new CompoundPropertyModel(new Person()));
      add(new FeedbackPanel("feedback"));
      TextField name = new TextField("name");
      name.add(RequiredValidator.getInstance());
      add(name);
      TextField email = new TextField("email");
      email.add(RequiredValidator.getInstance());
      email.add(EmailAddressPatternValidator.getInstance());
      add(email);
    }
    publicvoid onSubmit()
    {
      Person person = (Person) getModelObject();
      PageParameters params = new PageParameters();
      params.put("result", person);
      redirectTo(newPage(NextPage.class, params));
    }
  }
  public AddPersonPage()
  {
    add(new PersonForm("form"));
  }
}

Класс AddPersonPage, расширяющий базовый класс WebPage, управляет отображением страницы. Класс PersonForm, расширяющий Form, управляет отображением формы. Классы FeedbackPanel и TextField – это штатные компоненты библиотеки; FeedbackPanel используется для вывода сообщений об ошибках, а TextField управляет полями ввода данных. Все эти классы вложены друг в друга при помощи метода add(), в полном соответствии с вложенностью тегов в файле разметки. При инициализации каждому из классов передается строковый идентификатор, значение которого должно совпадать с идентификатором wicket:id в файле разметки.

Класс Метод onSubmit() представляет собой обработчик события ввода данных для формы. При помощи метода redirectTo() управление передается странице NextPage (реализация этой страницы здесь не рассматривается), которая должна иметь конструктор, позволяющий получить объект класса PageParameters с результатами.

Особый интерес представляет класс CompoundPropertyModel. Взаимодействие с бизнес-объектами в Wicket происходит при помощи специальных классов-посредников, реализующих интерфейс IModel. Благодаря модели CompoundPropertyModel, атрибуты name и email класса Person автоматически сопоставляются с компонентами, имеющими одноименные идентификаторы. Метод getModelObject() позволяет получить объект Person после HTTP-запроса с атрибутами, значения которых установил пользователь. Другие виды моделей будут рассмотрены далее.

В приведенном примере были использованы классы RequiredValidator и EmailAddressPatternValidator. Данные классы позволяют производить автоматическую проверку корректности результатов ввода. Основные виды таких классов представлены в таблице.

Название Назначение
RequiredValidator Проверка на обязательность заполнения поля
LengthValidator Проверка ограничений на длину строки ввода
IntegerValidator Проверка на числовое значение
PatternValidator Проверка строки по шаблону
EmailAddressPatternValidator Проверка формата электронного адреса
TypeValidator Проверка на возможность конвертации результата ввода
CustomValidator Базовый класс для создания собственных проверяющих классов

Если результат ввода не прошел проверку, метод onSubmit() не будет вызван и, посредством FeedbackPanel, пользователю будут отображены сообщения об ошибках. Тексты сообщений задаются в ресурсном файле, который в данном случае будет называться AddPersonPage.properties и содержать следующие строки.

form.name.RequiredValidator=Введите имя
form.email.RequiredValidator=Введите e-mail
form.email.EmailAddressPatternValidator=Неверный формат e-mail

Имена констант для сообщений имеют сложную форму, состоящую из идентификаторов формы, поля ввода и названия класса.

Итак, страница создана, но она еще не может получить управление. Для этого необходимо поместить в дескриптор web.xml описание сервлета WicketServlet в соответствии с приведенным ниже примером:

<web-app>

  <display-name>Wicket Demo Application</display-name>

  <servlet>
    <servlet-name>WicketDemo</servlet-name>
    <servlet-class>wicket.protocol.http.WicketServlet</servlet-class>
    <init-param>
      <param-name>applicationClassName</param-name>
      <param-value>wicketdemo.Application</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>WicketDemo</servlet-name>
    <url-pattern>/app</url-pattern>
  </servlet-mapping>

  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

</web-app>

Класс WicketServlet – это штатный сервлет библиотеки Wicket. Чтобы сервлет перехватил управление при входе пользователя в приложение, в файл index.jsp можно поместить конструкцию <jsp:forward page="/app" />. В качестве параметра сервлету передается полное имя класса Application. Этот класс используется для управления режимами работы приложения и позволяет, в случае необходимости, переопределить поведение системных классов Wicket, отвечающих за локализацию, кэширование, обработку ошибок времени выполнения, разбор файлов разметки, а также обеспечивающих доступ к ресурсам и поддержку сессий пользователей.

      public
      class Application extends WebApplication
{
  public Application()
  {
    getPages().setHomePage(AddPersonPage.class);
    getSettings().setStripWicketTags(true);
    getSettings().setResourcePollFrequency(Duration.ONE_SECOND);
  }
}

В конструкторе класса Application указывается, что страница AddPersonPage будет домашней страницей приложения, а также изменяется ряд настроек. Метод setStripWicketTags отключает отображение специальных тегов Wicket (см. далее) в генерируемом коде, а метод setResourcePollFrequency управляет режимом кэширования ресурсов. В нашем примере кэширование отключено, что позволяет разработчику видеть последствия изменений, вносимых в файлы разметки, без перезапуска сервера приложений. Разумеется, отключение кэширования снижает производительность и используется только на этапе отладки приложения.

Итак, приложение готово. При запуске сервера приложений создается объект WicketServlet, который, в свою очередь, создает объект класса Application. Далее Application передает управление объекту класса AddPersonPage, который генерирует HTML-страницу. После ввода данных WicketServlet получает HTTP-запрос от пользователя, автоматически вызывает проверяющие классы, устанавливает значения для атрибутов объекта Person и вызывает метод onSubmit().

Особо следует остановиться на том, каким образом происходит генерация HTML-страницы. Классы AddPersonPage, PersonForm, FeedbackPanel и TextField являются либо штатными классами Wicket, либо расширяют базовые классы, наследуя способность управлять содержимым файла разметки в соответствии с состоянием объектов. При генерации страницы теги, имеющие атрибут wicket:id, либо замещаются, либо дополняются динамически сгенерированными данными.

В приведенном примере, класс Person задает так называемую модель данных, которые обрабатываются на странице, класс AddPersonPage является контроллером, а файл AddPersonPage.html отвечает за представление данных. Таким образом, можно утверждать, что Web-приложения, создаваемые с помощью библиотеки Wicket, полностью соответствуют паттерну программирования MVC (Model-View-Controller), официально рекомендованному компанией Sun шаблону для реализации интерактивных приложений.

Стандартные компоненты

В нашем примере использовались стандартные компоненты Wicket: FeedbackPanel и TextField. Ниже приводится список основных компонентов, предоставляемых библиотекой, и HTML-теги, с которыми они обычно используются.

Название компонента Назначение Тег HTML
FeedbackPanel Отображение ошибок пользователя <span>
Image Изображение <img>
Label Динамически изменяемая текстовая метка <span>, <td>
MultilineLabel Многострочная текстовая метка <span>, <td>
Link Ссылка <a>
TextArea Область ввода текста <textarea>
TextField Поле ввода текста <input type=”text”>
PasswordTextField Поле ввода пароля <input type=”password”>
CheckBox Флажок <input type=”checkbox”>
RadioChoice Переключатель <input type=”radio”>
Button Кнопка <input type=”submit”>
DropDownChoice Выпадающий список <select>
ListChoice Список <select>

Это далеко не полный список. Помимо перечисленных базовых компонентов, Wicket предоставляет средства для организации табличного просмотра данных (классы DataView, DataTable, GridView), организации постраничного просмотра таблиц (PagingNavigator), просмотра данных в виде деревьев (Tree), генерации динамических изображений (RenderedDynamicImageResource). В данной статье возможности этих классов не рассматриваются.

Рассмотрим пример использования некоторых стандартных компонентов. Создадим страницу, которая позволяет пользователю выбрать цвет из списка и отображает результаты выбора. Файл разметки SelectionPage.html приведен ниже.

<html xmlns:wicket="http://wicket.sourceforge.net/">
<head>
  <title>Выбор цвета</title>
</head>
<body>
  <form wicket:id="form">
    Ваш предыдущий выбор: <span wicket:id="colorLabel">нет</span><br/>
    Выберите цвет:
    <select wicket:id="color">
      <option>Красный</option>
      <option>Желтый</option>
      <option>Зеленый</option>
    </select>
    <input wicket:id="submitButton" type="submit" value="Выбор"/><br/>
    <a wicket:id="selectLink" href="#">Выход</a>
  </form>
</body>
</html>

Соответствующий класс-контроллер использует компоненты Label, DropDownChoice, Link и Button.

      public
      class SelectionPage extends WebPage
{
  privatefinalstatic List COLORS = Arrays.asList(new String[]{"красный", "желтый", "зеленый"});

  publicfinalclass SelectionForm extends Form
  {
    private String selectedColor = "нет";

    public String getSelectedColor()
    {
      return selectedColor;
    }

    publicvoid setSelectedColor(String selectedColor)
    {
      this.selectedColor = selectedColor;
    }

    public SelectionForm(String s)
    {
      super(s);
      add(new Label("colorLabel", new PropertyModel(this, "selectedColor")));
      add(new DropDownChoice("color", new PropertyModel(this, "selectedColor"), COLORS));
      add(new Link("selectLink")
      {
        publicvoid onClick()
        {
          redirectTo(newPage(NextPage.class));
        }
      });
      add(new Button("submitButton")
      {
        protectedvoid onSubmit()
        {
          System.out.println("Selected color: " + getSelectedColor());
        }
      });
    }

  }
  public SelectionPage()
  {
    add(new SelectionForm("form"));
  }
}

В данном примере использована модель PropertyModel, посредством которой атрибут selectedColor класса SelectionForm связывается с классами Label и DropDownChoice. Компонент Link имеет собственный обработчик события onClick(), передающий управление другой странице. Компонент Button позволяет получить выбранное пользователем значение с помощью обработчика onSubmit().

Разработка повторно-используемых компонентов

Библиотека Wicket предоставляет иерархию классов, на базе которых можно создавать собственные повторно-используемые компоненты. Каждый компонент должен содержать класс-контроллер, а также может иметь собственный файл разметки и собственные ресурсные файлы. Для компонентов, не нуждающихся в файле разметки, достаточно расширить класс WebComponent и перекрыть метод onComponentTag(). Ниже приводится реализация компонента Spacer, позволяющего создать на странице пространство с высотой и шириной, задаваемой при помощи атрибутов width и height в файле разметки.

      public
      class Spacer extends WebComponent
{
  public Spacer(String s)
  {
    super(s);
    setRenderBodyOnly(true);
  }

  protectedvoid 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&amp;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 автоматически приведут к изменению в отображении всех страниц, в которых задействован данный компонент.

Наследование при разработке Web-страниц

Рассмотрим типовую задачу: необходимо создать приложение, все страницы которого оформлены единообразно, но имеют ряд отличий. Например, каждая страница должна иметь свой заголовок. В разных средствах разработки данная задача решается по-разному. Как правило, страницы компонуются из набора повторно-используемых шаблонов или компонент. Библиотека Wicket позволяет решить данную задачу с применением наследования. Создадим файл разметки для абстрактной базовой страницы приложения BasicPage.html

<html xmlns:wicket="http://wicket.sourceforge.net/">
<head>
  <title><span wicket:id="pageTitle">Page title</span></title>
  <link rel="stylesheet" type="text/css" href="style.css"/>
</head>
<body>
  <wicket:child/>
</body>
</html>

Данный пример предельно упрощен, BasicPage всего лишь подключает ко всем страницам таблицу каскадных стилей и позволяет менять заголовок страницы динамически. Интерес представляет только специальный тег <wicket:child/>, при помощи которого указывается, каким образом дочерние страницы будут расширять разметку BasicPage. Создадим контроллер страницы:

      public
      class BasicPage extends WebPage
{
  public BasicPage()
  {
    Label title = new Label("pageTitle", new StringResourceModel("pageTitle", this, null));
    title.setRenderBodyOnly(true);
    add(title);
  }
}

Значение компонента Label берется из ресурсного файла, для доступа к которому используется модель StringResourceModel. Ресурсный файл BasicPage.properties, должен содержать константу pageTitle.

pageTitle=Базовая страница

Теперь мы снова вернемся к странице AddPersonPage и переделаем ее таким образом, чтобы она расширяла базовую страницу BasicPage. Во-первых, класс-контроллер данной страницы должен расширять класс BasicPage.

      public
      class AddPersonPage extends BasicPage
{
  ...
}

Во-вторых, необходимо изменить файл AddPersonPage.html:

<html xmlns:wicket="http://wicket.sourceforge.net/">
<body>
  <wicket:extend>
    <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>
  </wicket:extend>
</body>
</html> 

В примере появился новый специальный тег <wicket:extend>. Он указывает, какая часть разметки будет использована для расширения разметки базовой страницы.

Поскольку заголовок для страницы AddPersonPage должен отличаться от заголовка базовой страницы, добавим в файл AddPersonPage.properties соответствующую константу.

pageTitle=Ввод персональных данных

После запуска приложения будет сгенерирована страница, похожая на ту, что представлена ниже.

<html>
<head>
  <title>Basic page</title>
  <link rel="stylesheet" type="text/css" href="style.css"/>
</head>
<body>
  <span>
    Пример приложения Wicket
    <hr/>
  </span>
  <div align="center" style="border:1px solid #000000">
    <span style="font-weight: bold">Введите данные</span>
    <form action="/wdemo/app?path=0:border:form&amp;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>

Подведем итог: страница AddPersonPage унаследовала от BasicPage не только Java-код, но и разметку страницы. Если бы в файле AddPersonPage.properties не существовало константы pageTitle, то использовалось бы значение из ресурсного файла базового класса.

Разграничение прав доступа

Задача разграничения прав доступа возникает перед разработчиками весьма часто. Библиотека Wicket помогает решить проблему с минимальными трудозатратами. Для поддержки сессий пользователей в библиотеке используется класс WebSession. Расширим возможности этого класса:

      public
      class AppSession extends WebSession
{
  private Account account;

  public AppSession(wicket.Application application)
  {
    super(application);
  }

  publicvoid setAccount(Account account)
  {
    this.account = account;
  }

  publicboolean isAuthenticated()
  {
    return account != null;
  }
}

Класс Account содержит сведения о пользователе. Будем считать, что если значение атрибута account установлено, пользователь имеет право доступа к странице. Теперь необходимо заставить приложение создавать класс AppSession вместо стандартного класса WebSession. Для этого переопределим в классе Application метод getSessionFactory().

      public
      class Application extends WebApplication
{
  …
  public ISessionFactory getSessionFactory()
  {
    returnnew ISessionFactory()
    {
      public Session newSession()
      {
        returnnew AppSession(Application.this);
      }

    };
  }
}

И, напоследок, изменим класс BasicPage таким образом, чтобы при обращении к странице возможность доступа проверялась автоматически. Для этого должен быть перекрыт метод checkAccess() класса WebPage таким образом, чтобы производился автоматический переход на страницу LoginPage, если пользователь не опознан.

      public
      class BasicPage extends WebPage
{
  ...
  public AppSession getAppSession()
  {
    return (AppSession) getSession();
  }

  protectedboolean checkAccess()
  {
    if (!getAppSession().isAuthenticated())
    {
      redirectToInterceptPage(newPage(LoginPage.class));
      returnfalse;
    }
    returntrue;
  }
}

Локализация приложений

Библиотека Wicket использует общепринятый на платформе Java подход для локализации приложений через ресурсные файлы. Например, чтобы страница AddPersonPage могла отображать сообщения на ошибках на немецком языке, достаточно создать файл AddPersonPage_de_DE.properties с альтернативными значениями констант. При помощи класса StringResourceModel значения для констант будут выбираться из ресурсного файла, соответствующего текущему языку приложения. Переключение языка возможно путем вставки в Java-код следующей строки:

getSession().setLocale(new Locale("de", "DE"));

Кроме того, Wicket позволяет локализовать страницы на уровне файлов разметки. Например, для поддержки германской версии страницы AddPersonPage, можно создать дополнительный файл разметки AddPersonPage_de_DE.html. Для локализации графических изображений должен быть использован компонент Image.

Изменение поведения системы

Библиотека Wicket предоставляет разработчику широкие возможности по расширению и переопределению поведения системных классов. Рассмотрим возможности библиотеки на примере изменения страницы вывода сообщений о системных ошибках. По умолчанию используется страница, содержащая сведения о произошедшей ошибке и о возможных причинах ее возникновения. Создавая дружественный интерфейс, разработчики иногда скрывают детальную, но бесполезную для конечного пользователя информацию об ошибке, сохраняя данные в журнальном файле или передавая их администратору по электронной почте. Решая данную задачу средствами Wicket, необходимо создать страницу ErrorPage, имеющую класс-контроллер следующего вида.

      public
      class ErrorPage extends WebPage
{
  public ErrorPage(Page page, RuntimeException ex)
  {
    // Обработка ошибок
  }

  publicboolean isErrorPage()
  {
    returntrue;
  }
}

Затем нужно переопределить стандартный обработчик ошибок в классе Application:

      public
      class Application extends WebApplication
{
  protected Page onRuntimeException(Page page, RuntimeException e)
  {
    returnnew ErrorPage(page, e);
  }
}

Заключение

При прочтении данной статьи сведущие программисты наверняка могли отметить тот факт, что авторы Wicket позаимствовали немало технических решений из таких известных средств разработки, как Tapestry и Swing. Действительно, это так. Привлекательность Wicket заключается в том, что идеи эти были творчески переработаны таким образом, чтобы максимально упростить процесс разработки приложений. В Wicket нет сложных дескрипторов компонентов, характерных для Tapestry. Библиотека Wicket не копирует Swing в точности, это было бы излишним при разработке Web-приложений. Повторное использование шаблонов разметки организовано проще и совершеннее, чем в Velocity и Struts Tiles. Сами файлы разметки создаются с использованием стандартных тегов HTML. Такой подход, во-первых, дает разработчикам больше свободы, чем подход, реализованный в JSF или Echo2, а во-вторых, позволяет распределить работу между Web-дизайнерами и разработчиками максимально удобным способом. Авторы заложили в Wicket средства для решения ряда типовых задач. Анализируя все эти факторы, можно смело утверждать, что Wicket является одним из наиболее интересных и перспективных средств компонентно-ориентированной Web-разработки на платформе Java.

В статье были рассмотрены лишь ключевые особенности Wicket. Чтобы познакомиться с Wicket ближе, посетите домашнюю страницу проекта по адресу http://wicket.sourceforge.net/. Библиотека распространяется по лицензии Apache, исходный код всех классов доступен для изучения. Дополнительные статьи доступны по адресу http://www.wicket-wiki.org.uk.


Эта статья опубликована в журнале RSDN Magazine #5-2005. Информацию о журнале можно найти здесь
    Сообщений 7    Оценка 145        Оценить