advertisement

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

100 %
0 %
advertisement
Information about Средства разработки web приложений (Web frameworks)

Published on June 25, 2008

Author: fedor.malyshkin

Source: slideshare.net

Description

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

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

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

Введение

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

Средства разработки веб-приложений:

JSP

Struts

Spring

Tapestry

JSF

Сравнение

Введение Данная презентация познакомит Вас с существующими библиотеками разработки веб-приложений на языке Java. Будут описаны основополагающие моменты, лежащие в их основе, приведены примеры их использования, описаны их преимущества и недостатки. Так же будут описаны классические модели реализации «тонких» клиентов, коим веб-приложение и является.

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

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

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

Основа архитектуры «тонких» клиентов В качестве основы для всех клиентов, связанных с пользовательским вводом (не обязательно «тонких»), используется MVC (Model-View-Controller). Эта архитектура разделяет приложение на: Модель данных ( Model ) , занимающуюся хранением данных, обработкой данных (бизнес - логикой), а так же всем остальными «не визуальными» вещами. Представление ( View ), занимающуюся отображением и представлением данных Контроллер ( Controller ), занимающийся коммуникацией между данными и представлением. В веб-приложениях данная модель называется « Model-2 » (что бы отделить от настольной реализации MVC ) и указать, на то что она является приемником « Model-1 » .

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

Эта архитектура разделяет приложение на:

Модель данных ( Model ) , занимающуюся хранением данных, обработкой данных (бизнес - логикой), а так же всем остальными «не визуальными» вещами.

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

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

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

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

JSP (Краткая характеристика) Положительные стороны: ? Отрицательные стороны: ?

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

?

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

?

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

Struts (Краткая характеристика) Положительные стороны: Много проектов реализованных с помощью данной библиотеки, подтверждает её стабильность и надёжность Огромное количество примеров и документации HTML библиотека тэгов одна из лучших Отрицательные стороны: Программирование «контроллера» - ActionForms – задача не из лёгких Невозможно автономное тестирование Ходят слухи, что проект «мёртв»

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

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

Огромное количество примеров и документации

HTML библиотека тэгов одна из лучших

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

Программирование «контроллера» - ActionForms – задача не из лёгких

Невозможно автономное тестирование

Ходят слухи, что проект «мёртв»

Spring ( Краткая характеристика ) Положительные стороны: Переопределение правил связки данных на форме и в приложении, правил навигации и проверки введённых значений Прозрачная интеграция с многочисленными средствами представления данных: JSP/JSTL, Tiles, Velocity, FreeMaker, Excel, XSL, PDF. Удобная среда для автономного тестирования Отрицательные стороны: Много XML (в области конфигурирования) Требует большого количества кода в JSP «Слишком» гибок

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

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

Прозрачная интеграция с многочисленными средствами представления данных: JSP/JSTL, Tiles, Velocity, FreeMaker, Excel, XSL, PDF.

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

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

Много XML (в области конфигурирования)

Требует большого количества кода в JSP

«Слишком» гибок

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

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

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

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()); } }

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=&quot;userController&quot; class=&quot;org.appfuse.web.UserController&quot;> <property name=&quot;userManager&quot; ref=&quot;userManager&quot;/> </bean>

<bean id=&quot;userController&quot; class=&quot;org.appfuse.web.UserController&quot;>

<property name=&quot;userManager&quot; ref=&quot;userManager&quot;/>

</bean>

Конфигурирование Spring <bean id=&quot;userController&quot; class=&quot;org.appfuse.web.UserController&quot;> <property name=&quot;userManager&quot; ref=&quot;userManager&quot;/> </bean> <bean id=&quot;viewResolver&quot; class=&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;> <property name=&quot;viewClass&quot; value=&quot;org.springframework.web.servlet.view.JstlView&quot;/> <property name=&quot;prefix&quot; value=&quot;/&quot;/> <property name=&quot;suffix&quot; value=&quot;.jsp&quot;/> </bean>

<bean id=&quot;userController&quot; class=&quot;org.appfuse.web.UserController&quot;>

<property name=&quot;userManager&quot; ref=&quot;userManager&quot;/>

</bean>

<bean id=&quot;viewResolver&quot;

class=&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;>

<property name=&quot;viewClass&quot; value=&quot;org.springframework.web.servlet.view.JstlView&quot;/>

<property name=&quot;prefix&quot; value=&quot;/&quot;/>

<property name=&quot;suffix&quot; value=&quot;.jsp&quot;/>

</bean>

Конфигурирование Spring <bean id=&quot;userController&quot; class=&quot;org.appfuse.web.UserController&quot;> <property name=&quot;userManager&quot; ref=&quot;userManager&quot;/> </bean> <bean id=&quot;viewResolver&quot; class=&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;> <property name=&quot;viewClass&quot; value=&quot;org.springframework.web.servlet.view.JstlView&quot;/> <property name=&quot;prefix&quot; value=&quot;/&quot;/> <property name=&quot;suffix&quot; value=&quot;.jsp&quot;/> </bean> <bean id=&quot;urlMapping&quot; class=&quot;org.springframework.web.servlet.handler.SimpleUrlHandlerMapping&quot;> <property name=&quot;mappings&quot;> <value> /users.html=userController </value> </property> </bean>

