## Платформа Java EE
- Набор стандартов и спецификаций для создания корпоративных приложений на Java
- Спецификации Java EE реализуются серверами приложений
- Apache Tomcat
- Sun/Oracle GlassFish
- BEA/Oracle WebLogic
- IBM WebSphere
- RedHat JBoss
## Сервлеты
- [Серверные сценарии](Серверные%20сценарии.md) написанные на Java
- Жизненным циклов сервлетов управляет веб-контейнер (он же контейнер сервлетов)
- В отличие от [CGI](CGI.md) запросы обрабатываются в отдельных потоках (а не процессах) на веб-контейнере
## Преимущества
- Выполняются быстрее, чем CGI-сценарии
- Хорошая масштабируемость
- Надежность и безопасность
- Платформенно-независимы
- Множество инструментов мониторинга и отладки
## Недостатки
- Слабое разделение уровня представления и бизнес-логики
- Возможны конфликты при параллельной обработке запросов
## Обработка HTTP-запроса
1. Браузер формирует [HTTP](../Сеть%20и%20API/HTTP.md)-запрос и отправляет его на сервер
2. Веб-контейнер создает объекты `HttpServletRequest` и `HttpServletResponse`
3. Веб-контейнер вызывает метод `service` у сервлета
4. Сервлет формирует ответ и записывает его в поток вывода `HttpServletResponse`
## Пример сервлета
```Java
package sample.servlet;
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 SampleServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException {
String pageTitle = "Пример сервлета";
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("");
...
out.println("");
}
}
```
## Конфигурация сервлета
Конфигурирование происходит в `WEB-INF/web.xml` (есть конечно аннотации, но это слишком современно). В `WEB-INF/classes` должны лежать скомпилированные джава-классы
```xml
SampleServlet
org.itmo.sample.SampleServlet>
SampleServlet
/sample
```
Полный файл `web.xml`
```xml
SampleServlet
org.itmo.sample.SampleServlet>
SampleServlet
/sample
```
## Жизненный цикл сервлета
- Жизненным циклом управляет веб-контейнер
- Методы, управляющие жизненным циклом, должен вызывать только веб-контейнер
### 1. Загрузка класса сервлета
Проверяются пути: `WEB-INF/classes/`, `WEB-INF/lib/*.jar`, стандартные классы Java SE и классы веб-контейнера
```xml
SampleServlet
org.itmo.sample.SampleServlet>
say-hello
true
```
### 2. Создание экземпляра сервлета
Создание через конструктор `new SampleServlet()`
### 3. Вызов метода init()
`init(config)` - принимает `config`
### 4. Обработка HTTP-запросов
На каждый запрос в новом потоке (на самом деле там пул потоков) вызывается метод `service()`
### 5. Уничтожение сервлета
Вызов метода `destroy()`
## Контекст сервлетов
- API, с помощью которого сервлет может взаимодействовать со своим контейнером
- Доступ к методам осуществляется через интерфейс `javax.servlet.ServletContext`
- У всех сервлетов внутри приложения общий контекст
- В контекст можно помещать общую для всех сервлетов информацию (методы `getAttribute` и `setAttribute`)
- Если приложение - распределенное, то на каждом экземпляре JVM контейнером создается свой контекст
```Java
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class DemoServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
res.setContentType("text/html");
PrintWriter pw = res.getWriter();
ServletContext context = getServletContext();
String driverName = context.getInitParameter("dname");
pw.println("driver name: " + driverName);
pw.close();
}
}
```
В `web.xml` до сервлетов
```xml
dname
org.postgresql.Driver
```
## HTTP-сессии
- Напомним, что HTTP - stateless
- `javax.servlet.HttpSession` - интерфейс, позволяющий идентифицировать конкретного клиента (браузер) при обработке множества HTTP-запросов от него
- Экземпляр `HttpSession` создается при первом обращении клиента к предложению и сохраняется некоторое (настраиваемое) время после последнего обращения
- Идентификатор сессии либо помещается в `cookie`, либо добавляется к URL. Если удалить этот идентификатор, то сервер создаст новую сессию
- В экземпляр `HttpSession` можно помещать общую для этой сессии информацию (`getAttribute` и `setAttribute`)
- Сессия привязана к конкретному приложению, у разных приложений - разные сессии
- В распределенном окружении обеспечивается сохранение целостности данных в HTTP-сессии
```Java
public class SimpleSession extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession();
out.println("");
...
out.println("session id: " + session.getId());
out.println("session timeout: " + session.getMaxInactiveInterval());
session.setMaxInactiveInterval(20*60);
out.println("new session timeout: " + session.getMaxInactiveInterval());
...
out.println("");
}
}
```
## Диспетчиризация запросов сервлетами
- Сервлеты могут делегировать обработку запросов другим ресурсам (сервлетам, JSP, HTML-страницам)
- Диспетчеризация осуществляется с помощью реализаций интерфейса `javax.servlet.RequestDispatcher`
- Два способа получения `RequestDispatcher` - через `ServletRequest` (абсолютный или относительный URL) и `ServletContext` (только абсолютный URL)
- Два способа делегирования - `forward` и `include`
- `forward` - используется `RequestDispatcher`, сервер передает запрос другому сервлету или JSP-странице внутри себя, не говоря об этом браузеру
- `include` - используется `response.sendRedirect()`, сервер не передает запрос внутри себя, а говорит браузеру куда сходить (статус-код: 302), url в браузере меняется
```Java
public class MyServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
RequestDispatcher dispatcher = request.getRequestDispatcher("index.jsp");
dispatcher.forward(request, response);
}
}
```
## Фильтры запросов
- Фильтры позволяют осуществлять пред- и постобработку запросов до и после передачи их ресурсу (сервлету, JSP или HTML-странице)
- Пример предобработки - допуск только авторизованных пользователей
- Пример постобработки - запись в лог времени обработки запроса
- Реализуют интерфейс `javax.servlet.Filter`
- Ключевой метод `doFilter`
- Метод `doFilter` класса `FilterChain` передает управление следующему фильтру или целевому ресурсу, таким образом возможна реализация последовательностей фильтров
```Java
public class MyFilter implements Filter {
@Override
public void init(FilterConfig arg0) throws ServletException {}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
PrintWrite out = resp.getWriter();
out.print("filter is invoked before");
chain.doFilter(req, resp); // sends to next resource
out.print("filter is invoked after);
}
@Override
public void destroy() {}
}
```
Конфигурация похожа на конфигурацию сервлетов
```xml
s1
HelloServlet
s1
/servlet1
f1
MyFilter
f1
/servlet1
```
> [!important] Порядок сверху вниз, но если использовать аннотации, то порядок недетерминирован