<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.linuxformat.ru/wiki/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://wiki.linuxformat.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Haanp</id>
		<title>Linuxformat - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.linuxformat.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Haanp"/>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:Contributions/Haanp"/>
		<updated>2026-05-13T13:32:22Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.19.20+dfsg-0+deb7u3</generator>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF91:Java_EE</id>
		<title>LXF91:Java EE</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF91:Java_EE"/>
				<updated>2008-10-18T03:27:50Z</updated>
		
		<summary type="html">&lt;p&gt;Haanp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java EE}}&lt;br /&gt;
''{{oncolor||red|ЧАСТЬ 3}} Каждый линусоид знает, что система уровня предприятия должна обеспечивать разграничение доступа. Антон Черноусов расскажет, что может предложить здесь Java EE.&lt;br /&gt;
__TOC__&lt;br /&gt;
В прошлый раз вы, под чутки руководством Александра, разобрались с JSP и переписали &amp;quot;Телефонную книгу&amp;quot; с учетом этой технологии. Сегодня мы двинемся дальше и поговорим об авторизации, сессиях, фильтрах и использовании разделяемых объектов в web-приложениях.&lt;br /&gt;
==Процесс передачи информации==&lt;br /&gt;
Давайте рассмотрим стандартную ситуацию: пользователь вызывает различные страницы одного web-приложения. Если бы этот &amp;quot;диалог&amp;quot; происходил по телефону, он был бы примерно таким:&lt;br /&gt;
*'''Пользователь (набирает номер): Алло, это приложение?'''&lt;br /&gt;
*Приложение: Да, это приложение.&lt;br /&gt;
*(Пользователь кладет трубку)&lt;br /&gt;
*'''Пользователь (набирает номер): Меня зовут Георг.'''&lt;br /&gt;
*Приложение: Да, Георг, мы вас внимательно слушаем.&lt;br /&gt;
*(Пользователь кладет трубку)&lt;br /&gt;
*'''Пользователь (набирает номер): Дайте мне, пожалуйста, всю информацию.'''&lt;br /&gt;
*Приложение: Возьмите...&lt;br /&gt;
Отметим, что после каждого обмена репликами пользователь кладет трубку, разрывая соединение - именно таким образом в большинстве случаев и происходит обмен данными между браузером пользователя и сервером, на котором работает web-приложение. Возникает резонный вопрос: как передавать информацию между соединениями, открываемые в рамках одной сессии? Для этого могут использоваться самые различные методы:&lt;br /&gt;
*перезапись URL;&lt;br /&gt;
*скрытые поля;&lt;br /&gt;
*cookie;&lt;br /&gt;
*сессионный объект.&lt;br /&gt;
Из всех представленных методов наиболее простым и в тоже время можным является сессионный объект (Session), реализованный в Java посредством интерфейса {{oncolor||red|javax.servlet.http.Session}}.&lt;br /&gt;
Ранее, чтобы получить данные от пользователя или обеспечить возможность их транспортировки внутри приложения, мы использовали объект типа &lt;br /&gt;
{{oncolor||red|HttpServletRequest}}. Основное отличие {{oncolor||red|HttpSession}} заключается во времени жизни, схематично изображенном на '''Рис.1'''. Объект типа {{oncolor||red|HttpServletRequest}} предназначен для передачи запроса (и необходимых данных) от браузера к web-приложению и существует только между запросом и ответом, в то время как объект {{oncolor||red|HttpSession}} обеспечивает средства для хранения и доступа к данным пользователя на протяжениии всего периода работы с приложением.&lt;br /&gt;
)(Рис.1) Время жизни объектов HttpServletRequest и HttpSession.&lt;br /&gt;
Следует, однако, иметь в виду, что отследить момент, когда пользователь перестает работать с приложением, не всегда возможно. Поэтому в настройках сервера устанавливается некоторое предельное время существования объекта {{oncolor||red|HttpSession}} после получения последнего запроса.&lt;br /&gt;
==Сессия==&lt;br /&gt;
Объект session в JSP является предопределеным, то есть с ним можно сразу же начинать работать. Чтобы создать сессионный объект в сервлете, воспользуемся следующим методом:&lt;/div&gt;</summary>
		<author><name>Haanp</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF91:Java_EE</id>
		<title>LXF91:Java EE</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF91:Java_EE"/>
				<updated>2008-10-17T16:30:15Z</updated>
		
		<summary type="html">&lt;p&gt;Haanp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java EE}}&lt;br /&gt;
