«1. Обзор

Сервлеты — это простые классы Java, которые запускаются в контейнере сервлетов.

HTTP-сервлеты (особый тип сервлетов) являются первоклассными компонентами веб-приложений Java. API HTTP-сервлетов предназначен для обработки HTTP-запросов через типичный цикл запрос-обработка-ответ, реализованный в протоколах клиент-сервер.

Кроме того, сервлеты могут управлять взаимодействием между клиентом (обычно веб-браузером) и сервером, используя пары ключ-значение в виде параметров запроса/ответа.

Эти параметры можно инициализировать и привязать к области действия всего приложения (параметры контекста) и области действия, специфичной для сервлета (параметры сервлета).

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

2. Инициализация параметров сервлета

Мы можем определить и инициализировать параметры сервлета, используя аннотации и стандартный дескриптор развертывания — файл «web.xml». Стоит отметить, что эти два варианта не исключают друг друга.

Давайте подробно рассмотрим каждый из этих вариантов.

2.1. Использование аннотаций

Инициализация параметров сервлетов с помощью аннотаций позволяет хранить конфигурацию и исходный код в одном месте.

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

Для этого мы реализуем наивный класс UserServlet, который собирает пользовательские данные через простую HTML-форму.

Во-первых, давайте посмотрим на файл JSP, который отображает нашу форму:

<!DOCTYPE html>
<html>
    <head>
        <title>Context and Initialization Servlet Parameters</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
        <h2>Please fill the form below:</h2>
        <form action="${pageContext.request.contextPath}/userServlet" method="post">
            <label for="name"><strong>Name:</strong></label>
            <input type="text" name="name" id="name">
            <label for="email"><strong>Email:</strong></label>
            <input type="text" name="email" id="email">
            <input type="submit" value="Send">
        </form>
    </body>
</html>

Обратите внимание, что мы закодировали атрибут действия формы с помощью EL (язык выражений). Это позволяет ему всегда указывать на путь «/userServlet», независимо от расположения файлов приложения на сервере.

Выражение «${pageContext.request.contextPath}» устанавливает динамический URL-адрес для формы, который всегда относится к контекстному пути приложения.

Вот наша первоначальная реализация сервлета:

@WebServlet(name = "UserServlet", urlPatterns = {"/userServlet"}, initParams={
@WebInitParam(name="name", value="Not provided"), 
@WebInitParam(name="email", value="Not provided")}))
public class UserServlet extends HttpServlet {
    // ...    
    
    @Override
    protected void doPost(
      HttpServletRequest request, 
      HttpServletResponse response)
      throws ServletException, IOException {
        processRequest(request, response);
        forwardRequest(request, response, "/WEB-INF/jsp/result.jsp");
    }
    
    protected void processRequest(
      HttpServletRequest request, 
      HttpServletResponse response)
      throws ServletException, IOException {
 
        request.setAttribute("name", getRequestParameter(request, "name"));
        request.setAttribute("email", getRequestParameter(request, "email"));
    }
    
    protected void forwardRequest(
      HttpServletRequest request, 
      HttpServletResponse response, 
      String path)
      throws ServletException, IOException { 
        request.getRequestDispatcher(path).forward(request, response); 
    }
    
    protected String getRequestParameter(
      HttpServletRequest request, 
      String name) {
        String param = request.getParameter(name);
        return !param.isEmpty() ? param : getInitParameter(name);
    }
}

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

Обратите внимание, что мы использовали метод getParameter() HttpServletRequest для извлечения данных из HTML-формы и метод getInitParameter() для доступа к параметрам инициализации сервлета.

Метод getRequestParameter() проверяет, являются ли параметры запроса name и email пустыми строками.

Если это пустые строки, то им присваиваются значения по умолчанию соответствующих параметров инициализации.

Метод doPost() сначала извлекает имя и адрес электронной почты, которые пользователь ввел в HTML-форму (если есть). Затем он обрабатывает параметры запроса и перенаправляет запрос в файл «result.jsp». запустите его, он должен сначала отобразить страницу HTML-формы.

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>User Data</title>
    </head>
    <body>
        <h2>User Information</h2>
        <p><strong>Name:</strong> ${name}</p>
        <p><strong>Email:</strong> ${email}</p>
    </body>
</html>

После того, как пользователь заполнил поля имени и адреса электронной почты и отправил форму, он выведет данные:

Если форма просто пуста, она отобразит параметры инициализации сервлета:

User Information
Name: the user's name
Email: the user's email 

~ ~~ В этом примере мы показали, как определить параметры инициализации сервлета с помощью аннотаций и как получить к ним доступ с помощью метода getInitParameter().

User Information 
Name: Not provided 
Email: Not provided

2.2. Использование стандартного дескриптора развертывания

Этот подход отличается от подхода, использующего аннотации, поскольку он позволяет нам сохранять конфигурацию и исходный код изолированными друг от друга.

