Как создать Servlet? Полное руководство

Если вы решили создать web проект на Java EE, то вам не обойтись без Servlet-ов. В этом уроке я продемонстрирую работу с Servlets, а также расскажу о их особенностях.

Шаг 0. Введение

Servlet – в первую очередь это простой Java интерфейс, реализация которого расширяет функциональные возможности сервера.

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

Шаг 1. Создание и конфигурирование проекта

Заходим в нами всеми любимую IDE Intellij IDEA и создаем Maven Project. Структура проекта простая и не сложная, один класс и стандартная структура Maven проекта.

Теперь откройте pom.xml и добавьте туда зависимость, которая позволит нам использовать Servlet-ы.

<?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.devcolibri</groupId>
    <artifactId>com.devcolibri.servlet</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

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

</project>

Обратите внимание, что мы используем Servlet версии 3.1 они присутствуют в Java EE7.

Шаг 2. Создание сервлета

Теперь создаем класс MainServlet.java как показано на скриншоте структуры выше, дальше наследуем его от HttpServlet и переопределяем два метода void doGet(…) и void doPost(…):

package com.devcolibri.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MainServlet extends HttpServlet {

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

        super.doGet(req, resp);
    }

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

        super.doPost(req, resp);
    }

}

Теперь разберем что да как. Как вы уже заметили мы унаследовались от HttpServlet это абстрактный класс GenericServlet который в свою очередь реализует интерфейс Servlet.

HttpServlet предназначен для написания сервлетов по типу общения клиент-сервер, а именно используя HTTP протокол.

Вспоминаем что такое HTTP протокол. Wiki говорит следующее:

HTTP (HyperText Transfer Protocol — «протокол передачи гипертекста») — протокол прикладного уровня передачи данных (изначально — в виде гипертекстовых документов в формате HTML, в настоящий момент используется для передачи произвольных данных).

Известно, что HTTP протокол имеет 7 методов передачи данных:

– DELETE
– HEAD
– GET
– OPTIONS
– POST
– PUT
– TRACE

Но только два из них пользуются особой популярностью, а именно GET и POST.  Метод GET вызвать легко, достаточно ввести в браузере ссылку и перейти по ней, а вот POST не так просто выполнить, один из простых способов используя form тег указать ему action. Но нам все это не потребуется.

Для того чтобы мы могли обрабатывать методы HTTP запроса в нашем сервлете, нужно переопределить соответствующий метод.

Но чаще всего используются методы GET и POST. Именно их мы и разберем на примере.

Шаг 3. Hello World Servlet

Для того чтобы создать наш первый Hello World нам нужно реализовать метод doGet:

package com.devcolibri.servlet;

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.io.PrintWriter;

public class MainServlet extends HttpServlet {

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

        PrintWriter out = resp.getWriter();
        out.print("<h1>Hello Servlet</h1>");

    }

}

Разберем пример. Как видите метод doGet принимает два параметра:

HttpServletRequest req – это запрос, который пришел к сервлету;

HttpServletResponse resp – это ответ который даст сервлет.

Теперь создаем папку src/main/webapp/WEB-INF, а там создаем файл web.xml в этом файле мы зарегистрируем наш сервлет и замапим его на URL.

Вот содержимое web.xml:

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

    <servlet>
        <servlet-name>mainServlet</servlet-name>
        <servlet-class>com.devcolibri.servlet.MainServlet</servlet-class>
    </servlet>

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

</web-app>

Мы описали два тега servlet и servlet-mapping и которые и заставят наш сервлет показаться в браузере по URL – /

В строке 8 мы указываем имя сервлета (оно может быть любое) это имя является идентификатором, и должно быть уникальным.

В строке 9 мы указываем полный пакетный путь к севрлету. После чего мы можем к нему обращаться по его name (идентификатору).

В строке 13 мы указываем имя сервлета (идентификатор) который хотим замапить на определенный URL.

Строка 14 говорит на какой URL мапить сервлет. Так как у нас стоит / – это значит что зайдя в корень проекта http://localhost:8080/servletexam/ мы получим сервлет, а именно то что в методе doGet.

Теперь собираем проект:

Теперь запускаем, как это сделать рассказано тут Intellij IDEA деплой на Tomcat.

После запуска перейдите по ссылке http://localhost:8080/servletexam/. Вы увидите следующее:

Дальше мы рассмотрим более правильный способ использования Servlets в веб-проектах.

Шаг 4. Используем JSP

Не совсем красиво выводить все HTML теги по средством response. Поэтому давайте прикрутим к сервлету jsp страничку.

