Итак, мы приступаем к написанию нашего приложения в виде интернет-решения.

В предыдущих частях Вы уже посмотрели основы взаимодействия броузера с сервером. Мы выяснили, что запросы пользователя посылаются на сервер, где их обрабатывает сервлет. Сервлет может сам создать необходимый HTML, но это достаточно неудобно и поэтому в подавляющем большинстве случаев все данные сервлет может передать JSP, которая покажет все эти данные в виде HTML-страницы.

JNDI — первое знакомство
Для начала мы с вами немножко изменим наше ядро — ManagementSystem. Во-первых, посмотрим на новую технологию, во-вторых — сделаем наше приложение более профессиональным.
оспользуемся системой JNDI — Java Naming Directory Interface — специальная система имен, которая позволяет делать следующее: хранить в некотором репозитории нужные нам классы и возвращать их по требованию приложений по имени. Что очень удобно — мы можем задавать параметры для нужного нам ресурса во внешнем конфигурационном файл, а не прописывать жестко в коде — что в общем-то всегда является не очень хорошим стилем.
Заметьте, что даже класс драйвера мы можем теперь менять независимо от кода нашего приложения — можем позже использовать другую базу данных — Oracle, Sybase, DB2 и другие.

Рекомендуем: Для более полного ознакомления с технологией JNDI я вам советую посмотреть следующие ссылки:

http://java.sun.com/products/jndi/tutorial/TOC.html — это подробное описание системы JNDI

http://tomcat.apache.org/tomcat-4.1-doc/jndi-resources-howto.html — описание использования JNDI для сервера Tomcat

Как и в прошлый раз мы создадим необходимые нам файлы в обычном редакторе. Сейчас мы с вами сделаем приложение, которое будет очень похоже на то, что было сделано в «Части 7 — Первые шаги в Интернет». У нас будет один сервлет, который покажет нам таблицу групп.

Итак, давайте создадим наши файлы.

web.xml

Как видите, мы описали всего один сервлет, для которого сделали маппинг (связку, отображение — русского термина так и не придумали), т.е. связали URL и сервлет. Это мы уже видели раньше. Но вот дальше у нас с вами новинка — мы описали ресурс. У него есть описание — DB Connection. Далее мы указали имя, по которому мы будем его запрашивать через JNDI — jdbc/StudentsDS. Также мы описали тип/класс возвращаемого ресурса — javax.sql.DataSource. И в конце мы указали кто отвечает за авторизацию — будет ли приложение само подставлять логин и пароль или этим будет заниматься контейнер — в нашем случае этим будет заниматься Tomcat.

Отметим, что при таком описании контейнер берет на себя все заботы по поддержанию коннекта к базе. Причем не одного, а целого пула — несколько штук коннектов. Это удобно тем, что создание коннекта — дело сложное, долгое и ресурсоемкое. Если мы имеем некоторый запас свободных коннектов — это ускоряет работу.

Для того, чтобы Tomcat знал какие параметры он должен подставить нам необходим еще один файл — context.xml.

Я думаю. что многие параметры для вас очевидны. Но все же опишем их.
name — имя ресурса — оно должно совпадать с тем, кторое указано в файле web.xml
type — опять же должно совпадать с тэгом >res-type> из web.xml
username — логин к базе данных
password — пароль
driverClassName — класс драйвера JDBC (мы его можем получить из описанного ранее файла mysql-connector-java-3.1.13-bin.jar). К нему мы чуть позже еще раз вернемся.
maxIdle — максимальное количество незадействованных коннектов — свободных.
maxWait — время (в миллисекундах), в течении которого пул коннектов будет пытаться отдать коннект по запросу прежде чем «выбросит» исключение о недоступности ресурса.
validationQuery — запрос который будет выполнятся для проверки валидности (правильности) коннекта перед отдачей его приложению.
url — URL для соединения — его мы уже использовали
maxActive — максимальное количество акивных коннектов. Если надо будет больше, то остальным придется подождать. (см. параметр maxWait)

