Эффективный способ обработки JSP с помощью JavaBeans
Очередная версия концепции технологии JavaServer Pages Model II уже получила достаточно широкую известность среди сообщества JSP-разработчиков. Основная идея данной концепции заключается в том, чтобы визуальное представление (HTML) было отделено от программного кода, выполняющего обработку. В данной статье предлагается рассмотреть удобный способ перемещения динамичного содержания, обработки и системы валидации из самой страницы JavaServer Page в соответствующий компонент JavaBean. Данная методика предполагает использование проектной модели Template Method Design Pattern, позволяющей реализовывать и многократно использовать стандартное поведение и дизайн JSP в пределах всего Web-приложения. Кроме того, такая модель обеспечивает простой механизм коммуникации между винами в рамках одной HTTP-сессии.
Содержание
- Обзор статической структуры
- Пример JSP
- Применение проектной модели Template Method Design Pattern
- Обработка форм, динамическое содержание, взаимодействие bean-компонентов
- Дополнения: среда моделирования
- Дополнения: пример
- Заключение
Технология JavaServer Pages (JSP) предлагает широкий выбор средств, облегчающих создание Web-приложений. Тем не менее, при использовании этих средств без предварительного планирования и структуры ваш код может незаметно для вас превратиться в смесь меток HTML, JSP и Java-кода, которую будет очень сложно анализировать, отлаживать и в последствии сопровождать. Задача, таким образом, заключается в том, чтобы изолировать код JSP, который очень похож на HTML, переместив рабочий код в компоненты JavaBeans. Преимущество такого подхода заключается в том, что HTML-программист или графический дизайнер могут заниматься разработкой визуальной части (с помощью многочисленных HTML-редакторов), в то время как вы - Java-программист - будете заниматься логикой приложения. Кроме того, такой подход позволит вам легко изменять "look and feel" одного и того же Web-приложения.
Предлагаемая мной модель "Template Method Design Рattern" позволяет применять одинаковый дизайн для всего приложения и реализовывать одинаковое поведение в каждой из JSP. В понятие поведения включены управление состоянием страницы, одинаковая обработка страницы и возникающих ошибок и механизм предоставления данных для совместного использования несколькими страницами. Это всё определяется только один раз, оставляя вам только необходимость заниматься специфическими особенностями конкретной страницы.
В качестве примера использования этой модели я покажу простое приложение для голосования. Было бы неплохо, если бы вы владели основами JSP и Java, и не помешали бы кое-какие знания UML.
Обзор статической структуры
В этом разделе приводится описание основных действующих элементов модели, а также образец приложения для голосования.
Центральный элемент данной оболочки состоит из двух стандартных файлов для включения JSP (JSP include file) и двух классов, описываемых далее. Их роль заключается в том, чтобы представлять стандартное поведение:- includeheader.jsp : Включать JSP-файл, который должен статично вноситься в начало каждой JSP.
- includefooter.jsp : Включать JSP-файл, который должен статично вноситься в конец каждой JSP.
- AbstractJSPBean: Абстрактный класс, который вы должны будете использовать в качестве прототипа (super type) всех классов JavaBean для JSP. Это основной класс нашей модели.
- SharedSessionBean : Используется для обеспечения связей между всеми JavaBean-объектами JSP в рамках одной HTTP-сессии.
Назначение Web-страницы JSP заключается в представлении данных. Каждая JSP должна иметь соответствующий компонент JavaBean, выполняющий специфическую для данной страницы логику. Каждая страница JSP должна статично включать в себя includeheader.jsp и includefooter.jsp. Каждый JavaBean должен расширять AbstractJSPBean, содержащий шаблонные методы, обеспечивающие стандартное поведение.
Приложение для голосования состоит из следующих JS-страниц и соответствующих им JavaBean-компонентов:
- login.jsp, LoginJSPBean : Аутентификация и log для голосования
- vote.jsp, VoteJSPBean : Выполнение голосования
- confirmation.jsp, ConfirmationJSPBean: Показ подтверждения и результатов голосованияface="Arial Cyr">
Мы не будем очень подробно рассматривать классы, которые эмулируют базу данных или бизнес-логику (Voter , Candidate и VoteDB), но они нужны для нашему примеру для нормальной работы. А теперь, поскольку внешнюю сторону я объяснил, давайте заглянем внутрь одной страницы JSP.
Пример JSP
Каждая страница должна придерживаться определённой структуры, чтобы соответствовать нашей модели.
Пример 1. login.jsp <% AbstractJSPBean
_abstractJSPBean = _loginJSPBean; %>
<%@ include
file="includeheader.jsp" %>
<html>
<head><title>Vote
Login</title></head>
<body
bgcolor="white">
<font size=4>
Please enter your Voter ID and Password
</font>
<font size="3" color="Red">
<jsp:getProperty name="_loginJSPBean"
property="errorMsg"/>
</font>
<font size=3>
<form
method=post>
Voter ID <input
type=text name=voterId value=<jsp:getProperty
name="_loginJSPBean"
property="voterId"/>>
Password <input type=password name=password
value=<jsp:getProperty
name="_loginJSPBean"
property="password"/>>
<input type=submit value="Login">
</form>
</font>
</body>
</html>
<%@ include
file="includefooter.jsp" %>
Структура JSP выглядит так: страница начинается несколькими утверждениями (JSP statement). Следующий за ними HTML-код никак не зависит от директив, утверждений, скриплетов и других элементов JSP. Единственным исключением являются директивы. Вам следует использовать только директивы для получения динамического содержания из бин-компонента. И наконец, страница заканчивается директивой включения (JSP include directive).
Рассмотрим некоторые из наиболее существенных утверждений JSP:
<jsp:useBean id="_loginJSPBean"
class="lbm.examples.LoginJSPBean" scope="session"/>
<jsp:setProperty name="_loginJSPBean" property="*"/>
Показанный выше код устанавливает связь между JSP и соответствующим ей бин-компонентом. Второе утверждение имплицитно передаёт значения всех полей формы (хранящихся в виде параметров HTTP-запроса) соответствующим свойствам бин-компонента. Код использует установочные методы бина. Более детальное описание того, как это всё работает можно найти в работе Говинда Сешарди "Advanced form processing using JSP".
<% AbstractJSPBean _abstractJSPBean =
_loginJSPBean; %>
<%@ include
file="includeheader.jsp" %>
Первое утверждение позволит includeheader.jsp выполнить стандартную обработку. А includeheader.jsp статично включается во второе утверждение. Обратите внимание, что _loginJSPBean и _abstractJSPBean теперь ссылаются на один и тот же объект, но только через разные интерфейсы.
Пример 2. includeheader.js <%-- Set the SharedSessionBean
--%>
<jsp:useBean id="_sharedSessionBean"
class="lbm.jsputil.SharedSessionBean" scope="session"/>
<%
_abstractJSPBean.setSharedSessionBean(_sharedSessionBean);
%>
<%-- Set implicit Servlet objects --%>
<% _abstractJSPBean.setRequest(request); %>
<% _abstractJSPBean.setResponse(response); %>
<% _abstractJSPBean.setServlet(this); %>
<%-- Perform the processing associated with the JSP
--%>
<% _abstractJSPBean.process(); %>
<%-- If getSkipPageOutput equals false, do not
output the JSP page --%>
<% if (!
_abstractJSPBean.getSkipPageOutput()) { %>
Класс includeheader.jsp является одним из ключевых элементов
нашей модели. Поэтому он будет использоваться всеми JSP-страницами.
Первые два утверждения, используемые в Примере 2, позволяют бин-компонентам JSP (хоть и из разных страниц, но в пределах одной и той же HTTP-сессии) взаимодействовать друг с другом. В принципе, каждая JSP будет иметь два JavaBean-компонента, ассоциирующихся со специфическим для этой JSP JavaBean-компонентом (к примеру, LoginJSPBeanface="Courier New Cyr" ) и стандартным SharedSessionBean. Таким образом, SharedSessionBean будет использоваться как общий элемент для связи всех страниц.
Следующие три утверждения из includeheader.jsp имеют дело имплицитными объектами Servlet.
<% _abstractJSPBean.setResponse(response); %>
<% _abstractJSPBean.setServlet(this); %>
Спецификация JSP обеспечивает доступ к имплицитным объектам, являющимся частью спецификации Java Servlet. Объекты типа request , response и servlet очень часто используются для обработки страницы. Поэтому они передаются в бин-компонент JSP.
<% _abstractJSPBean.process(); %>
Это утверждение инициирует процесс обработки, связанный со
страницей JSP. Как вы можете видеть, вы запускаете метод из
абстрактного бин-компонента JSP, а не какого-то конкретного
LoginJSPBean. Почему? В следующем разделе объясню.
Применение проектной модели Template Method Design Рattern
Основным рабочим элементом Template Method Design Рattern является AbstractJSPBean . Каждый отдельный JavaBean-компонент JSP должен расширять этот класс.
Пример 3. AbstractJSPBean.java package lbm.jsputil;
import java.util.*;
import javax.servlet.http.*;
import javax.servlet.*;
public abstract class
AbstractJSPBean {
/* constants used for _state
*/
public static final int NEW = 0;
public static final int FIRSTPASS = 1;
public
static final int PROC = 2;
public static final int
ERR = -1;
private int _state; // current state
private String _errorMsg; // current message that
is being appended
//
during validation
// private boolean _skipPageOutput;
// should the page output be skipped
private SharedSessionBean _sharedSessionBean;
// used for associating the
// JSP Bean with the HTTP
// Session
/*
standard Servlet objects that need to be setup for each JSP
Bean */
protected HttpServletRequest _request;
protected HttpServletResponse _response;
protected Servlet _servlet;
public
AbstractJSPBean () {
setState(NEW);
}
protected abstract void
beanProcess() throws java.io.IOException;
protected abstract void beanFirstPassProcess() throws
java.io.IOException;
protected abstract void
beanFooterProcess() throws java.io.IOException;
protected abstract String getJSPCode();
public
void process() throws java.io.IOException {
setSkipPageOutput(false); // by default do not skip page
output.
//Specific bean process
// methods can override it.
if (getState() == NEW) {
setState(FIRSTPASS);
beanFirstPassProcess();
}
else {
resetErrorMsg();
setState(PROC);
beanProcess();
}
// validation that all
common fields have been properly set by the
// application this is
actually checking that the code has been
// written properly
String l_err = "";
if (_sharedSessionBean == null) l_err = l_err + ";
SharedSessionBean
must be set";
if (_request ==
null) l_err = l_err + "; Request must be set";
if (_response == null) l_err = l_err + ";
Response must be set";
if (_servlet ==
null) l_err = l_err + "; Servlet must be set";
if (l_err != "") throw new
IllegalStateException(l_err);
}
public void footerProcess() throws java.io.IOException {
beanFooterProcess();
}
protected void addErrorMsg (String addErrorMsg)
{
if (_errorMsg == null) _errorMsg =
addErrorMsg;
else _errorMsg =
_errorMsg + " <br>n" + addErrorMsg;
setState(ERR);
}
protected
void resetErrorMsg () {
_errorMsg =
null;
}
public String getErrorMsg () {
if (_errorMsg == null) return "";
else return _errorMsg;
}
protected void setState (int newState) {
_state = newState;
}
public int getState () {
return _state;
}
public void
setSharedSessionBean (SharedSessionBean newSharedSessionBean)
{
if (_sharedSessionBean == null) {
_sharedSessionBean =
newSharedSessionBean;
_sharedSessionBean.putJSPBean(getJSPCode(), this);
} else {
if (_sharedSessionBean != newSharedSessionBean) {
throw new
IllegalStateException("SharedSessionBean is not set
properly. SharedSessionBean must be the same for all
PageBeans within the session");
}
}
}
public
SharedSessionBean getSharedSessionBean () {
return _sharedSessionBean;
}
public void setSkipPageOutput (boolean newSipPageOutput) {
_skipPageOutput = newSipPageOutput;
}
public boolean getSkipPageOutput () {
return _skipPageOutput;
}
protected void redirect (String redirectURL)
throws java.io.IOException {
// skip
the page output since we are redirecting
setSkipPageOutput(true);
_response.sendRedirect(redirectURL);
}
public void setRequest (HttpServletRequest
newRequest) {
_request = newRequest;
}
public void setResponse
(HttpServletResponse newResponse) {
_response = newResponse;
}
public
void setServlet (Servlet newServlet) {
_servlet = newServlet;
}
}
AbstractJSPBean содержит следующие абстрактные методы: beanFirstPassProcess(), beanProcess() и beanFooterProcess(). Эти методы названы примитивными методами (primitive method). Это просто дежурные методы, которые должны быть реализованы в конкретных подклассах JavaBean-компонентов JSP. Каждый из них расширяется в процессе выполнения конкретной фазы обработки JSP.
- beanFirstPassProcess() -- Обработка, выполняемая при первом обращении к странице, до того как появятся выходные данные. Он удобен для инициализации динамического содержания и подтверждения права доступа к странице. Вы можете посмотреть, как этот метод реализован в классе VoteJSPBean для подтверждения права доступа к странице и управления потоком данных в приложении. (См. Исходный код в разделе Дополнительные источники)
- beanProcess() -- Обработка, выполняемая во время второго и последующих вызовов страницы, до того как появятся выходные данные. Его можно использовать, к примеру, для подтверждения правильности заполнения HTML-форм и обновления баз данных. Вы можете посмотреть, как этот метод реализован в классе LoginJSPBean для выполнения обработки HTML-форм и в классе VoteJSPBean для сохранения информации в базе данных. (См. Исходный код в разделе Дополнительные источники)
- beanFooterProcess() -- Обработка, выполняемая после того как представление выходных данных заканчивается. Вы можете использовать его для окончания или прерывания сессии. . Вы можете посмотреть, как этот метод реализован в классе ConfirmationJSPBean для прекращения сессии, после того как голосование закончилось и появилась страница с подтверждением. (См. Исходный код в разделе Дополнительные источники)
А теперь обратим внимание на метод process(), приведенный ниже:
public void
process() throws java.io.IOException {
setSkipPageOutput(false); // by default do not skip page
output.
//Specific bean process
// methods can override it.
if (getState() == NEW) {
setState(FIRSTPASS);
beanFirstPassProcess();
} else {
resetErrorMsg();
setState(PROC);
beanProcess();
}
....
Сначала метод process() определяет состояние JSP, а затем, в зависимости от этого состояния, вызывает соответствующий примитивный метод. Он также устанавливает и нужное состояние JSP.
Методы process() и footerProcess() названы шаблонными методами (template method). Они вызываются непосредственно из JSP (из includeheader.jsp и includefooter.jsp ). Бин-компоненты не должны переопределять их функции. Шаблонные методы содержат стандартные структурные алгоритмы. Типичный алгоритм шаблонного метода отвечает за процесс обработки в нужные моменты времени вызывает примитивные (абстрактные) методы (beanFirstPassProcess() , beanProcess() и beanFooterProcess()), реализация которых зависит от конкретного JavaBean-компонента JSP. Структурные алгоритмы могут также вызывать и конкретные методы, реализованные в AbstractJSPBean. Все только что сказанное представляет собой сущность проектной модели Template Method Design Pattern.Преимущества этого подхода заключаются в следующем:
- Вы можете многократно использовать один и тот же код, заложив стандартное поведение в шаблонном методе.
- Вы применяете одинаковый дизайн и поведение в пределах всего приложения.
Кроме логики обработки, AbstractJSPBean содержит следующие методы, помогающие подклассам (JavaBean-компонента конкретного JSP) реализовывать свои задачи в процессе обработки. Эти методы тоже нельзя переопределять.
- Методы для обработки ошибок пользователя -- addErrorMsg() , resetErrorMsg() и getErrorMsg()
- Методы для управления состоянием страницы -- setState() и getState()
- Методы для управления связями с SharedSessionBean
- Методы, определяющие, выдавать ли получаемый результат в виде HTML как части JSP или нет -- setSkipPageOutput() и getSkipPageOutput()
- Метод redirect
- Методы доступа к объектам сервлета -- request , response и servlet
Обработка форм, динамическое содержание, взаимодействие bean-компонентов
В Примере 4 показан один из JavaBean-компонентов JSP, LoginJSPBean, который реализует специфический для страницы механизм обработки.
Пример 4. LoginJSPBean package lbm.examples;
import lbm.jsputil.*;
import java.util.*;
public class LoginJSPBean extends AbstractJSPBean {
public static final String PAGE_CODE = "login";
private String _voterId;
private String _password;
private Voter
_voter = null;
public LoginJSPBean() {
}
public void setVoterId (String
newVoterId) {
_voterId = newVoterId;
}
public String getVoterId() {
if (_voterId == null) return
"";
else return _voterId;
}
public void setPassword (String
newPassword) {
_password = newPassword;
}
public
String getPassword() {
if
(_password == null) return "";
else return _password;
}
public Voter getVoter () {
return
_voter;
}
protected void beanProcess () throws java.io.IOException
{
if (_voterId == null ||
_voterId.equals("")) {
addErrorMsg("Voter must be entered");
}
if
(_password == null || _password.equals("")) {
addErrorMsg("Password must
be entered");
}
if (getState() != ERR) {
//If all the fields are entered, try to login the voter
Voter voter =
VoteDB.login(_voterId, _password);
if (voter == null) {
addErrorMsg("Unable to authenticate the Voter.
Please try
again.");
}
else {
_voter = voter;
if (_voter.getVotedForCandidate() != null) {
// if the voter
has already voted, send the voter to the last
// page redirect("confirmation.jsp");
}
else {
// go to the Vote page
redirect("vote.jsp");
}
}
}
}
protected void beanFirstPassProcess() throws
java.io.IOException {
}
protected
void beanFooterProcess() throws java.io.IOException {
}
protected String getJSPCode() {
return PAGE_CODE;
}
}
Обратите внимание на set- и get-методы класса LoginJSPBean. Как отмечалось ранее, они используются для обеспечения динамичного соответствия и для передачи значений между полями формы (параметры запросов) и свойствами бин-компонента.
Метод beanProcess(), показанный в том же Примере 4, иллюстрирует некоторые основные моменты обработки. Этот метод выполняется во время второго и последующих вызовов страницы, прежде чем начнёт выдаваться результат. Это означает, что он будет выполнен только после того, как пользователь нажмёт на кнопку Login и сработает соответствующее действие.
Сначала вы подтверждаете, что обязательные для ввода поля voterId и password заполнены. О любой обнаруженной ошибке тут же сообщается вызовом метода addErrorMsg . Этот метод устанавливает свойство errorMsg класса AbstractJSPBean, которое используется JSP для отображения ошибок пользователя:
<jsp:getProperty name="_loginJSPBean"
property="errorMsg"/>
Если подтверждение правильности ввода данных проходит успешно, метод beanProcess() вызывает базу данных для подтверждения прав пользователя. И в конце он переадресует полученный ответ на соответствующую страницу, вызвав метод redirect(). Реализованный в классе AbstractJSPBean . >
А теперь давайте рассмотрим несколько методов из класса VoteJSPBean. Они проиллюстрируют другие аспекты нашей модели, такие как взаимодействие между JavaBean-компонентами JSP и управлением процессом выполнения приложения.
Пример 5. Метод beanFirstPassProcess() класса VoteJSPBean > protected void
beanFirstPassProcess() throws java.io.IOException {
// get the Voter from Login page
_voter = null;
LoginJSPBean loginJSPBean =
(LoginJSPBean)
getSharedSessionBean().getJSPBean(LoginJSPBean.PAGE_CODE);
if (loginJSPBean != null) {
_voter =
loginJSPBean.getVoter();
}
if (_voter == null) {
// voter is not logged in yet.
Send it to Login page
setState(NEW);
redirect("login.jsp");
}
}face="Courier New">
Показанный метод использует объект _sharedSessionBean класса AbstractJSPBean. Класс SharedSessionBean использует простой метод, обеспечивающий взаимодействие между всеми JavaBean-объектами JSP в рамках одной HTTP-сессии. Он хранит карту (Map) всех JavaBean-компонентов JSP в рамках одной сессии. Map является интерфейсом, соединяющим Java Collections framework, представленную в Java 1.2. Для тех знаком с Java 1.1, это очень сильно будет напоминать Hashtable. Ключом к JavaBean-компоненту JSP будет PAGE_CODE, который хранится в виде постоянной в каждом из классов JavaBean-компонентов JSP.
В этом примере метод beanFirstPassProcess() сначала определяет местонахождения объекта LoginJSPBean. Затем он достаёт объект Voter из объекта LoginJSPBean и сохраняет ссылку на него для последующего использования. Если Voter равен нулю, это значит, что пользователь попал на страницу голосования, не зарегистрировавшись вначале, и значит, будет переадресован на Login-страницу. Это простой пример управления процессом выполнения приложения. Можно создать и более сложные методы, использовать умные диспетчеры, но это выходит за рамки нашего обсуждения.
Пример 6. Метод getCandidateList() класса VoteJSPBea public String
getCandidateList () {
StringBuffer
candidateList = new StringBuffer();
Candidate candidate;
Iterator candidates = VoteDB.getCandidates();
while (candidates.hasNext()) {
candidate = (Candidate) candidates.next();
candidateList.append("<input type=radio
name="candidateName" value="");
candidateList.append(candidate.getName());
candidateList.append(""> ");
candidateList.append(candidate.getName());
candidateList.append("<br>n");
}
return candidateList.toString();
}
Метод getCandidateList(), показанный ниже, вызывается из с помощью следующего утверждения:
<jsp:getProperty name="_voteJSPBean"
property="candidateList"
Задача метода заключается в том, чтобы обеспечивать содержание HTML на основе данных, получаемых из базы данных. Это требует от Java-программиста владеть знаниями в области HTML. В противном случае, вы можете обзавестись библиотекой утилит HTML, которые будут формировать HTML за вас. Утилиты могли бы брать уже заранее подготовленные типы входных данных, вроде Iterator, и выдавать полученный результат в виде заранее созданного формата. Ещё одним вариантом может быть использование библиотек меток (См. Дополнительные источники)
Дополнения: среда моделирования
Отделив друг от друга визуальную часть и логику, модель даёт вам возможность модифицировать и то (JSP) и другое (bean) независимо друг от друга. То есть вы можете изменять логику в бин-компонентах, даже не прикасаясь к JSP, при условии что свойства бинов (сигнатуры их методов доступа) останутся неизменными. То же самое относится и к коду JSP, что предоставляет полную свободу HTML-разработчикам и графическим дизайнерам в вопросе изменения внешнего вида сайта без необходимости залазить в Java-код.
Вы также можете модифицировать и ключевые компоненты самой модели, чтобы они отвечали требованиям конкретного приложения. Можно добавить новые вспомогательные или переделать имеющиеся шаблонные методы. Важно не забывать, что ваши JSP и JavaBean-компоненты должны согласовываться друг с другом в рамках всего приложения.
Такая среда моделирования может показаться в начале сложной, что в принципе справедливо, учитывая три страницы кода в качестве примера приложения. Тем не менее, когда вы сами начнёте писать своё приложение, вы заметите, как всё чётко укладывается на своё место, и что объём кода, который вы пишите, растёт значительнее медленнее, чем сложность вашего приложения.
Показанная здесь модель не относится к многоуровневым средам, обычно используемым в Web-приложениях. В принципе речь в данном случае идёт только об уровне визуального представления данных с помощью JSP. Для построения трёх- и более уровневых систем придётся использовать не только JavaBean-компоненты, но и Enterprise JavaBean-компоненты, к которым они будут обращаться, или другие варианты реализации бизнес-логики.
Мой пример иллюстрирует применение среды моделирования для приложений, отслеживающих работу HTTP-сессий. Тем не менее, эта модель будет прекрасно работать, даже если вы не захотите полагаться на сессии. И страницы приложения и порядок его работы должны моделироваться независимо друг от друга. Возможно, что SharedSessionBean вам не понадобится. Вполне возможно, что вам нужны будут отдельные страницы для представления данных и отдельные для обработки и подтверждения, а HTML будет не нужен. Для этих целей можно воспользоваться beanFirstPassProcess() методом.
Дополнения: пример
Я применил и протестировал пример с помощью Tomcat 3.1. Он совместим со
спецификациями JSP 1.1 и Servlet 2.2. В этой статье не
рассматривались особенности применения JSP и Tomcat (См. Дополнительные источники)
Ознакомьтесь с исходным кодом класса VoteDB, чтобы получить Voter
Ids, которым вы сможете пользоваться для лога в процессе
тестирования (пароли такие же, как и IDs). Чтобы пример правильно
работал в браузере, нужно будет разрешить cookies. Если вы хотите,
что бы приложение работало без них, понадобится переписать
URL-адреса (с помощью метода encodeURL() из класса
javax.servlet.http.HttpServletResponse ). Придётся переписывать все
адреса в приложении, включая ссылки на ваши JSP, действия в метках
форм и адреса, используемые для переадресации HTTP-ответов в
JavaBean-компоненты JSP.
Заключение
Среда моделирования, предложенная в этой статье, представляет собой вполне доступное решение для проектирования JSP-приложений. Она позволяет неоднократно использовать созданный код, определяет архитектуру приложения и допускает возможность дальнейшего расширения. Одним из наиболее существенных преимуществ этой модели является возможность отделения логики от визуального представления для их независимого модифицирования.
Об авторе
Milan Adamovic является независимым консультантом и
живёт и работает в Ванкувере, Британская Колумбия, Канада. В сферу
его обязанностей входят системный анализ и проектирование,
(объектно-ориентированный анализ и проектирование, UML, Oracle CASE,
проектирование баз данных), программирование на Java для серверов
(сервлеты, JSP, EJB), база данных Oracle и другие программные языки.
Круг его интересов также включает Интернет-технологии, архитектуры
Web-приложений, методология разработки программного обеспечения.