LXF89:Java EE
Interlace (обсуждение | вклад) (Новая: '''Новая серия!''' Учимся писать серверные приложения на Java == Адресная книга == ''ЧАСТЬ 1: Театр, как извес...) |
Dionysius (обсуждение | вклад) (→Что нам потребуется?) |
||
(не показаны 2 промежуточные версии 2 участников) | |||
Строка 1: | Строка 1: | ||
+ | {{Цикл/Java EE}} | ||
'''Новая серия!''' Учимся писать серверные приложения на Java | '''Новая серия!''' Учимся писать серверные приложения на Java | ||
Строка 59: | Строка 60: | ||
* Библиотека Jetty (http://www.mortbay.org/). В принципе, это полноценный web-сервер, который может очень и очень многое. Нам будет полезна его особенность, позволяющая встроить web-сервер в наше приложение. | * Библиотека Jetty (http://www.mortbay.org/). В принципе, это полноценный web-сервер, который может очень и очень многое. Нам будет полезна его особенность, позволяющая встроить web-сервер в наше приложение. | ||
− | Все необходимые библиотеки есть на прилагаемом компакт-диске. | + | Все необходимые библиотеки [[Media:AddressBook.tar.bz2|и исходный код примера]] есть на прилагаемом компакт-диске. |
=== Что мы будем делать? === | === Что мы будем делать? === | ||
Строка 90: | Строка 91: | ||
import java.io.*; | import java.io.*; | ||
public class Contact implements Serializable { | public class Contact implements Serializable { | ||
− | private String _name = | + | private String _name = ""; |
− | private String _number = | + | private String _number = ""; |
− | private String _comment = | + | private String _comment = ""; |
public String getName() { return _name; } | public String getName() { return _name; } | ||
public String getNumber() { return _number; } | public String getNumber() { return _number; } | ||
Строка 121: | Строка 122: | ||
try { | try { | ||
_contactsByName = (SortedMap<String, Contact>) new XStream(). | _contactsByName = (SortedMap<String, Contact>) new XStream(). | ||
− | fromXML(new FileReader( | + | fromXML(new FileReader("contacts.xml")); |
} catch (Exception e) { } | } catch (Exception e) { } | ||
Строка 191: | Строка 192: | ||
private void saveContactsInformation() throws IOException { | private void saveContactsInformation() throws IOException { | ||
− | new XStream().toXML(_contactsByName, new FileWriter( | + | new XStream().toXML(_contactsByName, new FileWriter("contacts.xml")); |
} | } | ||
</source> | </source> | ||
Строка 221: | Строка 222: | ||
((Request) aRequest).setHandled(true); | ((Request) aRequest).setHandled(true); | ||
− | aRequest.setCharacterEncoding( | + | aRequest.setCharacterEncoding("utf-8"); |
− | aResponse.setCharacterEncoding( | + | aResponse.setCharacterEncoding("utf-8"); |
− | aResponse.addHeader( | + | aResponse.addHeader("Content-type", "text/html; charset=utf-8"); |
PrintWriter writer = aResponse.getWriter(); | PrintWriter writer = aResponse.getWriter(); | ||
− | writer.write( | + | writer.write("<html><head>" + |
− | + | "<title>Адресная книга</title>" + | |
− | + | "</head><body><h1>Адресная книга</h1>"); | |
} | } | ||
} | } | ||
Строка 255: | Строка 256: | ||
'''Листинг 6.''' Более сложный обработчик с разбором адреса | '''Листинг 6.''' Более сложный обработчик с разбором адреса | ||
<source lang="java"> | <source lang="java"> | ||
− | if ( | + | if ("/".equals(aTarget)) { |
− | writer.write( | + | writer.write("<a href=\"/add\">Добавить запись</a><br/>"); |
− | writer.write( | + | writer.write("<a href=\"/view\">Просмотреть записи</a><br/>"); |
} else { | } else { | ||
− | writer.write( | + | writer.write("<a href=\"/\">На главную</a><br/>"); |
− | if ( | + | if ("/add".equals(aTarget)) { |
− | writer.write( | + | writer.write("<h2>Добавление записи</h2>"); |
− | } else if ( | + | } else if ("/view".equals(aTarget)) { |
− | writer.write( | + | writer.write("<h2>Просмотр записей</h2>"); |
− | } else if ( | + | } else if ("/edit".equals(aTarget)) { |
− | writer.write( | + | writer.write("<h2>Редактирование записи</h2>"); |
− | } else if ( | + | } else if ("/remove".equals(aTarget)) { |
− | writer.write( | + | writer.write("<h2>Удаление записи</h2>"); |
} | } | ||
} | } | ||
− | writer.write( | + | writer.write("</body></html>"); |
</source> | </source> | ||
Строка 282: | Строка 283: | ||
'''Листинг 7.''' Добавляем обработчики отдельных действий | '''Листинг 7.''' Добавляем обработчики отдельных действий | ||
<source lang="java"> | <source lang="java"> | ||
− | if ( | + | if ("/add".equals(aTarget)) { |
− | writer.write( | + | writer.write("<h2>Добавление записи</h2>"); |
handleAdd(aRequest, writer); | handleAdd(aRequest, writer); | ||
− | } else if ( | + | } else if ("/view".equals(aTarget)) { |
− | writer.write( | + | writer.write("<h2>Просмотр записей</h2>"); |
handleView(writer); | handleView(writer); | ||
− | } else if ( | + | } else if ("/edit".equals(aTarget)) { |
− | writer.write( | + | writer.write("<h2>Редактирование записи</h2>"); |
handleEdit(aRequest, writer); | handleEdit(aRequest, writer); | ||
− | } else if ( | + | } else if ("/remove".equals(aTarget)) { |
− | writer.write( | + | writer.write("<h2>Удаление записи</h2>"); |
handleRemove(aRequest, writer); | handleRemove(aRequest, writer); | ||
} | } | ||
Строка 304: | Строка 305: | ||
private void handleAdd(HttpServletRequest aRequest, PrintWriter aWriter) | private void handleAdd(HttpServletRequest aRequest, PrintWriter aWriter) | ||
throws IOException { | throws IOException { | ||
− | if (aRequest.getParameter( | + | if (aRequest.getParameter("name") != null) { |
− | _addressBook.addContact(aRequest.getParameter( | + | _addressBook.addContact(aRequest.getParameter("name"), |
− | aRequest.getParameter( | + | aRequest.getParameter("number"), aRequest.getParameter("comment")); |
− | outputMessage(aWriter, | + | outputMessage(aWriter, "Контакт добавлен"); |
} | } | ||
− | outputForm(aWriter, aRequest, | + | outputForm(aWriter, aRequest, "", "", ""); |
} | } | ||
</source> | </source> | ||
− | В приведенном обработчике есть вызов метода '''aRequest.getParameter( | + | В приведенном обработчике есть вызов метода '''aRequest.getParameter("name")'''. Этот метод выдает значение параметра, который передает браузер из формы ('''<input type="text" name="name"/>'''). Причем сервлету все равно, каким методом (GET/POST) был передан параметр. Конкретно для обработки добавления контакта в коде проверяется, равен ли результат вызова '''null'''. Если так – значит, форма «не выполнялась», и добавлять нечего. В противном случае мы считываем три параметра (имя, телефон и комментарий), сохраняем контакт и выводим форму (вдруг пользователь захочет добавить еще один контакт?). |
Методы '''outputForm''' и '''outputMessage''' ('''листинг 9''') выводят форму (либо пустую, либо заполненную данными, которые нужно редактировать) и сообщение (чтобы пользователь понимал, что действие произошло, и как оно завершилось): | Методы '''outputForm''' и '''outputMessage''' ('''листинг 9''') выводят форму (либо пустую, либо заполненную данными, которые нужно редактировать) и сообщение (чтобы пользователь понимал, что действие произошло, и как оно завершилось): | ||
Строка 323: | Строка 324: | ||
String aName, String aNumber, String aComment) { | String aName, String aNumber, String aComment) { | ||
aWriter.write( | aWriter.write( | ||
− | + | "<form action=\"/edit\" method=\"post\">" + | |
− | + | "<input type=\"hidden\" name=\"edited\" value=\"" + | |
− | aRequest.getParameter( | + | aRequest.getParameter("number") + "\"/>" + "<table>" + |
− | + | "<tr><td>Имя: </td><td><input type=\"text\" name=\"name\" value=\"" + | |
− | aName + | + | aName + "\"/></td></tr>" + |
− | + | "<tr><td>Телефон: </td><td><input type=\"text\" name=\"number\" value=\"" + | |
− | aNumber + | + | aNumber + "\"/></td></tr>" + |
− | + | "<tr><td>Примечания: </td><td><input type=\"text\" name=\"comment\" value=\"" + | |
− | aComment + | + | aComment + "\"/></td></tr>" + |
− | + | "<tr><td colspan=\"2\" align=\"center\">" + | |
− | + | "<input type=\"submit\" name=\"Отправить\"/></td></tr>" + | |
− | + | "</table></form>"); | |
} | } | ||
private void outputMessage(PrintWriter aWriter, String aMessage) { | private void outputMessage(PrintWriter aWriter, String aMessage) { | ||
− | aWriter.write( | + | aWriter.write("<span style=\"color: green;\">" + aMessage + "</span>"); |
} | } | ||
</source> | </source> |
Текущая версия на 20:29, 30 декабря 2008
|
|
|
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
Новая серия! Учимся писать серверные приложения на Java
Содержание |
[править] Адресная книга
ЧАСТЬ 1: Театр, как известно, начинается с вешалки, а приложения уровня предприятий – с адресной книги: надо же где-то хранить сведения о клиентах. Александр Бабаев готов познакомить вас с азбукой Java EE.
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
Один из самых распространенных языков программирования для Интернета на настоящий момент – это PHP. Этот язык изначально задумывался для создания домашних страничек, небольших сайтов – и там работает замечательно.
В отличие от PHP, Java (та ее часть, которая помогает разрабатывать серверные приложения) сразу создавалась для крупных приложений уровня предприятия (так называемых Enterprise Applications). Поэтому в Java есть множество механизмов, которые помогают быстро строить очень крупные приложения. Очень крупные – это десятки тысяч транзакций в минуту. Сложных транзакций.
Обо всех возможностях этой технологии не рассказать ни в рамках одной статьи, ни даже в десятке. Но основные блоки JEE (Java Enterprise Edition), которые полезны не только в крупных приложениях, но и в средних и небольших, мы изучим обязательно. А на основании этого опыта можно будет двигаться дальше, читать книги, разрабатывать сложные системы.
[править] Сервлеты
Для начала решим, что же такое сервлет (servlet)? Этим термином принято называть серверное приложение, но чем отличается серверное приложение от клиентского? Клиентское ПО формирует запросы и отсылает их серверному, а задача серверной части – обработать запрос и вернуть на него ответ (рис. 1).
На стороне клиента присутствуют только действия, которые выполняются браузером (показ формы на HTML-странице, формирование стандартизованного запроса).
Серверная сторона в Java обычно состоит из контейнера, который содержит один или несколько сервлетов. Контейнер получает запрос, решает, какому сервлету он предназначен, и запускает на выполнение этот сервлет. Формально происходит примерно следующее:
- Пришедший от клиента запрос анализируется сервлет-контейнером, который создает на его основе специальный объект javax.servlet.ServletRequest.
- Контейнер решает (как – обычно описывается в специальном конфигурационном файле), какому сервлету предназначен запрос, и передает ему созданный на предыдущем шаге объект javax.servlet.ServletRequest, а также объект javax.servlet.ServletResponse – шаблон ответа, в который сервлет пишет все, что нужно возвратить клиенту.
- Сервлет обрабатывает запрос, заполняет объект javax.servlet.ServletResponse и после этого завершает работу.
- Контейнер получает заполненный объект javax.servlet.ServletResponse, после чего преобразует его в стандартизованное сообщение и передает клиенту.
[править] Что нам потребуется?
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
Мы предполагаем, что читатель знаком с тем, что такое HTML, и пробовал делать «странички на PHP» или чем-то аналогичном. Если словосочетания «GET-запрос», «POST-запрос» являются для вас китайской грамотой – прочтите врезку «Коротко об HTTP» (и запаситесь терпением). Подробнее про протокол HTTP можно прочитать в RFC2616, например тут: http://www.w3.org/Protocols/rfc2616/rfc2616.html.
Для работы нам понадобятся следующие инструменты:
- JDK 5 (или JDK 6) – если вы выполняли все задания предыдущей серии уроков Java, нужный дистрибутив, скорее всего, уже имеется в вашей системе (вы ведь выполняли задания, не так ли?). JDK можно бесплатно загрузить с сайта http://java.sun.com или установить из репозиториев вашего дистрибутива Linux. После установки JDK необходимо убедиться, что пути к каталогу $JDK/bin прописаны в переменной окружения PATH, а каталоги, в которых располагаются библиотеки классов, перечислены в CLASSPATH.
- Ваш любимый текстовый редактор.
- Библиотека Jetty (http://www.mortbay.org/). В принципе, это полноценный web-сервер, который может очень и очень многое. Нам будет полезна его особенность, позволяющая встроить web-сервер в наше приложение.
Все необходимые библиотеки и исходный код примера есть на прилагаемом компакт-диске.
[править] Что мы будем делать?
Для примера мы возьмем и напишем корпоративную адресную книгу, в которой будем сохранять телефоны сотрудников, причем каждый сможет добавить телефоны нужных людей, и все смогут просмотреть сохраненные телефоны. Итак, начнем.
Создадим иерархию каталогов для проекта, например, такую:
- ~/Programming/AddressBook/.
- build – каталог для скомпилированных классов.
- src – исходные тексты.
- libs – каталог для библиотек.
Заполним каталоги. Для начала возьмите Jetty, распакуйте архив, найдите в нем файлы jetty-6.1.0rc3.jar; jetty-util-6.1.0rc3.jar; servlet-api-2.5.jar и поместите их в каталог libs (можно взять и другую версию, правда, с известной долей осторожности – иногда меняются API, тогда наша программа просто не скомпилируется).
Теперь настало время придумать, как будет работать наша телефонная книга. Разумно будет создать четыре основных страницы:
- Главная – на ней будут ссылки помещены на остальные страницы приложения.
- Страница добавления нового контакта.
- Страница редактирования контакта.
- Страница поиска/просмотра контактов.
Классов в нашем приложении будет всего три:
- AddressBook. Главный класс, который запускается и «висит» в памяти, обрабатывая запросы пользователей. Обычно эту роль выполняет уже упомянутый сервлет-контейнер (роль которого может выполнять, например, Apache Tomcat), но мы избавились от него, использовав Jetty.
- AddressBookHandler. Класс-обработчик запросов пользователей. Именно этот класс и называется сервлетом. Он обычно подключается к сервлет-контейнеру через специфический конфигурационный файл, но мы избавились и от этого – спасибо, Jetty!
- Contact. Класс, который содержит поля контакта. Эти поля будут выводиться на странице и редактироваться. Его код очень простой:
Листинг 1. Контакт
import java.io.*; public class Contact implements Serializable { private String _name = ""; private String _number = ""; private String _comment = ""; public String getName() { return _name; } public String getNumber() { return _number; } public String getComment() { return _comment; } public void setData(String aName, String aNumber, String aComment) { _name = aName; _number = aNumber; _comment = aComment; } }
[править] Основной класс/класс запуска приложения (AddressBook)
Этот класс содержит метод main, инициализирует Jetty и подключает сервлет (AddressBookHandler, листинг 2).
Листинг 2. Класс запуска приложения
import org.mortbay.jetty.*; import org.mortbay.jetty.nio.*; import java.util.*; import java.io.*; public class AddressBook { private void start() throws Exception { try { _contactsByName = (SortedMap<String, Contact>) new XStream(). fromXML(new FileReader("contacts.xml")); } catch (Exception e) { } Server _jettyServer = new Server(); Connector connector = new SelectChannelConnector(); connector.setPort(8081); _jettyServer.setConnectors(new Connector[]{connector}); _jettyServer.setStopAtShutdown(true); Handler handler = new AddressBookHandler(this); _jettyServer.setHandler(handler); _jettyServer.start(); } public static void main(String[] args) throws Exception { new AddressBook().start(); } }
Также этот класс содержит саму адресную книгу:
Листинг 3. Адресная книга
private SortedMap<String, Contact> _contactsByName = new TreeMap<String,Contact>(); public SortedMap<String, Contact> getContactsByName() { return _contactsByName; } public Contact getContactByNumber(String aNumber) { for (Map.Entry<String, Contact> entry : _contactsByName.entrySet()) { if (entry.getValue().getNumber().equals(aNumber)) { return entry.getValue(); } } return null; }
и методы, которые позволяют добавлять/удалять/редактировать контакты:
Листинг 4. Работа с контактами
public void addContact(String aName, String aNumber, String aComment) throws IOException { Contact contact = new Contact(); contact.setData(aName, aNumber, aComment); _contactsByName.put(aName, contact); saveContactsInformation(); } public void removeContactByNumber(String aNumber) throws IOException { Contact contact = getContactByNumber(aNumber); if (contact != null) { _contactsByName.remove(contact.getName()); saveContactsInformation(); } } public void editContact(String aEditNumber, String aName, String aNumber, String aComment) throws IOException { Contact contact = getContactByNumber(aEditNumber); if (contact != null) { contact.setData(aName, aNumber, aComment); saveContactsInformation(); } } private void saveContactsInformation() throws IOException { new XStream().toXML(_contactsByName, new FileWriter("contacts.xml")); }
[править] Класс-обработчик (AddressBookHandler)
Обработка событий пользователя концентрируется в одном методе (public void handle(…)) класса AddressBookHandler. Самые главные параметры этого метода – второй aHttpServletRequest и третий aHttpServletResponse. Request – это запрос. В нем хранятся все данные, которые передал нам браузер пользователя. А Response – это объект, в который нужно записать все, что требуется передать пользователю. Например, на любой запрос пользователя можно отвечать страницей с гордым заголовком «адресная книга» (листинг 5):
Листинг 5. Код обработчика
import org.mortbay.jetty.handler.*; import org.mortbay.jetty.*; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class AddressBookHandler extends AbstractHandler { private AddressBook _addressBook = null; public AddressBookHandler(AddressBook aAddressBook) { _addressBook = aAddressBook; } public void handle(String aTarget, HttpServletRequest aRequest, HttpServletResponse aResponse, int aDispatchMode) throws IOException, ServletException { ((Request) aRequest).setHandled(true); aRequest.setCharacterEncoding("utf-8"); aResponse.setCharacterEncoding("utf-8"); aResponse.addHeader("Content-type", "text/html; charset=utf-8"); PrintWriter writer = aResponse.getWriter(); writer.write("<html><head>" + "<title>Адресная книга</title>" + "</head><body><h1>Адресная книга</h1>"); } }
Откомпилируйте полученный код:
cd ~/Programming/AddressBook/src javac –encoding utf-8 -cp ../libs/jetty-6.1.0rc3.jar:../libs/jetty-util-6.1.0rc3. jar:../libs/servlet-api-2.5.jar -d ../build *.java
И запустите (не забыв подключить все требуемые библиотеки):
cd ~/Programming/AddressBook/build java -cp ../libs/jetty-6.1.0rc3.jar:../libs/jetty-util-6.1.0rc3.jar:../libs/servletapi- 2.5.jar:. AddressBook
Терминал выводит несколько строчек и «зависает». Все правильно, сервер запустился. Запускать наше приложение будем пока именно так, чтобы его можно было легко выключить (Ctrl+C). Теперь откройте браузер и наберите в адресной строке: http://localhost:8081. Вот он, наш заголовок!
Вернемся к обработчику и попробуем уяснить, как различать запросы пользователей. Для этого в обработчике есть две возможности. Самая простая – посмотреть на первый параметр (aTarget), который содержит «файл» запроса (например в URL’е «http://www.linuxformat.ru/index.html» aTarget будет «/index.html»); посложнее – анализировать сам объект запроса. Воспользуемся первым вариантом, дописав в конец метода handle (прямо перед закрывающей скобкой) следующее:
Листинг 6. Более сложный обработчик с разбором адреса
if ("/".equals(aTarget)) { writer.write("<a href=\"/add\">Добавить запись</a><br/>"); writer.write("<a href=\"/view\">Просмотреть записи</a><br/>"); } else { writer.write("<a href=\"/\">На главную</a><br/>"); if ("/add".equals(aTarget)) { writer.write("<h2>Добавление записи</h2>"); } else if ("/view".equals(aTarget)) { writer.write("<h2>Просмотр записей</h2>"); } else if ("/edit".equals(aTarget)) { writer.write("<h2>Редактирование записи</h2>"); } else if ("/remove".equals(aTarget)) { writer.write("<h2>Удаление записи</h2>"); } } writer.write("</body></html>");
Попробуйте снова откомпилировать и запустить приложение, предварительно остановив предыдущую версию сервера. Обновите страницу в браузере – и побегайте по только что созданным страницам нашего сайта (корневая, она же «/», «/add», «/edit», «/remove»).
Теперь в соответствующих ветках if можно написать обработчики страничек. Для упрощения вынесем эти обработчики в отдельные методы (листинг 7):
Листинг 7. Добавляем обработчики отдельных действий
if ("/add".equals(aTarget)) { writer.write("<h2>Добавление записи</h2>"); handleAdd(aRequest, writer); } else if ("/view".equals(aTarget)) { writer.write("<h2>Просмотр записей</h2>"); handleView(writer); } else if ("/edit".equals(aTarget)) { writer.write("<h2>Редактирование записи</h2>"); handleEdit(aRequest, writer); } else if ("/remove".equals(aTarget)) { writer.write("<h2>Удаление записи</h2>"); handleRemove(aRequest, writer); }
Осталось понять, как именно обрабатывать соответствующие страницы. Рассмотрим, для примера, метод handleAdd() – остальные можно написать по аналогии:
Листинг 8. Обработчик добавления записи
private void handleAdd(HttpServletRequest aRequest, PrintWriter aWriter) throws IOException { if (aRequest.getParameter("name") != null) { _addressBook.addContact(aRequest.getParameter("name"), aRequest.getParameter("number"), aRequest.getParameter("comment")); outputMessage(aWriter, "Контакт добавлен"); } outputForm(aWriter, aRequest, "", "", ""); }
В приведенном обработчике есть вызов метода aRequest.getParameter("name"). Этот метод выдает значение параметра, который передает браузер из формы (<input type="text" name="name"/>). Причем сервлету все равно, каким методом (GET/POST) был передан параметр. Конкретно для обработки добавления контакта в коде проверяется, равен ли результат вызова null. Если так – значит, форма «не выполнялась», и добавлять нечего. В противном случае мы считываем три параметра (имя, телефон и комментарий), сохраняем контакт и выводим форму (вдруг пользователь захочет добавить еще один контакт?).
Методы outputForm и outputMessage (листинг 9) выводят форму (либо пустую, либо заполненную данными, которые нужно редактировать) и сообщение (чтобы пользователь понимал, что действие произошло, и как оно завершилось):
Листинг 9. Обработчик добавления записи
private void outputForm(PrintWriter aWriter, HttpServletRequest aRequest, String aName, String aNumber, String aComment) { aWriter.write( "<form action=\"/edit\" method=\"post\">" + "<input type=\"hidden\" name=\"edited\" value=\"" + aRequest.getParameter("number") + "\"/>" + "<table>" + "<tr><td>Имя: </td><td><input type=\"text\" name=\"name\" value=\"" + aName + "\"/></td></tr>" + "<tr><td>Телефон: </td><td><input type=\"text\" name=\"number\" value=\"" + aNumber + "\"/></td></tr>" + "<tr><td>Примечания: </td><td><input type=\"text\" name=\"comment\" value=\"" + aComment + "\"/></td></tr>" + "<tr><td colspan=\"2\" align=\"center\">" + "<input type=\"submit\" name=\"Отправить\"/></td></tr>" + "</table></form>"); } private void outputMessage(PrintWriter aWriter, String aMessage) { aWriter.write("<span style=\"color: green;\">" + aMessage + "</span>"); }
Для того, чтобы проверить работу нового обработчика, закомментируйте вызовы методов, которые еще не написаны (или напишите «заглушки» в виде пустых методов). Теперь можно снова остановить сервер, скомпилировать программу и запустить ее на выполнение. Если все набрано правильно, ошибок не последует, и можно будет просматривать табличку с контактами, добавлять их, редактировать и удалять. Наша адресная книга готова к работе!
На этом уроке вы создали свое первое JEE-приложение. Конечно, за кадром осталось множество возможностей – начиная с использования сессий, контроля корректности параметров, и заканчивая отделением дизайна от логики работы сервлета – но наша программа уже вполне работоспособна. И, конечно, история не заканчивается. В следующих статьях будет продолжение, посвященное развитию приложения в соответствии с усложнением запросов компании к адресной книге.