JavaRush /Java блог /Java Developer /Часть 6. Контейнеры сервлетов
Professor Hans Noodles
41 уровень

Часть 6. Контейнеры сервлетов

Статья из группы Java Developer
Этот материал — часть цикла “Введение в Enterprise-разработку”. Предыдущие статьи: Часть 6. Контейнеры сервлетов - 1В прошлой статье мы познакомились с сервлетами, научились с их помощью создавать веб-приложения. Пришло время повнимательнее взглянуть на то, без чего этот праздник был бы невозможен — контейнеры сервлетов.

Содержание:

Что такое контейнер сервлетов

Это программа, которая запускается на сервере и умеет взаимодействовать с созданными нами сервлетами. Иными словами, если мы хотим запустить наше веб-приложение на сервере, мы сначала разворачиваем контейнер сервлетов, а потом помещаем в него сервлеты. Схема работы проста: когда клиент обращается на сервер, контейнер обрабатывает его запрос, определяет, какой именно сервлет должен его обработать и передает его. Часть 6. Контейнеры сервлетов - 2

Как используют контейнеры сервлетов

Кроме маршрутизации запросов, контейнер сервлетов выполняет и другие функции:
  1. Динамически генерирует HTML-страницы с JSP-файлов.
  2. Зашифровывает/расшифровывает HTTPS-сообщения.
  3. Предоставляет разграниченный доступ для администрирования сервлетов.
В общем, звучит неплохо, осталось только разобраться, как это все применить. Ну а чтобы научиться что-то использовать, нужно просто... попробовать это использовать :) Поэтому сегодня будем практиковаться! Самый популярный контейнер сервлетов — Apache Tomcat. Он имеет открытый исходный код, и его можно использовать бесплатно. Скачай Tomcat для своей операционной системы по этой ссылке, и посмотрим на работу с контейнерами “в деле”.

Установка и запуск Tomcat

  1. Для установки Tomcat просто распакуй скачанный архив в нужную директорию.

  2. Учти, что для запуска и работы Tomcat нужна Java версии 8 или выше. Убедись, что переменная среды JAVA_HOME ссылается на актуальную версию jdk.

  3. Далее необходимо сконфигурировать доступ пользователей к Tomcat. Это делается в файле tomcat-users.xml, который находится в папке conf.

    В Tomcat заранее предусмотрены четыре роли:

    • manager-gui — доступ к графическому интерфейсу и странице статусов;
    • manager-script — доступ к текстовому интерфейсу и странице статусов;
    • manager-jmx — доступ к JMX и странице статусов;
    • manager-status — доступ только к странице статусов.

    Внутри тега <tomcat-users> явно пропишем эти роли и назначим их нашему юзеру:

    
    <role rolename="manager-gui"/>
    <role rolename="manager-script"/>
    <role rolename="manager-jmx"/>
    <role rolename="manager-status"/>
    <user username="user" password="password"
        roles="manager-gui, manager-script, manager-jmx, manager-status"/>
    

    Теперь все готово к запуску!

  4. В папке bin запусти файл startup.bat (startup.sh на Linux).

  5. Через несколько секунд в браузере открой ссылку http://localhost:8080/. Там появится графический менеджер:

    Часть 6. Контейнеры сервлетов - 3

    Если видишь такое меню, значит, Tomcat запущен.

  6. Если не работает, вручную проверь переменные среды JAVA_HOME и CATALINA_HOME:

    • JAVA_HOME — должна ссылаться на актуальную версию джавы 8+;
    • CATALINA_HOME — должна ссылаться на Tomcat или отсутствовать (не должна указывать на другую версию Tomcat).

Развертывание приложения в Tomcat

