Apache Tapestry - Компоненты

Как обсуждалось ранее, компоненты и страницы одинаковы, за исключением того, что страница является корневым компонентом и включает один или несколько дочерних компонентов. Компоненты всегда находятся внутри страницы и выполняют почти все динамические функции страницы.

Компоненты Tapestry отображают простые HTML-ссылки на сложные функции сетки с interactive AJAX. Компонент также может включать в себя другой компонент. Компоненты гобелена состоят из следующих предметов -

  • Component Class - Основной Java-класс компонента.

  • XML Template- Шаблон XML похож на шаблон страницы. Класс компонента отображает шаблон как окончательный результат. Некоторые компоненты могут не иметь шаблонов. В этом случае вывод будет генерироваться самим классом компонента с использованиемMarkupWriter класс.

  • Body- Компонент, указанный внутри шаблона страницы, может иметь настраиваемую разметку и называется «Тело компонента». Если в шаблоне компонента есть<body />element, то элемент <body /> будет заменен телом компонента. Это похоже на макет, описанный ранее в разделе шаблонов XML.

  • Rendering - Рендеринг - это процесс, который преобразует XML-шаблон и тело компонента в фактический вывод компонента.

  • Parameters - Используется для создания связи между компонентом и страницами и, таким образом, передачи данных между ними.

  • Events- Делегирует функциональные возможности компонентов своему контейнеру / родителю (страницам или другому компоненту). Он широко используется в целях навигации по страницам.

Рендеринг

Визуализация компонента выполняется в несколько заранее определенных этапов. Каждая фаза в системе компонентов должна иметь соответствующий метод, определенный соглашением или аннотацией в классе компонентов.

// Using annotaion 
@SetupRender 
void initializeValues() { 
   // initialize values 
}

// using convention 
boolean afterRender() { 
   // do logic 
   return true; 
}

Фазы, название метода и аннотации перечислены ниже.

Аннотации Имена методов по умолчанию
@SetupRender setupRender ()
@BeginRender beginRender ()
@BeforeRenderTemplate beforeRenderTemplate ()
@BeforeRenderBody beforeRenderBody ()
@AfterRenderBody afterRenderBody ()
@AfterRenderTemplate afterRenderTemplate ()
@AfterRender afterRender ()
@CleanupRender cleanupRender ()

У каждой фазы есть конкретная цель, и они следующие:

SetupRender

SetupRender запускает процесс рендеринга. Обычно он устанавливает параметры компонента.

BeginRender

BeginRender начинает рендеринг компонента. Обычно он отображает начальный / начальный тег компонента.

BeforeRenderTemplate

BeforeRenderTemplate используется для украшения шаблона XML, добавляя специальную разметку вокруг шаблона. Он также предоставляет возможность пропустить рендеринг шаблона.

BeforeRenderBody

BeforeRenderTemplate предоставляет возможность пропустить рендеринг основного элемента компонента.

AfterRenderBody

AfterRenderBody будет вызываться после рендеринга тела компонента.

AfterRenderTemplate

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

AfterRender

AfterRender является аналогом BeginRender и обычно отображает закрывающий тег.

CleanupRender

CleanupRender является аналогом SetupRender. Он освобождает / удаляет все объекты, созданные в процессе рендеринга.

Поток фаз рендеринга идет не только вперед. Он перемещается между фазами в зависимости от возвращаемого значения фазы.

Например, если метод SetupRender возвращает false, рендеринг переходит к этапу CleanupRender и наоборот. Чтобы получить четкое представление о потоке между различными фазами, проверьте поток на диаграмме, приведенной ниже.

Простой компонент

Давайте создадим простой компонент Hello, у которого будет выходное сообщение «Hello, Tapestry». Ниже приведен код компонента Hello и его шаблон.

package com.example.MyFirstApplication.components;  
public class Hello {  
}
<html  
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
  
   <div> 
      <p>Hello, Tapestry (from component).</p> 
   </div> 
  
</html>

Компонент Hello можно вызвать в шаблоне страницы как -

<html title = "Hello component test page" 
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
<t:hello />  
</html>

Точно так же компонент может отображать тот же вывод, используя MarkupWriter вместо шаблона, как показано ниже.

package com.example.MyFirstApplication.components; 
  
import org.apache.tapestry5.MarkupWriter; 
import org.apache.tapestry5.annotations.BeginRender;   

public class Hello { 
   @BeginRender 
   void renderMessage(MarkupWriter writer) { 
      writer.write("<p>Hello, Tapestry (from component)</p>"); 
   } 
}

