Описание тега servlets

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

Сервлеты

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

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

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

Установка

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

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

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

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

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

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

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

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

Предполагая, что в /WEB-INF/hello.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. IDE, такая как Eclipse, Netbeans или IntelliJ, сделает все это автоматически, когда вы создадите динамический веб-проект.

Обратите внимание, что @WebServlet аннотация работает только с контейнерами, поддерживающими Java EE 6 / Servlet 3.0 (Tomcat 7, Glassfish 3, JBoss AS 6 и т. д.), и если /WEB-INF/web.xml файл присутствует, то его <web-app> Объявление root также должно соответствовать версии 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 World. Когда вы открываете такую ​​страницу, вводя URL-адрес в адресной строке или переходя по ссылке или закладке, затем HTTPGET запрос будет запущен, и сервлет doGet()будет вызван метод. Когда форма сmethod="post" отправляется по URL-адресу сервлета, затем HTTP POST запрос будет запущен, и сервлет doPost() будет вызван метод.

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

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

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

Вот базовый начальный пример, в котором мы получаем список продуктов из базы данных, чтобы его можно было сразу представить, когда конечный пользователь открывает страницу продукта в интернет-магазине. ТолькоProductService class в приведенном ниже примере - это еще один настраиваемый класс, не описанный в этой вики, поскольку он выходит за рамки области применения, но его 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>, не оба.

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

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

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

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