53
Средства разработки web приложений (Web frameworks) Малышкин Фёдор 2 ноября 2007

Средства разработки web приложений (Web frameworks)

Embed Size (px)

DESCRIPTION

Средства разработки web приложений (Web frameworks)

Citation preview

Page 1: Средства разработки web приложений  (Web frameworks)

Средства разработки web приложений(Web frameworks)

Малышкин Фёдор

2 ноября 2007

Page 2: Средства разработки web приложений  (Web frameworks)

Содержание

Введение Основа архитектуры «тонких» клиентов Средства разработки веб-приложений:

JSPStrutsSpringTapestryJSF

Сравнение

Page 3: Средства разработки web приложений  (Web frameworks)

Введение

Данная презентация познакомит Вас с существующими библиотеками разработки веб-приложений на языке Java.

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

Так же будут описаны классические модели реализации «тонких» клиентов, коим веб-приложение и является.

Page 4: Средства разработки web приложений  (Web frameworks)

Основа архитектуры «тонких» клиентов

В качестве основы для всех клиентов, связанных с пользовательским вводом (не обязательно «тонких»), используется MVC (Model-View-Controller).

Эта архитектура разделяет приложение на: Модель данных (Model), занимающуюся хранением данных,

обработкой данных (бизнес - логикой), а так же всем остальными

«не визуальными» вещами. Представление (View), занимающуюся отображением и

представлением данных Контроллер (Controller), занимающийся коммуникацией между

данными и представлением. В веб-приложениях данная модель называется «Model-2»

(что бы отделить от настольной реализации MVC) и указать, на то что она является приемником «Model-1».

Page 5: Средства разработки web приложений  (Web frameworks)

Основа архитектуры «тонких» клиентов

DB

1) Запрос 2) Создание

3) Пересылка запроса

5) Ответ4) Извлечение

данных

Модель: Java Bean

Представление: JSP

Контроллер (Сервлет)

Page 6: Средства разработки web приложений  (Web frameworks)

JSP (Краткая характеристика)

Положительные стороны: ?

Отрицательные стороны: ?

Page 7: Средства разработки web приложений  (Web frameworks)

JSP (Жизненный цикл)

Запрос

Ответ

Компиляция JSP в Java класс

Выполнение Java класса

JSP

Page 8: Средства разработки web приложений  (Web frameworks)

Struts (Краткая характеристика)

Положительные стороны: Много проектов реализованных с помощью данной библиотеки,

подтверждает её стабильность и надёжность Огромное количество примеров и документации HTML библиотека тэгов одна из лучших

Отрицательные стороны: Программирование «контроллера» - ActionForms – задача не из

лёгких Невозможно автономное тестирование Ходят слухи, что проект «мёртв»

Page 9: Средства разработки web приложений  (Web frameworks)

Spring (Краткая характеристика)

Положительные стороны: Переопределение правил связки данных на форме и в

приложении, правил навигации и проверки введённых значений Прозрачная интеграция с многочисленными средствами

представления данных: JSP/JSTL, Tiles, Velocity, FreeMaker, Excel,

XSL, PDF. Удобная среда для автономного тестирования

Отрицательные стороны: Много XML (в области конфигурирования) Требует большого количества кода в JSP «Слишком» гибок

Page 10: Средства разработки web приложений  (Web frameworks)

Spring (Жизненный цикл GET)

Запрос

Ответ

fromBackingObject()

initBinder()

showForm()

referenceData()

View (JSP, Velocity, Tiles...)

Page 11: Средства разработки web приложений  (Web frameworks)

Spring (Жизненный цикл POST)

Запрос

Ответ

fromBackingObject()

onBind()

onBindAndValidate()

showForm()/processFormSubmission()

Вызов Validator’а

ServletReequestDataBinder

Page 12: Средства разработки web приложений  (Web frameworks)

«Контроллер» Spring

public class UserController implements Controller {

private final Log log = LogFactory.getLog(UserController.class);

private UserManager mgr = null;

public void setUserManager(UserManager userManager) {

this.mgr = userManager;

}

public ModelAndView handleRequest(HttpServletRequest request,

HttpServletResponse response) throws Exception {

if (log.isDebugEnabled()) {

log.debug("entering 'handleRequest' method...");

}

return new ModelAndView("userList", "users", mgr.getUsers());

}

}