<bean id=&quot;userController&quot; class=&quot;org.appfuse.web.UserController&quot;>

<property name=&quot;userManager&quot; ref=&quot;userManager&quot;/>

</bean>

<bean id=&quot;viewResolver&quot;

class=&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;>

<property name=&quot;viewClass&quot; value=&quot;org.springframework.web.servlet.view.JstlView&quot;/>

<property name=&quot;prefix&quot; value=&quot;/&quot;/>

<property name=&quot;suffix&quot; value=&quot;.jsp&quot;/>

</bean>

<bean id=&quot;urlMapping&quot;

class=&quot;org.springframework.web.servlet.handler.SimpleUrlHandlerMapping&quot;>

<property name=&quot;mappings&quot;>

<value>

/users.html=userController

</value>

</property>

</bean>

JSP представление Spring <form:form commandName=&quot;user&quot; method=&quot;post&quot;> <form:errors path=&quot;*&quot; cssClass=&quot;error&quot;/> <form:hidden path=&quot;id&quot; /> <table class=&quot;detail&quot;> <tr> <th><label for=&quot;firstName&quot;> <fmt:message key=&quot;user.firstName&quot;/>:</label></th> <td> <form:input path=&quot;firstName&quot; id=&quot;firstName&quot;/> <form:errors path=&quot;firstName&quot; cssClass=&quot;fieldError&quot;/> </td> </tr> <tr> <th><label for=&quot;lastName&quot; class=&quot;required&quot;> * <fmt:message key=&quot;user.lastName&quot;/>:</label></th> <td> <form:input path=&quot;lastName&quot; id=&quot;firstName&quot;/> <form:errors path=&quot;lastName&quot; cssClass=&quot;fieldError&quot;/> </td> </tr>

<form:form commandName=&quot;user&quot; method=&quot;post&quot;>

<form:errors path=&quot;*&quot; cssClass=&quot;error&quot;/>

<form:hidden path=&quot;id&quot; />

<table class=&quot;detail&quot;>

<tr>

<th><label for=&quot;firstName&quot;>

<fmt:message key=&quot;user.firstName&quot;/>:</label></th>

<td>

<form:input path=&quot;firstName&quot; id=&quot;firstName&quot;/>

<form:errors path=&quot;firstName&quot; cssClass=&quot;fieldError&quot;/>

</td>

</tr>

<tr>

<th><label for=&quot;lastName&quot; class=&quot;required&quot;>

* <fmt:message key=&quot;user.lastName&quot;/>:</label></th>

<td>

<form:input path=&quot;lastName&quot; id=&quot;firstName&quot;/>

<form:errors path=&quot;lastName&quot; cssClass=&quot;fieldError&quot;/>

</td>

</tr>

JSP представление Spring <form:form commandName=&quot;user&quot; method=&quot;post&quot;> <form:errors path=&quot;*&quot; cssClass=&quot;error&quot;/> <form:hidden path=&quot;id&quot; /> <table class=&quot;detail&quot;> <tr> <th><label for=&quot;firstName&quot;> <fmt:message key=&quot;user.firstName&quot;/>:</label></th> <td> <form:input path=&quot;firstName&quot; id=&quot;firstName&quot;/> <form:errors path=&quot;firstName&quot; cssClass=&quot;fieldError&quot;/> </td> </tr> <tr> <th><label for=&quot;lastName&quot; class=&quot;required&quot;> * <fmt:message key=&quot;user.lastName&quot;/>:</label></th> <td> <form:input path=&quot;lastName&quot; id=&quot;firstName&quot;/> <form:errors path=&quot;lastName&quot; cssClass=&quot;fieldError&quot;/> </td> </tr>

<form:form commandName=&quot;user&quot; method=&quot;post&quot;>

<form:errors path=&quot;*&quot; cssClass=&quot;error&quot;/>

<form:hidden path=&quot;id&quot; />

<table class=&quot;detail&quot;>

<tr>

<th><label for=&quot;firstName&quot;>

<fmt:message key=&quot;user.firstName&quot;/>:</label></th>

<td>

<form:input path=&quot;firstName&quot; id=&quot;firstName&quot;/>

<form:errors path=&quot;firstName&quot; cssClass=&quot;fieldError&quot;/>

</td>

</tr>

<tr>

<th><label for=&quot;lastName&quot; class=&quot;required&quot;>

* <fmt:message key=&quot;user.lastName&quot;/>:</label></th>

<td>

<form:input path=&quot;lastName&quot; id=&quot;firstName&quot;/>

<form:errors path=&quot;lastName&quot; cssClass=&quot;fieldError&quot;/>

</td>

</tr>

Velocity представление Spring <form method=&quot;post&quot; action=&quot;#springUrl('/editUser.html')&quot;> #springFormHiddenInput(&quot;user.id&quot; '') <table> <tr> <th><label for=&quot;firstName&quot;>#springMessage(&quot;user.firstName&quot;):</label></th> <td> #springFormInput(&quot;user.firstName&quot; 'id=&quot;firstName&quot;') #springShowErrors(&quot;<br/>&quot; &quot;fieldError&quot;) </td> </tr> <tr> <th><label for=&quot;lastName&quot;>#springMessage(&quot;user.lastName&quot;):</label></th> <td> #springFormInput(&quot;user.lastName&quot; 'id=&quot;lastName&quot;') #springShowErrors(&quot;<br/>&quot; &quot;fieldError&quot;) </td> </tr>