Чтобы продемонстрировать, как определить параметры инициализации сервлета с помощью файла «web.xml», давайте сначала удалим аннотации initParam и @WebInitParam из класса UserServlet:

Затем давайте определим параметры инициализации сервлета в файл «web.xml»:

@WebServlet(name = "UserServlet", urlPatterns = {"/userServlet"}) 
public class UserServlet extends HttpServlet { ... }

Как показано выше, определение параметров инициализации сервлета с помощью файла «web.xml» сводится к использованию \u003cinit-param\u003e, \u003cparam-name\u003e и Теги \u003cпараметр-значение\u003e.

<?xml version="1.0" encoding="UTF-8"?>
<web-app  
  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" version="3.1">
    <servlet>
        <display-name>UserServlet</display-name>
        <servlet-name>UserServlet</servlet-name>
        <init-param>
            <param-name>name</param-name>
            <param-value>Not provided</param-value>
        </init-param>
        <init-param>
            <param-name>email</param-name>
            <param-value>Not provided</param-value>
        </init-param>
    </servlet>
</web-app>

«Кроме того, можно определить столько параметров сервлета, сколько необходимо, если мы придерживаемся приведенной выше стандартной структуры.

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

3. Инициализация параметров контекста

Иногда нам нужно определить некоторые неизменяемые данные, которые должны быть глобально доступны и доступны через веб-приложение.

Из-за глобального характера данных мы должны использовать параметры инициализации контекста всего приложения для хранения данных, а не прибегать к аналогам сервлета.

Несмотря на то, что невозможно определить параметры инициализации контекста с помощью аннотаций, мы можем сделать это в файле «web.xml».

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

Этого можно добиться с помощью нескольких параметров контекста.

Давайте соответствующим образом рефакторим файл «web.xml»:

На этот раз мы использовали теги \u003ccontext-param\u003e, \u003cparam-name\u003e и \u003cparam-value\u003e для определения контекстные параметры провинции и страны.

<web-app 
  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" version="3.1">
    <context-param>
        <param-name>province</param-name>
        <param-value>Mendoza</param-value>
    </context-param>
    <context-param>
        <param-name>country</param-name>
        <param-value>Argentina</param-value>
    </context-param>
    <!-- Servlet initialization parameters -->
</web-app>

Конечно, нам нужно реорганизовать класс UserServlet, чтобы он мог получать эти параметры и передавать их на страницу результатов.

Вот соответствующие разделы сервлета:

Обратите внимание на реализацию метода getContextParameter(), который сначала получает контекст сервлета через getServletContext(), а затем получает параметр контекста с помощью метода getInitParameter().

@WebServlet(name = "UserServlet", urlPatterns = {"/userServlet"})
public class UserServlet extends HttpServlet {
    // ...
    
    protected void processRequest(
      HttpServletRequest request, 
      HttpServletResponse response)
      throws ServletException, IOException {
 
        request.setAttribute("name", getRequestParameter(request, "name"));
        request.setAttribute("email", getRequestParameter(request, "email"));
        request.setAttribute("province", getContextParameter("province"));
        request.setAttribute("country", getContextParameter("country"));
    }

    protected String getContextParameter(String name) {-
        return getServletContext().getInitParameter(name);
    }
}

Затем нам нужно реорганизовать файл «result.jsp», чтобы он мог отображать параметры контекста вместе с параметрами, специфичными для сервлета:

Наконец, мы можем повторно развернуть приложение и выполнить его один раз. снова.

<p><strong>Name:</strong> ${name}</p>
<p><strong>Email:</strong> ${email}</p>
<p><strong>Province:</strong> ${province}</p>
<p><strong>Country:</strong> ${country}</p>

Если пользователь заполнит HTML-форму именем и адресом электронной почты, то он отобразит эти данные вместе с параметрами контекста:

В противном случае будут выведены параметры инициализации сервлета и контекста:

User Information 
Name: the user's name 
Email: the user's email
Province: Mendoza
Country: Argentina

Хотя пример надуман, он показывает, как использовать параметры инициализации контекста для хранения неизменяемых глобальных данных.

User Information 
Name: Not provided 
Email: Not provided
Province: Mendoza 
Country: Argentina

Поскольку данные привязаны к контексту приложения, а не к конкретному сервлету, мы можем получить к ним доступ из одного или нескольких сервлетов, используя методы getServletContext() и getInitParameter().

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

В этой статье мы изучили ключевые концепции параметров инициализации контекста и сервлета, а также способы их определения и доступа к ним с помощью аннотаций и файла «web.xml».

В течение некоторого времени в Java наблюдалась сильная тенденция избавляться от файлов конфигурации XML и переходить на аннотации, когда это возможно.

CDI, Spring, Hibernate и многие другие являются яркими примерами этого.

Тем не менее, нет ничего плохого в использовании файла «web.xml» для определения контекста и параметров инициализации сервлета.

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

Как обычно, все примеры кода, показанные в этой статье, доступны на GitHub.

«