JavaRush /Java блог /Random UA /Ваш перший додаток з використанням Java-сервлетів
Джон Дориан
37 рівень

Ваш перший додаток з використанням Java-сервлетів

Стаття з групи Random UA
Всім привіт! У цій статті ви познайомитеся з таким базовим поняттям веб-розробки, як сервлети, і зможете написати простий додаток з їх використанням. Ваш перший додаток з використанням Java-сервлетів - 1Щоб уникнути зайвих дій, ми не починатимемо з нуля, і продовжимо роботу над нашим додатком з моєї попередньої статті про Hibernate . Однак, оскільки ми тільки починаємо знайомитися з сервлетами, я прибрав із програми все, що пов'язано з класом Auto, і залишив лише клас User та дії з ним. Структура проекту виглядатиме так: Ваш перший додаток з використанням Java-сервлетів - 2Отже, сервлети! Вікіпедія говорить: "Сервлет є інтерфейсом Java, реалізація якого розширює функціональні можливості сервера. Сервлет взаємодіє з клієнтами за допомогою принципу запит-відповідь." І це справді так. Тут ми вперше стикаємося з поняттям "клієнт-серверна архітектура програми". Суть її цілком проста і уміщається на одній картинці (взята звідси ).
Ваш перший додаток з використанням Java-сервлетів - 3
Клієнт звертається до сервера за допомогою надсилання HTTP-запиту. Сервер формує необхідні дані (наприклад, отримує їх із бази даних) та повертає клієнту. Найпростіший приклад: в якійсь соціальній мережі ви натискаєте кнопку "Друзі" і відправляєте таким чином запит серверу. Сервер уточнює у базі даних список ваших друзів і повертає його вам (клієнту). Список HTTP-запитів досить великий, але якщо ви ніколи з ними не стикалися, то для кращого розуміння краще прочитати про них, наприклад, тут . Наше завдання полягає в наступному: Створити CRUD-додаток із використанням сервлетів. Програма повинна вміти створювати, змінювати та видаляти користувачів з бази даних, використовуючи для цього сервлет, що обробляє запити HTTP. Наш додаток зі статті про Hibernate вже вміло робити це, проте він справлявся прямо з Java-коду, точніше - з методу main(). Тут же запити буде надсилати саме клієнт, тобто Ви :) Перше, що нам потрібно зробити, це додати нові залежності в наш файл pom.xml
<xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.itis4</groupId>
    <artifactId>UsersDaoProject</artifactId>
    <version>1.0-SNAPSHOT</version>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.6</version>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <!-- PostgreSQL  -->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.4.1212.jre7</version>
        </dependency>

        <!-- Hibernate 5.2.6 Final -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.2.6.Final</version>
        </dependency>

        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.4.RELEASE</version>
        </dependency>

    </dependencies>

</project>
Ми додали 3 залежності:
  1. Сама бібліотека javax.servlet-api;
  2. Бібліотека тегів JSTL. Вона буде потрібна для створення клієнтської сторони, а саме сторінок JSP;
  3. Spring-WebMVC. Нам знадобиться один клас Spring'a, про який ми поговоримо трохи згодом.
Управління роботою сервлетів здійснює контейнер сервлетів. У нашому випадку ми будемо використовувати Apache Tomcat. Досить популярна штука, і, ймовірно, ви вже про нього чули :) Життєвий цикл сервлета складається з наступних кроків:
  1. У разі відсутності сервлета у контейнері.
    • Клас сервлету завантажується контейнером.
    • Контейнер створює екземпляр класу сервлету.
    • Контейнер викликає метод init(). Цей метод ініціалізує сервлет і викликається в першу чергу до того, як сервлет зможе обслуговувати запити. За весь життєвий цикл метод init() викликається лише один раз.
  2. Обслуговування запиту клієнта. Кожен запит обробляється у окремому потоці. Контейнер викликає метод service() для кожного запиту. Цей метод визначає тип запиту, що прийшов, і розподіляє його у відповідний цьому типу метод для обробки запиту. Розробник сервлету має надати реалізацію цих методів. Якщо надійшов запит, метод якого не реалізований, викликається метод батьківського класу і зазвичай завершується поверненням помилки ініціатору запиту.
  3. Якщо контейнер необхідно видалити сервлет, він викликає метод destroy(), який знімає сервлет з експлуатації. Подібно до методу init(), цей метод теж викликається одного разу за весь цикл сервлету.