<form method=&quot;post&quot; action=&quot;#springUrl('/editUser.html')&quot;>

#springFormHiddenInput(&quot;user.id&quot; '')

<table>

<tr>

<th><label for=&quot;firstName&quot;>#springMessage(&quot;user.firstName&quot;):</label></th>

<td>

#springFormInput(&quot;user.firstName&quot; 'id=&quot;firstName&quot;')

#springShowErrors(&quot;<br/>&quot; &quot;fieldError&quot;)

</td>

</tr>

<tr>

<th><label for=&quot;lastName&quot;>#springMessage(&quot;user.lastName&quot;):</label></th>

<td>

#springFormInput(&quot;user.lastName&quot; 'id=&quot;lastName&quot;')

#springShowErrors(&quot;<br/>&quot; &quot;fieldError&quot;)

</td>

</tr>

Spring Web Flow Инфраструктура позволяющая определять последовательность переходов между страницами Определяется программно или через XML Правила навигации активируются на основании строковых значений, возвращённых вызванными методами (подобно JSF )

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

Определяется программно или через XML

Правила навигации активируются на основании строковых значений, возвращённых вызванными методами (подобно JSF )

Spring Web Flow <webflow id=&quot;userFlow&quot; start-state=&quot;setupForm&quot;> <action-state id=&quot;setupForm&quot;> <action bean=&quot;userFormAction&quot;/> <transition on=&quot;success&quot; to=&quot;display.nameForm&quot;/> </action-state> <view-state id=&quot;display.nameForm&quot; view=&quot;flow/name&quot;> <transition on=&quot;submit&quot; to=&quot;display.addressForm&quot;> <action bean=&quot;userFormAction&quot; method=&quot;bindAndValidate&quot;/> </transition> <transition on=&quot;cancel&quot; to=&quot;finish&quot;/> </view-state> <view-state id=&quot;display.addressForm&quot; view=&quot;flow/address&quot;> <transition on=&quot;previous&quot; to=&quot;display.nameForm&quot;> <action bean=&quot;userFormAction&quot; method=&quot;bindAndValidate&quot;/> </transition> <transition on=&quot;submit&quot; to=&quot;display.otherForm&quot;> <action bean=&quot;userFormAction&quot; method=&quot;bindAndValidate&quot;/> </transition> <transition on=&quot;cancel&quot; to=&quot;finish&quot;/> </view-state>

<webflow id=&quot;userFlow&quot; start-state=&quot;setupForm&quot;>

<action-state id=&quot;setupForm&quot;>

<action bean=&quot;userFormAction&quot;/>

<transition on=&quot;success&quot; to=&quot;display.nameForm&quot;/>

</action-state>

<view-state id=&quot;display.nameForm&quot; view=&quot;flow/name&quot;>

<transition on=&quot;submit&quot; to=&quot;display.addressForm&quot;>

<action bean=&quot;userFormAction&quot; method=&quot;bindAndValidate&quot;/>

</transition>

<transition on=&quot;cancel&quot; to=&quot;finish&quot;/>

</view-state>

<view-state id=&quot;display.addressForm&quot; view=&quot;flow/address&quot;>

<transition on=&quot;previous&quot; to=&quot;display.nameForm&quot;>

<action bean=&quot;userFormAction&quot; method=&quot;bindAndValidate&quot;/>

</transition>

<transition on=&quot;submit&quot; to=&quot;display.otherForm&quot;>

<action bean=&quot;userFormAction&quot; method=&quot;bindAndValidate&quot;/>

</transition>

<transition on=&quot;cancel&quot; to=&quot;finish&quot;/>

</view-state>

Tapestry ( Краткая характеристика ) Положительные стороны: Очень эффективна после изучения Шаблоны являются HTML , что очень хорошо для дизайнеров Хорошее сообщество пользователей Отрицательные стороны: Документация достаточно сложна для восприятия Крутая кривая обучения Мало примеров Долгие циклы релизов – ведущие релизы 1-2 раза в год

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

Очень эффективна после изучения

Шаблоны являются HTML , что очень хорошо для дизайнеров

Хорошее сообщество пользователей

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

Документация достаточно сложна для восприятия

Крутая кривая обучения

Мало примеров

Долгие циклы релизов – ведущие релизы 1-2 раза в год

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

Класс 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(&quot;entered 'save' method&quot;); } getUserManager().saveUser(getUser()); UserList nextPage = (UserList) cycle.getPage(&quot;users&quot;); nextPage.setMessage(getMessages().format(&quot;user.saved&quot;, getUser().getFullName())); throw new PageRedirectException(nextPage); }

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(&quot;entered 'save' method&quot;);

}

getUserManager().saveUser(getUser());

UserList nextPage = (UserList) cycle.getPage(&quot;users&quot;);