''{{oncolor||red|ЧАСТЬ 3}} Каждый линусоид знает, что система уровня предприятия должна обеспечивать разграничение доступа. Антон Черноусов расскажет, что может предложить здесь Java EE.&lt;br /&gt;
__TOC__&lt;br /&gt;
В прошлый раз вы, под чутки руководством Александра, разобрались с JSP и переписали &amp;quot;Телефонную книгу&amp;quot; с учетом этой технологии. Сегодня мы двинемся дальше и поговорим об авторизации, сессиях, фильтрах и использовании разделяемых объектов в web-приложениях.&lt;br /&gt;
==Процесс передачи информации==&lt;br /&gt;
Давайте рассмотрим стандартную ситуацию: пользователь вызывает различные страницы одного web-приложения. Если бы этот &amp;quot;диалог&amp;quot; происходил по телефону, он был бы примерно таким:&lt;br /&gt;
*'''Пользователь (набирает номер): Алло, это приложение?'''&lt;br /&gt;
*Приложение: Да, это приложение.&lt;br /&gt;
*(Пользователь кладет трубку)&lt;br /&gt;
*'''Пользователь (набирает номер): Меня зовут Георг.'''&lt;br /&gt;
*Приложение: Да, Георг, мы вас внимательно слушаем.&lt;br /&gt;
*(Пользователь кладет трубку)&lt;br /&gt;
*'''Пользователь (набирает номер): Дайте мне, пожалуйста, всю информацию.'''&lt;br /&gt;
*Приложение: Возьмите...&lt;br /&gt;
Отметим, что после каждого обмена репликами пользователь кладет трубку, разрывая соединение - именно таким образом в большинстве случаев и происходит обмен данными между браузером пользователя и сервером, на котором работает web-приложение. Возникает резонный вопрос: как передавать информацию между соединениями, открываемые в рамках одной сессии? Для этого могут использоваться самые различные методы:&lt;br /&gt;
*перезапись URL;&lt;br /&gt;
*скрытые поля;&lt;br /&gt;
*cookie;&lt;br /&gt;
*сессионный объект.&lt;br /&gt;
Из всех представленных методов наиболее простым и в тоже время можным является сессионный объект (Session), реализованный в Java посредством интерфейса {{oncolor||red|javax.servlet.http.Session}}.&lt;br /&gt;
Ранее, чтобы получить данные от пользователя или обеспечить возможность их транспортировки внутри приложения, мы использовали объект типа &lt;br /&gt;
{{oncolor||red|HttpServletRequest}}. Основное отличие {{oncolor||red|HttpSession}} заключается во времени жизни, схематично изображенном на '''Рис.1'''. Объект типа {{oncolor||red|HttpServletRequest}} предназначен для передачи запроса (и необходимых данных) от браузера к web-приложению и существует только между запросом и ответом, в то время как объект {{oncolor||red|HttpSession}} обеспечивает средства для хранения и доступа к данным пользователя на протяжениии всего периода работы с приложением.&lt;br /&gt;
)(Рис.1) Время жизни объектов HttpServletRequest и HttpSession.&lt;br /&gt;
Следует, однако, иметь в виду, что отследить момент, когда пользователь перестает работать с приложением, не всегда возможно. Поэтому в настройках сервера устанавливается некоторое предельное время существования объекта {{oncolor||red|HttpSession}} после получения последнего запроса.&lt;/div&gt;</summary>
		<author><name>Haanp</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF91:Java_EE</id>
		<title>LXF91:Java EE</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF91:Java_EE"/>
				<updated>2008-10-17T16:20:41Z</updated>
		
		<summary type="html">&lt;p&gt;Haanp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java EE}}&lt;br /&gt;
''{{oncolor||red|ЧАСТЬ 3}} Каждый линусоид знает, что система уровня предприятия должна обеспечивать разграничение доступа. Антон Черноусов расскажет, что может предложить здесь Java EE.&lt;br /&gt;
__TOC__&lt;br /&gt;
В прошлый раз вы, под чутки руководством Александра, разобрались с JSP и переписали &amp;quot;Телефонную книгу&amp;quot; с учетом этой технологии. Сегодня мы двинемся дальше и поговорим об авторизации, сессиях, фильтрах и использовании разделяемых объектов в web-приложениях.&lt;br /&gt;
==Процесс передачи информации==&lt;br /&gt;
Давайте рассмотрим стандартную ситуацию: пользователь вызывает различные страницы одного web-приложения. Если бы этот &amp;quot;диалог&amp;quot; происходил по телефону, он был бы примерно таким:&lt;br /&gt;
*'''Пользователь (набирает номер): Алло, это приложение?'''&lt;br /&gt;
*Приложение: Да, это приложение.&lt;br /&gt;
*(Пользователь кладет трубку)&lt;br /&gt;
*'''Пользователь (набирает номер): Меня зовут Георг.'''&lt;br /&gt;
*Приложение: Да, Георг, мы вас внимательно слушаем.&lt;br /&gt;
*(Пользователь кладет трубку)&lt;br /&gt;
*'''Пользователь (набирает номер): Дайте мне, пожалуйста, всю информацию.'''&lt;br /&gt;
*Приложение: Возьмите...&lt;br /&gt;
Отметим, что после каждого обмена репликами пользователь кладет трубку, разрывая соединение - именно таким образом в большинстве случаев и происходит обмен данными между браузером пользователя и сервером, на котором работает web-приложение. Возникает резонный вопрос: как передавать информацию между соединениями, открываемые в рамках одной сессии? Для этого могут использоваться самые различные методы:&lt;br /&gt;
*перезапись URL;&lt;br /&gt;
*скрытые поля;&lt;br /&gt;
*cookie;&lt;br /&gt;
*сессионный объект.&lt;br /&gt;
Из всех представленных методов наиболее простым и в тоже время можным является сессионный объект (Session), реализованный в Java посредством интерфейса javax.servlet.http.Session.&lt;/div&gt;</summary>
		<author><name>Haanp</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF91:Java_EE</id>
		<title>LXF91:Java EE</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF91:Java_EE"/>
				<updated>2008-10-15T18:16:00Z</updated>
		
		<summary type="html">&lt;p&gt;Haanp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java EE}}&lt;br /&gt;
