«1. Обзор

В этой статье мы рассмотрим ключевой аспект веб-разработки на Java — сервлеты.

2. Сервлет и контейнер

Проще говоря, сервлет — это класс, который обрабатывает запросы, обрабатывает их и отвечает ответом.

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

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

3. Зависимости Maven

Чтобы добавить поддержку сервлетов в наше веб-приложение, требуется зависимость javax.servlet-api:

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

Последнюю зависимость maven можно найти здесь.

Конечно, нам также нужно настроить контейнер сервлетов для развертывания нашего приложения; это хорошее место для начала развертывания WAR на Tomcat.

4. Жизненный цикл сервлета

Давайте рассмотрим набор методов, определяющих жизненный цикл сервлета.

4.1. init()

Метод init предназначен для вызова только один раз. Если экземпляр сервлета не существует, веб-контейнер:

  1. Loads the servlet class
  2. Creates an instance of the servlet class
  3. Initializes it by calling the init method

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

public void init() throws ServletException {
    // Initialization code like set up database etc....
}

4.2. service()

Этот метод вызывается только после успешного завершения метода init() сервлета.

Контейнер вызывает метод service() для обработки запросов, поступающих от клиента, интерпретирует тип HTTP-запроса (GET, POST, PUT, DELETE и т. д.) и вызывает методы doGet, doPost, doPut, doDelete и т. д. как подходящее.

public void service(ServletRequest request, ServletResponse response) 
  throws ServletException, IOException {
    // ...
}

4.3. destroy()

Вызывается контейнером сервлетов, чтобы вывести сервлет из эксплуатации.

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

public void destroy() {
    // 
}

5. Пример сервлета

Давайте теперь настроим полный пример обработки информации с использованием формы.

Для начала давайте определим сервлет с отображением /calculateServlet, который будет собирать информацию, переданную формой POST, и возвращать результат с помощью RequestDispatcher:

@WebServlet(name = "FormServlet", urlPatterns = "/calculateServlet")
public class FormServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, 
      HttpServletResponse response)
      throws ServletException, IOException {

        String height = request.getParameter("height");
        String weight = request.getParameter("weight");

        try {
            double bmi = calculateBMI(
              Double.parseDouble(weight), 
              Double.parseDouble(height));
            
            request.setAttribute("bmi", bmi);
            response.setHeader("Test", "Success");
            response.setHeader("BMI", String.valueOf(bmi));

            RequestDispatcher dispatcher 
              = request.getRequestDispatcher("index.jsp");
            dispatcher.forward(request, response);
        } catch (Exception e) {
            response.sendRedirect("index.jsp");
        }
    }

    private Double calculateBMI(Double weight, Double height) {
        return weight / (height * height);
    }
}

Как показано выше, классы, аннотированные с помощью @WebServlet, должны расширять Класс javax.servlet.http.HttpServlet. Важно отметить, что аннотация @WebServlet доступна только начиная с Java EE 6.

Аннотация @WebServlet обрабатывается контейнером во время развертывания, и соответствующий сервлет становится доступным по указанным шаблонам URL. Стоит отметить, что, используя аннотацию для определения шаблонов URL, мы можем избежать использования дескриптора развертывания XML с именем web.xml для сопоставления нашего сервлета.

Если мы хотим отобразить сервлет без аннотаций, мы можем вместо этого использовать традиционный файл web.xml:

<web-app ...>

    <servlet>
       <servlet-name>FormServlet</servlet-name>
       <servlet-class>com.root.FormServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>FormServlet</servlet-name>
        <url-pattern>/calculateServlet</url-pattern>
    </servlet-mapping>

</web-app>

Далее, давайте создадим базовую HTML-форму:

<form name="bmiForm" action="calculateServlet" method="POST">
    <table>
        <tr>
            <td>Your Weight (kg) :</td>
            <td><input type="text" name="weight"/></td>
        </tr>
        <tr>
            <td>Your Height (m) :</td>
            <td><input type="text" name="height"/></td>
        </tr>
        <th><input type="submit" value="Submit" name="find"/></th>
        <th><input type="reset" value="Reset" name="reset" /></th>
    </table>
    <h2>${bmi}</h2>
</form>

Наконец, Убедитесь, что все работает как положено, давайте также напишем быстрый тест:

public class FormServletLiveTest {

    @Test
    public void whenPostRequestUsingHttpClient_thenCorrect() 
      throws Exception {

        HttpClient client = new DefaultHttpClient();
        HttpPost method = new HttpPost(
          "http://localhost:8080/calculateServlet");

        List<BasicNameValuePair> nvps = new ArrayList<>();
        nvps.add(new BasicNameValuePair("height", String.valueOf(2)));
        nvps.add(new BasicNameValuePair("weight", String.valueOf(80)));

        method.setEntity(new UrlEncodedFormEntity(nvps));
        HttpResponse httpResponse = client.execute(method);

        assertEquals("Success", httpResponse
          .getHeaders("Test")[0].getValue());
        assertEquals("20.0", httpResponse
          .getHeaders("BMI")[0].getValue());
    }
}

6. Сервлет, HttpServlet и JSP

Важно понимать, что технология Servlet не ограничивается протоколом HTTP.

На практике это почти всегда так, но Servlet — это универсальный интерфейс, а HttpServlet — это расширение этого интерфейса, добавляющее специфическую поддержку HTTP, например, doGet и doPost и т. д.

Наконец, Servlet Технология также является основной движущей силой ряда других веб-технологий, таких как JSP — JavaServer Pages, Spring MVC и т. д.

7. Заключение

В этой быстрой статье мы представили основы сервлетов в Java-сети. применение.

Пример проекта можно загрузить и запустить как проект GitHub.