Сервлет - это интерфейс прикладного программирования (API) Java, работающий на сервере, который может перехватывать запросы, сделанные клиентом, и может генерировать / отправлять ответ соответствующим образом.

Сервлеты

Сервлет - это интерфейс прикладного программирования (API) Java, работающий на сервере, который может перехватывать запросы, сделанные клиентом, и может генерировать / отправлять ответ соответствующим образом. Хорошо известным примером является HttpServlet, который предоставляет методы для подключения HTTPзапросов с использованием популярных методы HTTP, такие как GETи POST, Вы можете настроить HttpServletдля прослушивания определенного шаблона HTTP-URL, который можно настроить в web.xml, или в последнее время с помощью Java EE 6, с @WebServletаннотаций. Многие веб-платформы Java EE построены на основе сервлетов, таких как JSF, JAX-RS, Spring MVC, Struts, Wicket и так далее. См. Также В чем разница между JSF, сервлетом и JSP?

Жизненный цикл

Когда сервлет запрашивается в первый раз или при запуске веб-приложения, контейнер сервлета создаст его экземпляр и сохранит его в памяти в течение срока службы веб-приложения. Один и тот же экземпляр будет повторно использоваться для каждого входящего запроса, URL-адрес которого соответствует шаблону URL-адреса сервлета. Вы можете получить доступ к запрошенным данным с помощью HttpServletRequestи обработать их ответ HttpServletResponse. Оба объекта доступны как аргументы метода внутри любого из переопределенных методов HttpServlet, таких как doGet()для предварительной обработки запроса и doPost()опубликовать обработать запрос. См. Также Как работают сервлеты? Создание экземпляров, сеансы, общие переменные и многопоточность.

Установка

Для запуска сервлетов вам необходимо:

  • JDK (JRE достаточно, только если на сервере есть собственный компилятор).
  • Контейнер сервлетов.
  • По желанию, интегрированная среда разработки с поддержкой Java EE.

Есть несколько контейнеров сервлетов.

Существуют также серверы приложений Java EE, которые, в свою очередь, также содержат контейнер сервлета помимо других API Java EE, таких как JSF, JPA, EJB и т. Д. См. Также Что такое Java EE?

Установка контейнера сервлетов - это всего лишь вопрос загрузки файла zip / gz и его извлечения в любом месте по вашему выбору.

Как правило, вы также хотели бы использовать IDE, например Eclipse, IntelliJили Netbeans, поэтому вам не нужно вручную компилировать и создавать исходные файлы с помощью javacвновь и вновь. Достойные интегрированные среды разработки имеют плагины для плавной интеграции контейнера сервлета и импорта необходимых API-интерфейсов Java EE в путь сборки проекта. Смотрите также Как импортировать javax API .servlet в моем проекте Eclipse?

Hello World # 1 (постобработка запроса)

Постобработка запроса, такая как отправка и проверка формы POST, является наиболее известным вариантом использования сервлета. Атрибут action HTML <form> может указывать на URL-адрес сервлета, а method="post" запускает метод doPost() сервлета, в котором вы можете свободно управлять запросом HTTP и ответ.

Предполагая, что в /WEB-INF/hello.jsp есть JSP, который выглядит следующим образом ...

<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Servlet Hello World</title>
        <style>.error { color: red; } .success { color: green; }</style>
    </head>
    <body>
        <form action="hello" method="post">
            <h1>Hello</h1>
            <p>
                <label for="name">What's your name?</label>
                <input id="name" name="name" value="${fn:escapeXml(param.name)}">
                <span class="error">${messages.name}</span>
            </p>
            <p>
                <label for="age">What's your age?</label>
                <input id="age" name="age" value="${fn:escapeXml(param.age)}">
                <span class="error">${messages.age}</span>
            </p>
            <p>
                <input type="submit">
                <span class="success">${messages.success}</span>
            </p>
        </form>
    </body>
</html>

(fn:escapeXml() предназначен для защиты вашей страницы от XSSпри повторном отображении контролируемого пользователем ввода; если JSTL этого не делает в общем, не работает, тогда, вероятно, ваш контейнер сервлетов не поддерживает его из коробки (например, Tomcat), вы можете установить его, просто поместив jstl-1.2.jar в /WEB-INF/lib, см. также jstl)