nextPage.setMessage(getMessages().format(&quot;user.saved&quot;, getUser().getFullName()));

throw new PageRedirectException(nextPage);

}

Конфигурирование Tapestry <application name=&quot;tapestry&quot;> <page name=&quot;Home&quot; specification-path=&quot;/pages/home.page&quot;/> <page name=&quot;users&quot; specification-path=&quot;/pages/users.page&quot;/> <page name=&quot;userForm&quot; specification-path=&quot;/pages/userForm.page&quot;/> <library id= “ contrib ” specification p ath=&quot;/org/apache/tapestry/contrib/Contrib.library&quot;/> </application>

<application name=&quot;tapestry&quot;>

<page name=&quot;Home&quot; specification-path=&quot;/pages/home.page&quot;/>

<page name=&quot;users&quot; specification-path=&quot;/pages/users.page&quot;/>

<page name=&quot;userForm&quot; specification-path=&quot;/pages/userForm.page&quot;/>

<library id= “ contrib ” specification p ath=&quot;/org/apache/tapestry/contrib/Contrib.library&quot;/>

</application>

Конфигурирование Tapestry <page-specification class=&quot;org.appfuse.web.UserForm&quot;> <bean name=&quot;delegate“ class=&quot;org.apache.tapestry.valid.ValidationDelegate&quot;/> <component id=&quot;form&quot; type=&quot;Form&quot;> <binding name=&quot;delegate&quot; value=&quot;ognl:beans.delegate&quot;/> <binding name=&quot;clientValidationEnabled&quot; value=&quot;true&quot;/> </component> <property name=&quot;user&quot;/> <inject property=&quot;userManager&quot; object=&quot;spring:userManager&quot;/> <component id=&quot;lastNameField&quot; type=&quot;TextField&quot;> <binding name=&quot;value&quot; value=&quot;user.lastName&quot;/> <binding name=&quot;validators&quot; value=&quot;validators:required&quot;/> <binding name=&quot;displayName&quot; value=&quot;message:lastName&quot;/> </component> </page-specification>

<page-specification class=&quot;org.appfuse.web.UserForm&quot;>

<bean name=&quot;delegate“ class=&quot;org.apache.tapestry.valid.ValidationDelegate&quot;/>

<component id=&quot;form&quot; type=&quot;Form&quot;>

<binding name=&quot;delegate&quot; value=&quot;ognl:beans.delegate&quot;/>

<binding name=&quot;clientValidationEnabled&quot; value=&quot;true&quot;/>

</component>

<property name=&quot;user&quot;/>

<inject property=&quot;userManager&quot; object=&quot;spring:userManager&quot;/>

<component id=&quot;lastNameField&quot; type=&quot;TextField&quot;>

<binding name=&quot;value&quot; value=&quot;user.lastName&quot;/>

<binding name=&quot;validators&quot; value=&quot;validators:required&quot;/>

<binding name=&quot;displayName&quot; value=&quot;message:lastName&quot;/>

</component>

</page-specification>

HTML представление Tapestry <form jwcid=&quot;@Form&quot; delegate=&quot;ognl:beans.delegate&quot; name=&quot;userForm&quot;> <input type=&quot;hidden&quot; jwcid=&quot;@Hidden&quot; value=&quot;ognl:user.id&quot;/> <table class=&quot;detail&quot;> <tr> <th> <label for=&quot;firstName&quot;><span key=&quot;firstName&quot;>First Name</span></label>: </th> <td><input jwcid=&quot;@TextField&quot; type=&quot;text&quot; value=&quot;ognl:user.firstName&quot; id=&quot;firstName&quot;/></td> </tr> <tr> <th> <label jwcid=&quot;@FieldLabel&quot; field=&quot;ognl:components.lastNameField&quot;>Last Name</label>: </th> <td><input jwcid=&quot;lastNameField&quot; type=&quot;text&quot; id=&quot;lastName&quot;/></td> </tr> <tr> <th> <label for=&quot;birthday&quot;><span key=&quot;birthday&quot;>Birthday</span></label>: </th> <td> <input jwcid=&quot;@DatePicker&quot; format=&quot;message:date.format&quot; type=&quot;text ” size=&quot;11&quot; value=&quot;ognl:user.birthday&quot; id=&quot;birthday&quot;/> </td> </tr>

<form jwcid=&quot;@Form&quot; delegate=&quot;ognl:beans.delegate&quot; name=&quot;userForm&quot;>

<input type=&quot;hidden&quot; jwcid=&quot;@Hidden&quot; value=&quot;ognl:user.id&quot;/>

<table class=&quot;detail&quot;>

<tr>

<th>

<label for=&quot;firstName&quot;><span key=&quot;firstName&quot;>First Name</span></label>:

</th>

<td><input jwcid=&quot;@TextField&quot; type=&quot;text&quot; value=&quot;ognl:user.firstName&quot; id=&quot;firstName&quot;/></td>

</tr>

<tr>

<th>

<label jwcid=&quot;@FieldLabel&quot; field=&quot;ognl:components.lastNameField&quot;>Last Name</label>:

</th>

<td><input jwcid=&quot;lastNameField&quot; type=&quot;text&quot; id=&quot;lastName&quot;/></td>