Для этого создаем mypage.jsp в webapp:

И содержимое этого файла:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Devcolibri.com</title>
</head>
<body>
    <h1>Hello Servlet</h1>
</body>
</html>

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

Дальше редактируем метод doGet в нашем MainServlet:

package com.devcolibri.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MainServlet extends HttpServlet {

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

        req.getRequestDispatcher("mypage.jsp").forward(req, resp);

    }

}

В 15-й строке мы с запроса получаем Request Dispatcher (Диспетчер Запросов) и указываем ему jsp страницу которая будет отображаться при обращении к данному методуGET. Метод forward(req, resp) перенаправляет наш запрос на jsp страницу.

Теперь если пересобрать приложение Maven-ом и запустить, то получим уже вывод на страницу в браузере содержимого mypage.jsp.

Шаг 5. Передаем данные с Servlet на JSP

Для того чтобы передать какие либо дынные на JSP нам нужно в сервлете в request добавить атрибут.

Чтобы добавить атрибут в request нужно вызвать метод setAttribute(String key, Object value), где

key – это ключ по которому вы получите доступ к данным на JSP;

value – данные которые мы передаем.

package com.devcolibri.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MainServlet extends HttpServlet {

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

        req.setAttribute("name", "Devcolibri");

        req.getRequestDispatcher("mypage.jsp").forward(req, resp);

    }

}

Как видите в строке 15 я передаю имя с ключем (name) и значением (Devcolibri).

Теперь чтобы принять эти данные на JSP нужно обратится к ключу по определенной конструкции ${key}

Давайте на нашей mypage.jsp примем данные с сервлета:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Devcolibri.com</title>
</head>
<body>
    <h1>Hello ${name}</h1>
</body>
</html>

Теперь пересобираем проект с помощью Maven и запускаем. Мы увидим следующий результат:

Вот видим результат, где вместо World выводится Devcolibri.

Шаг 6. Улучшаем сервлет и удаляем web.xml

Согласитесь не совсем удобно регистрировать наш сервлет в web.xml, особенно если у нас будет не один-два сервлета, а 100+, тогда это будет неудобно :) Но в этом есть и плюс, когда все сервлеты зарегистрированы в одном месте, а именно web.xml мы можем удобно их перемапить на другой URL.

Я больше предпочитаю способ регистрации сервлетов, который опишу ниже.

Для начало проаннотируем сервлет аннотацией @WebServlet:

package com.devcolibri.servlet;

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 java.io.IOException;

@WebServlet("/")
public class MainServlet extends HttpServlet {

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

        req.setAttribute("name", "Devcolibri");

        req.getRequestDispatcher("mypage.jsp").forward(req, resp);

    }

}

Данная аннотация регистрирует сервлет в контексте приложения, это тоже самое что мы делали в web.xml:

<servlet>
    <servlet-name>mainServlet</servlet-name>
    <servlet-class>com.devcolibri.servlet.MainServlet</servlet-class>
</servlet>

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

Аннотация принимает как параметр строку, именно эта строка соответствует тегу url-pattern, тоесть это URL по которому будет доступен сервлет.

Вы возможно зададите вопрос, – Зачем тогда этот web.xml? В нашем случае он уже не надо, поэтому смело его удаляем вместе с папкой WEB-INF.

Но если на этом этапе собрать проект и задеплоить, то он у нас не задеплоится, и будет ругаться на отсутствие web.xml. Для того чтобы это исправить идем в pom.xml и в maven-war-plugin добавляем свойство которое делает не обязательным web.xml:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.1.1</version>
    <configuration>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </configuration>
</plugin>

Именно этот Maven плагин отвечает за сборку war архива, который мы потом деплоим на сервер приложений.

Конечная структура проекта выглядит так:

Теперь пересобираем проект вызвав в Maven фазу Install и деплоим на сервер приложений. Напоминаю как это делать со студии Intellij IDEA можно глянуть тут. И мы получим тот же результат, но без лишних файлов и с аннотацией:

На этом все, надеюсь данный туториал будет вам полезен. На вопросы отвечу в комментариях :)

Также читайте серию статей «Spring Data JPA. Работа с БД»: часть 1, часть 2 и часть 3

ПОХОЖИЕ ПУБЛИКАЦИИ

133879
16/04/2014