Давайте изменим шаблон компонента и включим элемент <body />, как показано в блоке кода ниже.

<html>  
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
   
   <div> 
      <t:body /> 
   </div> 
</html>

Теперь шаблон страницы может включать тело в разметку компонента, как показано ниже.

<html title = "Hello component test page" 
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
   
   <t:hello> 
      <p>Hello, Tapestry (from page).</p> 
   </t:hello> 
</html>

Результат будет следующим -

<html> 
   <div> 
      <p>Hello, Tapestry (from page).</p> 
   </div> 
</html>

Параметры

Основная цель этих параметров - создать связь между полем компонента и свойством / ресурсом страницы. Используя параметры, компонент и соответствующая ему страница обмениваются данными и передают данные между собой. Это называетсяTwo Way Data Binding.

Например, компонент текстового поля, используемый для представления возраста на странице управления пользователями, получает свое начальное значение (доступное в базе данных) через параметр. Опять же, после того, как возраст пользователя обновлен и отправлен обратно, компонент отправит обратно обновленный возраст через тот же параметр.

Чтобы создать новый параметр в классе компонента, объявите поле и укажите @Parameterаннотация. Этот @Parameter имеет два необязательных аргумента, а именно:

  • required- делает параметр обязательным. Гобелен вызывает исключение, если он не предусмотрен.

  • value - указывает значение параметра по умолчанию.

Параметр должен быть указан в шаблоне страницы как атрибуты тега компонента. Значение атрибутов следует указывать с помощью Binding Expression / Expansion, которые мы обсуждали в предыдущих главах. Некоторые из расширений, которые мы узнали ранее:

  • Property expansion (prop:«val») - Получить данные из свойства класса страницы.

  • Message expansion (message:«val») - Получить данные из ключа, определенного в файле index.properties.

  • Context expansion (context:«val») - Получите данные из папки веб-контекста / src / main / webapp.

  • Asset expansion (asset:«val») - Получить данные из ресурсов, встроенных в файл jar, / META-INF / assets.

  • Symbol expansion (symbol:«val») - Получить данные из символов, определенных в AppModule.javafile.

У Tapestry есть еще много полезных расширений, некоторые из которых приведены ниже -

  • Literal expansion (literal:«val») - Буквальная строка.

  • Var expansion (var:«val») - Разрешить чтение или обновление переменной рендеринга компонента.

  • Validate expansion (validate:«val»)- Специализированная строка, используемая для определения правила проверки объекта. Например, проверка: требуется, minLength = 5.

  • Translate (translate:«val») - Используется для указания класса транслятора (преобразование представления на стороне клиента в представление на стороне сервера) при проверке ввода.

  • Block (block:«val») - Идентификатор блочного элемента в шаблоне.

  • Component (component:«val») - Идентификатор другого компонента в шаблоне.

Все указанные выше расширения доступны только для чтения, за исключением расширения свойств и расширения Var. Они используются компонентом для обмена данными со страницей. При использовании раскрытия в качестве значений атрибутов${...}не следует использовать. Вместо этого просто используйте расширение без символов доллара и скобок.

Компонент, использующий параметр

Давайте создадим новый компонент HelloWithParameter, изменив компонент Hello, чтобы динамически отображать сообщение, добавив name параметр в классе компонента и соответственно изменив шаблон компонента и шаблон страницы.

  • Создайте новый класс компонента HelloWithParameter.java.

  • Добавьте личное поле и назовите его @Parameterаннотация. Используйте обязательный аргумент, чтобы сделать его обязательным.

@Parameter(required = true) 
private String name;
  • Добавьте частное поле, результат с @Properyаннотация. Свойство result будет использовано в шаблоне компонента. Шаблон компонента не имеет доступа к полям, помеченным@Parameter и может получить доступ только к полям, помеченным @Property. Переменная, доступная в шаблонах компонентов, называется переменными визуализации.

@Property 
 private String result;
  • Добавьте метод RenderBody и скопируйте значение из параметра имени в свойство результата.

@BeginRender 
void initializeValues() { 
   result = name; 
}
  • Добавить новый шаблон компонента HelloWithParamter.tml и используйте свойство result для визуализации сообщения.

<div> Hello, ${result} </div>
  • Добавьте новое свойство Username на тестовой странице (testhello.java).

public String getUsername() { 
   return "User1"; 
}
  • Используйте только что созданный компонент в шаблоне страницы и установите свойство Username в параметре name для HelloWithParameter составная часть.

<t:helloWithParameter name = "username" />

