О сайте Начало Java Студенческий отдел кадров Статьи Курсы по Java Вопросы/Ответы
Часть 9 - Простое WEB-приложение

Студенческий отдел кадров

Пособие по 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>&nbsp;</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 - Тестирование с точки зрения разработчика