''{{oncolor||red|ЧАСТЬ 3}} Каждый линусоид знает, что система уровня предприятия должна обеспечивать разграничение доступа. Антон Черноусов расскажет, что может предложить здесь Java EE.&lt;br /&gt;
__TOC__&lt;br /&gt;
В прошлый раз вы, под чутки руководством Александра, разобрались с JSP и переписали &amp;quot;Телефонную книгу&amp;quot; с учетом этой технологии. Сегодня мы двинемся дальше и поговорим об авторизации, сессиях, фильтрах и использовании разделяемых объектов в web-приложениях.&lt;br /&gt;
==Процесс передачи информации==&lt;br /&gt;
Давайте рассмотрим стандартную ситуацию: пользователь вызывает различные страницы одного web-приложения. Если бы этот &amp;quot;диалог&amp;quot; происходил по телефону, он был бы примерно таким:&lt;br /&gt;
'''Пользователь (набирает номер): Алло, это приложение?'''&lt;br /&gt;
Приложение: Да, это приложение.&lt;br /&gt;
(Пользователь кладет трубку)&lt;/div&gt;</summary>
		<author><name>Haanp</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF91:Java_EE</id>
		<title>LXF91:Java EE</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF91:Java_EE"/>
				<updated>2008-10-15T18:12:24Z</updated>
		
		<summary type="html">&lt;p&gt;Haanp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java EE}}&lt;br /&gt;
''{{oncolor||red|ЧАСТЬ 3}} Каждый линусоид знает, что система уровня предприятия должна обеспечивать разграничение доступа. Антон Черноусов расскажет, что может предложить здесь Java EE.&lt;br /&gt;
__TOC__&lt;br /&gt;
В прошлый раз вы, под чутки руководством Александра, разобрались с JSP и переписали &amp;quot;Телефонную книгу&amp;quot; с учетом этой технологии. Сегодня мы двинемся дальше и поговорим об авторизации, сессиях, фильтрах и использовании разделяемых объектов в web-приложениях.&lt;br /&gt;
==Процесс передачи информации==&lt;br /&gt;
Давайте рассмотрим стандартную ситуацию: пользователь вызывает различные страницы&lt;/div&gt;</summary>
		<author><name>Haanp</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF91:Java_EE</id>
		<title>LXF91:Java EE</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF91:Java_EE"/>
				<updated>2008-10-15T18:11:49Z</updated>
		
		<summary type="html">&lt;p&gt;Haanp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java EE}}&lt;br /&gt;
'{{oncolor||red|ЧАСТЬ 3}} Каждый линусоид знает, что система уровня предприятия должна обеспечивать разграничение доступа. Антон Черноусов расскажет, что может предложить здесь Java EE.&lt;br /&gt;
__TOC__&lt;br /&gt;
В прошлый раз вы, под чутки руководством Александра, разобрались с JSP и переписали &amp;quot;Телефонную книгу&amp;quot; с учетом этой технологии. Сегодня мы двинемся дальше и поговорим об авторизации, сессиях, фильтрах и использовании разделяемых объектов в web-приложениях.&lt;br /&gt;
==Процесс передачи информации==&lt;br /&gt;
Давайте рассмотрим стандартную ситуацию: пользователь вызывает различные страницы&lt;/div&gt;</summary>
		<author><name>Haanp</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF89:Java_EE</id>
		<title>LXF89:Java EE</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF89:Java_EE"/>
				<updated>2008-10-12T18:04:31Z</updated>
		
		<summary type="html">&lt;p&gt;Haanp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java EE}}&lt;br /&gt;