Теперь давайте посмотрим на изменения, которые мы сделали в файле ManagementSuystem.java. Сначала я приведу код, а после этого мы рассмотрим наши изменения.

ManagementSystem.java

Самое важное изменение находится в методе getInstance().
Раньше наш класс загружал драйвер и устанавливал соединение. Теперь мы видим, что соединения класс не делает — он только запрашивает ресурс по имени (отметим. что именно по тому имени, которое указано в файла web.xml и context.xml). А уже Tomcat берет на себя все необходимые действия — открывает соединение (несколько штук сразу), проверяет правильность и т.д.

Возможно, что в нашем случае в таком подходе нет необходимости, но это удобно при большом количестве баз данных, коннектов и прочего.

Также надо отметить новый метод – getStudentById(..). Он достаточно очевидный – получаем данные конкретного студента по его ID. Он нам пригодится.

Приведем код нашего сервлета — SimpleList.java

Ну и по традиции добавим код для двух классов — Group.java и Student.java

Group.java

Student.java

Для компиляции наших классов иерархия файлов должна выглядеть так:

Я скопировал файл servlet-api.jar из директории <TOMCAT_HOME>\lib. Так удобнее собирать. Об этом мы говорили в раньше.
Для того, чтобы скомпилировать классы набираем команду (текущая директория та, в которой находится каталог students):

Теперь скопируем все наши файлы в директорию <TOMCAT_HOME>\webapps\studentsApp. Структура файлов в каталоге должна выглядеть так:

Что касается файла 
mysql-connector-java-3.1.13-bin.jar — теперь он должен находится в каталоге <TOMCAT_HOME>\lib.
Если все нормально собралось и скопировалось, то запускаем Tomcat и после старта открываем броузер и набираем строку

По идее мы должны получить список групп из нашей базы. И теперь мы перейдем непосредственно к написанию нашего приложения.

Студенческий отдел кадров — WEB-приложение
В данном приложении автор не собирается делать какие-то супер красивые и удобные HTML-странички. Посему будет все очень просто — во-первыхЮ чтобы было понятнее. Во-вторых — цель проекта познакомиться, а не вдаваться в тонкости GUI.
Давайте перечислим еще раз те формы, котоыре нам потребуются:
1. Главная форма, которая показывает список групп, поле для ввода года и список студентов, соответсвующий выбранной группе и году. В этой же форме можно выполнять удаление студента и удаление всех студентов из выделенной группы.
2. Форма для ввода данных о студенте — мы можем использовать одну форму для добавления и для редактирования.

Давайте немного подробнее опишем эти формы.

Итак — главная форма.

Для ввода года будем использовать обычное текстовое поле — можно с помощью JavaScript проверку корректности, но мы не будем этого делать — упростим все до предела.

Список групп будет обычным выпадающим списком.

Список студентов оформим в виде таблицы где удаление и редактирование мы сделаем просто — каждый студент в списке может быть выделен с помощью радиокнопки (RadioButton). После этого достаточно нажать кнопку — Редактировать, Удалить — и можно посылать команду на сервер.

Форма для редактирования/добавления студента — мы просто перечислим поля. Для поля «Пол» используем радиокнопки, для поля «Группа» — список. Дату будем вводить просто строкой — не будем усложнять.

Разобравшись с формами попробуем набросать список команд. В общем-то он и определит, какие сервлеты нам потребуются. Мы постараемся не делать список слишком длинным, тем более, что те же команды редактирования/добавления студента в общем-то можно свести к одной — если мы передаем ID студента =0, то можно сказать, что надо добавить. Иначе — редактировать.

Итак наш список выглядит следующим образом:
— Показать список студентов для определенного года и определенной группы.
— Удалить студента
— Редактировать/добавить студента