40 комментариев к статье "Как создать Servlet? Полное руководство"

  1. Вот спасибо: все четко, кратко и понятно!!!

  2. что не так я делаю? после деплоя у меня открывается главная страница tomcat и все. причем артефакты я там найти не могу а ссылка http://localhost:8080/servletexam/ вообще не работает….

  3. Удалил web.xml и без maven-war-plugin все нормально задеплоилось.

  4. Отличная статься, а какие есть еще варианты добавить данные на страницу кроме ${name}, к примеру на index после обработки сменить значение в поле ввода?

  5. Делал все сам, качал исходник – в обоихслучиях после деплоя и запуска сервера появляется 404 The requested resource is not available.
    Подскажите, как с этим бороться?

  6. Статья содержательная и информативная, спасибо огромное автору.

  7. Без maven-war-plugin деплоится без ошибок. Но если пересобирать в maven, то ругается на отсутствие web.xml.
    После добавления ….. в pom.xml пытаемся пересобрать в maven и получаем ошибку unrecognised tag ‘plugin’.
    Лечится так: нужно тег ….. заключить в родительские теги и . Теперь pom.xml должен принять следующий вид:

    org.apache.maven.plugins
    maven-war-plugin
    2.1.1

    false

    З.Ы. Использую IDEA 14.0.2

  8. Спасибо большое за статью

  9. Спасибо большое, мне очень помогло!

  10. Не работает. Откуда вообще взялось “servletexam” в “http://localhost:8080/servletexam/” ?!

  11. Попробуйте задать этой странице mypage.jsp стили, css, прикрутить js. Все это работать в таком случае не будет, на stackoverflow полно вопросов на данную тему. Есть какое-нибудь решение?

  12. Благодарю за полезный урок,
    в своем проекте хочу создать сервлет, который будет выполнять несколько sql запросов-> передавать результат jsp-> на основание этого будет строиться таблица
    Не могу понять как в сервлете несколько запросов создавать, подскажите пожалуйста
    по результатам

  13. Не работает у мен этот код. Чего я только уже не пробовал. Страницу jsp я не создавал. И с web.xml пробовал, и без него. не открывает у меня Томкат это war. А мне позарез нужен сервлет, который будет обрабатывать входящий запрос и выдавать результат. Как мне всю эту логику в неработающий сервлет засунуть ума не приложу. Уже несколько дней мучаюсь :(

  14. Отличная статья ! Все просто, доступно, понятно .

  15. javax.servlet
    javax.servlet-api
    3.1.0
    Добрый день! А как узнать версию сервлета? Что то я ни где этого найти не могу.

  16. Не понял, почему http://localhost:8080/servletexam/ . Мы его нигде не задаем. Любой URL типа http://localhost:8080/что_угодно выдаст нам наш сервлет.

  17. Спасибо. Инфа помогла разобратся с некоторіми вопросами

  18. Подскажите пожалуйста, как в jsp подключить картинки и js, используя данную архитектуру.

  19. Не разворачивается проект в tomcat8, выдается 500 ошибка:
    type Exception report

    message Path mypage.jsp does not start with a “/” character

    description The server encountered an internal error that prevented it from fulfilling this request.

    exception

    java.lang.IllegalArgumentException: Path mypage.jsp does not start with a “/” character
    org.apache.catalina.connector.Request.getRequestDispatcher(Request.java:1366)
    org.apache.catalina.connector.RequestFacade.getRequestDispatcher(RequestFacade.java:613)
    com.devcolibri.servlet.MainServlet.doGet(MainServlet.java:19)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:618)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    note The full stack trace of the root cause is available in the Apache Tomcat/8.0.14 (Debian) logs.

    В чем может быть причина?

  20. Подскажите почему у меня создается файл с расширение jar, а не war? Все делаю по инструкции, уйму раз перепроверял все, выполнил все как в статье на данном сайте по деплою на томкат. Делаю все в intelilij idea 2016.2 ultimate. спасибо за помощь)

  21. Большое спасибо, очень чётко сделано, жалко лайкнуть нельзя для всего интернета.)

  22. Может кому поможет:

    При переопределении метода через Code -> Override Methods (Ctrl+O) -> doGet(), автоматически устанавливается super.doGet(req, resp);
    После деплоя вылезает ошибка 405, контент соответственно не отображается.

    in your doGet() method, get rid of super.doGet(req, resp);
    The HttpServlet basically follows the template method pattern where all non-overridden HTTP methods returns a HTTP 405 error “Method not supported”. When you override such a method, you should not call super method, because you would otherwise still get the HTTP 405 error. The same story goes on for your doPost() method.

  23. Большое спасибо. Именно в таком формате статьи и рулят. Последовательные, понятные. Продолжайте в том же духе

  24. Полезная статья, многое разъяснила

  25. Классный урок спасибо!

  26. спасибо огромное!

Добавить комментарий