'''Новая серия!''' Учимся писать серверные приложения на Java&lt;br /&gt;
&lt;br /&gt;
== Адресная книга ==&lt;br /&gt;
''ЧАСТЬ 1: Театр, как известно, начинается с вешалки, а приложения уровня предприятий – с адресной книги: надо же где-то хранить сведения о клиентах. '''Александр Бабаев''' готов познакомить вас с азбукой Java EE.''&lt;br /&gt;
&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=Наш эксперт&lt;br /&gt;
|Содержание=&lt;br /&gt;
'''Александр Бабаев'''&amp;lt;br&amp;gt;Разработчик открытой мультиблог-системы jDnevnik – победитель конкурсов IBM WAS CE Contest 2006 и конкурса проектов для разработчиков на Java - Java конкурс 2005.&lt;br /&gt;
|Ширина=150px}}&lt;br /&gt;
&lt;br /&gt;
Один из самых распространенных языков программирования для Интернета на настоящий момент – это PHP. Этот язык изначально задумывался для создания домашних страничек, небольших сайтов – и там работает замечательно.&lt;br /&gt;
&lt;br /&gt;
В отличие от PHP, Java (та ее часть, которая помогает разрабатывать серверные приложения) сразу создавалась для крупных приложений уровня предприятия (так называемых Enterprise Applications). Поэтому в Java есть множество механизмов, которые помогают быстро строить очень крупные приложения. Очень крупные – это десятки тысяч транзакций в минуту. Сложных транзакций.&lt;br /&gt;
&lt;br /&gt;
Обо всех возможностях этой технологии не рассказать ни в рамках одной статьи, ни даже в десятке. Но основные блоки JEE (Java Enterprise Edition), которые полезны не только в крупных приложениях, но и в средних и небольших, мы изучим обязательно. А на основании этого опыта можно будет двигаться дальше, читать книги, разрабатывать сложные системы.&lt;br /&gt;
&lt;br /&gt;
=== Сервлеты ===&lt;br /&gt;
[[Изображение:Img_89_82_1.jpg|thumb|right|450px|'''Рис. 1.''' Процесс обработки запроса]]&lt;br /&gt;
Для начала решим, что же такое сервлет (servlet)? Этим термином принято называть серверное приложение, но чем отличается серверное приложение от клиентского? Клиентское ПО формирует запросы и отсылает их серверному, а задача серверной части – обработать запрос и вернуть на него ответ ('''рис. 1''').&lt;br /&gt;
&lt;br /&gt;
На стороне клиента присутствуют только действия, которые выполняются браузером (показ формы на HTML-странице, формирование стандартизованного запроса).&lt;br /&gt;
&lt;br /&gt;
Серверная сторона в Java обычно состоит из контейнера, который содержит один или несколько сервлетов. Контейнер получает запрос, решает, какому сервлету он предназначен, и запускает на выполнение этот сервлет. Формально происходит примерно следующее:&lt;br /&gt;
&lt;br /&gt;
* Пришедший от клиента запрос анализируется сервлет-контейнером, который создает на его основе специальный объект '''javax.servlet.ServletRequest'''.&lt;br /&gt;
* Контейнер решает (как – обычно описывается в специальном конфигурационном файле), какому сервлету предназначен запрос, и передает ему созданный на предыдущем шаге объект '''javax.servlet.ServletRequest''', а также объект '''javax.servlet.ServletResponse''' – шаблон ответа, в который сервлет пишет все, что нужно возвратить клиенту.&lt;br /&gt;
* Сервлет обрабатывает запрос, заполняет объект '''javax.servlet.ServletResponse''' и после этого завершает работу.&lt;br /&gt;
* Контейнер получает заполненный объект '''javax.servlet.ServletResponse''', после чего преобразует его в стандартизованное сообщение и передает клиенту.&lt;br /&gt;
&lt;br /&gt;
=== Что нам потребуется? ===&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=Коротко о HTTP&lt;br /&gt;
|Содержание=&lt;br /&gt;
Протокол HTTP был предложен Тимом Бернерсом-Ли, работавшим тогда в CERN, в марте 1990 года как механизм для доступа к документам в Интернете и облегчения навигации посредством использования гипертекста. В HTTP разделяются понятия «запрос» и «ответ», то есть то, как браузер запрашивает страницу и то, чем сервер на это отвечает. И запрос, и ответ состоят из заголовка и тела. В запросе присутствует еще и строка запроса. Заголовок описывает передаваемые данные, внутри тела передается обычно результат (страница HTML или файл). Существует несколько типов запросов, но наиболее распространены два:&lt;br /&gt;
* '''GET''' Запрашивает содержимое указанного ресурса.&lt;br /&gt;
* '''POST''' Передает пользовательские данные (например, из формы HTML) заданному ресурсу. Данные включаются в тело запроса.&lt;br /&gt;
&lt;br /&gt;
Вот пример (не точный) простого HTTP-диалога:&amp;lt;br&amp;gt;&lt;br /&gt;
'''Запрос'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GET /site/index.html HTTP/1.1&lt;br /&gt;
Host: ru.wikipedia.org&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Ответ'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTP/1.0 200 OK&lt;br /&gt;
Server: Apache&lt;br /&gt;
Content-Type: text/html; charset=utf-8&lt;br /&gt;
Content-Length: 2121&lt;br /&gt;
(Дальше идет 2121 байт текста странички index.html)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|Ширина=45%}}&lt;br /&gt;
Мы предполагаем, что читатель знаком с тем, что такое HTML, и пробовал делать «странички на PHP» или чем-то аналогичном. Если словосочетания «GET-запрос», «POST-запрос» являются для вас китайской грамотой – прочтите врезку «Коротко об HTTP» (и запаситесь терпением). Подробнее про протокол HTTP можно прочитать в RFC2616, например тут: http://www.w3.org/Protocols/rfc2616/rfc2616.html.&lt;br /&gt;
&lt;br /&gt;
Для работы нам понадобятся следующие инструменты:&lt;br /&gt;
* JDK 5 (или JDK 6) – если вы выполняли все задания предыдущей серии уроков Java, нужный дистрибутив, скорее всего, уже имеется в вашей системе (вы ведь выполняли задания, не так ли?). JDK можно бесплатно загрузить с сайта http://java.sun.com или установить из репозиториев вашего дистрибутива Linux. После установки JDK необходимо убедиться, что пути к каталогу '''$JDK/bin''' прописаны в переменной окружения PATH, а каталоги, в которых располагаются библиотеки классов, перечислены в CLASSPATH.&lt;br /&gt;
* Ваш любимый текстовый редактор.&lt;br /&gt;
* Библиотека Jetty (http://www.mortbay.org/). В принципе, это полноценный web-сервер, который может очень и очень многое. Нам будет полезна его особенность, позволяющая встроить web-сервер в наше приложение.&lt;br /&gt;
&lt;br /&gt;
Все необходимые библиотеки есть на прилагаемом компакт-диске.&lt;br /&gt;
&lt;br /&gt;
=== Что мы будем делать? ===&lt;br /&gt;
Для примера мы возьмем и напишем корпоративную адресную книгу, в которой будем сохранять телефоны сотрудников, причем каждый сможет добавить телефоны нужных людей, и все смогут просмотреть сохраненные телефоны. Итак, начнем.&lt;br /&gt;
&lt;br /&gt;
Создадим иерархию каталогов для проекта, например, такую:&lt;br /&gt;
* '''~/Programming/AddressBook/.'''&lt;br /&gt;
* '''build''' – каталог для скомпилированных классов.&lt;br /&gt;
* '''src''' – исходные тексты.&lt;br /&gt;
* '''libs''' – каталог для библиотек.&lt;br /&gt;
&lt;br /&gt;
Заполним каталоги. Для начала возьмите Jetty, распакуйте архив, найдите в нем файлы '''jetty-6.1.0rc3.jar'''; '''jetty-util-6.1.0rc3.jar'''; '''servlet-api-2.5.jar''' и поместите их в каталог '''libs''' (можно взять и другую версию,&lt;br /&gt;
правда, с известной долей осторожности – иногда меняются API, тогда наша программа просто не скомпилируется).&lt;br /&gt;
&lt;br /&gt;
Теперь настало время придумать, как будет работать наша телефонная книга. Разумно будет создать четыре основных страницы:&lt;br /&gt;
* Главная – на ней будут ссылки помещены на остальные страницы приложения.&lt;br /&gt;
* Страница добавления нового контакта.&lt;br /&gt;
* Страница редактирования контакта.&lt;br /&gt;
* Страница поиска/просмотра контактов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Классов в нашем приложении будет всего три:&lt;br /&gt;
* '''AddressBook.''' Главный класс, который запускается и «висит» в памяти, обрабатывая запросы пользователей. Обычно эту роль выполняет уже упомянутый сервлет-контейнер (роль которого может выполнять, например, Apache Tomcat), но мы избавились от него, использовав Jetty.&lt;br /&gt;
* '''AddressBookHandler.''' Класс-обработчик запросов пользователей. Именно этот класс и называется сервлетом. Он обычно подключается к сервлет-контейнеру через специфический конфигурационный файл, но мы избавились и от этого – спасибо, Jetty!&lt;br /&gt;
* '''Contact.''' Класс, который содержит поля контакта. Эти поля будут выводиться на странице и редактироваться. Его код очень простой:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Листинг 1.''' Контакт&lt;br /&gt;
&amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
import java.io.*;&lt;br /&gt;
public class Contact implements Serializable {&lt;br /&gt;
    private String _name = &amp;quot;&amp;quot;;&lt;br /&gt;
    private String _number = &amp;quot;&amp;quot;;&lt;br /&gt;
    private String _comment = &amp;quot;&amp;quot;;&lt;br /&gt;
    public String getName() { return _name; }&lt;br /&gt;
    public String getNumber() { return _number; }&lt;br /&gt;
    public String getComment() { return _comment; }&lt;br /&gt;
    public void setData(String aName, String aNumber, String aComment) {&lt;br /&gt;
        _name = aName;&lt;br /&gt;
        _number = aNumber;&lt;br /&gt;
        _comment = aComment;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Основной класс/класс запуска приложения (AddressBook) ===&lt;br /&gt;
Этот класс содержит метод '''main''', инициализирует Jetty и подключает сервлет ('''AddressBookHandler''', '''листинг 2''').&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Листинг 2.''' Класс запуска приложения&lt;br /&gt;
&amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
import org.mortbay.jetty.*;&lt;br /&gt;
import org.mortbay.jetty.nio.*;&lt;br /&gt;
&lt;br /&gt;
import java.util.*;&lt;br /&gt;
import java.io.*;&lt;br /&gt;
&lt;br /&gt;
public class AddressBook {&lt;br /&gt;
    private void start() throws Exception {&lt;br /&gt;
        try {&lt;br /&gt;
            _contactsByName = (SortedMap&amp;lt;String, Contact&amp;gt;) new XStream().&lt;br /&gt;
                fromXML(new FileReader(&amp;quot;contacts.xml&amp;quot;));&lt;br /&gt;
        } catch (Exception e) { }&lt;br /&gt;
&lt;br /&gt;
        Server _jettyServer = new Server();&lt;br /&gt;
        Connector connector = new SelectChannelConnector();&lt;br /&gt;
        connector.setPort(8081);&lt;br /&gt;
        _jettyServer.setConnectors(new Connector[]{connector});&lt;br /&gt;
        _jettyServer.setStopAtShutdown(true);&lt;br /&gt;
        Handler handler = new AddressBookHandler(this);&lt;br /&gt;
        _jettyServer.setHandler(handler);&lt;br /&gt;
        _jettyServer.start();&lt;br /&gt;
    }&lt;br /&gt;
    public static void main(String[] args) throws Exception {&lt;br /&gt;
        new AddressBook().start();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также этот класс содержит саму адресную книгу:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Листинг 3.''' Адресная книга&lt;br /&gt;
&amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
private SortedMap&amp;lt;String, Contact&amp;gt; _contactsByName = new TreeMap&amp;lt;String,Contact&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
public SortedMap&amp;lt;String, Contact&amp;gt; getContactsByName() {&lt;br /&gt;
    return _contactsByName;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public Contact getContactByNumber(String aNumber) {&lt;br /&gt;
    for (Map.Entry&amp;lt;String, Contact&amp;gt; entry : _contactsByName.entrySet()) {&lt;br /&gt;
        if (entry.getValue().getNumber().equals(aNumber)) {&lt;br /&gt;
            return entry.getValue();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return null;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и методы, которые позволяют добавлять/удалять/редактировать контакты:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Листинг 4.''' Работа с контактами&lt;br /&gt;
&amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public void addContact(String aName, String aNumber, String aComment)&lt;br /&gt;
throws IOException {&lt;br /&gt;
    Contact contact = new Contact();&lt;br /&gt;
    contact.setData(aName, aNumber, aComment);&lt;br /&gt;
    _contactsByName.put(aName, contact);&lt;br /&gt;
    saveContactsInformation();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void removeContactByNumber(String aNumber) throws IOException {&lt;br /&gt;
    Contact contact = getContactByNumber(aNumber);&lt;br /&gt;
    if (contact != null) {&lt;br /&gt;
        _contactsByName.remove(contact.getName());&lt;br /&gt;
        saveContactsInformation();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public void editContact(String aEditNumber, String aName, String aNumber, String aComment)&lt;br /&gt;
throws IOException {&lt;br /&gt;
    Contact contact = getContactByNumber(aEditNumber);&lt;br /&gt;
    if (contact != null) {&lt;br /&gt;
        contact.setData(aName, aNumber, aComment);&lt;br /&gt;
        saveContactsInformation();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
private void saveContactsInformation() throws IOException {&lt;br /&gt;
    new XStream().toXML(_contactsByName, new FileWriter(&amp;quot;contacts.xml&amp;quot;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Класс-обработчик (AddressBookHandler) ===&lt;br /&gt;
Обработка событий пользователя концентрируется в одном методе ('''public void handle(…)''') класса '''AddressBookHandler'''. Самые главные параметры этого метода – второй '''aHttpServletRequest''' и третий '''aHttpServletResponse'''. '''Request''' – это запрос. В нем хранятся все данные, которые передал нам браузер пользователя. А '''Response''' – это объект, в который нужно записать все, что требуется передать пользователю. Например, на любой запрос пользователя можно отвечать страницей с гордым заголовком «адресная книга» ('''листинг 5'''):&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Листинг 5.''' Код обработчика&lt;br /&gt;
&amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
import org.mortbay.jetty.handler.*;&lt;br /&gt;
import org.mortbay.jetty.*;&lt;br /&gt;
&lt;br /&gt;
import javax.servlet.*;&lt;br /&gt;
import javax.servlet.http.*;&lt;br /&gt;
import java.io.*;&lt;br /&gt;
import java.util.*;&lt;br /&gt;
&lt;br /&gt;
public class AddressBookHandler extends AbstractHandler {&lt;br /&gt;
    private AddressBook _addressBook = null;&lt;br /&gt;
&lt;br /&gt;
    public AddressBookHandler(AddressBook aAddressBook) {&lt;br /&gt;
        _addressBook = aAddressBook;&lt;br /&gt;
    }&lt;br /&gt;
    public void handle(String aTarget, HttpServletRequest aRequest,&lt;br /&gt;
            HttpServletResponse aResponse, int aDispatchMode)&lt;br /&gt;
            throws IOException, ServletException {&lt;br /&gt;
&lt;br /&gt;
        ((Request) aRequest).setHandled(true);&lt;br /&gt;
        aRequest.setCharacterEncoding(&amp;quot;utf-8&amp;quot;);&lt;br /&gt;
        aResponse.setCharacterEncoding(&amp;quot;utf-8&amp;quot;);&lt;br /&gt;
        aResponse.addHeader(&amp;quot;Content-type&amp;quot;, &amp;quot;text/html; charset=utf-8&amp;quot;);&lt;br /&gt;
        PrintWriter writer = aResponse.getWriter();&lt;br /&gt;
        writer.write(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;quot; +&lt;br /&gt;
            &amp;quot;&amp;lt;title&amp;gt;Адресная книга&amp;lt;/title&amp;gt;&amp;quot; +&lt;br /&gt;
            &amp;quot;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Адресная книга&amp;lt;/h1&amp;gt;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Откомпилируйте полученный код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd ~/Programming/AddressBook/src&lt;br /&gt;
javac –encoding utf-8 -cp ../libs/jetty-6.1.0rc3.jar:../libs/jetty-util-6.1.0rc3.&lt;br /&gt;
jar:../libs/servlet-api-2.5.jar -d ../build *.java&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
И запустите (не забыв подключить все требуемые библиотеки):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd ~/Programming/AddressBook/build&lt;br /&gt;
java -cp ../libs/jetty-6.1.0rc3.jar:../libs/jetty-util-6.1.0rc3.jar:../libs/servletapi-&lt;br /&gt;
2.5.jar:. AddressBook&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Терминал выводит несколько строчек и «зависает». Все правильно, сервер запустился. Запускать наше приложение будем пока именно так, чтобы его можно было легко выключить ('''Ctrl+C'''). Теперь откройте браузер и наберите в адресной строке: '''&amp;lt;nowiki&amp;gt;http://localhost:8081&amp;lt;/nowiki&amp;gt;'''. Вот он, наш заголовок!&lt;br /&gt;
&lt;br /&gt;
Вернемся к обработчику и попробуем уяснить, как различать запросы пользователей. Для этого в обработчике есть две возможности. Самая простая – посмотреть на первый параметр ('''aTarget'''), который содержит «файл» запроса (например в URL’е «http://www.linuxformat.ru/index.html» '''aTarget''' будет «'''/index.html'''»); посложнее – анализировать сам объект запроса. Воспользуемся первым вариантом, дописав в конец метода '''handle''' (прямо перед закрывающей скобкой) следующее:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Листинг 6.''' Более сложный обработчик с разбором адреса&lt;br /&gt;
&amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
if (&amp;quot;/&amp;quot;.equals(aTarget)) {&lt;br /&gt;
    writer.write(&amp;quot;&amp;lt;a href=\&amp;quot;/add\&amp;quot;&amp;gt;Добавить запись&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;&amp;quot;);&lt;br /&gt;
    writer.write(&amp;quot;&amp;lt;a href=\&amp;quot;/view\&amp;quot;&amp;gt;Просмотреть записи&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;&amp;quot;);&lt;br /&gt;
} else {&lt;br /&gt;
    writer.write(&amp;quot;&amp;lt;a href=\&amp;quot;/\&amp;quot;&amp;gt;На главную&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (&amp;quot;/add&amp;quot;.equals(aTarget)) {&lt;br /&gt;
        writer.write(&amp;quot;&amp;lt;h2&amp;gt;Добавление записи&amp;lt;/h2&amp;gt;&amp;quot;);&lt;br /&gt;
    } else if (&amp;quot;/view&amp;quot;.equals(aTarget)) {&lt;br /&gt;
        writer.write(&amp;quot;&amp;lt;h2&amp;gt;Просмотр записей&amp;lt;/h2&amp;gt;&amp;quot;);&lt;br /&gt;
    } else if (&amp;quot;/edit&amp;quot;.equals(aTarget)) {&lt;br /&gt;
        writer.write(&amp;quot;&amp;lt;h2&amp;gt;Редактирование записи&amp;lt;/h2&amp;gt;&amp;quot;);&lt;br /&gt;
    } else if (&amp;quot;/remove&amp;quot;.equals(aTarget)) {&lt;br /&gt;
        writer.write(&amp;quot;&amp;lt;h2&amp;gt;Удаление записи&amp;lt;/h2&amp;gt;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
writer.write(&amp;quot;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Попробуйте снова откомпилировать и запустить приложение, предварительно остановив предыдущую версию сервера. Обновите страницу в браузере – и побегайте по только что созданным страницам нашего сайта (корневая, она же «'''/'''», «'''/add'''», «'''/edit'''», «'''/remove'''»).&lt;br /&gt;
&lt;br /&gt;
Теперь в соответствующих ветках '''if''' можно написать обработчики страничек. Для упрощения вынесем эти обработчики в отдельные методы ('''листинг 7'''):&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Листинг 7.''' Добавляем обработчики отдельных действий&lt;br /&gt;
&amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    if (&amp;quot;/add&amp;quot;.equals(aTarget)) {&lt;br /&gt;
        writer.write(&amp;quot;&amp;lt;h2&amp;gt;Добавление записи&amp;lt;/h2&amp;gt;&amp;quot;);&lt;br /&gt;
        handleAdd(aRequest, writer);&lt;br /&gt;
    } else if (&amp;quot;/view&amp;quot;.equals(aTarget)) {&lt;br /&gt;
        writer.write(&amp;quot;&amp;lt;h2&amp;gt;Просмотр записей&amp;lt;/h2&amp;gt;&amp;quot;);&lt;br /&gt;
        handleView(writer);&lt;br /&gt;
    } else if (&amp;quot;/edit&amp;quot;.equals(aTarget)) {&lt;br /&gt;
        writer.write(&amp;quot;&amp;lt;h2&amp;gt;Редактирование записи&amp;lt;/h2&amp;gt;&amp;quot;);&lt;br /&gt;
        handleEdit(aRequest, writer);&lt;br /&gt;
    } else if (&amp;quot;/remove&amp;quot;.equals(aTarget)) {&lt;br /&gt;
        writer.write(&amp;quot;&amp;lt;h2&amp;gt;Удаление записи&amp;lt;/h2&amp;gt;&amp;quot;);&lt;br /&gt;
        handleRemove(aRequest, writer);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Осталось понять, как именно обрабатывать соответствующие страницы. Рассмотрим, для примера, метод '''handleAdd()''' – остальные можно написать по аналогии:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Листинг 8.''' Обработчик добавления записи&lt;br /&gt;
&amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    private void handleAdd(HttpServletRequest aRequest, PrintWriter aWriter)&lt;br /&gt;
    throws IOException {&lt;br /&gt;
        if (aRequest.getParameter(&amp;quot;name&amp;quot;) != null) {&lt;br /&gt;
            _addressBook.addContact(aRequest.getParameter(&amp;quot;name&amp;quot;),&lt;br /&gt;
                aRequest.getParameter(&amp;quot;number&amp;quot;), aRequest.getParameter(&amp;quot;comment&amp;quot;));&lt;br /&gt;
            outputMessage(aWriter, &amp;quot;Контакт добавлен&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        outputForm(aWriter, aRequest, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В приведенном обработчике есть вызов метода '''aRequest.getParameter(&amp;quot;name&amp;quot;)'''. Этот метод выдает значение параметра, который передает браузер из формы ('''&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;name&amp;quot;/&amp;gt;'''). Причем сервлету все равно, каким методом (GET/POST) был передан параметр. Конкретно для обработки добавления контакта в коде проверяется, равен ли результат вызова '''null'''. Если так – значит, форма «не выполнялась», и добавлять нечего. В противном случае мы считываем три параметра (имя, телефон и комментарий), сохраняем контакт и выводим форму (вдруг пользователь захочет добавить еще один контакт?).&lt;br /&gt;
&lt;br /&gt;
Методы '''outputForm''' и '''outputMessage''' ('''листинг 9''') выводят форму (либо пустую, либо заполненную данными, которые нужно редактировать) и сообщение (чтобы пользователь понимал, что действие произошло, и как оно завершилось):&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Листинг 9.''' Обработчик добавления записи&lt;br /&gt;
&amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
private void outputForm(PrintWriter aWriter, HttpServletRequest aRequest,&lt;br /&gt;
        String aName, String aNumber, String aComment) {&lt;br /&gt;
    aWriter.write(&lt;br /&gt;
        &amp;quot;&amp;lt;form action=\&amp;quot;/edit\&amp;quot; method=\&amp;quot;post\&amp;quot;&amp;gt;&amp;quot; +&lt;br /&gt;
        &amp;quot;&amp;lt;input type=\&amp;quot;hidden\&amp;quot; name=\&amp;quot;edited\&amp;quot; value=\&amp;quot;&amp;quot; +&lt;br /&gt;
            aRequest.getParameter(&amp;quot;number&amp;quot;) + &amp;quot;\&amp;quot;/&amp;gt;&amp;quot; + &amp;quot;&amp;lt;table&amp;gt;&amp;quot; +&lt;br /&gt;
        &amp;quot;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;Имя: &amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;input type=\&amp;quot;text\&amp;quot; name=\&amp;quot;name\&amp;quot; value=\&amp;quot;&amp;quot; +&lt;br /&gt;
            aName + &amp;quot;\&amp;quot;/&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;quot; +&lt;br /&gt;
        &amp;quot;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;Телефон: &amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;input type=\&amp;quot;text\&amp;quot; name=\&amp;quot;number\&amp;quot; value=\&amp;quot;&amp;quot; +&lt;br /&gt;
            aNumber + &amp;quot;\&amp;quot;/&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;quot; +&lt;br /&gt;
        &amp;quot;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;Примечания: &amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;input type=\&amp;quot;text\&amp;quot; name=\&amp;quot;comment\&amp;quot; value=\&amp;quot;&amp;quot; +&lt;br /&gt;
            aComment + &amp;quot;\&amp;quot;/&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;quot; +&lt;br /&gt;
        &amp;quot;&amp;lt;tr&amp;gt;&amp;lt;td colspan=\&amp;quot;2\&amp;quot; align=\&amp;quot;center\&amp;quot;&amp;gt;&amp;quot; +&lt;br /&gt;
            &amp;quot;&amp;lt;input type=\&amp;quot;submit\&amp;quot; name=\&amp;quot;Отправить\&amp;quot;/&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;quot; +&lt;br /&gt;
        &amp;quot;&amp;lt;/table&amp;gt;&amp;lt;/form&amp;gt;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    private void outputMessage(PrintWriter aWriter, String aMessage) {&lt;br /&gt;
        aWriter.write(&amp;quot;&amp;lt;span style=\&amp;quot;color: green;\&amp;quot;&amp;gt;&amp;quot; + aMessage + &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для того, чтобы проверить работу нового обработчика, закомментируйте вызовы методов, которые еще не написаны (или напишите «заглушки» в виде пустых методов). Теперь можно снова остановить сервер, скомпилировать программу и запустить ее на выполнение. Если все набрано правильно, ошибок не последует, и можно будет просматривать табличку с контактами, добавлять их, редактировать и удалять. Наша адресная книга готова к работе!&lt;br /&gt;
&lt;br /&gt;
На этом уроке вы создали свое первое JEE-приложение. Конечно, за кадром осталось множество возможностей – начиная с использования сессий, контроля корректности параметров, и заканчивая отделением дизайна от логики работы сервлета – но наша программа уже вполне работоспособна. И, конечно, история не заканчивается. В следующих статьях будет продолжение, посвященное развитию приложения в соответствии с усложнением запросов компании к адресной книге.&lt;/div&gt;</summary>
		<author><name>Haanp</name></author>	</entry>

	</feed>