Замечение: Умение правильно проектировать набор нужных сервлетов — дело опыта. Так что проектируйте, делайте, ломайте и заново стройте — после нескольких попыток вы научитесь этому занимательному делу.

Я не буду утверждать, что сделал оптимальный набор — возможно кому-то захочется сделать его более полным, кому-то покажется, что кое-какие команды можно реализовать одним сервлетом. но как сделано — так сделано. Мне важно показать технологию в действии.

Мы будем использовать сервлеты для получения данных, преобразования и потом вызывать JSP для отображения.

Пойдем по порядку — главная форма — MainFrameServlet.
Как уже говорилось в предыдущих частях JSP служит для того, чтобы показать данные которые ей передал сервлет. Профессионалы могут поспорить, но мне важно, чтобы вы поняли вот какой момент — сервлет собирает все данные по разным таблицам, по разным файла и т.д., кладет это все в некоторую структуру и передает JSP, которая занимается тем, что из этой структуры «вытаскивает» нужные данные и кладет их на соотвтествующее место на странице.

Как видите для реализации команды нам надо три компонента:
— сервлет, который выполняет какие-то действия, собирает необходимые нам данные и кладет их в
— структуру, которая содержит все необходимые данные для показа на
— JSP странице, которая «вынимает» из структуры данные и располагает их по странице

Начнем мы со второго пункта — состав структуры достаточно очевиден — год, список групп, ID конкретной группы, список студентов для конкретной группы и данного года. Для всех таких структур создадим новый пакет — students.web.forms.

Мы еще вернемся к этому вопросу, но все-таки предварительного упоминания этот момент заслуживает:

JSP 2.0 и выше используется так называемы «Язык выражений» (ЯВ) или Expression Language (EL) — основная его идея в том, чтобы не писать страшные конструкции типа

<%= request.getParameter(«parameter») %>

ЯВ имеет упрощенный синтаксис обращения к полям объектов, которые находятся в JSP (это как раз наша структура, которая содержит много данных). Писать постоянно формулы и get/set методы не очень интересно и поэтому был сделан ЯВ. В нем обращение к данным гораздо приятнее на вид.
Очень важно учесть, что ЯВ требует правильного именования полей и наличия методов set/get. Чуть ниже приведен код нашей структуры и там можно увидеть как именовать поля и методы доступа к ним.
Т.е. получим вот такой вот класс:

MainFrameForm.java

Код для сервлета нашей главной страницы:

MainFrameServlet.java

Теперь нам необходимо сделать страницу JSP, которая будет нам показывать наши результаты. Эту страницу мы положим в корень каталога для нашего WEB-приложения.

Вам необходимо обратить внимание на следующие моменты:

1.       <%@ taglib prefix=»c» uri=»http://java.sun.com/jsp/jstl/core» %> — команда, которая загружает библиотеку стандартных тэгов – тот самыйJSTL о котором мы говорили в предыдущей части.

2.       Фрагменты из JSP

c:forEach – специальный тэг, который позволяет перебрать элементы коллекции

c:choose – тэг для выбора из вариантов по условию c:when и то, что не подошло будет выполнятеся в теле тэгаc:otherwise

Стоит отметить, что JSTL является достаточно мощным инструментом и я советую Вам потратить время на изучение тэгов. Мне очень понравилась книга
Сью Шпильман.  «JSTL. Практическое руководство для JSP-программистов». Очень кратко, но  по делу

MainFrame.jsp

Теперь рассмотрим код, который необходим для редактирования данных о студенте.

Первый наш класс содержит информацию, которую мы будем показывать на странице – он аналогичен MainFrameForm.java, только данные теперь будут о конкретном студенте.

StudentForm.java

Теперь код для нашего сервлета, который будет обрабатывать полученные данные.

StudentFrameServlet.java

И наконец JSP для отображения данных.

StudentFrame.jsp

Наш файл web.xml тоже притерпел некоторые изменения – в нем теперь два сервлета.

web.xml