Наш сервлет виглядатиме досить просто:
package servlets;

import models.User;
import services.UserService;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

public class UserSimpleServlet extends HttpServlet {

    private UserService service = new UserService();

    public void init(ServletConfig servletConfig) {
        try {
            super.init(servletConfig);
        } catch (ServletException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        List<User> users = service.findAllUsers();
        req.setAttribute("users", users);
        RequestDispatcher dispatcher = req.getRequestDispatcher("/showUsers.jsp");
        dispatcher.forward(req, resp);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        String name = req.getParameter("name");
        int age = Integer.parseInt(req.getParameter("age"));
        User user = new User(name, age);
        service.saveUser(user);
        resp.sendRedirect("/users");

    }

    @Override
    protected void  doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        int id = Integer.parseInt(req.getParameter("id"));
        User user = service.findUser(id);
        user.setName(req.getParameter("name"));
        user.setAge(Integer.parseInt(req.getParameter("age")));
        service.updateUser(user);
        resp.sendRedirect("/users");
    }

    @Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        int id = Integer.parseInt(req.getParameter("id"));
        service.deleteUser(service.findUser(id));
        resp.sendRedirect("/users");
    }
}
Як бачите, він містить у собі метод init(), про який писалося вище, і реалізує 4 методи, що збігаються з чотирма HTTP-запитами - doGet(), doPost(), doPut() та doDelete(). Кожен із них дозволить нам, відповідно, отримувати, створювати, редагувати та видаляти користувачів. Методи приймають на вхід об'єкти класів javax.servlet.http.HttpServletRequest і javax.servlet.http.HttpServletResponse - тобто запит, що надсилається на сервер, та відповідь, яку отримає клієнт. Усередині методів виконуються необхідні методи класу UserService, формується відповідь клієнту, після чого здійснюється перенаправлення на адресау /users. Наприклад, у методі doGet() ми отримуємо список усіх користувачів. Далі ми створюємо об'єкт класу RequestDispatcher, який дозволяє включати об'єкти в Http-запит, а також перенаправляти його до певного ресурсу (наприклад, клієнтської JSP-сторінці). У методі doPut() (оновлення даних користувача) ми обробляємо HTTP-запит, витягуємо з нього параметри id, name і age, знаходимо користувача із зазначеним id, присвоюємо йому ті name і age, які прийшли разом з ним у запиті, і повертаємось на сторінку /users. Однак, щоб усі ці методи коректно працювали, нам необхідно здійснити налаштування сервлету. Для цього ми використовуємо файл web.xml у папці WEB-INF. нам необхідно здійснити налаштування сервлету. Для цього ми використовуємо файл web.xml у папці WEB-INF. нам необхідно здійснити налаштування сервлету. Для цього ми використовуємо файл web.xml у папці WEB-INF.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1"
         xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <servlet>
        <servlet-name>UserSimpleServlet</servlet-name>
        <servlet-class>servlets.UserSimpleServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>UserSimpleServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <servlet-name>UserSimpleServlet</servlet-name>
    </filter-mapping>