Page 13: Средства разработки web приложений  (Web frameworks)

«Контроллер» Spring

public class UserController implements Controller {

private final Log log = LogFactory.getLog(UserController.class);

private UserManager mgr = null;

public void setUserManager(UserManager userManager) {

this.mgr = userManager;

}

public ModelAndView handleRequest(HttpServletRequest request,

HttpServletResponse response) throws Exception {

if (log.isDebugEnabled()) {

log.debug("entering 'handleRequest' method...");

}

return new ModelAndView("userList", "users", mgr.getUsers());

}

}

Page 14: Средства разработки web приложений  (Web frameworks)

Конфигурирование Spring

<bean id="userController" class="org.appfuse.web.UserController"><property name="userManager" ref="userManager"/></bean>

Page 15: Средства разработки web приложений  (Web frameworks)

Конфигурирование Spring

<bean id="userController" class="org.appfuse.web.UserController"><property name="userManager" ref="userManager"/></bean><bean id="viewResolver"class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/><property name="prefix" value="/"/><property name="suffix" value=".jsp"/></bean>

Page 16: Средства разработки web приложений  (Web frameworks)

Конфигурирование Spring

<bean id="userController" class="org.appfuse.web.UserController"><property name="userManager" ref="userManager"/></bean><bean id="viewResolver"class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/><property name="prefix" value="/"/><property name="suffix" value=".jsp"/></bean><bean id="urlMapping"class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><property name="mappings"><value>/users.html=userController</value></property></bean>

Page 17: Средства разработки web приложений  (Web frameworks)

JSP представление Spring

<form:form commandName="user" method="post"><form:errors path="*" cssClass="error"/><form:hidden path="id" /><table class="detail"><tr>

<th><label for="firstName"><fmt:message key="user.firstName"/>:</label></th>

<td><form:input path="firstName" id="firstName"/><form:errors path="firstName" cssClass="fieldError"/>

</td></tr><tr>

<th><label for="lastName" class="required">* <fmt:message key="user.lastName"/>:</label></th>

<td><form:input path="lastName" id="firstName"/><form:errors path="lastName" cssClass="fieldError"/>

</td></tr>

Page 18: Средства разработки web приложений  (Web frameworks)

JSP представление Spring

<form:form commandName="user" method="post"><form:errors path="*" cssClass="error"/><form:hidden path="id" /><table class="detail"><tr>

<th><label for="firstName"><fmt:message key="user.firstName"/>:</label></th>

<td><form:input path="firstName" id="firstName"/><form:errors path="firstName" cssClass="fieldError"/>

</td></tr><tr>

<th><label for="lastName" class="required">* <fmt:message key="user.lastName"/>:</label></th>

<td><form:input path="lastName" id="firstName"/><form:errors path="lastName" cssClass="fieldError"/>

</td></tr>

Page 19: Средства разработки web приложений  (Web frameworks)

Velocity представление Spring

<form method="post" action="#springUrl('/editUser.html')">#springFormHiddenInput("user.id" '')<table><tr>

<th><label for="firstName">#springMessage("user.firstName"):</label></th><td>

#springFormInput("user.firstName" 'id="firstName"')#springShowErrors("<br/>" "fieldError")

</td></tr><tr>

<th><label for="lastName">#springMessage("user.lastName"):</label></th><td>

#springFormInput("user.lastName" 'id="lastName"')#springShowErrors("<br/>" "fieldError")

</td></tr>

Page 20: Средства разработки web приложений  (Web frameworks)

Spring Web Flow

Инфраструктура позволяющая определять последовательность переходов между страницами

Определяется программно или через XML Правила навигации активируются на основании

строковых значений, возвращённых вызванными методами (подобно JSF)

Page 21: Средства разработки web приложений  (Web frameworks)

Spring Web Flow

<webflow id="userFlow" start-state="setupForm"><action-state id="setupForm">

<action bean="userFormAction"/><transition on="success" to="display.nameForm"/>

</action-state><view-state id="display.nameForm" view="flow/name">

<transition on="submit" to="display.addressForm"><action bean="userFormAction" method="bindAndValidate"/>

</transition><transition on="cancel" to="finish"/>