</tr>

<tr>

<th>

<label for=&quot;birthday&quot;><span key=&quot;birthday&quot;>Birthday</span></label>:

</th>

<td>

<input jwcid=&quot;@DatePicker&quot; format=&quot;message:date.format&quot; type=&quot;text ”

size=&quot;11&quot; value=&quot;ognl:user.birthday&quot; id=&quot;birthday&quot;/>

</td>

</tr>

HTML представление Tapestry <form jwcid=&quot;@Form&quot; delegate=&quot;ognl:beans.delegate&quot; name=&quot;userForm&quot;> <input type=&quot;hidden&quot; jwcid=&quot;@Hidden&quot; value=&quot;ognl:user.id&quot;/> <table class=&quot;detail&quot;> <tr> <th> <label for=&quot;firstName&quot;><span key=&quot;firstName&quot;>First Name</span></label>: </th> <td> <input jwcid=&quot;@TextField&quot; type=&quot;text&quot; value=&quot;ognl:user.firstName&quot; id=&quot;firstName&quot;/> </td> </tr> <tr> <th> <label jwcid=&quot;@FieldLabel&quot; field=&quot;ognl:components.lastNameField&quot;>Last Name</label> : </th> <td> <input jwcid=&quot;lastNameField&quot; type=&quot;text&quot; id=&quot;lastName&quot;/> </td> </tr> <tr> <th> <label for=&quot;birthday&quot;><span key=&quot;birthday&quot;>Birthday</span></label>: </th> <td> <input jwcid=&quot;@DatePicker&quot; format=&quot;message:date.format&quot; type=&quot;text ” size=&quot;11&quot; value=&quot;ognl:user.birthday&quot; id=&quot;birthday&quot;/> </td> </tr >

<form jwcid=&quot;@Form&quot; delegate=&quot;ognl:beans.delegate&quot; name=&quot;userForm&quot;>

<input type=&quot;hidden&quot; jwcid=&quot;@Hidden&quot; value=&quot;ognl:user.id&quot;/>

<table class=&quot;detail&quot;>

<tr>

<th>

<label for=&quot;firstName&quot;><span key=&quot;firstName&quot;>First Name</span></label>:

</th>

<td> <input jwcid=&quot;@TextField&quot; type=&quot;text&quot; value=&quot;ognl:user.firstName&quot; id=&quot;firstName&quot;/> </td>

</tr>

<tr>

<th>

<label jwcid=&quot;@FieldLabel&quot; field=&quot;ognl:components.lastNameField&quot;>Last Name</label> :

</th>

<td> <input jwcid=&quot;lastNameField&quot; type=&quot;text&quot; id=&quot;lastName&quot;/> </td>

</tr>

<tr>

<th>

<label for=&quot;birthday&quot;><span key=&quot;birthday&quot;>Birthday</span></label>:

</th>

<td>

<input jwcid=&quot;@DatePicker&quot; format=&quot;message:date.format&quot; type=&quot;text ”

size=&quot;11&quot; value=&quot;ognl:user.birthday&quot; id=&quot;birthday&quot;/>

</td>

</tr >

HTML представление Tapestry <form jwcid=&quot;@Form&quot; delegate=&quot;ognl:beans.delegate&quot; name=&quot;userForm&quot;> <input type=&quot;hidden&quot; jwcid=&quot;@Hidden&quot; value=&quot;ognl:user.id&quot;/> <table class=&quot;detail&quot;> <tr> <th> <label for=&quot;firstName&quot;><span key=&quot;firstName&quot;>First Name</span></label>: </th> <td><input jwcid=&quot;@TextField&quot; type=&quot;text&quot; value=&quot;ognl:user.firstName&quot; id=&quot;firstName&quot;/></td> </tr> <tr> <th> <label jwcid=&quot;@FieldLabel&quot; field=&quot;ognl:components.lastNameField&quot;>Last Name</label>: </th> <td><input jwcid=&quot;lastNameField&quot; type=&quot;text&quot; id=&quot;lastName&quot;/></td> </tr> <tr> <th> <label for=&quot;birthday&quot;><span key=&quot;birthday&quot;>Birthday</span></label>: </th> <td> <input jwcid=&quot;@DatePicker&quot; format=&quot;message:date.format&quot; type=&quot;text ” size=&quot;11&quot; value=&quot;ognl:user.birthday&quot; id=&quot;birthday&quot;/> </td> </tr >

<form jwcid=&quot;@Form&quot; delegate=&quot;ognl:beans.delegate&quot; name=&quot;userForm&quot;>

<input type=&quot;hidden&quot; jwcid=&quot;@Hidden&quot; value=&quot;ognl:user.id&quot;/>

<table class=&quot;detail&quot;>

<tr>

<th>

<label for=&quot;firstName&quot;><span key=&quot;firstName&quot;>First Name</span></label>:

</th>

<td><input jwcid=&quot;@TextField&quot; type=&quot;text&quot; value=&quot;ognl:user.firstName&quot; id=&quot;firstName&quot;/></td>

</tr>

<tr>

<th>