Запустить Tomcat у нас получилось, стало быть, пришло время развернуть в нем какой-то проект. Давай используем сервлеты из прошлой статьи. MainServlet:

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;

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

   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
       HttpSession session = req.getSession();
       Integer visitCounter = (Integer) session.getAttribute("visitCounter");
       if (visitCounter == null) {
           visitCounter = 1;
       } else {
           visitCounter++;
       }
       session.setAttribute("visitCounter", visitCounter);
       String username = req.getParameter("username");
       resp.setContentType("text/html");
       PrintWriter printWriter = resp.getWriter();
       if (username == null) {
           printWriter.write("Hello, Anonymous" + "
"); } else { printWriter.write("Hello, " + username + "
"); } printWriter.write("Page was visited " + visitCounter + " times."); printWriter.close(); } }
IndexServlet:

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 IndexServlet extends HttpServlet {

   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
       resp.sendRedirect(req.getContextPath() + "/hello");
   }
}
Перед развертыванием наши сервлеты необходимо упаковать в war-архив. Обычно для этого используется Мавен, но для создания war-архива нужен файл web.xml, в котором мапятся все сервлеты. Мы же писали сервлеты с использованием новой аннотации @WebServlet, поэтому web.xml у нас нет. Благо, IDEA может выполнить грязную работу за нас и поштучно завернуть наш проект в war-архив. Для этого нужно открыть структуру проекта (Ctrl + Shift + Alt + S) -> Artifacts -> Выбрать нужный варник -> Поставить галочку возле поля “Include in project build” -> Нажать “ОК”. Часть 6. Контейнеры сервлетов - 4Билдим проект с помощью комбинации Ctrl + F9. Теперь в директории target лежит наш war-архив Часть 6. Контейнеры сервлетов - 5Файл можно переназвать как-то попроще — например, servlet.war — и перенести в более удобное место — в C:\my\. Когда варник готов к использованию, помещаем его в контейнер. Это можно сделать двумя способами.
  1. С помощью графического интерфейса

    Для этого переходим по ссылке http://localhost:8080/manager/html. Tomcat должен запросить логин и пароль.

    Если ты повторял все действия за мной, то логин — user, пароль — password.

    После успешной авторизации ты увидишь Tomcat Web Application Manager. В разделе Applications уже содержатся 5 приложений — это служебные приложения Tomcat, необходимые для упрощения работы с ним. В будущем их можно будет удалить.

    Часть 6. Контейнеры сервлетов - 6

    Ниже находится раздел Deploy. С его помощью можно выбрать war-архив для развертывания. Пропишем путь и контекст вручную:

    Часть 6. Контейнеры сервлетов - 7

    Нажимаем “Deploy”, видим, что в разделе Applications появилось наше приложение:

    Часть 6. Контейнеры сервлетов - 8 С помощью графического интерфейса Tomcat мы его можем останавливать, перезапускать, устанавливать длину сессии и удалять. При развертывании мы указали контекст /demo, а значит, обращаться к нашему приложению нужно по ссылке http://localhost:8080/demo. Проверь, все должно работать.

  2. Через файловую систему

    Чтобы задеплоить приложение таким способом, необходимо открыть директорию, в которой разархивирован Tomcat, перейти в webapps. Здесь находятся знакомые нам служебные приложения:

    Часть 6. Контейнеры сервлетов - 9

    Все, что требуется от нас — переместить сюда наш servlet.war.

    Ждем несколько секунд, видим, что появилась новая папка servlet, а это значит, что наше приложение развернуто. Переходим в знакомый нам Application Manager интерфейс — http://localhost:8080/manager/. Здесь мы видим, что наше приложение развернуто в контексте /servlet:

    Часть 6. Контейнеры сервлетов - 10

    При развертывании таким способом, контекст автоматически присваивается по названию развернутого war-архива. Для смены контекста можно переназвать новосозданную папку с приложением, но перед этим нужно удалить варник: в ином случае Tomcat повторно развернет приложение с именем архива.

    Как видишь, деплоить приложения в Tomcat намного проще, чем может показаться. Но и другими его функциями пользоваться несложно. Давай проверим.

Использование HTTPS протокола вместо HTTP

Если помнишь, разницу между HTTP и HTTPS мы рассматривали в отдельной статье. HTTPS — тот же протокол, что и HTTP, только с использованием шифрования данных, которые передаются. На стороне клиента шифрованием занимается браузер, а шифрование на стороне сервера должны обеспечить мы. Так как HTTP запросы принимает и маршрутизирует Tomcat, логично будет делегировать ему и шифрование. Для этого необходимо:
  1. Сгенерировать самоподписанный сертификат;
  2. Сделать дополнительные настройки сервера.
Давай попрактикуемся в этом.

Генерация сертификата

В JDK независимо от версии поставляется большое количество утилит, одна из которых — keytool. Это инструмент для генерации ключей шифрования и работы с ними. Чтобы его использовать, с помощью командной строки перейдем в директорию C:\Program Files\Java\jdk1.8.0_181\bin и выполним команду keytool -genkey -alias tomcat -keyalg RSA.
  • keytool — запускаем утилиту с параметрами;
  • -genkey — указываем, что мы хотим сгенерировать новый ключ;
  • -alias tomcat — создаем псевдоним ключа;
  • -keyalg RSA — выбираем RSA как алгоритм генерации ключа.
После выполнения команды, утилита затеет с нами диалог: Часть 6. Контейнеры сервлетов - 11Вводим необходимую информацию. Теперь мы создали хранилище ключей в нашем домашнем каталоге (для Windows это C:\Users\{username}\.keystore) и ключ tomcat в нем. Мы сгенерировали простой сертификат, на который будет ругаться большинство браузеров. Такой сертификат не подойдет для коммерческих приложений: его можно использовать только в тестовых целях. На продакшн-сервере необходимо использовать сертификат от центра сертификации (например, https://letsencrypt.org/).

Настраиваем сервер

Теперь, когда сертификат готов, нужно подкорректировать серверные настройки, а именно — SSL-коннектор. Это делается в файле server.xml, который находится в apache-tomcat-9.0.30/conf/. Находим там блоки типа:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="150" SSLEnabled="true">
        <SSLHostConfig>
            <Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
                         type="RSA" />
        </SSLHostConfig>
 </Connector>
и возле них помещаем свою конфигурацию:

    <Connector
           protocol="org.apache.coyote.http11.Http11NioProtocol"
           port="8443" maxThreads="200"
           scheme="https" secure="true" SSLEnabled="true"
           keystoreFile="C:\Users\user\.keystore" keystorePass="mypass"
           clientAuth="false" sslProtocol="TLS"/>
Параметрам keystoreFile и keystorePass присваиваем актуальные для нас значения, сохраняем и перезапускаем Tomcat с помощью файлов shutdown.bat и startup.bat. Теперь сервер готов обрабатывать https-запросы, вот только немного по измененному адресу — https://localhost:8443/demo/hello. При переходе по ссылке у тебя появится предупреждение о сомнительности сертификата, что и неудивительно. Как описывалось немного ранее, для получения нормального сертификата нужно воспользоваться услугами одного из сервисов сертификации. Но пока мы достигли нашей цели: приложение работает по HTTPS-протоколу, а это главное!

Динамическая генерация HTML-страниц

Теперь продолжим обзор других фич контейнеров сервлетов — динамической генерации HTML-страниц. Представь себе идеальный мир, где вместо скучного статичного HTML-кода можно было бы писать JAVA-код, используя переменные, циклы, массивы и другие конструкции языка. Представил? Хорошая новость — что-то похожее существует, плохая — не в полной мере. Если ты не догадался, речь идет о технологии JSP (Java Server Pages). Если коротко, это технология, которая позволяет вставлять в HTML-страницу куски JAVA-кода. Правда, потом этот код все равно превращается в HTML перед отправкой клиенту, но он будет динамически сгенерирован с учетом различных факторов. Например, можно использовать условные конструкции, и в зависимости от какого-то условия отдавать различный контент. Пример JSP-страницы:

<%@ page language="java"" %>
<html>
<head>
<title>JSP</title>
</head>

<body>
<%
String firstName="name";
String secondName="surname";
    
    if(firstName.equals("name")){
      out.print("Hello :"+firstName+"<br>");
    }

    if(firstName.equals("name") && secondName.equals("surname"))
    {
      out.print("Hello, my dear friend! <br>");
    }
    else
    {
      out.print("I don’t know you. Go away! <br>");
    }
%>
</body>
</html>
Дополнительно о JSP можно почитать здесь. Вообще... мы не ради этого здесь собрались, а ради контейнеров сервлетов! Причем тут JSP? Все просто: превращение JAVA-кода из JSP в HTML-код осуществляет именно контейнер сервлетов. Когда сервлет собирается вернуть в качестве ответа JSP-контент, контейнер обращает на это внимание, и перед отправкой такого контента клиенту сначала превращает его в понятную для браузера HTML-страницу. Сегодня известно много аналогов технологии JSP — Thymeleaf, FreeMarket, Mustache и другие. Все они работаю по схожему принципу. Какой из них выбирать для работы — дело вкуса. Это касается и выбора контейнера сервлетов. В примерах мы использовали Tomcat — самый распространенный контейнер, но в некоторых проектах используются и другие. С самыми популярными стоит кратко ознакомиться и посмотреть на их отличия от Tomcat.

Альтернативы Tomcat

  1. GlassFish — контейнер с открытым исходным кодом, разработку которого поддерживает Oracle.

    В отличие от Tomcat, это полноценный веб-сервер, который кроме сервлетов может оперировать и другими компонентами из фреймворка JavaEE. В то же время, он использует намного больше оперативной памяти. Более гибкий при тонкой настройке сервера, что усложняет его использование. Стоит использовать при разработке приложений на фреймворке JavaEE.

  2. WildFly — ранее Jboss. Также имеет открытый исходный код. Разрабатывается компанией Red Hat. Название изменили, чтобы избежать путаницы с другим продуктом компании — JBoss Enterprise Application Platform.

    WildFly, как и GlassFish, — полноценный веб-сервер. Кстати, под капотом WildFly использует Tomcat, как контейнер сервлетов. В отличии от GlassFish, WildFly более легковесный и простой в настройке.

  3. Jetty — аналогично предыдущим имеет открытый исходный код. Развивается компанией Eclipse.

    Как и Tomcat, является простым контейнером сервлетов, без поддержки всех компонентов фреймворка JavaEE. В то же время, он более легковесный, и его можно запустить даже на мобильном телефоне. Он быстро запускается и останавливается, хорошо масштабируется. В отличие от Tomcat, имеет меньшее комьюнити и базу знаний.

  4. WebLogic — лицензированное программное обеспечение, требующие покупки перед использованием. Принадлежит компании Oracle.

    По сравнению с Tomcat, его функционал немного шире. Может работать с протоколом ftp. Но он не настолько гибкий при разработке и тестировании приложений.

  5. WebSphere ( WebSphere Application Server, если быть точным) — платное программное обеспечение. Разрабатывается компаниеей IBM. Аналогично WildFly и GlassFish является полноценным сервером приложений. Но у него более дружелюбный интерфейс настройки, плюс высокая надежность в работе.

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

Какой контейнер сервлетов или сервер приложений выбрать, зависит от конкретного проекта. Бывают проекты, где даже явный аутсайдер сможет проявить себя максимально качественно, но на первых порах лучше качественно разобраться с чем-то одним. Наверное, идеальный кандидат на роль этого одного — Tomcat. Первые шаги в его изучении мы уже сделали, а дальше дело за тобой! В завершающих статьях цикла “Введение в Enterprise-разработку” мы с тобой познакомимся с паттерном MVC. Часть 7. Знакомство с паттерном MVC (Model-View-Controller) Часть 8. Пишем небольшое приложение на spring-boot
Комментарии (25)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
AhanSere Уровень 25
4 апреля 2024
Можно сделать war-архив не с помощью IDEA, а с помощью Maven-а: достаточно в pom-файл добавить зависимость <dependency> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.4.0</version> </dependency> и плагин <build> <plugins> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.4.0</version> <configuration> <!-- <webResources> <resource> <directory>additional_resources</directory> </resource> </webResources> --> <archive> <manifest> <addClasspath>true</addClasspath> </manifest> </archive> </configuration> </plugin> </plugins> </build> <directory>additional_resources</directory> - сюда можно добавить дополнительные ресурсы в архив. Тогда war можно создать просто зайдя на вкладку Maven. выбрать папку Plugins - war - war:war и в папке target проекта появится архив
Dima Makarov Уровень 42
15 сентября 2023
Почему Tomcat выдает ошибку при деплое:

Сообщение: 	
ОШИБКА - Не удалось развернуть приложение на контекстном пути [/hello]
StrangeAngel Уровень 46
30 мая 2023
Ставьте 8 tomcat и библиотеки все в импортах, как в примерах в лекции, иначе намучаетесь. На https потратил пол дня, пока 8 tomcat не поставил.
рост Уровень 32
4 февраля 2023
ну крч адрес локалхост 8080 уже юз. и где исправить ето?
bprint Уровень 41
11 января 2023
Не могу настроить коннектор. Ничего не получается. Перечитал гору инфы. Все сделал правильно. HTTPS не открывается
Алексей Уровень 35
17 ноября 2022
Если кто м..дохается со страницей сертификата так, как я сообщаю, что лично мне помогла установка кода про коннектор ВЫШЕ кода про коннектор, который уже был в файле Windows 11, tomcat 9.0.68, jdk 1.8
LuneFox Уровень 41 Expert
2 апреля 2022
Для тех, кто повтоярет, в частности на Linux, пара моментов, на которых я позалипал: 1) Если проект собран в более новой JDK, а Tomcat работает со старой, то при переходе на страницу будет вылезать ошибка 500, а в причинах указаны несоответствия. Версии Java для справки:

Java 1.2 uses major version 46
Java 1.3 uses major version 47
Java 1.4 uses major version 48
Java 5 uses major version 49
Java 6 uses major version 50
Java 7 uses major version 51
Java 8 uses major version 52
Java 9 uses major version 53
Java 10 uses major version 54
Java 11 uses major version 55
Java 12 uses major version 56
Java 13 uses major version 57
Java 14 uses major version 58
Java 15 uses major version 59
Java 16 uses major version 60
Java 17 uses major version 61
Узнать томкатовскую версию Java можно здесь: localhost:8080/manager/status Варианта решения два: - Пересобрать проект, используя в проекте подходящую старую версию Java - Перевести Tomcat на работу с более новой версией Java: для этого в папке /usr/share/tomcat9/bin создаём файлик setenv.sh и прописываем туда путь к JDK, которую должен использовать Tomcat. Например, я установил версию 14 (58 по таблице):
JAVA_HOME=/usr/lib/jvm/java-14-openjdk-amd64
Перезапуск сервера - командой sudo systemctl restart tomcat9 (как и любую другую службу). 2) Ключи для HTTPS После генерации ключа (./bin/keytool) файл с ним (.keystore) лежит в домашней папке: - /home/user/.keystore (если запускали под юзером) - /root/.keystore (если запускали как root) Он скрытый, т.к. начинается на точку, поэтому проверьте, что видите скрытые файлы. Также убедитесь, что Tomcat имеет все права для работы с файлом ключа. Если он будет лежать в /root/ с правами только для root - HTTPS не заработает.
Alexander Shvets Уровень 30
2 февраля 2022
Возможно вы захотите повторить запуск сервлета указанного в статье с использованием tomcat10. В этом случае вам нужно будет обратить внимание что tomcat10 реализует Jakarta Servlet 5.0 а не Java Servlet API 4 (как это было в tomcat9)
Андрей Уровень 28
11 января 2022
Где находится хранилище ключей на mac? После того как сгенерировал ключ с помощью keytool -genkey -alias tomcat -keyalg RSA где найти этот сертификат?
Андрей Уровень 28
22 декабря 2021
Если у вас mac os, то для установки запуска понадобится 2 строчки

brew install tomcat
catalina run
Открываем http://localhost:8080/ и радуемся жизни