Книга 1 - Начальные сведения
Книга 2 - Более профессиональный подход |
Студенческий отдел кадров Пособие по JAVA-технологиям (с) AntonSaburov Итак,
мы приступаем к написанию нашего приложения в виде интернет-решения. В
предыдущих частях Вы уже посмотрели основы взаимодействия броузера с сервером.
Мы выяснили, что запросы пользователя посылаются на сервер, где их обрабатывает
сервлет. Сервлет может сам создать необходимый 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 <?xml version="1.0"
encoding="ISO-8859-1"?> <web-app
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4"> <display-name>Students
personnel</display-name>
<servlet>
<servlet-name>MainFrameServlet</servlet-name>
<servlet-class>students.web.MainFrameServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MainFrameServlet</servlet-name>
<url-pattern>/main</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. <?xml version="1.0"
encoding="UTF-8"?> <Context path="/studentsApp"> <Resource
name="jdbc/StudentsDS"
type="javax.sql.DataSource"
username="root"
password=""
driverClassName="com.mysql.jdbc.Driver"
maxIdle="2"
maxWait="5000"
validationQuery="SELECT 1"
url="jdbc:mysql://127.0.0.1:3306/students"
maxActive="4">
</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 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 берет
на себя все необходимые действия - открывает соединение (несколько штук сразу),
проверяет правильность и т.д. 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. Он
нам пригодится. Приведем
код нашего сервлета - MainFrameServlet.java 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 MainFrameServlet extends HttpServlet { public void
doGet(HttpServletRequest req, HttpServletResponse resp) throws
ServletException, IOException {
resp.setContentType("text/html;charset=windows-1251"); 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 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 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+ "
_R¤:"+educationYear; } public int compareTo(Object
obj) { return
this.toString().compareTo(obj.toString()); } } Для
компиляции наших классов иерархия файлов должна выглядеть так: students logic
-Group.java
-ManagementSystem.java
-Student.java web -MainFrameServlet.java -servlet-api.jar Я скопировал файл
servlet-api.jar из директории <TOMCAT_HOME>\common\lib. Так удобнее собирать. Об этом мы говорили в раньше. Для
того, чтобы скомпилировать классы набираем команду (текущая директория та, в которой
находится каталог students): javac -classpath .;servlet-api.jar students\web\*.java
students\logic\*.java Теперь
скопируем все наши файлы в директорию <TOMCAT_HOME>\webapps\studentsApp.
Структура файлов в каталоге должна выглядеть так: META-INF -context.xml WEB-INF classes students logic
-Group.class
-ManagementSystem.class
-Student.class web
-MainFrameServlet.class -web.xml Что касается файла mysql-connector-java-3.1.13-bin.jar. Теперь он должен находится в каталоге <TOMCAT_HOME>\common\lib. Если
все нормально собралось и скопировалось, то запускаем Tomcat и после старта
открываем броузер и набираем строку http://localhost:8090/studentsApp/main По
идее мы должны получить список групп из нашей базы. И теперь мы перейдем
непосредственно к написанию нашего приложения. Студенческий отдел кадров -
WEB-приложение В
данном приложении автор не собирается делать какие-то супер красивые и удобные HTML-странички.
Посему будет все очень просто - во-первыхЮ чтобы было понятнее. Во-вторых -
цель проекта познакомиться, а не вдаваться в тонкости GUI. Давайте
перечислим еще раз те формы, котоыре нам потребуются: 1.
Главная форма, которая показывает список групп, поле для ввода года и список
студентов, соответсвующий выбранной группе и году. В этой же форме можно
выполнять удаление студента и удаление всех студентов из выделенной группы. 2.
Форма для ввода данных о студенте - мы можем использовать одну форму для
добавления и для редактирования. Давайте
немного подробнее опишем эти формы. Итак
- главная форма. Для
ввода года будем использовать обычное текстовое поле - можно с помощью
JavaScript проверку корректности, но мы не будем этого делать - упростим все до
предела. Список
групп будет обычным выпадающим списком. Список
студентов оформим в виде таблицы где удаление и редактирование мы сделаем
просто - каждый студент в списке может быть выделен с помощью радиокнопки
(RadioButton). После этого достаточно нажать кнопку - Редактировать, Удалить -
и можно посылать команду на сервер. Форма
для редактирования/добавления студента - мы просто перечислим поля. Для поля
"Пол" используем радиокнопки, для поля "Группа" - список.
Дату будем вводить просто строкой - не будем усложнять. Разобравшись
с формами попробуем набросать список команд. В общем-то он и определит, какие
сервлеты нам потребуются. Мы постараемся не делать список слишком длинным, тем
более, что те же команды редактирования/добавления студента в общем-то можно
свести к одной - если мы передаем ID студента =0, то можно сказать, что надо
добавить. Иначе - редактировать. Итак
наш список выглядит следующим образом: -
Показать список студентов для определенного года и определенной группы. -
Удалить студента -
Редактировать/добавить студента Замечение: Умение правильно
проектировать набор нужных сервлетов - дело опыта. Так что проектируйте,
делайте, ломайте и заново стройте - после нескольких попыток вы научитесь этому
занимательному делу. Я
не буду утверждать, что сделал оптимальный набор - возможно кому-то захочется
сделать его более полным, кому-то покажется, что кое-какие команды можно
реализовать одним сервлетом. но как сделано - так сделано. Мне важно показать
технологию в действии. Мы
будем использовать сервлеты для получения данных, преобразования и потом
вызывать JSP для отображения. Пойдем
по порядку - главная форма - MainFrameServlet (мы его уже создавали чуть раньше
- так что нам потребуется просто его изменить). Как
уже говорилось в предыдущих частях JSP служит для того, чтобы показать данные
которые ей передал сервлет. Профессионалы могут поспорить, но мне важно, чтобы
вы поняли вот какой момент - сервлет собирает все данные по разным таблицам, по
разным файла и т.д., кладет это все в некоторую структуру и передает JSP,
которая занимается тем, что из этой структуры "вытаскивает" нужные
данные и кладет их на соотвтествующее место на странице. Как
видите для реализации команды нам надо три компонента: - сервлет,
который выполняет какие-то действия, собирает необходимые нам данные и кладет
их в -
структуру, которая содержит все необходимые данные для показа на -
JSP странице, которая "вынимает" из структуры данные и располагает их
по странице Начнем
мы со второго пункта - состав структуры достаточно очевиден - год, список
групп, ID конкретной группы, список студентов для конкретной группы и данного
года. Для всех таких структур создадим новый пакет - students.web.forms. Мы
еще вернемся к этому вопросу, но все-таки предварительного упоминания этот
момент заслуживает: JSP
2.0 и выше используется так называемы "Язык выражений" (ЯВ) -
основная его идея в том, чтобы не писать страшные конструкции типа <%=
request.getParameter("parameter") %> ЯВ
имеет упрощенный синтаксис обращения к полям объектов, которые находятся в JSP
(это как раз наша структура, которая содержит много данных). Писать постоянно
формулы и get/set методы не очень интересно и поэтому был сделан ЯВ. В нем
обращение к данным гораздо приятнее на вид. Очень
важно учесть, что ЯВ требует правильного именования полей и наличия методов
set/get. Чуть ниже приведен код нашей структуры и там можно увидеть как
именовать поля и методы доступа к ним. Т.е.
получим вот такой вот класс: MainFrameForm.java 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 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 { 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); } // Переопределим стандартные методы 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 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; } } Теперь
нам необходимо сделать страницу JSP, которая будет нам показывать наши
результаты. Эту страницу мы положим в корень каталога для нашего WEB-приложения. Вам
необходимо обратить внимание на следующие моменты: 1.
<%@
taglib uri="/WEB-INF/tld/c.tld" prefix="c"
%> - команда, которая загружает библиотеку стандартных тэгов – тот самый JSTL о
котором мы говорили в предыдущей части. 2.
Фрагменты
из JSP c:forEach –
специальный тэг, который позволяет перебрать элементы коллекции c:choose –
тэг для выбора из вариантов по условию c:when
и то, что не
подошло будет выполнятеся в теле тэга c:otherwise Стоит
отметить, что JSTL является достаточно мощным инструментом и я советую Вам
потратить время на изучение тэгов. Мне очень понравилась книга Сью
Шпильман. «JSTL. Практическое
руководство для JSP-программистов». Очень кратко, но по делу MainFrame.jsp <%@ page contentType="text/html;
charset=windows-1251" %> <%@ taglib uri="/WEB-INF/tld/c.tld"
prefix="c" %> <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 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 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; import students.web.forms.StudentForm; 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 { 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 <%@ page contentType="text/html;
charset=windows-1251" %> <%@ taglib uri="/WEB-INF/tld/c.tld"
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 <?xml version="1.0"
encoding="ISO-8859-1"?> <web-app
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<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-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>
<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 - ее у него
нет. Советую найти и загрузить файл jakarta-taglibs-standard-current.zip
который находится - http://www.apache.org/dist/jakarta/taglibs/standard/jakarta-taglibs-standard-current.zip извлечь
оттуда библиотеки jstl.jar и standard.jar и положить их в
<TOMCAT_HOME>\common\lib (туда, куда мы поместили драйвер для MySQL).
Тогда все должно работать хорошо. В принципе можно устанавливать библиотеку
вместе с приложением в каталог WEB-INF\lib, но т.к. большинство приложений
будет использовать JSTL, то имеет смысл положить библиотеки в общий доступ. Также
оттуда надо извлечь каталог tld и положить его в папке WEB-INF. Таким образом у
вас получится вот такая структура каталогов и файлов: 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 tld -c.tld -c-1_0.tld
-c-1_0-rt.tld -fmt.tld
-fmt-1_0.tld -fmt-1_0-rt.tld -fn.tld
-permittedTaglibs.tld
-scriptfree.tld -sql.tld
-sql-1_0.tld
-sql-1_0-rt.tld -x.tld -x-1_0.tld
-x-1_0-rt.tld -web.xml -MainFrame.jsp Вот
и все, что мне хотелось рассказать о WEB-программировании. Конечно
же, мы не смогли просмотреть очень многое, но надеюсь, что Вам стало проще
ориентироваться в его многообразии. А пока мы перейдем к несколько иной стороне
программирования – к тестированию. Встречайте – Часть 10
- Тестирование с точки зрения разработчика |