</web-app>
Всі теги в цьому файлі, в принципі, інтуїтивно зрозумілі, але пройдемося по них послідовно. <welcome-file-list> - вказана стартова JSP-сторінка, яка відкриватиметься першою під час запуску програми. У нашому випадку, це сторінка index.jsp. <servlet> - реєстрація нашого класу UserSimpleServlet як сервлет. <servlet-mapping> – дуже важливий тег. Він визначає URL, які будуть оброблятися сервлетом. У нашому випадку це взагалі всі URL, тому ми вказуємо просто "/". Але, наприклад, якби у нас була програма з користувачами та їх машинами, то можна було б створити другий сервлет - SimpleAutoServlet. Тоді мапінгом для користувача-сервлета було б "/users" (тобто запити, що стосуються обробки користувачів), а для авто-сервлета - "/autos". І, нарешті, <filter>. Він визначає в собі об'єкт класу org.springframework.web.filter.HiddenHttpMethodFilter. Стаття не стосується Spring'a, тому не розповідатиму про нього в подробицях. Скажу лише, що до нашого додатку він прикручений лише як додаткова фіча. Справа в тому, що для створення сторони клієнта ми будемо використовувати JSP-сторінки. Наші дані відображатимуться на сторінці як таблиця зі списком користувачів. Всередині JSP-сторінок використовуватимуться HTML-теги <form/>. А для надсилання даних з <form/> можуть бути використані лише HTTP-запити GET та POST. Тобто для всіх трьох операцій – оновлення, видалення та створення користувача – нам довелося б використовувати лише POST-запити. Використання PUT та DELETE запитів було б нам недоступним. І, в принципі, це цілком нормально і нескладно реалізувати, але клас HiddenHttpMethodFilter дозволяє нам їх використати. Таким чином, читачеві буде більш очевидно буде видно різниця між операціями в додатку. Зрештою, переходимо до клієнтської частини. Вона представлена ​​п'ятьма JSP-сторінками. index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Здравствуйте!</title>
</head>
<body>
Если вы хотите начать работу с базой данных пользователей - <br>
нажмите кнопку ниже:

<form action = "users" method="get">
    <input type="submit" value="Начать работу с базой данных">
</form>
</body>
</html>
addUser.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Добавить нового пользователя</title>
</head>
<body>
<form action = "/users" method="post">
    <input required type="text" name="name" placeholder="Ім'я">
    <input required type="text" name="age" placeholder="Возраст">
    <input type="submit" value="Сохранить">
</form>
</body>
</html>
deleteUser.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Удалить пользователя</title>
</head>
<body>

Вы действительно хотите удалить пользователя ${param.id}?

&lform action="/users/${param.id}" method="post">
    <input type="hidden" name="id" value="${param.id}">
    <input type="hidden" name="_method" value="delete">
    <input type="submit" value="Удалить">
</form>

</body>
</html>
showUsers.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Список пользователей</title>
</head>
<body>
<table border="2">
    <tr>
        <td>ID</td>
        <td>Ім'я</td>
        <td>Возраст</td>
        <td>Действия</td>
    </tr>
    <c:forEach items="${users}" var = "user">
        <tr>
            <td>${user.getId()}</td>
            <td>${user.getName()}</td>
            <td>${user.getAge()}</td>
            <td>
                <form action = "updateUser.jsp" method="post">
                    <input type="hidden" name="id" value="${user.getId()}">
                    <input type="hidden" name="name" value="${user.getName()}">
                    <input type="hidden" name="age" value="${user.getAge()}">
                    <input type="submit" value="Изменить" style="float:left">
                </form>
                <form action="deleteUser.jsp" method="post">
                    <input type="hidden" name="id" value="${user.getId()}">
                    <input type="submit" value="Удалить" style="float:left">
                </form></td>
        </tr>
    </c:forEach>
</table>

<form action = "addUser.jsp">
    <input type="submit" value="Добавить нового пользователя">
</form>
</body>
</html>
updateUser.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Изменить данные пользователя</title>
</head>
<body>

Редактировать пользователя

<form action="/users/${param.id}" method="post">
    <input type="hidden" name = "id" value="${param.id}">
    <input type="text" name="name" value="${param.name}" placeholder=${param.name}>
    <input type="text" name="age" value="${param.age}" placeholder=${param.age}>
    <input type="hidden" name="_method" value="put">
    <input type="submit" value="Обновить">
</form>