Полный список выглядит следующим образом -

package com.example.MyFirstApplication.components;  

import org.apache.tapestry5.annotations.*;  
public class HelloWithParameter { 
   @Parameter(required = true) 
   private String name; 
     
   @Property 
   private String result; 
   
   @BeginRender 
   void initializeValues() { 
      result = name; 
   } 
}
<html  
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
   
   <div> Hello, ${result} </div> 
  
</html>
package com.example.MyFirstApplication.pages;  

import org.apache.tapestry5.annotations.*;  
public class TestHello { 
   public String getUsername() { 
      return "User1"; 
   } 
}
<html title = "Hello component test page" 
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
   <t:helloWithParameter name = "username" />
   
</html>

Результат будет следующим -

<div> Hello, User1 </div>

Расширенный параметр

В предыдущих главах мы анализировали, как создать и использовать простой параметр в пользовательском компоненте. Расширенный параметр также может содержать полную разметку. В этом случае разметка должна быть указана внутри тега компонента, такого как подраздел в шаблоне страницы. Встроенный компонент if имеет разметку как для успешного, так и для неудачного состояния. Разметка успеха указывается как тело тега компонента, а разметка ошибки указывается с помощьюelseparameter.

Давайте посмотрим, как использовать ifсоставная часть. Компонент if имеет два параметра -

  • test - Простой параметр на основе свойств.

  • Else - Расширенный параметр, используемый для указания альтернативной разметки, если условие не выполняется

Tapestry проверит значение свойства test, используя следующую логику, и вернет true или false. Это называетсяType Coercion, способ преобразования объекта одного типа в объект другого типа с тем же содержимым.

  • Если тип данных String, «True», если не пусто, а не буквальная строка «False» (без учета регистра).

  • Если тип данных Number, Истина, если не ноль.

  • Если тип данных Collection, Истина, если не пусто.

  • Если тип данных Object, True (если он не равен нулю).

Если условие выполняется, компонент отображает свое тело; в противном случае он отображает тело параметра else.

Полный список выглядит следующим образом -

package com.example.MyFirstApplication.pages; 
public class TestIf { 
   public String getUser() { 
      return "User1"; 
   } 
}

<html title = "If Test Page" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter">  
   
   <body> 
      <h1>Welcome!</h1>  
      <t:if test = "user"> 
         Welcome back, ${user} 
         <p:else>
            Please <t:pagelink page = "login">Login</t:pagelink>  
         </p:else> 
      </t:if>
   </body>
   
</html>

События компонентов / Навигация по страницам

Приложение "Гобелен" - это collection of Pagesвзаимодействуют друг с другом. До сих пор мы научились создавать отдельные страницы без какой-либо связи между ними. Основная цель события Component - обеспечить взаимодействие между страницами (в том числе внутри страниц) с помощью событий на стороне сервера. Большинство событий компонентов происходят из событий на стороне клиента.

Например, когда пользователь щелкает ссылку на странице, Tapestry вызывает эту же страницу с целевой информацией вместо вызова целевой страницы и вызывает событие на стороне сервера. Страница Tapestry будет фиксировать событие, обрабатывать целевую информацию и выполнять перенаправление на стороне сервера на целевую страницу.

Гобелен следует за Post/Redirect/Get (RPG) design patternдля навигации по страницам. В RPG, когда пользователь отправляет запрос на публикацию, отправляя форму, сервер обрабатывает опубликованные данные, но не возвращает ответ напрямую. Вместо этого он выполнит перенаправление на стороне клиента на другую страницу, которая выдаст результат. Шаблон RPG используется для предотвращения дублирования отправки формы с помощью кнопки возврата в браузере, кнопки обновления браузера и т. Д. Tapestry предоставляет шаблон RPG, предоставляя следующие два типа запросов.

  • Component Event Request- Этот тип запроса нацелен на определенный компонент на странице и вызывает события внутри компонента. Этот запрос выполняет только перенаправление и не выводит ответ.

  • Render Request - Эти типы запросов нацелены на страницу и передают ответ обратно клиенту.

Чтобы понять события компонентов и навигацию по страницам, нам нужно знать шаблон URL-адреса запроса гобелена. Шаблон URL для обоих типов запроса выглядит следующим образом:

  • Component Event Requests -

/<<page_name_with_path>>.<<component_id|event_id>>/<<context_information>>
  • Render Request -

/<<page_name_with_path>>/<<context_information>>