... вот как должен выглядеть класс com.example.controller.HelloServlet:

package com.example.controller;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // Preprocess request: we actually don't need to do any business stuff, so just display JSP.
        request.getRequestDispatcher("/WEB-INF/hello.jsp").forward(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // Postprocess request: gather and validate submitted data and display the result in the same JSP.

        // Prepare messages.
        Map<String, String> messages = new HashMap<String, String>();
        request.setAttribute("messages", messages);

        // Get and validate name.
        String name = request.getParameter("name");
        if (name == null || name.trim().isEmpty()) {
            messages.put("name", "Please enter name");
        } else if (!name.matches("\\p{Alnum}+")) {
            messages.put("name", "Please enter alphanumeric characters only");
        }

        // Get and validate age.
        String age = request.getParameter("age");
        if (age == null || age.trim().isEmpty()) {
            messages.put("age", "Please enter age");
        } else if (!age.matches("\\d+")) {
            messages.put("age", "Please enter digits only");
        }

        // No validation errors? Do the business job!
        if (messages.isEmpty()) {
            messages.put("success", String.format("Hello, your name is %s and your age is %s!", name, age));
        }

        request.getRequestDispatcher("/WEB-INF/hello.jsp").forward(request, response);
    }

}

Скомпилируйте код и поместите его в папку /WEB-INF/classes. В этом конкретном случае файл класса должен оказаться в /WEB-INF/classes/com/example/controller/HelloServlet.class. Такая среда разработки, как Eclipse, Netbeans или IntelliJ, сделает все это автоматически, когда вы создадите динамический веб-проект.

Обратите внимание, что @WebServletработает только в Java EE 6 / Контейнеры с поддержкой Servlet 3.0 (Tomcat 7, Glassfish 3, JBoss AS 6 и т. Д.) И, если присутствует файл /WEB-INF/web.xml, то его корневое объявление <web-app> должно также соответствовать версии Servlet 3.0.

<?xml version="1.0" encoding="UTF-8"?>
<web-app 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">

</web-app>

Если вы используете / нацеливаете более старую версию сервлета, такую как Servlet 2.5, вы должны удалить аннотацию и отобразить сервлет в файле /WEB-INF/web.xml следующим образом, что фактически делает то же самое:

<?xml version="1.0" encoding="UTF-8"?>
<web-app 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5"> 

    <servlet>
        <servlet-name>helloServlet</servlet-name>
        <servlet-class>com.example.controller.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>helloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

В любом случае, он в основном сообщает контейнеру сервлета, что он должен сделать следующее под прикрытием:

HelloServlet helloServlet = new HelloServlet(); // Construct servlet.
helloServlet.init(servletConfig); // Initialize servlet with config.
helloServlet.init(); // Initialize servlet without config.
servlets.put("/hello", helloServlet); // Add to servlet mapping.

Разверните веб-приложение и перейдите по адресу http: // localhost: 8080 / contextname / hello(без расширения .jsp!), Чтобы открыть Hello Мировая страница. Когда вы открываете страницу следующим образом, введя URL-адрес в адресной строке или перейдя по ссылке или закладке, будет запущен запрос HTTP GET и будет вызван метод сервлета doGet(). Когда в URL сервлета отправляется форма с method="post", тогда будет запущен запрос HTTP POST и будет вызван метод сервлета doPost().

Обратите внимание, что JSP помещен в папку /WEB-INF, чтобы предотвратить прямой доступ к JSP, когда пользователь вводит свой URL в адресную строку браузера. Это является обязательным, когда требуется вызвать метод doGet() сервлета перед отображением JSP, например, когда необходимо предварительно загрузить некоторые данные.

Hello World # 2 (предварительная обработка запроса)

Предварительная обработка запроса, такая как предварительная загрузка списка, который должен быть представлен немедленно по «простому ванильному» GET-запросу (который используется, когда вы переходите по ссылке / закладке или сами вводите URL-адрес в адрес браузера), является менее известным примером использования для сервлет. Хотя он широко используется и в реальном мире, обычный базовый учебник по сервлетам, найденный в Интернете, не объясняет этого вообще. Однако это довольно просто: вам просто нужно реализовать бизнес-задачу в методе doGet(), а не в doPost().