</view-state><view-state id="display.addressForm" view="flow/address">

<transition on="previous" to="display.nameForm"><action bean="userFormAction" method="bindAndValidate"/>

</transition><transition on="submit" to="display.otherForm">

<action bean="userFormAction" method="bindAndValidate"/></transition><transition on="cancel" to="finish"/>

</view-state>

Page 22: Средства разработки web приложений  (Web frameworks)

Tapestry (Краткая характеристика)

Положительные стороны: Очень эффективна после изучения Шаблоны являются HTML, что очень хорошо для дизайнеров Хорошее сообщество пользователей

Отрицательные стороны: Документация достаточно сложна для восприятия Крутая кривая обучения Мало примеров Долгие циклы релизов – ведущие релизы 1-2 раза в год

Page 23: Средства разработки web приложений  (Web frameworks)

Tapestry (Жизненный цикл)

Запрос

Ответ

Инициализация страницы pageBeginRender()Публикация

свойств страницы

Вызов методов-«слушателей»

Активация следующей страницы

pageBeginRender()

Отображение исключения

Page 24: Средства разработки web приложений  (Web frameworks)

Класс Tapestry

public abstract class UserForm extends BasePage {public abstract UserManager getUserManager();public abstract void setUser(User user);public abstract User getUser();public void save(IRequestCycle cycle) {

if (log.isDebugEnabled()) {log.debug("entered 'save' method");

}getUserManager().saveUser(getUser());UserList nextPage = (UserList) cycle.getPage("users");nextPage.setMessage(getMessages().format("user.saved", getUser().getFullName()));

throw new PageRedirectException(nextPage);}

Page 25: Средства разработки web приложений  (Web frameworks)

Конфигурирование Tapestry

<application name="tapestry"><page name="Home" specification-path="/pages/home.page"/><page name="users" specification-path="/pages/users.page"/><page name="userForm" specification-path="/pages/userForm.page"/>

<library id=“contrib” specificationpath="/org/apache/tapestry/contrib/Contrib.library"/>

</application>

Page 26: Средства разработки web приложений  (Web frameworks)

Конфигурирование Tapestry

<page-specification class="org.appfuse.web.UserForm"><bean name="delegate“ class="org.apache.tapestry.valid.ValidationDelegate"/><component id="form" type="Form">

<binding name="delegate" value="ognl:beans.delegate"/><binding name="clientValidationEnabled" value="true"/>

</component><property name="user"/><inject property="userManager" object="spring:userManager"/><component id="lastNameField" type="TextField">

<binding name="value" value="user.lastName"/><binding name="validators" value="validators:required"/><binding name="displayName"

value="message:lastName"/></component>

</page-specification>

Page 27: Средства разработки web приложений  (Web frameworks)

HTML представление Tapestry

<form jwcid="@Form" delegate="ognl:beans.delegate" name="userForm"><input type="hidden" jwcid="@Hidden" value="ognl:user.id"/><table class="detail"><tr>

<th><label for="firstName"><span key="firstName">First Name</span></label>:

</th><td><input jwcid="@TextField" type="text" value="ognl:user.firstName" id="firstName"/></td>

</tr><tr>

<th><label jwcid="@FieldLabel" field="ognl:components.lastNameField">Last Name</label>:</th><td><input jwcid="lastNameField" type="text" id="lastName"/></td>

</tr><tr>

<th><label for="birthday"><span key="birthday">Birthday</span></label>:

</th><td>

<input jwcid="@DatePicker" format="message:date.format" type="text”size="11" value="ognl:user.birthday" id="birthday"/>

</td></tr>

Page 28: Средства разработки web приложений  (Web frameworks)

HTML представление Tapestry

<form jwcid="@Form" delegate="ognl:beans.delegate" name="userForm"><input type="hidden" jwcid="@Hidden" value="ognl:user.id"/><table class="detail"><tr>

<th><label for="firstName"><span key="firstName">First Name</span></label>:

</th><td><input jwcid="@TextField" type="text" value="ognl:user.firstName" id="firstName"/></td>

</tr><tr>

<th><label jwcid="@FieldLabel" field="ognl:components.lastNameField">Last Name</label>:</th><td><input jwcid="lastNameField" type="text" id="lastName"/></td>

</tr><tr>

<th><label for="birthday"><span key="birthday">Birthday</span></label>:

</th><td>

<input jwcid="@DatePicker" format="message:date.format" type="text”size="11" value="ognl:user.birthday" id="birthday"/>

</td></tr>

Page 29: Средства разработки web приложений  (Web frameworks)

HTML представление Tapestry

<form jwcid="@Form" delegate="ognl:beans.delegate" name="userForm"><input type="hidden" jwcid="@Hidden" value="ognl:user.id"/><table class="detail"><tr>

<th><label for="firstName"><span key="firstName">First Name</span></label>:

</th><td><input jwcid="@TextField" type="text" value="ognl:user.firstName" id="firstName"/></td>

</tr><tr>

<th><label jwcid="@FieldLabel" field="ognl:components.lastNameField">Last Name</label>:</th><td><input jwcid="lastNameField" type="text" id="lastName"/></td>

</tr><tr>

<th><label for="birthday"><span key="birthday">Birthday</span></label>:

</th><td>

<input jwcid="@DatePicker" format="message:date.format" type="text”size="11" value="ognl:user.birthday" id="birthday"/>

</td></tr>

Page 30: Средства разработки web приложений  (Web frameworks)

Улучшения в следующей версии Tapestry

Богатая поддержка аннотаций Высокий уровень конфигурирования – базирование на IoC

контейнере Hivemind Требует меньше кода – более простая реализация

классов реализующих логику страниц Поддержка URL дружественных к пользователю Компоненты Tacos AJAX

Page 31: Средства разработки web приложений  (Web frameworks)

JSF (Краткая характеристика)

Положительные стороны: J2EE Стандарт Быстрая и простая разработка Богата библиотека навигации (аналог Spring Web Flow)

Отрицательные стороны: Мешанина из JSP тэгов Плохая поддержка «легковесных» вызовов (REST) Нет единого источника реализации

Page 32: Средства разработки web приложений  (Web frameworks)

JSF (Жизненный цикл)

Page 33: Средства разработки web приложений  (Web frameworks)

Бин страницы JSF

public class UserForm {private String id;public User user = new User();public UserManager mgr;public void setId(String id) {

this.id = id;}public void setUser(User user) {

this.user = user;}public void setUserManager(UserManager userManager) {

this.mgr = userManager;}public String edit() {

if (id != null) {// assuming editsetUser(mgr.getUser(id));

}return "success";

}

Page 34: Средства разработки web приложений  (Web frameworks)

Конфигурация JSF

<application><variable-resolver>

org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver><locale-config>

<default-locale>en</default-locale><supported-locale>en</supported-locale><supported-locale>es</supported-locale>

</locale-config><message-bundle>messages</message-bundle>

</application><navigation-rule>

<from-view-id>/userForm.jsp</from-view-id><navigation-case>

<from-outcome>cancel</from-outcome><to-view-id>/userList.jsp</to-view-id>

</navigation-case><navigation-case>

<from-outcome>success</from-outcome><to-view-id>/userList.jsp</to-view-id><redirect/>

</navigation-case></navigation-rule>

Page 35: Средства разработки web приложений  (Web frameworks)

Конфигурация JSF

<application><variable-resolver>

org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver><locale-config>

<default-locale>en</default-locale><supported-locale>en</supported-locale><supported-locale>es</supported-locale>

</locale-config><message-bundle>messages</message-bundle>

</application><navigation-rule>

<from-view-id>/userForm.jsp</from-view-id><navigation-case>

<from-outcome>cancel</from-outcome><to-view-id>/userList.jsp</to-view-id>

</navigation-case><navigation-case>

<from-outcome>success</from-outcome><to-view-id>/userList.jsp</to-view-id><redirect/>

</navigation-case></navigation-rule>

Page 36: Средства разработки web приложений  (Web frameworks)

Конфигурация JSF

<managed-bean><managed-bean-name>userForm</managed-bean-name><managed-bean-class>org.appfuse.web.UserForm</managed-bean-class><managed-bean-scope>request</managed-bean-scope><managed-property>

<property-name>id</property-name><value>#{param.id}</value>

</managed-property><managed-property>

<property-name>userManager</property-name><value>#{userManager}</value>

</managed-property></managed-bean>

Page 37: Средства разработки web приложений  (Web frameworks)

JSP представление JSF

<f:view><f:loadBundle var="messages" basename="messages"/><h:form id="userForm"><h:inputHidden value="#{userForm.user.id}">

<f:convertNumber/></h:inputHidden><h:panelGrid columns="3" styleClass="detail" columnClasses="label">

<h:outputLabel for="firstName" value="#{messages['user.firstName']}"/><h:inputText value="#{userForm.user.firstName}" id="firstName"/><h:message for="firstName" styleClass="errorMessage"/><h:outputLabel for="lastName" value="#{messages['user.lastName']}"/><h:inputText value="#{userForm.user.lastName}" id="lastName" required="true"/><h:message for="lastName" styleClass="errorMessage"/><h:outputLabel for="birthday" value="#{messages['user.birthday']}"/><t:inputCalendar monthYearRowClass="yearMonthHeader"

weekRowClass="weekHeader" id="birthday"currentDayCellClass="currentDayCell" value="#{userForm.user.birthday}"renderAsPopup="true" addResources="false"/>

<h:message for="birthday" styleClass="errorMessage"/>

Page 38: Средства разработки web приложений  (Web frameworks)

JSP представление JSF

<f:view><f:loadBundle var="messages" basename="messages"/><h:form id="userForm"><h:inputHidden value="#{userForm.user.id}">

<f:convertNumber/></h:inputHidden><h:panelGrid columns="3" styleClass="detail" columnClasses="label">

<h:outputLabel for="firstName" value="#{messages['user.firstName']}"/><h:inputText value="#{userForm.user.firstName}" id="firstName"/><h:message for="firstName" styleClass="errorMessage"/><h:outputLabel for="lastName" value="#{messages['user.lastName']}"/><h:inputText value="#{userForm.user.lastName}" id="lastName" required="true"/><h:message for="lastName" styleClass="errorMessage"/><h:outputLabel for="birthday" value="#{messages['user.birthday']}"/><t:inputCalendar monthYearRowClass="yearMonthHeader"

weekRowClass="weekHeader" id="birthday"currentDayCellClass="currentDayCell"

value="#{userForm.user.birthday}"renderAsPopup="true" addResources="false"/>

<h:message for="birthday" styleClass="errorMessage"/>

Page 39: Средства разработки web приложений  (Web frameworks)

JSP представление JSF

<f:view><f:loadBundle var="messages" basename="messages"/><h:form id="userForm"><h:inputHidden value="#{userForm.user.id}">

<f:convertNumber/></h:inputHidden><h:panelGrid columns="3" styleClass="detail" columnClasses="label">

<h:outputLabel for="firstName" value="#{messages['user.firstName']}"/><h:inputText value="#{userForm.user.firstName}" id="firstName"/><h:message for="firstName" styleClass="errorMessage"/><h:outputLabel for="lastName" value="#{messages['user.lastName']}"/><h:inputText value="#{userForm.user.lastName}" id="lastName" required="true"/><h:message for="lastName" styleClass="errorMessage"/><h:outputLabel for="birthday" value="#{messages['user.birthday']}"/><t:inputCalendar monthYearRowClass="yearMonthHeader"

weekRowClass="weekHeader" id="birthday"currentDayCellClass="currentDayCell"

value="#{userForm.user.birthday}"renderAsPopup="true" addResources="false"/>

<h:message for="birthday" styleClass="errorMessage"/>

Page 40: Средства разработки web приложений  (Web frameworks)

Улучшения в следующей версии JSF (1.2)

Унифицированный EL – лучшая поддержка JSTL Фокусировка на лёгком использовании Расширенная поддержка AJAX Дополнительные реализации: ADF Faces, Facelets

Page 41: Средства разработки web приложений  (Web frameworks)

Сравнение. Критерии

Сортируемые/Листаемые списки – насколько просто создать список данных с листаемыми страницами и возможностями сортировки.

Возможность создания закладок – может ли пользователь создавать закладки на страницы для последующего обращения к ним?

Валидация - проверка введённых значений. Тестируемость – возможности для автономного

тестирования классов, составляющих клиента, вне контейнера.

Page 42: Средства разработки web приложений  (Web frameworks)

Сравнение. Критерии

Интернационализация Модификация «на лету» - принятие исправлений без

необходимости перекомпиляции или перезапуска контейнера

Поддержка разработчиками Производительность/Масштабируемость «Компонетность» - возможность создания повторно-

используемых, параметризуемых модулей Возможности языка выражений

Page 43: Средства разработки web приложений  (Web frameworks)

Сортируемые/Листаемые списки

JSP – никакой поддержки Spring & Struts могут использовать библиотеки тэгов, типа

“DisplayTag” Tapestry имеет contrib:Table компонент JSF имеет h:dataTable компонент без возможностей

сортировки – необходимо писать свою собственную логику для реализации данного функционала

Page 44: Средства разработки web приложений  (Web frameworks)

Возможность создания закладок

JSP, String & Strut имеют полный контроль над строкой запроса

Tapestry имеет слегка корявую поддержку создания закладок, но всё же все возможности реализованы

JSF делает POST для всего – закладки даже не рассматриваются (но при желании и это можно обойти)

Page 45: Средства разработки web приложений  (Web frameworks)

Валидация

JSP – «собственные» решения, либо перенос проверки в модель данных

String & Struts используют проект Apache – Commons Validator – надёжное и зрелое решение

Tapestry – хорошая архитектура валидации – хорошие сообщения (даже без необходимости корректировки под свои нужды)

JSF – «некрасивые» сообщения об ошибках по-умолчанию (но легко исправляется)

Page 46: Средства разработки web приложений  (Web frameworks)

Тестируемость

Struts – необходимо использование StrutsTestCase JSP, Spring – легко тестируется с использованием средств

генерации «заглушек» (mock) (EasyMock, jMock, Spring Mock…)

Tapestry – неочевидное тестирование, т.к. классы абстрактные – класс Creator помогает

JSF – самое простая архитектура для тестирования – классы – просто бины

Page 47: Средства разработки web приложений  (Web frameworks)

Интернационализация

JSTL <fmt:message> позволяет делать это легко почти в любой реализации

JSP, Struts, Spring, JSF – используют один ResourceBundle на язык

Tapestry – предпочитает отдельные файлы для страниц/компонентов

JSF требует, что данные с локализацией были объявлены на каждой странице

Page 48: Средства разработки web приложений  (Web frameworks)

Модификация «на лету»

JSP – самый гибкий в данном случае (конечно при корректном использовании). JSP файлы перекомпиливаются при каждом изменении, а вот классы нет.

Tapestry, Spring & Struts – всё (страницы, компоненты, библиотеки и конфигурационные файлы) (кроме классов) перечитывается при изменении.

JSF – не перечитываются конфигурационные файлы.

Page 49: Средства разработки web приложений  (Web frameworks)

Поддержка разработчиками

JSP & JSF – стандарт, большое сообщество разработчиков и множество документации

Spring – большое количество примеров и документации, хорошая поддержка разработчиками библиотеки

Tapestry – мало хорошей, понятной документации. Мало примеров.

Struts – отсутствие поддержки со стороны разработчиков, но при этом много документации и примеров использования в больших проектах

Page 50: Средства разработки web приложений  (Web frameworks)

Производительность / Масштабируемость

JSP – хорошие показатели, в связи с отсутствием каких-либо промежуточных уровней

Tapestry – после версии 4.0 (где было удалено широкое использование интроспекции) скорость стала сравнима с JSP

JSF – не самые лучшие показатели… Spring & Struts – адекватные показатели.

Page 51: Средства разработки web приложений  (Web frameworks)

«Компонетность»

JSP – тэг-файлы и тэги. Tapestry – очень ориентированная на создание и

использование компонетов, хорошая интеграция с JavaScript.

JSF – хорошие возможности по созданию компонентов, но создавать не так легко как в Tapestry.

Spring & Struts – лишь то же, что даёт JSP.

Page 52: Средства разработки web приложений  (Web frameworks)

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

JSP, JSF, Spring, Struts – богатые возможности EL говорят сами за себя.

Tapestry – вместо EL используется OGNL, который предоставляет ещё большие возможности.

Page 53: Средства разработки web приложений  (Web frameworks)

Финал

Выбирайте с умом…