Некоторые из примеров шаблонов URL-адресов:

  • Индексную страницу можно запросить https://«domain»/«app»/index.

  • Если страница указателя доступна под администратором подпапки, ее может запросить https://«domain»/«app»/admin/index.

  • Если пользователь нажимает на ActionLink component с участием id test на странице индекса, тогда URL будет https://«domain»/«app»/index.test.

События

По умолчанию гобелен поднимает OnPassivate а также OnActivateсобытия для всех запросов. Для типа запроса события «Компонент» гобелен вызывает одно или несколько дополнительных событий в зависимости от компонента. Компонент ActionLink вызывает событие Action, а компонент Form вызывает несколько событий, напримерValidate, Success, так далее.,

События могут обрабатываться в классе страницы с помощью соответствующего обработчика метода. Обработчик метода создается либо по соглашению об именах методов, либо с помощью@OnEventаннотация. Формат соглашения об именах методов:On«EventName»From«ComponentId».

Событие действия компонента ActionLink с id test можно обработать одним из следующих методов -

void OnActionFromTest() { 
}  
@OnEvent(component = "test", name = "action") 
void CustomFunctionName() { 
}

Если в имени метода нет какого-либо конкретного компонента, то метод будет вызываться для всех компонентов с соответствующими событиями.

void OnAction() { 
}

OnPassivate и OnActivate Event

OnPassivate используется для предоставления контекстной информации для обработчика событий OnActivate. В общем, Tapestry предоставляет контекстную информацию, и ее можно использовать в качестве аргумента в обработчике OnActivateevent.

Например, если контекстная информация имеет тип 3 типа int, то событие OnActivate может вызываться как -

void OnActivate(int id) { 
}

В некоторых случаях контекстная информация может быть недоступна. В этой ситуации мы можем предоставить контекстную информацию обработчику события OnActivate через обработчик события OnPassivate. Тип возвращаемого значения обработчика события OnPassivate следует использовать в качестве аргумента обработчика события OnActivate.

int OnPassivate() { 
   int id = 3; 
   return id; 
} 
void OnActivate(int id) { 
}

Возвращаемые значения обработчика событий

Tapestry выдает перенаправление страниц на основе возвращаемых значений обработчика событий. Обработчик событий должен возвращать одно из следующих значений.

  • Null Response- Возвращает нулевое значение. Tapestry создаст URL-адрес текущей страницы и отправит клиенту в качестве перенаправления.

public Object onAction() { 
   return null; 
}
  • String Response- Возвращает строковое значение. Tapestry создаст URL-адрес страницы, соответствующей значению, и отправит клиенту в качестве перенаправления.

public String onAction() { 
   return "Index"; 
}
  • Class Response- Возвращает класс страницы. Tapestry создаст URL-адрес возвращенного класса страницы и отправит клиенту в качестве перенаправления.

public Object onAction() { 
   return Index.class 
}
  • Page Response- Возвращает поле с аннотацией @InjectPage. Tapestry создаст URL-адрес внедренной страницы и отправит клиенту в качестве перенаправления.

@InjectPage 
private Index index;  

public Object onAction(){ 
   return index; 
}
  • HttpError- Возвращает объект HTTPError. Tapestry выдаст ошибку HTTP на стороне клиента.

public Object onAction(){ 
   return new HttpError(302, "The Error message); 
}
  • Link Response- Возвращает экземпляр ссылки напрямую. Tapestry создаст URL из объекта Link и отправит клиенту в качестве перенаправления.

  • Stream Response - возвращает StreamResponseобъект. Tapestry отправит поток в ответ прямо в браузер клиента. Он используется для создания отчетов и изображений напрямую и отправки их клиенту.

  • Url Response - возвращает java.net.URLобъект. Tapestry получит соответствующий URL-адрес от объекта и отправит клиенту в качестве перенаправления.

  • Object Response- Возвращает любые значения, кроме указанных выше. Гобелен вызовет ошибку.

Контекст события

Как правило, обработчик событий может получить контекстную информацию с помощью аргументов. Например, если контекстная информация имеет тип 3 типа int, то обработчик события будет -

Object onActionFromTest(int id) {  
}

Tapestry правильно обрабатывает контекстную информацию и передает ее методам через аргументы. Иногда Tapestry может не справиться с этим должным образом из-за сложности программирования. В это время мы можем получить полную контекстную информацию и обработать ее самостоятельно.

Object onActionFromEdit(EventContext context) { 
   if (context.getCount() > 0) { 
      this.selectedId = context.get(0); 
   } else { 
      alertManager.warn("Please select a document."); 
      return null; 
   } 
}