</body>
</html>
Сторінка JSP (Java Server Page) містить текст двох типів: статичні вихідні дані, які можуть бути оформлені в одному з текстових форматів (HTML, SVG, WML або XML), та JSP-елементи, які конструюють динамічний вміст. Для розуміння того, що таке JSP я дозволю собі скопіпастить шматочок дуже гарної статті одного автора ( звідси ). "По суті JSP при першому зверненні перетворюється на сервлет і працює вже як сервлет. Це дуже важливо зрозуміти. JSP НЕ Є сторінкою на кшталт HTML-сторінки— програмісту-початківцю важливо чітко усвідомлювати, що це ще один сервлет — просто його висновок не треба програмувати. Його можна просто намалювати. І у потрібні місця підставити дані. Але т.к. JSP-сторінка хоч якось нагадує HTML, то дизайнерові буде простіше. І я ще раз наполегливо говорю початківцям — JSP є СЕРВЛЕТОМ. Її підготовка з усіма даними відбувається на сервері. Саме там підставляються усі дані. А користувачеві в браузер приходить вже готова HTML-сторінка, на якій ніяких ознак JAVA немає." Ви можете самі переконатися в тому, що JSP-сторінка дійсно є сервлетом, адже на кожній сторінці вказано метод, який необхідно виконати. Наприклад, на стартовій сторінці на сторінці index.jsp вказано, що при натисканні на кнопку "Почати роботу з базою даних" буде виконано method="get". Решту JSP складає звичайна статична HTML-розмітка, тому докладно зупинятися на них не будемо - це тема окремої статті, яких чимало на просторах Інтернету. ми створабо наш додаток, залишилося випробувати його у справі! Для цього нам знадобиться згаданий вище контейнер сервлетів Apache Tomcat. Завантажити кота можназ офіційного сайту (я використовую 8 версію). Далі нам потрібно створити в IDEA конфігурацію для запуску нашої програми через Tomcat. Для цього відкриваємо вкладку "Edit Configurations", Ваш перший додаток з використанням Java-сервлетів - 4створюємо нову конфігурацію Ваш перший додаток з використанням Java-сервлетів - 5та вибираємо Tomcat Server Local. У вкладці Application Server вказуємо шлях до папки, де лежить Tomcat Ваш перший додаток з використанням Java-сервлетів - 6Далі переходимо на вкладку Deployment. Ваш перший додаток з використанням Java-сервлетів - 7Тут здійснюється налаштування розгортання нашої програми на локальному сервері. Наживаємо "+", вибираємо "Artifact"-> Ім'я Вашого Проекту: war (ми будемо збирати додаток у war-файл). Ваш перший додаток з використанням Java-сервлетів.Ось, загалом, і все! На сторінці "Server" ви можете побачити, що програма буде працювати за адресаою "http://localhost:8080/". Збережіть цю конфігурацію і якось назвіть (у мене назва конфіга - "Tommy"). Далі, на вкладці Maven в IDEA (праворуч) скористаємося war-плагіном для складання нашого проекту в war-файл (Plugins -> war -> war:war). Ваша перша програма з використанням Java-сервлетів - 9Після того, як складання було здійснено, запускаємо програму та чекаємо. Ваш перший додаток з використанням Java-сервлетів - 10Успіх! Стартова сторінка запустилася. Тепер натисніть кнопку "Почати роботу з базою даних". Наша JSP сторінка index.jsp сформує GET-запит, який буде оброблений сервером. Сервер сформує відповідь і поверне її нам у вигляді списку всіх існуючих користувачів (якщо вони, звичайно, є у БД). А ось і вони! Ваша перша програма з використанням Java-сервлетів - 12Ваша перша програма з використанням Java-сервлетів - 13Теж працює! Ось ми і написали наш перший додаток із використанням сервлетів. Як бачите, все виявилося не так вже й складно :) Як домашнє завдання Ви можете, наприклад, повернути в додаток функціонал роботи з автомобілями з попередньої статті. Тобто. створити для автомобілів окремий сервлет та jsp-сторінки та навчити наш додаток виводити список автомобілів користувача, додавати йому нові машини, а також редагувати та видаляти їх. PS Сервлети та JSP - технології досить давні, і на просторах інтернету часто можна зустріти коментарі на кшталт "кому потрібна ця старість?". Відповідь досить проста - вона потрібна насамперед тим, хто працюватиме на справжніх проектах, в яких цілком можливо купа написаного з їх використанням коду. І перепилювати "старі" на щось нове,"Head First Servlets and JSP" (лише англійською). Її писали самі автори, як і знамениту супер-книгу " Head First Java " , що багатьом може бути гарантом якості:) Сподіваюся, ця стаття була корисна читачам! Якщо Ви хотіли б побачити нові статті – не забудьте підтримати автора у конкурсі, поставивши "Подобається". А краще - "Дуже подобається" :) Дякую за увагу, та успіхів у навчанні!
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