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

Post on 17-May-2015

3.930 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

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

TRANSCRIPT

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

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

2 ноября 2007

Содержание

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

JSPStrutsSpringTapestryJSF

Сравнение

Введение

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

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

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

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

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

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

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

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

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

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

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

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

DB

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

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

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

данных

Модель: Java Bean

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

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

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

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

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

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

Запрос

Ответ

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

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

JSP

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

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

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

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

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

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

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

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

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

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

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

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

Запрос

Ответ

fromBackingObject()

initBinder()

showForm()

referenceData()

View (JSP, Velocity, Tiles...)

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

Запрос

Ответ

fromBackingObject()

onBind()

onBindAndValidate()

showForm()/processFormSubmission()

Вызов Validator’а

ServletReequestDataBinder

«Контроллер» 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());

}

}

«Контроллер» 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());

}

}

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

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

Конфигурирование 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>

Конфигурирование 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>

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>

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>

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>

Spring Web Flow

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

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

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

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>

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

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

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

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

Запрос

Ответ

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

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

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

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

pageBeginRender()

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

Класс 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);}

Конфигурирование 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>

Конфигурирование 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>

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>

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>

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>

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

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

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

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

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

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

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

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

Бин страницы 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";

}

Конфигурация 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>

Конфигурация 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>

Конфигурация 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>

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"/>

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"/>

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"/>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Валидация

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Финал

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

top related