Итак, мы приступаем к написанию нашего приложения в виде интернет-решения.
В предыдущих частях Вы уже посмотрели основы взаимодействия броузера с сервером. Мы выяснили, что запросы пользователя посылаются на сервер, где их обрабатывает сервлет. Сервлет может сам создать необходимый 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name>Students personnel</display-name> <servlet> <servlet-name>SimpleList</servlet-name> <servlet-class>students.web.SimpleList</servlet-class> </servlet> <servlet-mapping> <servlet-name>SimpleList</servlet-name> <url-pattern>/simple</url-pattern> </servlet-mapping> <resource-ref> <description>DB Connection</description> <res-ref-name>jdbc/StudentsDS</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> </web-app> |
Как видите, мы описали всего один сервлет, для которого сделали маппинг (связку, отображение — русского термина так и не придумали), т.е. связали URL и сервлет. Это мы уже видели раньше. Но вот дальше у нас с вами новинка — мы описали ресурс. У него есть описание — DB Connection. Далее мы указали имя, по которому мы будем его запрашивать через JNDI — jdbc/StudentsDS. Также мы описали тип/класс возвращаемого ресурса — javax.sql.DataSource. И в конце мы указали кто отвечает за авторизацию — будет ли приложение само подставлять логин и пароль или этим будет заниматься контейнер — в нашем случае этим будет заниматься Tomcat.
Отметим, что при таком описании контейнер берет на себя все заботы по поддержанию коннекта к базе. Причем не одного, а целого пула — несколько штук коннектов. Это удобно тем, что создание коннекта — дело сложное, долгое и ресурсоемкое. Если мы имеем некоторый запас свободных коннектов — это ускоряет работу.
Для того, чтобы Tomcat знал какие параметры он должен подставить нам необходим еще один файл — context.xml.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?xml version="1.0" encoding="UTF-8"?> <Context path="/studentsApp"> <Resource driverClassName="com.mysql.jdbc.Driver" maxActive="4" maxIdle="2" maxWait="5000" name="jdbc/StudentsDS" username="root" password="root" type="javax.sql.DataSource" url="jdbc:mysql://127.0.0.1:3306/students" validationQuery="SELECT 1"> </Resource> </Context> |
Я думаю. что многие параметры для вас очевидны. Но все же опишем их.
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
package students.logic; import java.sql.Connection; import java.sql.Date; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; public class ManagementSystem { private static Connection con; private static ManagementSystem instance; private static DataSource dataSource; private ManagementSystem() { } public static synchronized ManagementSystem getInstance() { if (instance == null) { try { instance = new ManagementSystem(); Context ctx = new InitialContext(); instance.dataSource = (DataSource) ctx.lookup("java:comp/env/jdbc/StudentsDS"); con = dataSource.getConnection(); } catch (NamingException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } return instance; } public List getGroups() throws SQLException { List groups = new ArrayList(); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("SELECT group_id, groupName, curator, speciality FROM groups"); while (rs.next()) { Group gr = new Group(); gr.setGroupId(rs.getInt(1)); gr.setNameGroup(rs.getString(2)); gr.setCurator(rs.getString(3)); gr.setSpeciality(rs.getString(4)); groups.add(gr); } rs.close(); stmt.close(); return groups; } public Collection getAllStudents() throws SQLException { Collection students = new ArrayList(); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("SELECT student_id, firstName, patronymic, surName, " + "sex, dateOfBirth, group_id, educationYear FROM students ORDER BY surName, firstName, patronymic"); while (rs.next()) { Student st = new Student(rs); students.add(st); } rs.close(); stmt.close(); return students; } public Collection getStudentsFromGroup(Group group, int year) throws SQLException { Collection students = new ArrayList(); PreparedStatement stmt = con.prepareStatement("SELECT student_id, firstName, patronymic, surName, " + "sex, dateOfBirth, group_id, educationYear FROM students " + "WHERE group_id = ? AND educationYear = ? " + "ORDER BY surName, firstName, patronymic"); stmt.setInt(1, group.getGroupId()); stmt.setInt(2, year); ResultSet rs = stmt.executeQuery(); while (rs.next()) { Student st = new Student(rs); students.add(st); } rs.close(); stmt.close(); return students; } public Student getStudentById(int studentId) throws SQLException { Student student = null; PreparedStatement stmt = con.prepareStatement("SELECT student_id, firstName, patronymic, surName," + "sex, dateOfBirth, group_id, educationYear FROM students WHERE student_id = ?"); stmt.setInt(1, studentId); ResultSet rs = stmt.executeQuery(); while (rs.next()) { student = new Student(rs); } rs.close(); stmt.close(); return student; } public void moveStudentsToGroup(Group oldGroup, int oldYear, Group newGroup, int newYear) throws SQLException { PreparedStatement stmt = con.prepareStatement("UPDATE students SET group_id = ?, educationYear=? " + "WHERE group_id = ? AND educationYear = ?"); stmt.setInt(1, newGroup.getGroupId()); stmt.setInt(2, newYear); stmt.setInt(3, oldGroup.getGroupId()); stmt.setInt(4, oldYear); stmt.execute(); } public void removeStudentsFromGroup(Group group, int year) throws SQLException { PreparedStatement stmt = con.prepareStatement("DELETE FROM students WHERE group_id = ? AND educationYear = ?"); stmt.setInt(1, group.getGroupId()); stmt.setInt(2, year); stmt.execute(); } public void insertStudent(Student student) throws SQLException { PreparedStatement stmt = con.prepareStatement("INSERT INTO students " + "(firstName, patronymic, surName, sex, dateOfBirth, group_id, educationYear)" + "VALUES( ?, ?, ?, ?, ?, ?, ?)"); stmt.setString(1, student.getFirstName()); stmt.setString(2, student.getPatronymic()); stmt.setString(3, student.getSurName()); stmt.setString(4, new String(new char[]{student.getSex()})); stmt.setDate(5, new Date(student.getDateOfBirth().getTime())); stmt.setInt(6, student.getGroupId()); stmt.setInt(7, student.getEducationYear()); stmt.execute(); } public void updateStudent(Student student) throws SQLException { PreparedStatement stmt = con.prepareStatement("UPDATE students " + "SET firstName=?, patronymic=?, surName=?, sex=?, dateOfBirth=?, group_id=?," + "educationYear=? WHERE student_id=?"); stmt.setString(1, student.getFirstName()); stmt.setString(2, student.getPatronymic()); stmt.setString(3, student.getSurName()); stmt.setString(4, new String(new char[]{student.getSex()})); stmt.setDate(5, new Date(student.getDateOfBirth().getTime())); stmt.setInt(6, student.getGroupId()); stmt.setInt(7, student.getEducationYear()); stmt.setInt(8, student.getStudentId()); stmt.execute(); } public void deleteStudent(Student student) throws SQLException { PreparedStatement stmt = con.prepareStatement("DELETE FROM students WHERE student_id = ?"); stmt.setInt(1, student.getStudentId()); stmt.execute(); } } |
Самое важное изменение находится в методе getInstance().
Раньше наш класс загружал драйвер и устанавливал соединение. Теперь мы видим, что соединения класс не делает — он только запрашивает ресурс по имени (отметим. что именно по тому имени, которое указано в файла web.xml и context.xml). А уже Tomcat берет на себя все необходимые действия — открывает соединение (несколько штук сразу), проверяет правильность и т.д.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public static synchronized ManagementSystem getInstance() { if (instance == null) { try { instance = new ManagementSystem(); Context ctx = new InitialContext(); instance.dataSource = (DataSource) ctx.lookup("java:comp/env/jdbc/StudentsDS"); con = dataSource.getConnection(); } catch (NamingException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } return instance; } |
Возможно, что в нашем случае в таком подходе нет необходимости, но это удобно при большом количестве баз данных, коннектов и прочего.
Также надо отметить новый метод – getStudentById(..). Он достаточно очевидный – получаем данные конкретного студента по его ID. Он нам пригодится.
Приведем код нашего сервлета — SimpleList.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
package students.web; import java.io.IOException; import java.io.PrintWriter; import java.sql.SQLException; import java.util.Iterator; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import students.logic.Group; import students.logic.ManagementSystem; public class SimpleList extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text / html;charset=UTF-8"); PrintWriter pw = resp.getWriter(); pw.println("<B> Список групп</B>"); pw.println("<table border = 1>"); try { List l = ManagementSystem.getInstance().getGroups(); for (Iterator it = l.iterator(); it.hasNext();) { Group gr = (Group) it.next(); pw.println("<tr>"); pw.println("<td>" + gr.getGroupId() + "</td>"); pw.println("<td>" + gr.getNameGroup() + "</td>"); pw.println("<td>" + gr.getCurator() + "</td>"); pw.println("<td>" + gr.getSpeciality() + "</td>"); pw.println("</tr >"); } } catch (SQLException e) { throw new ServletException(e); } pw.println("</table>"); } } |
Ну и по традиции добавим код для двух классов — Group.java и Student.java
Group.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
package students.logic; public class Group { private int groupId; private String nameGroup; private String curator; private String speciality; public String getCurator() { return curator; } public void setCurator(String curator) { this.curator = curator; } public int getGroupId() { return groupId; } public void setGroupId(int groupId) { this.groupId = groupId; } public String getNameGroup() { return nameGroup; } public void setNameGroup(String nameGroup) { this.nameGroup = nameGroup; } public String getSpeciality() { return speciality; } public void setSpeciality(String speciality) { this.speciality = speciality; } public String toString() { return nameGroup; } } |
Student.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
package students.logic; import java.sql.ResultSet; import java.sql.SQLException; import java.text.DateFormat; import java.util.Date; public class Student implements Comparable { private int studentId; private String firstName; private String surName; private String patronymic; private Date dateOfBirth; private char sex; private int groupId; private int educationYear; public Student(ResultSet rs) throws SQLException { setStudentId(rs.getInt(1)); setFirstName(rs.getString(2)); setPatronymic(rs.getString(3)); setSurName(rs.getString(4)); setSex(rs.getString(5).charAt(0)); setDateOfBirth(rs.getDate(6)); setGroupId(rs.getInt(7)); setEducationYear(rs.getInt(8)); } public Student() { } public Date getDateOfBirth() { return dateOfBirth; } public void setDateOfBirth(Date dateOfBirth) { this.dateOfBirth = dateOfBirth; } public int getEducationYear() { return educationYear; } public void setEducationYear(int educationYear) { this.educationYear = educationYear; } public int getGroupId() { return groupId; } public void setGroupId(int groupId) { this.groupId = groupId; } public int getStudentId() { return studentId; } public void setStudentId(int studentId) { this.studentId = studentId; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getPatronymic() { return patronymic; } public void setPatronymic(String patronymic) { this.patronymic = patronymic; } public String getSurName() { return surName; } public void setSurName(String surName) { this.surName = surName; } public char getSex() { return sex; } public void setSex(char sex) { this.sex = sex; } public String toString() { return surName + " " + firstName + " " + patronymic + " " + DateFormat.getDateInstance(DateFormat.SHORT).format(dateOfBirth) + " " + groupId + " " + educationYear; } public int compareTo(Object obj) { return this.toString().compareTo(obj.toString()); } } |
Для компиляции наших классов иерархия файлов должна выглядеть так:
1 2 3 4 5 6 7 8 |
students logic -Group.java -ManagementSystem.java -Student.java web -SimpleList.java -servlet-api.jar |
Я скопировал файл servlet-api.jar из директории <TOMCAT_HOME>\lib. Так удобнее собирать. Об этом мы говорили в раньше.
Для того, чтобы скомпилировать классы набираем команду (текущая директория та, в которой находится каталог students):
1 |
javac -classpath .;servlet-api.jar students\web\*.java students\logic\*.java |
Теперь скопируем все наши файлы в директорию <TOMCAT_HOME>\webapps\studentsApp. Структура файлов в каталоге должна выглядеть так:
1 2 3 4 5 6 7 8 9 10 11 12 |
META-INF -context.xml WEB-INF classes students logic -Group.class -ManagementSystem.class -Student.class web -SimpleList.class -web.xml |
Что касается файла
mysql-connector-java-3.1.13-bin.jar — теперь он должен находится в каталоге <TOMCAT_HOME>\lib.
Если все нормально собралось и скопировалось, то запускаем Tomcat и после старта открываем броузер и набираем строку
1 |
http://localhost:8090/studentsApp/simple |
По идее мы должны получить список групп из нашей базы. И теперь мы перейдем непосредственно к написанию нашего приложения.
Студенческий отдел кадров — 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
package students.web.forms; import java.util.Collection; public class MainFrameForm { private int year; private int groupId; private Collection groups; private Collection students; public void setYear(int year) { this.year = year; } public int getYear() { return year; } public void setGroupId(int groupId) { this.groupId = groupId; } public int getGroupId() { return groupId; } public void setGroups(Collection groups) { this.groups = groups; } public Collection getGroups() { return groups; } public void setStudents(Collection students) { this.students = students; } public Collection getStudents() { return students; } } |
Код для сервлета нашей главной страницы:
MainFrameServlet.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
package students.web; import java.io.IOException; import java.sql.SQLException; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.Iterator; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import students.logic.Group; import students.logic.ManagementSystem; import students.logic.Student; import students.web.forms.MainFrameForm; import students.web.forms.StudentForm; public class MainFrameServlet extends HttpServlet { protected void processRequest(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // Установка кодировки для принятия параметров req.setCharacterEncoding("UTF-8"); int answer = 0; try { answer = checkAction(req); } catch (SQLException sql_e) { throw new IOException(sql_e.getMessage()); } if (answer == 1) { // Тут надо сделать вызов другой формы, которая перенаправит сервлет // на другую JSP для ввода данных о новом студенте try { Student s = new Student(); s.setStudentId(0); s.setDateOfBirth(new Date()); s.setEducationYear(Calendar.getInstance().get(Calendar.YEAR)); Collection groups = ManagementSystem.getInstance().getGroups(); StudentForm sForm = new StudentForm(); sForm.initFromStudent(s); sForm.setGroups(groups); req.setAttribute("student", sForm); getServletContext().getRequestDispatcher("/StudentFrame.jsp").forward(req, resp); return; } catch (SQLException sql_e) { throw new IOException(sql_e.getMessage()); } } if (answer == 2) { // Тут надо сделать вызов другой формы, которая перенаправит сервлет // на другую JSP для ввода данных о студенте try { if (req.getParameter("studentId") != null) { int stId = Integer.parseInt(req.getParameter("studentId")); Student s = ManagementSystem.getInstance().getStudentById(stId); Collection groups = ManagementSystem.getInstance().getGroups(); StudentForm sForm = new StudentForm(); sForm.initFromStudent(s); sForm.setGroups(groups); req.setAttribute("student", sForm); getServletContext().getRequestDispatcher("/StudentFrame.jsp").forward(req, resp); return; } } catch (SQLException sql_e) { throw new IOException(sql_e.getMessage()); } } String gs = req.getParameter("groupId"); String ys = req.getParameter("year"); if (answer == 3) { // Здесь мы перемещаем стедунтов в другую группу String newGs = req.getParameter("newGroupId"); String newYs = req.getParameter("newYear"); try { Group g = new Group(); g.setGroupId(Integer.parseInt(gs)); Group ng = new Group(); ng.setGroupId(Integer.parseInt(newGs)); ManagementSystem.getInstance().moveStudentsToGroup(g, Integer.parseInt(ys), ng, Integer.parseInt(newYs)); // Теперь мы будем показывать группу, куда переместили gs = newGs; ys = newYs; } catch (SQLException sql_e) { throw new IOException(sql_e.getMessage()); } } int groupId = -1; if (gs != null) { groupId = Integer.parseInt(gs); } int year = Calendar.getInstance().get(Calendar.YEAR); if (ys != null) { year = Integer.parseInt(ys); } MainFrameForm form = new MainFrameForm(); try { Collection groups = ManagementSystem.getInstance().getGroups(); Group g = new Group(); g.setGroupId(groupId); if (groupId == -1) { Iterator i = groups.iterator(); g = (Group) i.next(); } Collection students = ManagementSystem.getInstance().getStudentsFromGroup(g, year); form.setGroupId(g.getGroupId()); form.setYear(year); form.setGroups(groups); form.setStudents(students); } catch (SQLException sql_e) { throw new IOException(sql_e.getMessage()); } req.setAttribute("form", form); getServletContext().getRequestDispatcher("/MainFrame.jsp").forward(req, resp); } // Здесь мы проверям какое действие нам надо сделать – и возвращаем ответ private int checkAction(HttpServletRequest req) throws SQLException { if (req.getParameter("Add") != null) { return 1; } if (req.getParameter("Edit") != null) { return 2; } if (req.getParameter("MoveGroup") != null) { return 3; } if (req.getParameter("Delete") != null) { if (req.getParameter("studentId") != null) { Student s = new Student(); s.setStudentId(Integer.parseInt(req.getParameter("studentId"))); ManagementSystem.getInstance().deleteStudent(s); } return 0; } return 0; } // Переопределим стандартные методы public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { processRequest(req, resp); } public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { processRequest(req, resp); } } |
Теперь нам необходимо сделать страницу 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
<%@ page contentType="text/html; charset=utf-8" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>Список студентов</title> </head> <body> <form action="<c:url value="/main"/>" method="POST"> <table> <tr> <td>Год:<input type="text" name="year" value="${form.year}"/><br/></td> <td>Список групп: <select name="groupId"> <c:forEach var="group" items="${form.groups}"> <c:choose> <c:when test="${group.groupId==form.groupId}"> <option value="${group.groupId}" selected><c:out value="${group.nameGroup}"/></option> </c:when> <c:otherwise> <option value="${group.groupId}"><c:out value="${group.nameGroup}"/></option> </c:otherwise> </c:choose> </c:forEach> </select> </td> <td><input type="submit" name="getList" value="Обновить"/></td> </tr> </table> <p/> <b>Список студентов для выбранных параметров:<b> <br/> <table> <tr> <th> </th> <th>Фамилия</th> <th>Имя</th> <th>Отчество</th> </tr> <c:forEach var="student" items="${form.students}"> <tr> <td><input type="radio" name="studentId" value="${student.studentId}"></td> <td><c:out value="${student.surName}"/></td> <td><c:out value="${student.firstName}"/></td> <td><c:out value="${student.patronymic}"/></td> </tr> </c:forEach> </table> <table> <tr> <td><input type="submit" value="Add" name="Add"/></td> <td><input type="submit" value="Edit" name="Edit"/></td> <td><input type="submit" value="Delete" name="Delete"/></td> </tr> </table> <p/> <b>Переместить студентов в группу<b> <br/> <table> <tr> <td>Год:<input type="text" name="newYear" value="${form.year}"/><br/></td> <td>Список групп: <select name="newGroupId"> <c:forEach var="group" items="${form.groups}"> <option value="${group.groupId}"><c:out value="${group.nameGroup}"/></option> </c:forEach> </select> </td> <td><input type="submit" name="MoveGroup" value="Переместить"/></td> </tr> </table> </form> </body> </html> |
Теперь рассмотрим код, который необходим для редактирования данных о студенте.
Первый наш класс содержит информацию, которую мы будем показывать на странице – он аналогичен MainFrameForm.java, только данные теперь будут о конкретном студенте.
StudentForm.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
package students.web.forms; import java.text.SimpleDateFormat; import java.util.Collection; import students.logic.Student; public class StudentForm { private static SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy"); private int studentId; private String firstName; private String surName; private String patronymic; private String dateOfBirth; private int sex; private int groupId; private int educationYear; private Collection groups; public void initFromStudent(Student st) { this.studentId = st.getStudentId(); this.firstName = st.getFirstName(); this.surName = st.getSurName(); this.patronymic = st.getPatronymic(); this.dateOfBirth = sdf.format(st.getDateOfBirth()); if (st.getSex() == 'М') { this.sex = 0; } else { this.sex = 1; } this.groupId = st.getGroupId(); this.educationYear = st.getEducationYear(); } public String getDateOfBirth() { return dateOfBirth; } public void setDateOfBirth(String dateOfBirth) { this.dateOfBirth = dateOfBirth; } public int getEducationYear() { return educationYear; } public void setEducationYear(int educationYear) { this.educationYear = educationYear; } public int getGroupId() { return groupId; } public void setGroupId(int groupId) { this.groupId = groupId; } public int getStudentId() { return studentId; } public void setStudentId(int studentId) { this.studentId = studentId; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getPatronymic() { return patronymic; } public void setPatronymic(String patronymic) { this.patronymic = patronymic; } public String getSurName() { return surName; } public void setSurName(String surName) { this.surName = surName; } public int getSex() { return sex; } public void setSex(int sex) { this.sex = sex; } public void setGroups(Collection groups) { this.groups = groups; } public Collection getGroups() { return groups; } } |
Теперь код для нашего сервлета, который будет обрабатывать полученные данные.
StudentFrameServlet.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
package students.web; import java.io.IOException; import java.sql.SQLException; import java.text.SimpleDateFormat; import java.text.ParseException; import java.util.Calendar; import java.util.Collection; import java.util.Iterator; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import students.logic.Group; import students.logic.ManagementSystem; import students.logic.Student; import students.web.forms.MainFrameForm; public class StudentFrameServlet extends HttpServlet { private static final SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy"); protected void processRequest(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // Установка кодировки для принятия параметров req.setCharacterEncoding("UTF-8"); String sId = req.getParameter("studentId"); // Если пользователь нажал кнопку ОК – тогда мы обновляем данные (добавляем нового студента) if (sId != null && req.getParameter("OK") != null) { try { // Если ID студента больше 0, то мы редактируем его данные if (Integer.parseInt(sId) > 0) { updateStudent(req); } // Иначе это новый студент else { insertStudent(req); } } catch (SQLException sql_e) { sql_e.printStackTrace(); throw new IOException(sql_e.getMessage()); } catch (ParseException p_e) { throw new IOException(p_e.getMessage()); } } // А теперь опять получаем данные для отображения на главной форме String gs = req.getParameter("groupId"); String ys = req.getParameter("educationYear"); int groupId = -1; if (gs != null) { groupId = Integer.parseInt(gs); } int year = Calendar.getInstance().get(Calendar.YEAR); if (ys != null) { year = Integer.parseInt(ys); } MainFrameForm form = new MainFrameForm(); try { Collection groups = ManagementSystem.getInstance().getGroups(); Group g = new Group(); g.setGroupId(groupId); if (groupId == -1) { Iterator i = groups.iterator(); g = (Group) i.next(); } Collection students = ManagementSystem.getInstance().getStudentsFromGroup(g, year); form.setGroupId(g.getGroupId()); form.setYear(year); form.setGroups(groups); form.setStudents(students); } catch (SQLException sql_e) { throw new IOException(sql_e.getMessage()); } req.setAttribute("form", form); getServletContext().getRequestDispatcher("/MainFrame.jsp").forward(req, resp); } public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { processRequest(req, resp); } public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { processRequest(req, resp); } private void updateStudent(HttpServletRequest req) throws SQLException, ParseException { Student s = prepareStudent(req); ManagementSystem.getInstance().updateStudent(s); } private void insertStudent(HttpServletRequest req) throws SQLException, ParseException { Student s = prepareStudent(req); ManagementSystem.getInstance().insertStudent(s); } private Student prepareStudent(HttpServletRequest req) throws ParseException { Student s = new Student(); s.setStudentId(Integer.parseInt(req.getParameter("studentId"))); s.setFirstName(req.getParameter("firstName").trim()); s.setSurName(req.getParameter("surName").trim()); s.setPatronymic(req.getParameter("patronymic").trim()); s.setDateOfBirth(sdf.parse(req.getParameter("dateOfBirth").trim())); if (req.getParameter("sex").equals("0")) { s.setSex('М'); } else { s.setSex('Ж'); } s.setGroupId(Integer.parseInt(req.getParameter("groupId").trim())); s.setEducationYear(Integer.parseInt(req.getParameter("educationYear").trim())); return s; } } |
И наконец JSP для отображения данных.
StudentFrame.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
<%@ page contentType="text/html; charset=utf-8" %> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <html> <head> <title>Список студентов</title> </head> <body> <form action="<c:url value="/edit"/>" method="POST"> <input type="hidden" name="studentId" value="${student.studentId}"/> <table> <tr> <td>Фамилия:</td><td><input type="text" name="surName" value="${student.surName}"/></td> </tr> <tr> <td>Имя:</td><td><input type="text" name="firstName" value="${student.firstName}"/></td> </tr> <tr> <td>Отчество:</td><td><input type="text" name="patronymic" value="${student.patronymic}"/></td> </tr> <tr> <td>Дата рождения:</td><td><input type="text" name="dateOfBirth" value="${student.dateOfBirth}"/></td> </tr> <tr> <td>Пол:</td> <td> <c:choose> <c:when test="${student.sex==0}"> <input type="radio" name="sex" value="0" checked>М</input> <input type="radio" name="sex" value="1">Ж</input> </c:when> <c:otherwise> <input type="radio" name="sex" value="0">М</input> <input type="radio" name="sex" value="1" checked>Ж</input> </c:otherwise> </c:choose> </td> </tr> <tr> <td>Группа:</td> <td> <select name="groupId"> <c:forEach var="group" items="${student.groups}"> <c:choose> <c:when test="${group.groupId==student.groupId}"> <option value="${group.groupId}" selected><c:out value="${group.nameGroup}"/></option> </c:when> <c:otherwise> <option value="${group.groupId}"><c:out value="${group.nameGroup}"/></option> </c:otherwise> </c:choose> </c:forEach> </select> </td> </tr> <tr> <td>Год обучения:</td><td><input type="text" name="educationYear" value="${student.educationYear}"/></td> </tr> </table> <table> <tr> <td><input type="submit" value="OK" name="OK"/></td> <td><input type="submit" value="Cancel" name="Cancel"/></td> </tr> </table> </form> </body> </html> |
Наш файл web.xml тоже притерпел некоторые изменения – в нем теперь два сервлета.
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name>Students personnel</display-name> <servlet> <servlet-name>MainFrameServlet</servlet-name> <servlet-class>students.web.MainFrameServlet</servlet-class> </servlet> <servlet> <servlet-name>StudentFrameServlet</servlet-name> <servlet-class>students.web.StudentFrameServlet</servlet-class> </servlet> <servlet> <servlet-name>SimpleList</servlet-name> <servlet-class>students.web.SimpleList</servlet-class> </servlet> <servlet-mapping> <servlet-name>MainFrameServlet</servlet-name> <url-pattern>/main</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>StudentFrameServlet</servlet-name> <url-pattern>/edit</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>SimpleList</servlet-name> <url-pattern>/simple</url-pattern> </servlet-mapping> <resource-ref> <description>DB Connection</description> <res-ref-name>jdbc/StudentsDS</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> </web-app> |
В процессе работы Tomcat не может загрузить библиотеку тэгов JSTL — ее у него нет. Советую найти и загрузить файлы из каталога примеров, который идет вместе с Tomcat — каталог «TOMCAT_HOME/webapps/examples/WEB-INF/lib» — jstl.jar и standard.jar и положить их в <TOMCAT_HOME>\lib (туда, куда мы поместили драйвер для MySQL). Тогда все должно работать хорошо. В принципе можно устанавливать библиотеку вместе с приложением в каталог WEB-INF\lib, но т.к. большинство приложений будет использовать JSTL, то имеет смысл положить библиотеки в общий доступ.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
META-INF -context.xml WEB-INF classes students logic -Group.class -ManagementSystem.class -Student.class web forms -MainFrameForm.class - StudentForm.class -MainFrameServlet.class -StudentFrameServlet.class -MainFrame.jsp -StudentFrame.jsp |
Вот и все, что мне хотелось рассказать о WEB-программировании. Конечно же, мы не смогли просмотреть очень многое, но надеюсь, что Вам стало проще ориентироваться в его многообразии. А пока мы перейдем к несколько иной стороне программирования – к тестированию. Встречайте – Часть 10 — Тестирование с точки зрения разработчика
Я внес исправления и добавил архив с исходным кодом в виде проекта под NetBeans: Исходный код