Эффективный способ обработки JSP с помощью JavaBeans

Автор: content Понедельник, Апрель 9th, 2012 Нет комментариев

Рубрика: Язык Java

Очередная версия концепции технологии JavaServer Pages Model II уже получила достаточно широкую известность среди сообщества JSP-разработчиков. Основная идея данной концепции заключается в том, чтобы визуальное представление (HTML) было отделено от программного кода, выполняющего обработку. В данной статье предлагается рассмотреть удобный способ перемещения динамичного содержания, обработки и системы валидации из самой страницы JavaServer Page в соответствующий компонент JavaBean. Данная методика предполагает использование проектной модели Template Method Design Pattern, позволяющей реализовывать и многократно использовать стандартное поведение и дизайн JSP в пределах всего Web-приложения. Кроме того, такая модель обеспечивает простой механизм коммуникации между винами в рамках одной HTTP-сессии.

Технология 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» 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» 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.setRequest(request); %>
<% _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-приложений, методология разработки программного обеспечения.
Источник: http://www.javaportal.ru/java/articles/JSP_JavaBeans.html

Оставить комментарий

Чтобы оставлять комментарии Вы должны быть авторизованы.

Похожие посты