<label jwcid=&quot;@FieldLabel&quot; field=&quot;ognl:components.lastNameField&quot;>Last Name</label>:

</th>

<td><input jwcid=&quot;lastNameField&quot; type=&quot;text&quot; id=&quot;lastName&quot;/></td>

</tr>

<tr>

<th>

<label for=&quot;birthday&quot;><span key=&quot;birthday&quot;>Birthday</span></label>:

</th>

<td>

<input jwcid=&quot;@DatePicker&quot; format=&quot;message:date.format&quot; type=&quot;text ”

size=&quot;11&quot; value=&quot;ognl:user.birthday&quot; id=&quot;birthday&quot;/>

</td>

</tr >

Улучшения в следующей версии Tapestry Богатая поддержка аннотаций Высокий уровень конфигурирования – базирование на IoC контейнере Hivemind Требует меньше кода – более простая реализация классов реализующих логику страниц Поддержка URL дружественных к пользователю Компоненты Tacos AJAX

Богатая поддержка аннотаций

Высокий уровень конфигурирования – базирование на IoC контейнере Hivemind

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

Поддержка URL дружественных к пользователю

Компоненты Tacos AJAX

JSF ( Краткая характеристика ) Положительные стороны: J2EE Стандарт Быстрая и простая разработка Богата библиотека навигации (аналог Spring Web Flow ) Отрицательные стороны: Мешанина из JSP тэгов Плохая поддержка «легковесных» вызовов ( REST ) Нет единого источника реализации

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

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 edit setUser(mgr.getUser(id)); } return &quot;success&quot;; }

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 edit

setUser(mgr.getUser(id));

}

return &quot;success&quot;;

}

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

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

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

<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=&quot;messages&quot; basename=&quot;messages&quot;/> <h:form id=&quot;userForm&quot;> <h:inputHidden value=&quot;#{userForm.user.id}&quot;> <f:convertNumber/> </h:inputHidden> <h:panelGrid columns=&quot;3&quot; styleClass=&quot;detail&quot; columnClasses=&quot;label&quot;> <h:outputLabel for=&quot;firstName&quot; value=&quot;#{messages['user.firstName']}&quot;/> <h:inputText value=&quot;#{userForm.user.firstName}&quot; id=&quot;firstName&quot;/> <h:message for=&quot;firstName&quot; styleClass=&quot;errorMessage&quot;/> <h:outputLabel for=&quot;lastName&quot; value=&quot;#{messages['user.lastName']}&quot;/> <h:inputText value=&quot;#{userForm.user.lastName}&quot; id=&quot;lastName&quot; required=&quot;true&quot;/> <h:message for=&quot;lastName&quot; styleClass=&quot;errorMessage&quot;/> <h:outputLabel for=&quot;birthday&quot; value=&quot;#{messages['user.birthday']}&quot;/> <t:inputCalendar monthYearRowClass=&quot;yearMonthHeader&quot; weekRowClass=&quot;weekHeader&quot; id=&quot;birthday&quot; currentDayCellClass=&quot;currentDayCell&quot; value=&quot;#{userForm.user.birthday}&quot; renderAsPopup=&quot;true&quot; addResources=&quot;false&quot;/> <h:message for=&quot;birthday&quot; styleClass=&quot;errorMessage&quot;/>

<f:view>

<f:loadBundle var=&quot;messages&quot; basename=&quot;messages&quot;/>

<h:form id=&quot;userForm&quot;>

<h:inputHidden value=&quot;#{userForm.user.id}&quot;>

<f:convertNumber/>

</h:inputHidden>

<h:panelGrid columns=&quot;3&quot; styleClass=&quot;detail&quot; columnClasses=&quot;label&quot;>

<h:outputLabel for=&quot;firstName&quot; value=&quot;#{messages['user.firstName']}&quot;/>

<h:inputText value=&quot;#{userForm.user.firstName}&quot; id=&quot;firstName&quot;/>

<h:message for=&quot;firstName&quot; styleClass=&quot;errorMessage&quot;/>

<h:outputLabel for=&quot;lastName&quot; value=&quot;#{messages['user.lastName']}&quot;/>

<h:inputText value=&quot;#{userForm.user.lastName}&quot; id=&quot;lastName&quot; required=&quot;true&quot;/>

<h:message for=&quot;lastName&quot; styleClass=&quot;errorMessage&quot;/>

<h:outputLabel for=&quot;birthday&quot; value=&quot;#{messages['user.birthday']}&quot;/>

<t:inputCalendar monthYearRowClass=&quot;yearMonthHeader&quot;

weekRowClass=&quot;weekHeader&quot; id=&quot;birthday&quot;

currentDayCellClass=&quot;currentDayCell&quot; value=&quot;#{userForm.user.birthday}&quot;

renderAsPopup=&quot;true&quot; addResources=&quot;false&quot;/>

<h:message for=&quot;birthday&quot; styleClass=&quot;errorMessage&quot;/>