Вот базовый начальный пример, где мы получаем список продуктов из базы данных, чтобы его можно было представить сразу же, когда конечный пользователь откроет страницу продукта в интернет-магазине. Только класс ProductService в приведенном ниже примере является другим пользовательским классом и не описан в этой вики, поскольку он выходит за рамки, но его метод list() должен быть достаточно простым. В приведенном ниже примере предполагается, что это EJB, но это может быть что угодно, см. Также, например, этот пост.

package com.example.controller;

import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.example.business.ProductService;
import com.example.model.Product;

@WebServlet("/products")
public class ProductServlet extends HttpServlet {

    @EJB
    private ProductService productService;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // Preprocess request: load list of products for display in JSP.
        List<Product> products = productService.list();
        request.setAttribute("products", products);
        request.getRequestDispatcher("/WEB-INF/products.jsp").forward(request, response);
    }

}

Вот как должен выглядеть /WEB-INF/products.jsp:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Our Products</title>
    </head>
    <body>
        <h1>Products</h1>
        <table>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>Description</th>
                <th>Price</th>
            </tr>
            <c:forEach items="${products}" var="product">
                <tr>
                    <td>${product.id}</td>
                    <td><c:out value="${product.name}" /></td>
                    <td><c:out value="${product.description}" /></td>
                    <td><fmt:formatNumber value="${product.price}" type="currency" /></td>
                </tr>
            </c:forEach>
       </table>
    </body>
</html>

(<c:out> предназначен для защиты вашей страницы от XSSпри повторном отображении контролируемого пользователем ввода, он эффективно работает то же самое, что и fn:escapeXml())

Разверните веб-приложение и перейдите на страницу http: // localhost: 8080 / contextname / products(без расширения .jsp!). Он вызовет метод doGet() сервлета, который загружает продукты из БД, сохраняет его в области запроса и пересылает запрос / ответ для представления результатов.

Чтобы продвинуться дальше, вы можете отфильтровать товары по параметру запроса, полученному из формы поиска GET, следующим образом:

<form action="products">
    <input type="text" name="query" />
    <input type="submit" value="Search" />
</form>

Или гиперссылка (или закладка) следующим образом:

<a href="products?query=java">Search for products with keyword "java"</a>

С участием

String query = request.getParameter("query");
List<Product> products = productService.find(query);
// ...

Это также, как работают поисковые системы, такие как Google!

Стиль кодирования и рекомендации

  • НЕ вызывайте метод doGet() из метода doPost() или наоборот, или пусть они оба вызывают какой-то другой распространенный метод, например processRequest(). Это не верно. Каждый из этих двух методов HTTP имеет свою четкую ответственность: предварительная обработка или пост-обработка HTTP-запроса. Если вы намереваетесь подключить все методы HTTP, вы должны переопределить метод service(). См. Также Шаблон переднего контроллера.

  • НЕ выводите HTML в сервлете, используя операторы out.print(). Это только усложняет обслуживание. HTML-код принадлежит jsp, где у вас есть свобода писать HTML так, как вам хочется, без необходимости использовать методы Java и строки в кавычках. С другой стороны, НЕ используйте скриптлеты (встроенный сырой код Java) внутри файлов JSP. Это только усложняет обслуживание. Java-код принадлежит к Java-классам, где у вас есть свобода писать Java так, как вы хотите, не возиться с уродливыми <% %>вещами. См. Также Как избежать использования кода Java в файлах JSP?

  • НЕ используйте <jsp:useBean>, если вы уже используете сервлет для обработки модели. Это приведет только к путанице и проблемам с обслуживанием, потому что <jsp:useBean> придерживается другого уровня подхода MVC, чем когда вы используете сервлеты. Это либо сервлеты, либо <jsp:useBean>, но не оба.

Характеристики

Интернет-ресурсы и учебные пособия

Часто задаваемые вопросы

Связанные теги