Статьи

«Простой» компонент JSF 2.0 против гобелена

Я только что увидел забавный пример JSF 2.0 в блоге Джима Дрисколла . Он создает простой компонент, предназначенный только для вывода, для отображения текста желтым цветом с использованием встроенного стиля CSS. Чтобы упростить ситуацию (мои цитаты), он использует JSF.

Вот его страница JSF:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ez="http://java.sun.com/jsf/composite/simpleout">
<h:head>
    <title>Yellow Text Example</title>
</h:head>
<h:body>
        <h1>Editable Text Example</h1>
        <h:form id="form1">
                <ez:out value="Test Value"/>
            <p><h:commandButton value="reload"/></p>
            <h:messages/>
        </h:form>
</h:body>
</html>

Не так уж и плохо … соответствующая часть <ez:out value="Test Value">, это ссылка на его компонент Out внутри его библиотеки simpleout. JSF много интерпретирует в URL-адресах пространства имен.

С другой стороны, реализация этого простого компонента кажется немного неуправляемой:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:composite="http://java.sun.com/jsf/composite">
<head>
<title>This will not be present in rendered output</title>
</head>
<body>

<composite:interface name="yellowOut"
                     displayName="Very Basic Output Component"
                     preferred="true"
                     expert="false"
                     shortDescription="A basic example">
    <composite:attribute name="value" required="false"/>
</composite:interface>

<composite:implementation>
    <h:outputText value="#{compositeComponent.attrs.value}" style="background-color: yellow"/>
</composite:implementation>
</body>
</html>

Вы можете как-то смутно видеть внутри всего этого беспорядка, что делает компонент. Меня лично беспокоит name="yellowOut"… имя компонента «out» или «yellowOut»? Кроме того, по сравнению с готовящейся версией Tapestry, вы можете заметить, что включены несколько намеков на инструменты визуального конструктора.

Итак, как выглядит гобеленовый эквивалент?

Ну, наш шаблон страницы будет выглядеть примерно так : * :

<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
<head>
  <title>Yellow Text Example (Tapestry)</title>
</head>
<body>
  <h1>Yellow Text Example</h1>
  <t:form t:id="form1">
    <t:out value="Test Value"/>
   <p><input type="submit" value="reload"/></p>
  </t:form>
</body>
</html>

Пространство имен Tapestry идентифицирует элементы и атрибуты, которые на самом деле не являются HTML, но контролируются Tapestry. Это включает в себя встроенные компоненты Tapestry, такие как Form, а также определенные пользователем компоненты, такие как Out.

Сам компонент Out состоит из двух частей: Java-класс для определения параметров (и, в реальном примере, для предоставления другой логики и свойств) и соответствующий шаблон для выполнения вывода ** . Первый класс:

package org.example.myapp.components;

import org.apache.tapestry5.BindingConstants;
import org.apache.tapestry5.annotations.*;

public class Out
{
  @Property
  @Parameter(defaultPrefix = BindingConstants.LITERAL)
  private String value;
}

Аннотация @Parameter в поле значения помечает поле как параметр. Атрибут defaultPrefix настроен для указания того, что по умолчанию выражение привязки (атрибут value внутри шаблона страницы) следует интерпретировать как буквенную строку (в отличие от обычного по умолчанию выражения свойства).

Аннотация @Property указывает Tapestry предоставить метод получения и установки для поля, чтобы к нему можно было получить доступ из шаблона.

<span style="background-color: yellow">${value}</span>

Опять же, это тривиальный пример. Нам даже не нужно было определять пространство имен Tapestry для этого шаблона. ${value}Является расширением , которое выводит значение свойства компонента , например Out, который сам по себе является символьной строкой ( «Тест Значение») , связанная с параметром значения компонента Out в.

Давайте добавим небольшое улучшение: если значение равно нулю или пусто, даже не отображайте тег <span>. Это достигается одним из двух способов.

Во-первых, мы можем немного изменить шаблон, чтобы превратить тег <span> в компонент If, который отображает тег span:

<span t:type="if" t:test="value" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd" style="background-color: yellow;">${value}</span>

Компонент If оценивает свой тестовый параметр и, если имеет значение true, визуализирует свой тег (в данном случае <span>), его атрибуты не-Tapestry (стиль) и его тело ( ${value}).

Кроме того, мы можем оставить шаблон в покое и прервать рендеринг компонента в классе Java:

  boolean beforeRenderTemplate()
  {
    return ! (value == null || value.equals(""));  
  }

Это метод фазы рендеринга Tapestry , своего рода необязательный метод обратного вызова, который может контролировать способ визуализации компонента. Мы возвращаем true для рендеринга в обычном режиме и false, чтобы пропустить рендеринг шаблона. Tapestry вызывает этот метод в нужное время в соответствии с соглашением об именах, хотя аннотацию можно использовать, если вам больше по вкусу.

Это хороший пример того, как Tapestry действительно сокращает погоню по сравнению с другими системами. Как использование компонента, так и его определение просты, кратки и удобочитаемы. Кроме того, компоненты Tapestry могут хорошо масштабироваться, добавляя подкомпоненты в шаблон, а также дополнительные свойства и логику в классе Java. Наконец, мы также можем увидеть намек на то, как Tapestry избавляет вас от большого количества низкоуровневой рутинной работы, такой как использование аннотации @Property вместо написания этих методов вручную (Tapestry имеет широкий набор таких инструментов метапрограммирования, созданных в).

* Я не уверен, почему оригинальная версия использовала форму, но я покорно воссоздал это здесь.

** Для такого простого компонента я бы не стал использовать шаблон и делал все это в коде.