JSP представление JSF <f:view> <f:loadBundle var=&quot;messages&quot; basename=&quot;messages&quot;/> <h:form id=&quot;userForm&quot;> <h:inputHidden value=&quot;#{userForm.user.id}&quot;> <f:convertNumber/> </h:inputHidden> <h:panelGrid columns=&quot;3&quot; styleClass=&quot;detail&quot; columnClasses=&quot;label&quot;> <h:outputLabel for=&quot;firstName&quot; value=&quot;#{messages['user.firstName']}&quot;/> <h:inputText value=&quot;#{userForm.user.firstName}&quot; id=&quot;firstName&quot;/> <h:message for=&quot;firstName&quot; styleClass=&quot;errorMessage&quot;/> <h:outputLabel for=&quot;lastName&quot; value=&quot;#{messages['user.lastName']}&quot;/> <h:inputText value=&quot;#{userForm.user.lastName}&quot; id=&quot;lastName&quot; required=&quot;true&quot; /> <h:message for=&quot;lastName&quot; styleClass=&quot;errorMessage&quot;/> <h:outputLabel for=&quot;birthday&quot; value=&quot;#{messages['user.birthday']}&quot;/> <t:inputCalendar monthYearRowClass=&quot;yearMonthHeader&quot; weekRowClass=&quot;weekHeader&quot; id=&quot;birthday&quot; currentDayCellClass=&quot;currentDayCell&quot; value=&quot;#{userForm.user.birthday}&quot; renderAsPopup=&quot;true&quot; addResources=&quot;false&quot;/> <h:message for=&quot;birthday&quot; styleClass=&quot;errorMessage&quot;/>

<f:view>

<f:loadBundle var=&quot;messages&quot; basename=&quot;messages&quot;/>

<h:form id=&quot;userForm&quot;>

<h:inputHidden value=&quot;#{userForm.user.id}&quot;>

<f:convertNumber/>

</h:inputHidden>

<h:panelGrid columns=&quot;3&quot; styleClass=&quot;detail&quot; columnClasses=&quot;label&quot;>

<h:outputLabel for=&quot;firstName&quot; value=&quot;#{messages['user.firstName']}&quot;/>

<h:inputText value=&quot;#{userForm.user.firstName}&quot; id=&quot;firstName&quot;/>

<h:message for=&quot;firstName&quot; styleClass=&quot;errorMessage&quot;/>

<h:outputLabel for=&quot;lastName&quot; value=&quot;#{messages['user.lastName']}&quot;/>

<h:inputText value=&quot;#{userForm.user.lastName}&quot; id=&quot;lastName&quot; required=&quot;true&quot; />

<h:message for=&quot;lastName&quot; styleClass=&quot;errorMessage&quot;/>

<h:outputLabel for=&quot;birthday&quot; value=&quot;#{messages['user.birthday']}&quot;/>

<t:inputCalendar monthYearRowClass=&quot;yearMonthHeader&quot;

weekRowClass=&quot;weekHeader&quot; id=&quot;birthday&quot;

currentDayCellClass=&quot;currentDayCell&quot; value=&quot;#{userForm.user.birthday}&quot;

renderAsPopup=&quot;true&quot; addResources=&quot;false&quot;/>

<h:message for=&quot;birthday&quot; styleClass=&quot;errorMessage&quot;/>

JSP представление JSF <f:view> <f:loadBundle var=&quot;messages&quot; basename=&quot;messages&quot;/> <h:form id=&quot;userForm&quot;> <h:inputHidden value=&quot;#{userForm.user.id}&quot;> <f:convertNumber/> </h:inputHidden> <h:panelGrid columns=&quot;3&quot; styleClass=&quot;detail&quot; columnClasses=&quot;label&quot;> <h:outputLabel for=&quot;firstName&quot; value=&quot;#{messages['user.firstName']}&quot;/> <h:inputText value=&quot;#{userForm.user.firstName}&quot; id=&quot;firstName&quot;/> <h:message for=&quot;firstName&quot; styleClass=&quot;errorMessage&quot;/> <h:outputLabel for=&quot;lastName&quot; value=&quot;#{messages['user.lastName']}&quot;/> <h:inputText value=&quot;#{userForm.user.lastName}&quot; id=&quot;lastName&quot; required=&quot;true&quot; /> <h:message for=&quot;lastName&quot; styleClass=&quot;errorMessage&quot;/> <h:outputLabel for=&quot;birthday&quot; value=&quot;#{messages['user.birthday']}&quot;/> <t:inputCalendar monthYearRowClass=&quot;yearMonthHeader&quot; weekRowClass=&quot;weekHeader&quot; id=&quot;birthday&quot; currentDayCellClass=&quot;currentDayCell&quot; value=&quot;#{userForm.user.birthday}&quot; renderAsPopup=&quot;true&quot; addResources=&quot;false&quot;/> <h:message for=&quot;birthday&quot; styleClass=&quot;errorMessage&quot;/>

<f:view>

<f:loadBundle var=&quot;messages&quot; basename=&quot;messages&quot;/>

<h:form id=&quot;userForm&quot;>

<h:inputHidden value=&quot;#{userForm.user.id}&quot;>

<f:convertNumber/>

</h:inputHidden>

<h:panelGrid columns=&quot;3&quot; styleClass=&quot;detail&quot; columnClasses=&quot;label&quot;>

<h:outputLabel for=&quot;firstName&quot; value=&quot;#{messages['user.firstName']}&quot;/>