В процессе работы Tomcat не может загрузить библиотеку тэгов JSTL — ее у него нет. Советую найти и загрузить файлы из каталога примеров, который идет вместе с Tomcat — каталог «TOMCAT_HOME/webapps/examples/WEB-INF/lib» — jstl.jar и standard.jar и положить их в <TOMCAT_HOME>\lib (туда, куда мы поместили драйвер для MySQL). Тогда все должно работать хорошо. В принципе можно устанавливать библиотеку вместе с приложением в каталог WEB-INF\lib, но т.к. большинство приложений будет использовать JSTL, то имеет смысл положить библиотеки в общий доступ.

Вот и все, что мне хотелось рассказать о WEB-программировании. Конечно же, мы не смогли просмотреть очень многое, но надеюсь, что Вам стало проще ориентироваться в его многообразии. А пока мы перейдем к несколько иной стороне программирования – к тестированию. Встречайте – Часть 10 — Тестирование с точки зрения разработчика

Я внес исправления и добавил архив с исходным кодом в виде проекта под NetBeans: Исходный код

30 comments to Простое WEB-приложение

  • samsim  says:

    Хороший пример использование данного скрипта. Надо будет как то попробовать самому написать что то подобное. Автору респект!

  • Aleksei  says:

    org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot create JDBC driver of class » for connect URL ‘null’

    • admin  says:

      Я не очень понял вопрос, но есть подозрение, что не указан URL для коннекта. Хотя лучше все-таки боле подробно писать.

  • Aleksei  says:

    такая ошибка возникает при попытке зайти по адресу http://localhost:8080/studentsApp/simple
    Все классы и xml файлы — из примера. Я так понимаю, что Tomcat не может определить где находиться com.mysql.jdbc_5.1.5.jar… Пробовал копировать его в разные директории, но ошибка все время та же…

    • admin  says:

      Я проверял пример, который лежит в виде архива в статье — http://www.java-course.ru/students/Sources/part09.zip
      Лучше прислать просто архив Вашего проекта на почту — я постараюсь посмотреть. Потому что надо смотреть более подробно.

  • Aleksei  says:

    Спасибо! Разобрался! Файл context.xml находился не в каталоге META-INF.

  • AlexanderS  says:

    Добрый день!
    Скачал архив с проектом для NetBeans. Попробовал запустить — всё заработало. Однако возникла проблема с кодировкой: при попытке передать что-либо на русском переданные записи в базе данных и в броузере отображались как знаки вопроса(?). Проблему решил, вставив параметр characterEncoding=UTF-8 в URL к базе данных,т.е пишем:
    url=»jdbc:mysql://127.0.0.1:3306/students?characterEncoding=UTF-8»
    Уважаемый, admin, подскажите, почему без этого параметра текст на русском не отображается нормально, учитывая, что при создании базы данных кодировка utf8 уже была указана (базу создавал, используя код из раздела «База данных»)?

    • admin  says:

      Дело в том, что кроме базы данных, надо указать, что само соединение будет использовать при передаче кодировку UTF-8. По умолчанию используется кодировка cp-1251. Вот и получаются вопросы вместо символов.

  • Баклан Беларускі  says:

    Респект и уважуха автору статей, не смотря на опечатки в тексте и листингах. Пусть воздастся Вам и детям Вашим! 🙂

  • Anton  says:

    А почему конекшен не клозится?

    • admin  says:

      Потому что берем один коннекшен и используем только его. В принципе наверно можно переделать так, чтобы каждый раз брать из пула новый коннект. Но руки не доходят.

      • Alex  says:

        Прежде всего спасибо большое за статью!
        У меня тоже вопрос по коннекшину — действительно, у нас нет кода, который закрывал бы коннекшн, когда мы прекращаем работу с приложением. Скажите, есть ли смысл переопределить в классе ManagementSystem метод finalize и добавить туда con.close(), чтобы коннекшн наверняка закрывался при уничтожении объекта класса?
        А также интересно, сколько будет «жить» сам инстанс класса ManagementSystem?
        Обычно пишется, что объект живет до тех пор, пока на него есть ссылка.
        Но если мы, к примеру, мы зашли в аппликейшн, сделали какое-то действие, а потом ничего не делаем. Т.е. есть период простоя. Когда в таком случае начнут уничтожаться объекты? Или это зависит от сервера?
        Спасибо.

        • admin  says:

          Спасибо за добрые слова и замечание. Я с ним согласен — момент получился достаточно спорным и скорее всего надо переписать на более достойное решение с закрытием коннекта. Но очень не хотелось как-то сильно менять код на тот момент — грешен, поленился. Я очень хочу переписать «Отдел кадров» полностью. Сейчас работаю над разделом «Начала Java», в котором по сути собираюсь разобрать все, о чем говориться в первой книге «Отдела кадров», кроме EJB.
          Т.е. план сделать из «Отдела кадров» сразу профессиональное приложение со сборкой на Maven и сразу с вариантом Hibernate, Spring, EJB. Надеюсь, что до конца следующего года я смогу завершить работу над «Началами» и приступить к совершенно новой версии «Отдела кадров».

          • Alex  says:

            Спасибо за ответ.
            У меня есть еще вопросы по коннекшинам и могопоточности (заранее прошу простить, если скажу глупость или изложение будет сумбурным):
            1. Мы делаем объект класса ManagenetSystem только один (singleton), т.е. одновременно 2 и более пользователей не смогут делать операции в нашем приложении, им надо будет ждать своей очереди, пока объект не разлочится одним пользователем/потоком и не станет доступен другому. Я правильно понимаю?
            2. Если это так, то у нас одновременно будет использоваться только один коннект из пула, а остальные будут резервными, на случай обрыва первого. Так ли это?
            3. Правильно ли я понимаю, что для того, чтобы позволить нескольким юзерам работать с базой, как вариант, можно разбить ManagementSystem на 2 части/класса: 1я — операции чтения данных в БД, 2я — операции редактирования данных. Для первой можно позволить создание нескольких объектов класса, для 2й — синглтон, чтобы избежать коллизий? Это, конечно, все условно, уверен, что есть более валидный способ. Здесь просто хочется понять, насколько адекватна сама идея.
            4. Метод ManagementSystem().getInstance() имеет директиву synchronized. Что в данном случае является потоком? И как долго он живет?
            Т.е., как я понимаю, поток возникает, когда приходит get риквест на сервер (т.е. приходит юзер) и заканчивается после того, как на риквест отправляется ответ. Так ли это?
            Спасибо.

          • admin  says:

            Вы правы — пример сделан не очень хорошо. Так сложилось исторически — пока шли от обычного приложения в вебу.
            Мне уже об этой ситуации писали и я признаю, что просто поленился. Надо переделать, что я очень хочу сделать. Буду стараться.

            Корректно было бы при каждом запросе запрашивать коннект из пула, работать с ним и в конце честно закрывать/отдавать обратно в пул.

  • Esme  says:

    Добрый день, Антон.
    Большое спасибо за огромный труд, который вы проделали, и, надеюсь, вы продолжите эту работу! 🙂 Ваши статьи мне очень помогают в освоении java.
    Хочу сказать, что вплоть до этой статьи я не испытывала особых затруднений в освоении материала. Информация изложена четко, с примерами и комментариями 🙂
    А на этой статье я «застряла». Очень резкий переход от предыдущего материала к новому. Сразу так много новых вещей к изучению , и довольно скудные объяснения.
    Ваш пример у меня почти сразу заработал (единственное, что я изменила – это использование MS SQL вместо MySQL). А вот применение технологий к разработке своего приложения – вот тут пришлось сильно «попотеть» 🙂 И это при том, что предыдущие примеры я тоже «приводила» к своей задаче, то есть аналогичные модули уже были написаны. Если вы возьметесь переписывать статьи, о чем вы говорили выше, возможно, вы учтете мой отзыв.
    Некоторые вещи мне до конца не понятны: почему «вход» должен осуществляется через index.jsp, где прописана ссылка на «главный» сервлет. С главного сервлета можно осуществить переходы на другие страницы (сервлеты). Можно ли организовать несколько «сервлетов», которые работали бы на отдельных страницах?

    • admin  says:

      Спасибо за отклик. Я постараюсь учесть Ваши пожелания.
      По вопросам — в общем-то вход с index.jsp не обязателен, но эта страница может использоваться «по умолчанию», что удобно. И честно скажу — это не самое удачное решение. Я надеюсь, что смогу переписать «Студенческий отдел кадров» в другом виде.

  • Aloe  says:

    Добрый день!
    Спасибо за ваши материалы — очень помогают в освоении java.
    Не подскажите вкратце, как запустить готовое приложение? Его сначала надо собрать а потом положить в томкат?

    • admin  says:

      Спасибо за добрые слова. По поводу вопроса: готовое — это исходники или уже готовый WAR-файл ?

  • Aloe  says:

    Выложенный проект под NetBeans — что нужно сделать, чтобы его запустить?

    • admin  says:

      Если установлен NetBeans, то можно попробовать просто запустить проект — Tomcat сам стартует, установит приложение, стартует его и запустит браузер.
      Второй вариант — собрать WAR-файл, скопировать его в директорию /webapps, потом стартовать Tomcat, убедиться, что Tomcat распаковал WAR в этой же директории, самому запустить браузер и набрать
      http://localhost:8080/studentsApp/

      (studentsApp/ — nочнее надо посмотреть в какую папку распакуется WAR и ее написать в строке браузера)

      • Aloe  says:

        Попробовала запустить — проект успешно собрался, томкат подключен, показывает первую страницу, а при «переходе на главную страницу» выдает:
        java.lang.NullPointerException
        students.logic.ManagementSystem.getGroups(ManagementSystem.java:44)
        students.web.MainFrameServlet.processRequest(MainFrameServlet.java:104)
        students.web.MainFrameServlet.doGet(MainFrameServlet.java:148)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
        org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)

        не знаете, в чем может быть проблема?

        • Aloe  says:

          students.sql — запустила, на порту 3306, соединение есть
          не знаю что нетак

          • admin  says:

            Без кода и логов Томката я тоже не смогу ответить на этот вопрос.

        • admin  says:

          Как я понимаю упало на третьей строке из этого куска
          public List getGroups() throws SQLException {
          List groups = new ArrayList();
          Statement stmt = con.createStatement();

          Судя по всему само приложение не получило соединение с базой данных. Надо смотреть логи Томката, чтобы понять, что именно не получилось. Может драйвер не положили, может еще что.

        • Денис  says:

          У меня была аналогичная ошибка.
          Вылечилось изменением в context.xml: validationQuery=»SELECT 1 from dual»
          Правда я работаю с Ораклом.

  • serg1961  says:

    супер курс
    читал взахлеб
    все работает
    для запуска tomcat в последней версии
    исправте config tomcat
    спасибо cyberforum
    :noJuliConfig
    set «JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%»
    ..
    :noJuliManager
    set «JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER%»
    to
    :noJuliConfig
    set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%
    ..
    :noJuliManager
    set JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER%

  • some8uddy  says:

    Для Tomcat 7 заработало после добавления файла jstl-1.2.jar в каталог WEB-INF\lib. Добавление в TOMCAT_HOME/webapps/examples/WEB-INF/lib не помогало.

  • Александр  says:

    Большое спасибо за статью, до прочтения страшно было лезть в дебри Java для web. Сейчас понимаю в каком направлении хочу развиваться.

    • admin  says:

      И Вам спасибо, что читаете. Удачи.

Leave a reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.