Что такое сервлет?
Сегодня просто решил немного прогуляться в ознакомлении — а чего там в Джава,
Пробежался по статьям и сразу везде инфа про сервлеты. Везде пишут детали, а абстрактного описания и назначения нет.
Правильно понимаю, что это абстракция, которая нам по сути оборачивает реквест/респонс и дает интерфейс для работы с сервером в приложении.
Если по аналогии с PHP — это что-то абстрактное типа php-fpm/cgi (создает только поток, а не процесс) и что выводит нам удобный интерфейс (некий аналог пхпшных $_POST/$_GET, завернутых в интерфейс PSR Request/Response) для работы с абстракцией http внутри веб-приложения?
- Вопрос задан более трёх лет назад
- 922 просмотра
3 комментария
Простой 3 комментария
Максим Федоров @Maksclub Автор вопроса
Алексей Черемисин гляньте вопрос, пожалуйста
Ох, и правы, и нет. Завтра с утра попробую ответить.
Решения вопроса 3
Я конечно извиняюсь и не разу не джавер, но беглый гуглинг отлично дает ответ и не путает апплеты (которые мы отлично помним) с сервлетами.
https://ru.wikipedia.org/wiki/%D0%A1%D0%B5%D1%80%D.
Ответ написан более трёх лет назад
Комментировать
Нравится 3 Комментировать
mayton2019 @mayton2019
Bigdata Engineer
Сервлет — это аналог CGI. Была когда-то давно такая техника. Но в современной разработке сервлеты уже не принято использовать. Их заменяют на Rest-endpoints, GraphQL-endpoints которые отдают чистый контент в виде JSON/XML.
Ответ написан более трёх лет назад
Нравится 1 1 комментарий
Максим Федоров @Maksclub Автор вопроса
- Spring Boot
- Selenium Standalone Server
Я мастер на все руки, я козлик Элек Мэк 🙂
Ну пойдем.
1) Сервлет — не аналог CGI, и не аналог PHP
Если уж говорить про аналоги, то ближе всего это FastCGI, но тоже очень далеко.
В отличии от CGI/FastCGI — это ресурс, который:
— имеет четко заданный жизненный цикл с сохранением состояний на приложение, сессию, запрос
— имеет ресурсы, передаваемые ему сервером приложения (авторизация, внешние ресурсы, ресурсы приложения, ресурсы запроса, ресурсы сессии)
— может включать в себя так называемые фильтры пре/пост обработки
— может взаимодействовать с ресурсами приложения и контейнера
В рамках сравнения с PHP, сервлет не имеет встроенного языка шаблонов. И прямой аналог этомы — JSP, которые компилируются перед исполнением в тот же сервлет.
2) Сервлет — строительный кирпичик для контейнеров web-приложений.
Другими словами, есть контейнер (web) приложений, который реализует жизненный цикл сервлетов и фактически является web-сервером, в котором и живут эти web-приложения, обмениваются ресурсами и их используют.
3) Напрямую на сервлетах сейчас достаточно редко пишут, хотя по быстрому набросать websocket очень даже можно. Обычно используют фреймфорки типа spring, javalin, jooby, vaadin, wicklets, tapesty и т.д. (их сотни под разные нужды и задачи!). Все эти фреймворки (библиотеки и обертки) делают удобным работу с API сервлетов, языками шаблонов (их тоже — десятки) и взаимедействием с ресурсами.
4) Кроме сервлетов, есть еще куча всего, что можно сделать без создания сервлета, но получить полноценный web (хотя внутри это все будет обернуто в сервлет скорее всего).
5) кроме сервлетов появились и новые фреймворки, расчитанные на микросервисы, и не обеспечивающие спецификацию сервлетов, например jooby, javalin и т.д.
Вот код простого, боевого, приложения, в котором уже есть web-сервер, держащий нагрузку в несколько тысяч RPS.
import io.javalin.Javalin; public class HelloWorld < public static void main(String[] args) < Javalin app = Javalin.create().start(7000); app.get("/", ctx ->ctx.result("Hello World")); > >
Сервлеты
Клиентский доступ из интернета или корпоративного интранета, конечно же, является легким способом позволить многим получить или предоставить доступ к данным и ресурсам [4].
Этот тип доступа основывается на клиентах, использующий стандартный для World Wide Web Язык Гипертекстовой Разметки (Hypertext Markup Language — HTML) и Протокол Передачи Гипертекста (Hypertext Transfer Protocol — HTTP). Сервлетное API является набором абстрактных общих решений рабочей среды, соответствующих HTTP запросам.
Традиционно, способ решения таких проблем, как возможность для Интернет клиента обновления базы данных, состояла в создании HTML страницы с текстовыми полями и кнопкой «Submit». Пользователь впечатывал соответствующую информацию в текстовые поля и нажимал кнопку «Submit». Данные передавались вместе с URL, который говорил серверу, что делать с данными, указывая расположение программы Common Gateway Interface (CGI), которую запускал сервер, обеспечивая программу данными, которые она требовала. CGI программа обычна написана на Perl, Python, C, C++ или любом другом языке, который умеет читать стандартный ввод и писать в стандартный вывод. Это все, что предоставлял Web сервер: вызывалась CGI программа и использовались стандартные потоки (или, как возможный вариант для ввода, использовалась переменная окружения) для ввода и вывода. CGI программа отвечала за все остальное. Во-первых, она просматривала данные и решала, является ли их формат корректным. Если нет, CGI программа должна производить HTML страницу для описания проблемы; эта страница передавалась Web серверу (через стандартный вывод из CGI программы), который посылал ее назад пользователю. Пользователь должен был, обычно, вернуться на страницу и попробовать снова. Если данные были корректными, CGI программа обрабатывала данные соответствующим способом, возможно, добавляла их в базу данных. Затем она должна была произвести соответствующую HTML страницу для Web сервера, чтобы он вернул ее пользователю.
Было бы идеально перейти к решению, полностью основанному на Java — апплет на клиентской стороне для проверки и пересылки данных и сервлет на серверной стороне для приема и обработки данных. К сожалению, хотя апплеты предоставляют технологию с вполне достаточной поддержкой, они проблематичны в использовании на Web, поскольку вы не можете рассчитывать на поддержку определенной версии Java на клиентском Web браузере; фактически, вы не можете рассчитывать, что Web браузер вообще поддерживает Java! В Интранете вы можете потребовать, чтобы определенная поддержка была доступна, что позволит реализовать намного большую гибкость в том, что вы можете сделать, но в Web более безопасный подход состоит в том, чтобы вся обработка была на стороне сервера, а клиенту доставлялся обычный HTML. Таким образом, ни один пользователь не будет отклонен вашим сайтом по причине того, что у него нет правильно установленного программного обеспечения.
Поскольку сервлеты предоставляют великолепное решение для программной поддержки на стороне сервера, они являются одним из наиболее популярных причин перехода на Java. Не только потому, что они предоставляют рабочую среду, которая заменяет CGI программирование (и снижает количество throny CGI проблем), но весь ваш код приобретает портируемость между платформами, получаемую от использования Java, и вы приобретаете доступ ко всему Java API (за исключением, конечно, того, которое производит GUI, такого, как Swing).
Основа сервлета
Архитектура API сервлета основывается на том, что классический провайдер сервиса использует метод service( ), через который все клиентские запросы будут посылаться программным обеспечением контейнера сервлетов, и методы жизненного цикла init( ) и destroy( ), которые вызываются только в то время, когда сервлет загружается и выгружается (это случается редко).
public interface Servlet <
public void init ( ServletConfig config ) throws ServletException;
public ServletConfig getServletConfig () ;
public void service ( ServletRequest req, ServletResponse res )
throws ServletException, IOException;
public String getServletInfo () ;
public void destroy () ;
>
Основное назначение getServletConfig( ) состоит в возвращении объекта ServletConfig, который содержит параметры инициализации и запуска для этого сервлета. getServletInfo( ) возвращает строку, содержащую информацию о сервлете, такую, как автор, версия и авторские права.
Класс GenericServlet является оболочечной реализацией этого интерфейса и обычно не используется. Класс HttpServlet является расширением GenericServlet и специально предназначен для обработки HTTP протокола — HttpServelt является одним из тех классов, которые вы будете использовать чаще всего.
Наибольшее удобство атрибутов сервлетного API состоит во внешних объектах, которые вводятся вместе с классом HttpServlet для его поддержки. Если вы взглянене на метод service( ) в интерфейсе Servlet, вы увидите, что он имеет два параметра: ServeltRequest и ServletResponse. Вместе с классом HttpServlet, эти два объекта предназначены для HTTP: HttpServletRequest и HttpServletResponse. Вот простейший пример, который показывает использование HttpServelResponse:
//: c15:servlets:ServletsRule.java
//
import javax.servlet.*;
public class ServletsRule extends HttpServlet int i = 0 ; // «постоянство» сервлета
public void service ( HttpServletRequest req, HttpServletResponse res )
throws IOException res.setContentType ( «text/html» ) ;
PrintWriter out = res.getWriter () ;
out.print ( «
out.print ( «A server-side strategy» ) ;
out.print ( «
out.print ( «
Servlets Rule! » + i++ ) ;
out.print ( «
» ) ;
out.close () ;
>
> // /:~
Программа ServletsRule настолько проста, насколько может быть прост сервлет. Сервлет инициализируется только один раз путем вызова его метода init( ), при загрузке сервлета после того, как контейнер сервлетов будет загружен в первый раз. Когда клиент создает запрос к URL, который представлен сервлетом, контейнер сервлетов перехварывает этот запрос и совершает вызов метода service( ) после установки объектов HttpServletRequest и HttpServletResponse.
Основная ответственность метода service( ) состоит во взаимодействии с HTTP запросом, который посылает клиент, и в построении HTTP ответа, основываясь на атрибутах, содержащихся в запросе. ServletsRule манипулирует только объектом ответа, не обращая внимания на то, что посылает клиент.
После установки типа содержимого клиента (которое должно всегда выполнятся прежде, чем будет получен Writer или OutputStream), метод getWriter( ) объекта ответа производит объект PrintWriter, который используется для записи символьных данных ответа (другой вариант: getOutputStream( ) производит OutputStream, используемый для бинарного ответа, который применим для более специализированных решений).
Оставшаяся часть программы просто посылает HTML клиенту (предполагается, что вы понимаете HTML, так что эта часть не объясняется), как последовательность строк. Однако, обратите внимание на включение «счетчика показов», представленного переменной i. Он автоматически конвертируется в строку в инструкции print( ).
Когда вы запустите программу, вы увидите, что значение i сохраняется между запросами к сервлету. Это важное свойство сервлетов: так как только один сервлет определенного класса загружается в контейнер, и он никогда не выгружается (до тех пор, пока контейнер не завершит свою работу, что обычно случается только при перезагрузке серверного компьютера), любые поля сервлета этого класса действительно становятся постоянными объектами. Это значит, что вы можете без усилий сохранять значения между запросами к сервлету, в то время, как в CGI вы должны записывать значения на диск, чтобы сохранить их, что требует большого количества дурацкого окружения для правильного их получения, а в результате получаем не кроссплатформенное решение.
Конечно, иногда Web сервер, а таким образом и контейнер сервлетов, должны перегружаться, как часть ухода или во время пропадания питания. Для предотвращения потери любой постоянной информации методы сервлета init( ) и destroy( ) автоматически вызываются во время загрузки или выгрузки клиента, что дает вам возможность сохранить важные данные во время остановки и восстановления после перезагрузки. Контейнер сервлетов вызывает метод destroy( ) когда он завершает свою работу, так что вы всегда получаете возможность сохранить значимые данные до тех пор, пока серверная машина не будет сконфигурирована разумным способом.
Есть другая особенность при использовании HttpServlet. Этот класс обеспечивает методы doGet( ) и doPost( ), которые приспособлены для CGI «GET» пересылки от клиента и CGI «POST». GET и POST отличаются только деталями в способе пересылки данных, которые лично я предпочитаю игнорировать. Однако, большинство доступной информации, которую я видел, поддерживает создание раздельных методов doGet( ) и doPost( ), вместо единого общего метода service( ), который обрабатывает оба случая. Такое предпочтение кажется достаточно общим, но я никогда не видел объяснения, способного заставить меня поверить в то, что это не является наследием от CGI программистов, которые должны были учитывать имеют ли они дело с методом GET или POST. Так что действуя в духе «делать самые простые вещи, которые только могут работать», [5] я просто буду использовать метод service( ) в этом примере, и позволю этому методу заботится о выборе GET vs. POST. Однако, имейте в виду, что я могу что-то упустить, и что фактически может быть отличная причина для использования методов doGet( ) и doPost( ).
Когда бы форма не отсылалась сервлету, HttpServletRequest посупает со всеми предварительно загруженными данными формы, хранящимися как пары ключ-значение. Если вы знаете имя поля, вы можете просто использовать его напрямую в методе getParameter( ), чтобы найти значение. Вы можете также получить Enumiraton (старая форма Итератора) из имен полей, как показано в следующем примере. Этот пример также демонстрирует как один сервлет может быть использован для воспроизведения страницы, содержащей форму, и для страницы ответа (более хорошее решение вы увидите позже, в разделе о JSP). Если Enumiration пустое, значит нет полей; это означает, что форма не была отправлена. В этом случае производится форма, а кнопка подтверждения будет повторно вызывать тот же самый сервлет. Однако если поля существуют, они будут отображены.
//: c15:servlets:EchoForm.java
// Группа пар имя-значение любой HTML формы
//
import javax.servlet.*;
public class EchoForm extends HttpServlet public void service ( HttpServletRequest req, HttpServletResponse res )
throws IOException res.setContentType ( «text/html» ) ;
PrintWriter out = res.getWriter () ;
Enumeration flds = req.getParameterNames () ;
if ( !flds.hasMoreElements ()) // Нет отосланной формы — создаем:
out.print ( «» ) ;
out.print ( «
» ) ;
>
else out.print ( «
Your form contained:
» ) ;
while ( flds.hasMoreElements ()) String field = ( String ) flds.nextElement () ;
String value = req.getParameter ( field ) ;
out.print ( field + » = » + value + «
» ) ;
>
>
out.close () ;
>
> // /:~
Вы можете заметить одно препятствие, из-за которого Java не выглядит предназначенной для обработки строк в памяти — форматирование возвращаемой страницы достаточно тягостно из-за символов завершения строки, эскейп-символов и знаков «+», необходимых для построения объектов String. Для огромных HTML страницы становится неразумным помещение кода прямо в Java. Одно из решений состоит в хранении страницы, как отдельного текстового файла, который потом открывается и передается Web серверу. Если вы выполните замену любого вида для содержимого этой страницы, это будет нехорошо, так как Java плохо обрабатывает строки. В этом случае вам, вероятно, лучше использовать более подходящее решение (Python может быть моим выбором; существует версия, которая сама встраивается в Java и называется JPython) для генерации страницы ответа.
Сервлеты и многопоточность (multithreading)
Контейнер сервлетов имеет пул нитей (thread), которые он будет диспетчеризировать для обработки запросов клиентов. Они вполне подходят для случая, когда два клиентских запроса поступают одновременно и должны одновременно обработаться вашим методом service( ). Поэтому метод service( ) должен быть выполнен безопасным для многопоточности способом. Любой доступ к общим ресурсам (файлам, базам данных) должен быть гарантировано использоваться с ключевым словом synchronized.
Следующий простой пример помещает выражение synchronized вокруг метода нити slepp( ). Это блокирует все другие нити до тех пор, пока не пройдет указанное время (пять секунд). Когда будете тестировать, вы должны запустить несколько экземпляров браузера и обратится к этому сревлету настолько быстро, насколько вы способны — вы увидите, что каждый экземпляр браузера будет ожидать, пока не получит ответ.
//: c15:servlets:ThreadServlet.java
//
import javax.servlet.*;
public class ThreadServlet extends HttpServlet int i;
public void service ( HttpServletRequest req, HttpServletResponse res )
throws IOException res.setContentType ( «text/html» ) ;
PrintWriter out = res.getWriter () ;
synchronized ( this ) try Thread.currentThread () .sleep ( 5000 ) ;
>
catch ( InterruptedException e ) System.err.println ( «Interrupted» ) ;
>
>
out.print ( «
Finished » + i++ + «
» ) ;
out.close () ;
>
> // /:~
Также возможно синхронизировать весь сервлет, поместив ключевое слово synchronized перед методом service( ). Фактически, есть только одна причина использовать выражение synchronized, если есть критическая секция в ходе выполнения, которая может быть не выполнена. В этом случае, вы можете предотвратить накладные расходы на каждую синхронизацию в блоке с помощью использования выражения synchronized. С другой стороны, все нити все равно будут ожидать, так что вы можете точно так же синхронизировать весь метод.
Обработка сессий с помощью сервлетов
HTTP является сессионным протоколом, так что вы не можете общаться из одного обращения к серверу с другим обращением, не зависимо от того, одна и та же персона опрашивает ваш сайт, или это полностью разные персоны. Большое усилие было вложено в механизм, который позволяет Web разработчику отслеживать сессии. Компании не смогли бы заниматься электронной коммерцией без отслеживания клиента и элементов, которые он положил в свою корзину покупок, например.
Есть несколько методов отслеживания сессии, но наиболее общим методом состоит в постоянстве «cookies», которые являются внутренней частью стандарта Интернет. HTTP Working Group of the Internet Engineering Task Force вписала cookies в официальный стандарт RFC 2109 (ds.internic.net/rfc/rfc2109.txt или проверьте www.cookiecentral.com).
Cookie — это ни что иное, как маленькие кусочки информации, посылаемые Web сервером браузеру. Браузер хранит cookie на локальном диске и когда другой вызов обращается к URL’у, с которым ассоциированы cookie, cookie просто посылается вместе с вызовом, таким образом обеспечивается отсылка необходимой информации серверу (обычно так обеспечивают определенный способ, с помощью которого серверу можно сообщить, что это вы совершаете вызов). Однако клиенты могут отключить возможность браузера принимать cookies. Если ваш сайт должен отслеживать клиента с отключенными cookies, другой механизм отслеживания сессии (перезапись URL или спрятанные поля формы) должен встраиваться вручную, так как возможность отслеживания сессии, встроенная в API сервлета, основывается на cookies.
Класс Cookie
API сервлета (версия 2.0 и следующие) обеспечивают класс Cookie. Этот класс встроен во все детали HTTP заголовков и позволяет устанавливать различные атрибуты cookie. Использование cookie достаточно просто: необходимо позаботиться о добавлении его в объект ответа. Конструктор принимает имя cookie в качестве первого аргумента и значение в качестве второго. Cookie добавляются в объект ответа прежде, чем вы посылаете какое либо содержимое.
Cookie oreo = new Cookie ( «TIJava» , «2002» ) ;
res.addCookie ( oreo ) ;
Cookie получаются назад с помощью метода getCookies( ) объекта HttpServletRequest( ), который возвращает массив объектов cookie.
Cookie [] cookies = req.getCookies () ;
Затем вы можете вызвать getValue( ) для каждого cookie, чтобы получить стоку содержимого cookie. В приведенном выше примере метод getValue(«TIJava») произведет строку, содержащую «2002».
Класс Session
Сессия — это одна или несколько страниц, запрошенных клиентом на Web сайте во время определенного периода времени. Если вы покупаете продукты в режиме он-лайн, например, вы хотите, чтобы ваша сессия ограничивалась периодом от того момента, когда вы в первый раз добавили элемент в «свою корзину покупок» до момента, когда вы подтвердите выбор. Каждый добавленный вами элемент в корзину покупок будет результатом нового HTTP соединения, которое не знает о предыдущих соединениях или элементах в корзине покупок. Чтобы компенсировать этот недостаток информации, механизм обеспечивает спецификацию cookie, позволяющую вашему сервлету выполнить отслеживание сессии.
Объект сессии сервлета живет на серверной стороне коммуникационного канала; его целью является сбор полезных данных об этом клиенте, таких как перемещение клиента по сайту и взаимодействие с вашим Web сайтом. Эти данные могут относиться к текущей сессии и являться, например, элементами в корзине покупок, или это могут быть такие данные, как информация об авторизации, которая была введена клиентом при первом обращении к вашему Web сайту и поэтому ее не нужно вводить еще раз во время определенного набора транзакций.
Класс Session API сервлета использует класс Cookie, чтобы выполнить эту работу. Однако все объекты Session нуждаются в уникальном идентификаторе определенного рода, хранящемся у клиента и передающемся на сервер. Web сайты могут также использовать другие типы отслеживания сессии, но этот механизм будет более сложным для реализации, так как он не встроен в API сервлета (то есть, вы должны написать его руками, обработав ситуации, когда клиент отключает cookies).
Вот пример, который реализует отслеживание сессии с помощью API сервлета:
//: c15:servlets:SessionPeek.java
// Используем класс HttpSession.
//
import java.io.*;
public class SessionPeek extends HttpServlet public void service ( HttpServletRequest req, HttpServletResponse res )
throws ServletException, IOException // Получаем объект Session до любой
// посылки клиенту.
HttpSession session = req.getSession () ;
res.setContentType ( «text/html» ) ;
PrintWriter out = res.getWriter () ;
out.println ( «
out.println ( «
out.println ( »
SessionPeek
» ) ;
// Простой щетчик обращений для этой сессии.
Integer ival = ( Integer ) session.getAttribute ( «sesspeek.cntr» ) ;
if ( ival == null )
ival = new Integer ( 1 ) ;
else
ival = new Integer ( ival.intValue () + 1 ) ;
session.setAttribute ( «sesspeek.cntr» , ival ) ;
out.println ( «You have hit this page » + ival + « times.
» ) ;
out.println ( «
» ) ;
out.println ( «Saved Session Data
» ) ;
// Цикл по всем данным сессии:
Enumeration sesNames = session.getAttributeNames () ;
while ( sesNames.hasMoreElements ()) String name = sesNames.nextElement () .toString () ;
Object value = session.getAttribute ( name ) ;
out.println ( name + » = » + value + «
» ) ;
>
out.println ( »
Session Statistics
» ) ;
out.println ( «Session ID: » + session.getId () + «
» ) ;
out.println ( «New Session: » + session.isNew () + «
» ) ;
out.println ( «Creation Time: » + session.getCreationTime ()) ;
out.println ( «(» + new Date ( session.getCreationTime ()) + «)
» ) ;
out.println ( «Last Accessed Time: » + session.getLastAccessedTime ()) ;
out.println ( «(» + new Date ( session.getLastAccessedTime ())
+ «)
» ) ;
out.println ( «Session Inactive Interval: »
+ session.getMaxInactiveInterval ()) ;
out.println ( «Session ID in Request: » + req.getRequestedSessionId ()
+ «
» ) ;
out.println ( «Is session id from Cookie: »
+ req.isRequestedSessionIdFromCookie () + «
» ) ;
out.println ( «Is session id from URL: »
+ req.isRequestedSessionIdFromURL () + «
» ) ;
out.println ( «Is session id valid: » + req.isRequestedSessionIdValid ()
+ «
» ) ;
out.println ( «» ) ;
out.close () ;
>
public String getServletInfo () return «A session tracking servlet» ;
>
> // /:~
Внутри метода service( ) метод getSession( ) вызывается для объекта запроса, который возвращает объект Session, ассоциированный с этим запросом. Объект Session не посылается по сети, вместо этого он живет на сервере и ассоциируется с клиентом и его запросом.
getSession( ) существует в двух версиях: без параметра, как использовано здесь, и getSession(boolean). getSession(true) эквивалентно вызову getSession( ). Причина для булевского значения состоит в объявлении состояния, с которым вы хотите создать объект сессии, если он не найден. getSession(true) более желательный вызов, отсюда появилась версия getSession( ).
Объект Session, если он не новый, может дать нам детальную информацию о клиенте, взяв ее из предыдущих визитов. Если объект Session новый, то программа начнет собирать информацию об активности этого клиента в этом визите. Сбор этой информации о клиенте выполняется с помощью методов setAttribute( ) и getAttribute( ) объекта сессии.
java.lang.Object getAttribute ( java.lang.String )
void setAttribute ( java.lang.String name, java.lang.Object value )
Объект Session использует простые пары имя-значение для загрузки информации. Имя является строкой, а значение может быть любым объектом, наследованным от java.lang.Object. SessionPeek следит за там, сколько раз клиент возвращался назад во время этой сессии. Это выполняется с помощью объекта Integer, называемого sesspeek.cntr. Если име не найдено, создается Integer со значением равным единице, в противном случае Integer создается с инкрементированным значением по сравнению с предыдущим сохраненным Integer. Новый Integer помещается в объект Session. Если вы используете тот же самый ключ в вызове setAttribute( ), то новый объект переписывает старый. Инкрементированный счетчик используется для отображения количества визитов клиента во время этой сессии.
getAttributeNames( ) имеет отношение к getAttribute( ) и setAttribute( ); он возвращает перечисление имен объектов, которые включены в объект Session. Цикл while в SessionPeek показывает этот метод в действии.
Вы можете удивиться, как долго хранится объект Session. Ответ зависит от контейнера сервлетов, который вы используете; обычно, по умолчанию, это 30 минут (1800 секунд), что вы можете увидеть из вызова метода getMaxInactiveInterval( ) в ServletPeek. Тесты могут воспроизводить разные результаты в зависмиости от контейнера сервлетов. Иногда объект Session может храниться всю ночь, но я никогда не видел случая, когда объект Session исчезал в течение времени меньшего, чем указано в интервале не активности. Вы можете попробовать путем установки интервала не активности с помощью метода setMaxInactiveInterval( ) в значение 5 секунд и посмотреть, останется ли ваш объект Session или он будет очищен в соответствующее время. Это может стать атрибутом, который вы захотите исследовать при выборе контейнера сервлетов.
Запуск примеров сервлета
Если вы еще не работали с Сервером приложений, который обрабатывает сервлеты Sun и JSP технологию для вас, вы можете загрузить Tomcat реализацию Java сервлетов и JSP, которая является бесплатной реализацией с открытыми исходниками, санкционированная Sun. Tomcat можно найти на jakarta.apache.org.
Следуйте инструкциям для установки Tomcat реализации, затем отредактируйте файл server.xml, чтобы указать место в вашем дереве директорий, где будут размещены ваши сервлеты. Когда вы запустите программу Tomcat, вы сможете протестировать ваши сервлеты.
Заключение
Это была только короткая интродукция в сервлеты; есть целые книги, посвещенные этой теме. Однако это введение должно дать вам достаточно мыслей, чтобы начать. Кроме того, многие мысли следующего раздела имеют обратную совместимость с сервлетами.
Упражнения
- Измените ServletsRule.java, перекрыв метод destroy( ), чтобы сохранить значение i в файле, и метод init( ), чтобы восстановить значение. Продемонстрируйте, что это работает, перегрузив контейнер сервлетов. Если у вас нет существующего контейнера сервлетов, вам необходимо загрузить, установить и запустить Tomcat с сайта jakarta.apache.org, чтобы иметь возможность запускать сервлеты.
- Создайте сервлет, который добавляет cookie в объект ответа, таким образом, хранит его на стороне клиента. Добавьте код в сервлет, который получает и отображает cookie. Если у вас нет существующего контейнера сервлетов, вам необходимо загрузить, установить и запустить Tomcat с сайта jakarta.apache.org, чтобы иметь возможность запускать сервлеты.
- Создайте сервлет, который использует объект Session для хранения информации о сессии по вашему выбору. В этом же сервлете получите и отобразите эту сессионную информацию. Если у вас нет существующего контейнера сервлетов, вам необходимо загрузить, установить и запустить Tomcat с сайта jakarta.apache.org, чтобы иметь возможность запускать сервлеты.
- Создайте сервлет, который изменяет интервал не активности сессии, устанавливая значение 5 секунд, с помощью вызова getMaxInactiveInterval( ). Проверьте, чтобы посмотреть, что сессия в самом деле теряет силу через 5 секунд. Если у вас нет существующего контейнера сервлетов, вам необходимо загрузить, установить и запустить Tomcat с сайта jakarta.apache.org, чтобы иметь возможность запускать сервлеты.
Grundlagen
Servlets sind Java-Klassen, welche in einer Java-Webanwendung zum Einsatz kommen. Dabei empfängt ein Servlet bestimmte Anfragen von Clients (abhängig von der URL) und kann diese beantworten. Der Inhalt kann dabei dynamisch generiert werden.
Java-Webanwendungen benötigen einen speziellen Webserver, die einen Web- bzw. Servlet-Container enthalten. Der bekannteste Webserver hierfür ist wohl Apache Tomcat. Für einige Webserver (z. B. den Microsoft-Webserver IIS) können Module verwendet werden, um auch dort Java-Webanwendungen ausführen zu können.
Bei dem Begriff Servlet handelt es sich um ein sogenanntes Kofferwort, welches sich aus den Begriffen Server und Applet (clientseitige Java-Anwendungen innerhalb einer Webseite) zusammensetzt. Servlets sind also wie Applets „kleine“ Anwendungen, die in einem Container laufen. Servlets laufen dabei in einem Container (um genauer zu sein dem Web- bzw. Servlet-Container) auf dem Webserver.
Servlets bauen aus technischer Sicht auf der CGI-Schnittstelle auf. Im Gegensatz zu anderen serverseitigen Technologien, wie z. B. PHP oder ASP.NET, werden bei Servlets HTML- und Programmcode nicht gemischt, vielmehr wird die komplette Ausgabe (also z. B. der HTML-Code) vom Programm (in diesem Fall also vom Java-Programm) erzeugt.
Schnittstellen
Eine Servlet-Klasse wird von der Klasse HttpServlet (Package javax.servlet.http ) abgeleitet. Diese Klasse implementiert unter anderem das Interface Servlet (Package javax.servlet ).
Um auf eingehende Anfragen zu reagieren, müssen zu allererst die Funktionen doGet() und doPost() sowie ggf. auch doPut() und doDelete() überschrieben werden. Die oben genannten Funktionen werden immer dann aufgerufen, wenn eine Anfrage zum Servlet mit der jeweiligen HTTP-Methode gesendet wird, d. h. sendet jemand eine GET-Anfrage an ein Servlet, so wird dessen Funktion doGet() aufgerufen. Möchten Sie für alle HTTP-Methoden die gleiche Funktion verwenden, so können Sie auch die Methode service() überschreiben. Alle diese Funktionen geben keinen Wert zurück und besitzen als Übergabeparameter ein Objekt der Interfaces HttpServletRequest und HttpServletResponse . Des Weiteren können diese Methoden Ausnahmen der Klassen ServletException und IOException werfen.
Das Interface HttpServletRequest ermöglicht den Zugriff auf einige Anfrage-Informationen, wie z. B. die HTTP-Methode, die Anfragezeile oder die URL. Zudem können auch Formulardaten (GET/URL-Parameter sowie POST-Parameter), die Session des Besuchers und Cookies abgerufen werden. Durch das Interface HttpServletResponse ist es möglich, Informationen über die HTTP-Antwort abzurufen, aber auch zu ändern. Des Weiteren ist es auch möglich, Weiterleitungen oder das Setzen von Cookies mit Hilfe dieser Interfaces zu realisieren. Beide Interfaces werden wir jedoch im nächsten Thema noch genauer besprechen.
Wie viele andere Klassen besitzt auch die HttpServlet -Klasse die Funktionen init() und destroy() . Diese können überschrieben werden, um Ressourcen für das Servlet zu reservieren und am Ende wieder freizugeben. Bei dem Aufruf eines Servlets wird vom Servlet-Container als erstes eine Instanz des Objekts erstellt und dann die init() -Methode aufgerufen. Anschließend wird eine der doX() -Methoden bzw. die service() -Methode aufgerufen. Am Ende wird die destroy() -Funktion aufgerufen und letztendlich die Objektinstanz wieder gelöscht.
Konfiguration
Servlets bzw. Java-Webanwendungen müssen grundsätzlich konfiguriert werden. Dafür gibt es die Datei web.xml , welche auch als Deployment Descriptor bezeichnet wird. Diese Datei (im Falle einer Web-Anwendung) besitzt das Wurzelelement web-app . In dieser Datei wird üblicherweise das Attribut version sowie einige XML-spezifische Attribute ( xmlns u. a.) angegeben. Dies sieht dann wie folgt aus:
Jedes Servlet, welches nachher von außen zugänglich sein soll, muss in der web.xml -Datei erstmal registriert werden. Dazu wird das Element servlet angegeben. In diesem befinden sich wiederum die Elemente servlet-name und servlet-class . Der Wert innerhalb von servlet-name legt den internen (für die XML-Datei geltenden) Namen des Servlets fest. Im Element servlet-class wird die Klasse des Servlets inkl. dem Package angegeben.
HelloServlet de.hwh.bsp.hallowelt.HelloServlet
Um nun eine gewisse URL mit einem Servlet zu verbinden, benötigen wir das Element servlet-mapping , welchem die Elemente servlet-name (dort wird der interne Name des Servlets „von oben“ angegeben) und url-pattern untergeordnet werden. Als Wert des Elements url-pattern kann ein URL-Muster angegeben werden. Dabei ist es auch möglich, mit dem Wildcard-Zeichen * zu arbeiten. Mit dem Muster /Download/*.zip könnte man bspw. alle Anfragen auf eine ZIP-Datei aus dem Ordner /Download/ auf ein gewisses Servlet lenken.
HelloServlet /
Neben den genannten Elementen gibt es noch viele weitere, die dazu genutzt werden können, eine Web-Anwendung zu konfigurieren. Hierzu zählt z. B. das automatische Timeout von Sessions.
Erstes Servlet
Nachdem wir uns nun mit der grundlegenden Theorie in Bezug auf Servlets beschäftigt haben, wollen wir nun unser erstes Servlet erstellen. Alle in diesem Tutorial enthaltenen Beispiele wurden mit der Entwicklungsumgebung NetBeans erstellt und mit dem JDK 8 (mit der Java EE Version 6) kompiliert.
Um eine Java-Webanwendung zu erstellen, müssen wir als erstes ein neues Projekt anlegen. Bei der Projekt-Erstellung müssen wir unter „Categories“ „Java Web“ auswählen. In der Auswahlbox „Project“ wählen wir „Web Application“.
Als nächstes werden Name und Speicherort des Projekts festgelegt. Anschließend werden die Servereinstellungen festgelegt. Dort muss der Server, die Java-EE-Version und der Pfad ausgewählt bzw. eingegeben werden. Wurde noch kein Server angelegt, was bei der ersten Erstellung des ersten Projekts der Fall ist, so müssen Sie diesen zuerst erstellen. Hier können Sie, sofern Sie mit XAMPP entwickeln, NetBeans mit dem in XAMPP enthaltenen Apache Tomcat Webserver verbinden. Dazu wählen Sie als erstes „Apache Tomcat or TomEE“ aus und geben anschließend den Pfad des Server-Verzeichnisses sowie einen Benutzernamen und ein Passwort ein.
Im letzten Schritt können noch Frameworks ausgewählt werden, welche eingebunden werden sollen. Für unsere Servlet-Beispiele benötigen wir jedoch keine Frameworks.
Von NetBeans wird bei den oben genannten Schritten eine JSP-Seite (Datei index.jsp ) erzeugt. Diese können Sie löschen, da wir diese zurzeit nicht benötigen. Unter dem Projektordner „Source Packages“ können Sie bei Bedarf ein Package und anschließend ein Servlet anlegen. Nach dem Festlegen des Namens und des Speicherorts können Sie das Servlet dem Deployment Descriptor hinzufügen. Auch hier ist uns der Assistent von NetBeans eine große Hilfe. Dadurch werden die Einstellungen automatisch in die Datei web.xml hinzugefügt. Beim Erstellen des ersten Servlets wird die Datei web.xml angelegt.
Das Erstellen eines neuen Servlets mit Hilfe des Assistenten erzeugt eine Java-Quellcodedatei, in welcher die Klasse des Servlets definiert ist. In der Klasse werden die Methoden doGet() , doPost() und getServletInfo() überschrieben. doGet() und doPost() rufen die lokale Funktion processRequest() auf.
Das Projekt kann direkt von der IDE heraus in den Webserver geladen und das Ergebnis betrachtet werden. Auch das Debuggen von Java Web-Anwendungen ist möglich.
Im folgenden Beispiel wurde der Quellcode etwas gekürzt und der Inhalt der Funktion processRequest() verändert. Bei diesem und den folgenden Beispielen haben Sie die Möglichkeit, sich das Ergebnis anzuschauen, indem Sie auf die Lupe klicken. Ein Klick auf den Pfeil nach unten startet den Download des NetBeans-Projekts.
Servlet (HelloServlet.java):
package de.hwh.bsp.hallowelt; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class HelloServlet extends HttpServlet < protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException < // Ausgabe als Text-Datei response.setContentType("text/plain;charset=UTF-8"); // Ausgabe durchführen PrintWriter out = response.getWriter(); out.println("Hallo Welt!"); out.println(); out.println("Aktuelles Datum und Uhrzeit: " + (new Date()).toString()); out.close(); >@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException < processRequest(request, response); >@Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException < processRequest(request, response); >>
Konfiguration (web.xml):
HelloServlet de.hwh.bsp.hallowelt.HelloServlet HelloServlet / 30
Создаём веб-приложение с Java Servlets
Многие привыкли писать на Java десктопные и мобильные приложения. Но что насчёт веб-приложений? Сегодня мы расскажем, как создать такое средствами Java, Servlet API и JSP без каких-либо сложных фреймворков.
Одной из самых приятных особенностей Java является её многогранная природа. Конечно, создание традиционных десктопных и даже мобильных приложений — это здорово. Но что, если вы хотите уйти с проторенных дорожек и зайти на территорию разработки web приложений на Java? Для вас есть хорошая новость: в комплекте с языком идёт полноценный Servlet API, который позволяет вам создавать надёжные веб-приложения без особых хлопот.
Это статья для продолжающих. Если вы только начинаете знакомство с Java, советуем пройти быстрый старт, посмотреть видеокурс и выбрать одну из книг для новичков.
Создание приложений на Java с помощью Servlets
Встречайте сервлеты, особый тип Java-программ, выполняемый в пределах веб-контейнера (также называемый контейнером сервлетов, как, например, Tomcat и Jelly), которые позволяют обрабатывать запросы клиентов и ответы сервера просто и эффективно. Сейчас не время и не место дотошно объяснять вам, что из себя представляет сервлет. Достаточно сказать, что сервлеты создаются и уничтожаются их контейнерами, а не разработчиком, и действуют как промежуточный уровень между клиентами (как правило, веб-браузерами) и другими приложениями, запущенными на сервере (например, базами данных).
Сервлет — классная штука, которая помимо всего прочего может принимать данные от клиента, как правило через GET и POST-запросы, работать с cookie и параметрами сеанса. А ещё она обрабатывает данные через дополнительные уровни приложений и отправляет выходные данные клиенту как в текстовом, так и в бинарном форматах (HTML, XML, PDF, JPG, GIF и т.д.), во многих случаях используя Java Server Pages (JSP) файлы.
Лучше всего начинать работу с сервлетами через конкретный пример. Мы создадим простое веб-приложение, которое позволит клиентам регистрироваться с помощью простой HTML-формы. Данные, предоставленные клиентами, будут собираться сервлетом и проверяться валидаторами.
Разбираемся с конфигурационными файлами
Чтобы вы понимали структуру нашего будущего приложения, вот как она будет выглядеть:
Первым шагом к созданию приложения является определение так называемого дескриптора развёртывания. Он указывает, как приложение должно быть развёрнуто в определенной среде. Когда дело касается веб-приложений, дескриптор развёртывания представляет собой простой XML-файл, называемый web.xml и является частью стандартной спецификации Java EE. В нашем случае он будет выглядеть так:
Как вы видите, web.xml только определяет версию Java Servlet Specification (3.1), которую мы будем использовать в приложении. Разумеется, в нём может быть гораздо больше содержимого, включая директивы сопоставления сервлетов, параметры инициализации, список приветственных файлов и несколько дополнительных настроек. Но чтобы не усложнять процесс разработки, давайте оставим его таким как есть.
Так как наше приложение будет использовать Servlet API и Java Servlet Pages (JSP) для отображения данных клиента, нам нужно загрузить все необходимые JAR. Maven сделает за нас трудную работу, вот как будет выглядеть файл POM:
4.0.0 com.electricalweb.customerapplication customerapplication war 1.0-SNAPSHOT Customer Application http://maven.apache.org junit junit 4.12 test javax.servlet javax.servlet-api 3.1.0 jstl jstl 1.2 javax.el el-api 2.2 Customer Application
Если говорить просто, pom.xml определяет все зависимости, необходимые для работы с сервлетами: JSP, Java Standard Tag Library (JSTL) и Java Expression Language (JEL).
Итак, мы уже создали конфигурационные файлы приложения. Однако в текущем состоянии оно буквально ничего не делает. Мы хотим, чтобы клиенты могли регистрироваться с помощью HTML-формы, поэтому следующее, что нам нужно сделать, — это создать JSP-файлы, которые будут отображать вышеупомянутую форму и данные клиента после успешного завершения регистрации. Этим мы сейчас и займёмся.
Работаем над внешним видом
Внешний вид приложения будет определяться двумя JSP-файлами — в контексте MVC они называются представлениями. Первый будет отвечать за отображение формы регистрации и возможных ошибок, вызванных после проверки введённых данных. Второй будет обычной страницей приветствия, в которой будут показаны данные, введённые клиентом, после успешного завершения процесса регистрации.