<h:inputText value=&quot;#{userForm.user.firstName}&quot; id=&quot;firstName&quot;/>

<h:message for=&quot;firstName&quot; styleClass=&quot;errorMessage&quot;/>

<h:outputLabel for=&quot;lastName&quot; value=&quot;#{messages['user.lastName']}&quot;/>

<h:inputText value=&quot;#{userForm.user.lastName}&quot; id=&quot;lastName&quot; required=&quot;true&quot; />

<h:message for=&quot;lastName&quot; styleClass=&quot;errorMessage&quot;/>

<h:outputLabel for=&quot;birthday&quot; value=&quot;#{messages['user.birthday']}&quot;/>

<t:inputCalendar monthYearRowClass=&quot;yearMonthHeader&quot;

weekRowClass=&quot;weekHeader&quot; id=&quot;birthday&quot;

currentDayCellClass=&quot;currentDayCell&quot; value=&quot;#{userForm.user.birthday}&quot;

renderAsPopup=&quot;true&quot; addResources=&quot;false&quot;/>

<h:message for=&quot;birthday&quot; styleClass=&quot;errorMessage&quot;/>

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

Унифицированный EL – лучшая поддержка JSTL

Фокусировка на лёгком использовании

Расширенная поддержка AJAX

Дополнительные реализации: ADF Faces, Facelets

Сравнение . Критерии Сортируемые / Листаемые списки – насколько просто создать список данных с листаемыми страницами и возможностями сортировки. Возможность создания закладок – может ли пользователь создавать закладки на страницы для последующего обращения к ним? Валидация - проверка введённых значений. Тестируемость – возможности для автономного тестирования классов, составляющих клиента, вне контейнера.

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

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

Валидация - проверка введённых значений.

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

Сравнение . Критерии Интернационализация Модификация «на лету» - принятие исправлений без необходимости перекомпиляции или перезапуска контейнера Поддержка разработчиками Производительность / Масштабируемость «Компонетность» - возможность создания повторно-используемых, параметризуемых модулей Возможности языка выражений

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

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

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

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

«Компонетность» - возможность создания повторно-используемых, параметризуемых модулей

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

Сортируемые / Листаемые списки JSP – никакой поддержки Spring & Struts могут использовать библиотеки тэгов, типа “DisplayTag” Tapestry имеет contrib:Table компонент JSF имеет h:dataTable компонент без возможностей сортировки – необходимо писать свою собственную логику для реализации данного функционала

JSP – никакой поддержки

Spring & Struts могут использовать библиотеки тэгов, типа “DisplayTag”

Tapestry имеет contrib:Table компонент

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

Возможность создания закладок JSP, String & Strut имеют полный контроль над строкой запроса Tapestry имеет слегка корявую поддержку создания закладок, но всё же все возможности реализованы JSF делает POST для всего – закладки даже не рассматриваются (но при желании и это можно обойти)

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

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

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

Валидация JSP – «собственные» решения, либо перенос проверки в модель данных String & Struts используют проект Apache – Commons Validator – надёжное и зрелое решение Tapestry – хорошая архитектура валидации – хорошие сообщения (даже без необходимости корректировки под свои нужды) JSF – «некрасивые» сообщения об ошибках по-умолчанию (но легко исправляется)

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

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

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

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

Тестируемость Struts – необходимо использование StrutsTestCase JSP, Spring – легко тестируется с использованием средств генерации «заглушек» ( mock ) (EasyMock, jMock, Spring Mock…) Tapestry – неочевидное тестирование, т.к. классы абстрактные – класс Creator помогает JSF – самое простая архитектура для тестирования – классы – просто бины

Struts – необходимо использование StrutsTestCase

JSP, Spring – легко тестируется с использованием средств генерации «заглушек» ( mock ) (EasyMock, jMock, Spring Mock…)

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

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

Интернационализация JSTL <fmt:message> позволяет делать это легко почти в любой реализации JSP, Struts, Spring, JSF – используют один ResourceBundle на язык Tapestry – предпочитает отдельные файлы для страниц / компонентов JSF требует, что данные с локализацией были объявлены на каждой странице

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

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

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

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

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

Add a comment

Related pages

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

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

Стажировка-2014, занятие 8. Общая архитектура web ...

Общая архитектура web-приложений, web frameworks. by 7bits. on Jul 08, 2015. ... Средства разработки web ...
Read more

3 средства автоматизации проектирования корпоративных ...

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

Презентация на тему: "logo_M_color". Скачать бесплатно и ...

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

Поддержка разработки веб-приложений HTML5

Поддержка разработки ... Функция Responsive Web ... Предусмотрены средства ...
Read more

Кроссплатформенные фреймворки vs. native-инструменты. Что ...

... которые предназначены для разработки web-приложений, ... для них средства разработки.
Read more

Разработка WEB приложений - VironIT

Домой » Услуги » Разработка web приложений ... разработки веб ... средства ...
Read more

Download Microsoft .NET Framework 4 (веб-установщик) from ...

Framework 4 требуется для выполнения и разработки приложений, ... Web Developer. Size: 349 ... средства ...
Read more