Сервлеты – это серверные программы, написанные на Java. В отличие от CGI-скриптов, код инициализации сервлета выполняется только один раз. Кроме того, отдельные потоки на сервере обрабатывают каждый клиентский запрос. Это предотвращает создание лишних процессов, увеличивая, таким образом, производительность сервера. При этом сервлеты наследуют все достоинства языка программирования Java. Например, подобно всем стандартным классам Java, сервлет не зависит от платформы и может использоваться в различных операционных системах. Также сервлет может пользоваться большими возможностями Java, такими как работа в сети, многопоточность, Java Database Connectivity (JDBC – Взаимодействие с базами данных на Java), и многими другими.
Итак, Servlet - это небольшая программа Java, которая работает в веб-сервере. Сервлеты получают и отвечают на запросы веб-клиентов, как правило, по протоколу HTTP, HyperText Transfer Protocol.
Сервлеты основные классы в любом веб-приложении, единственные классы, которые либо выполняют ответы на запросы или делегируют эту работу какому-либо другому элементу приложения в другой части приложения. Веб-контейнер, в котором вы запускаете ваше приложение будет иметь один или более сервлетов. Эти сервлеты управляют сервисами JavaServer Pages, показывающими списки каталогов и обеспечивая доступ к статическим ресурсам, таким как HTML-страниц и рисунки. Здесь попробуем написать и настроить пользовательские сервлеты, которые составляют приложение.
Каждый Servlet реализует интерфейс javax.servlet.Servlet, но, как правило, не напрямую. Servlet это простой интерфейс, содержащий методы для инициализации и уничтожения Servlet и обслуживания запросов. Тем не менее, метод service будет вызываться для любого запроса любого типа, даже если он не запрос HTTP (теоретически предполагается, что ваш веб-контейнер поддерживает такой запрос). Например, в будущем вполне возможно, что новые сервлеты могут быть добавлены в Java EE для поддержки файлов File Transfer Protocol (FTP). По этой причине, существуют различные классы сервлетов, которые вы можете расширять вместо этого. По состоянию на Java EE 7, только протокол Servlet поддерживается в настоящее время HTTP. Почти во всех случаях, сервлеты наследуют от javax.servlet.GenericServlet.
GenericServlet все еще независимый от протокола Servlet с одинственным абстрактный методом service, но она содержит несколько вспомогательных методы для регистрации и получения информации о приложении и configuration сервлета.
Для ответа на запросы HTTP, javax.servlet.http.HttpServlet расширяет (extends) GenericServlet и реализует метод service, чтобы принимать только запросы HTTP. Затем он обеспечивает пустые реализации для методов, соответствующих каждому типу метода HTTP.
import javax.servlet.http.HttpServlet; public class HelloServlet extends HttpServlet { }
Начнем изучение с HelloWorld программы, использующей doGet метод. Прежде всего следует отметить, что все дальнейшие наши проекты будут выполняться в перспективе JavaEE и проект должен создаваться как Dynamic Web Project, для работы которого предназначен WEB - контейнер для выполнения сервлетов и JSP. Для разработки всех компонентов лабораторной работы целесообразно создать один проект Dynamic Web Project, например, Lab4, в котором будут размещаться различные элементы, начиная с сервлетов. Сервлеты размещаются в пакетах, находящихся в разделе Java Resourses/src. Точно также как и для других Java классов в src можно создавать пакеты для сервлетов. Более того, в одном пакете с сервлетами могут находиться другие классы. Итак, создаем проект, присваиваем ему имя и убеждаемся, что используется соответствующая Target Runtime.
Нажмите кнопку Next и в открывшемся окне еще раз нажмите кнопку Next, пропуская диалоговое окно Java Configure project for building a Java application, и появится окно Web Module Configure web module settings. В том окне установите флажок Generate web.xml deployment descriptor и нажмите кнопку Finish.
В результате выполненных шагов создается соответствующий проект со структурой каталогов, соответствующей Dynamic Web Project. После нажатия на расширители содержимое проекта будет выглядеть следующим образом:
Создадим пакет ifmo.ru.servlet. Для этого выделяем src и после нажатия на правую кнопку выбираем Package и вводим наименование пакета (ifmo.ru.servlet ) в поле Name открывшегося окна и нажимаем кнопку Finish.
Далее выделяем только что созданный пакет и для создания в нем сервлета после нажатия правой кнопки выбираем из конекстного меню New и Servlet, вводим в открывшемся диалоговом окне в поле Class name HelloServlet и нажимаем Next и еще раз Next. При этом открывается окно Create Servlet Specify modifiers, interfaces to implement, and method stubs to generate. В этом окне отметить заглушки для методов, как показано на рисунке ниже и нажать кнопку Finish.
В диалоговом окне выше отмечаются те методы, которые планируется использовать в процессе создания сервлета. Откроется окно редактирования, подготовленное для ввода необходимого кода, в котором выполните необходимые изменения, приводящие к следующему содержанию:
port java.io.IOException; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class HelloServlet */ @WebServlet("/HelloServlet") public class HelloServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public HelloServlet() { super(); // TODO Auto-generated constructor stub } /** * @see Servlet#init(ServletConfig) */ public void init() throws ServletException { System.out.println("Servlet " + this.getServletName() + " has started."); } /** * @see Servlet#destroy() */ public void destroy() { System.out.println("Servlet " + this.getServletName() + " has stopped."); } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().println("Hello, World!"); } }В составе метода doGet обратите внимание на команду
response.getWriter().println("Hello, World!");
Это команда использует метод println() для объекта PrintWriter, который создается по команде response.getWriter(). Для выполнения сервлета HelloServlet выделите его и, нажав правую кнопку, выберите из контекстного меню Run As/Run on Server. В процессе запуска в диалоговом окне Run on Server Select which server to use следует выбрать соответствующий сервер (GlassFish 4) и нажать кнопку Finish для выполнения сервлета. В результате откроется встроенный браузер и будет выведено сообщение Hello, World! из сервлета HelloServlet .
Поздравляю, надеюсь, что сервлет отработал. При этом из метода init() было выведено сообщение в представление Console.
Это сообщение будет выведено лишь однажды, вне зависимости от того, сколько раз вы обращались к сервлету. Попробуйте... Метод destroy() выведет сообщение, если сервер, будет перезапущен. Попробуйте перегрузить север...(Выбрать сервер, нажать правую кнопку и Restart). Общая идея использования сервлетов состоит в том, что метод doGet и другие различные методы HTTP отображаются в методах request. Метод service класса Servlet, обслуживает все входящие запросы. В конечном счете, сервлет должен проанализировать и обработать данные входящего запроса на основе используемого протокола и затем вернуть response в соответствующем протоколе клиенту.
В частности, в протоколе HTTP, метод service должен проанализировать заголовки и параметры, которые посылает клиент, а затем вернуть правильный response HTTP, который, по крайнем мере, включает в себя минимальные заголовки HTTP (даже если само тело ответа пустое). На самом деле, реализация этой процедуры достаточно сложна, включает в себя много шагов и может отличаться от веб-контейнера к веб-контейнеру. Применение расширения HttpServlet состоит в том, что вам не придется беспокоиться о каких-либо деталях этих шагов. Хотя реальность такова, что метод service должен сделать много чего, прежде чем ответить пользователю, при том что разработчик, использующий HttpServlet, должен сделать совсем немного.
Для обработки запроса и ответа соответственно используются HttpServletRequest и HttpServletResponse. Эти аргументы в различных методах, определенных HttpServlet, позволяют вам читать параметры, передаваемые от клиента, принимать файлы, загружаемые из POST форм, читать сырые данные, содержащиеся в теле запроса (для таких работ используются запросы PUT или тело запроса JSON), читать и обрабатывать заголовки response, и писать содержимое ответа обратно клиенту. Существует много функций, которые можно выполнить во время обслуживания запроса, но в реальности обычно необходимо выполнить одну или несколько этих функций.
Интерфейс HttpServletRequest является расширением ServletRequest, который обеспечивает дополнительную информацию по конкретному протоколу HTTP о принятом запросе. Он определяет десятки методов, которые можно использовать для получения сведений о запросе HTTP. Он также позволяет задавать атрибуты request. Получение параметров из Request
Параметры request принимаются в двух различных формах: через параметры request (также называемые параметрами URI), или в теле закодированного в application/form или multipart/form (как правило, называются post переменные или переменные form). Параметры запроса поддерживаются со всеми методами request и содержатся в первой строке данных в запросе HTTP, как показано в следующем примере:
GET /index.jsp?productId=9781118656464&category=Books HTTP/1.1В этом примере имеется два параметра request, содержащиеся в запросе: productId, который определяет ISBN книги качестве значения и category, которые имеют значение Books. Эти же параметры также могут быть переданы в теле запроса, как POST переменные. POST переменные могут быть включены только в POST запросы. Рассмотрим следующий пример:
POST /index.jsp?returnTo=productPage HTTP/1.1 Host: www.example.com Content-Length: 48 Content-Type: application/x-www-form-urlencoded addToCart&productId=9781118656464&category=Books
Запрос POST выше содержит переменные POST (предписывающие сайту добавить книгу в корзину) и параметры запроса (предписывающие сайту вернуться на страницу productPage после выполнения задачи).
Хотя существует разница в доставке этих двух типов параметров, они по существу, одинаковы, и передают, в основном, ту же информацию. Servlet API не делает различий между двумя типами передачи параметров.
Метод getParameter возвращает одно значение параметра. Если параметр имеет несколько значений, getParameter возвращает первое значение, в то время как getParameterValues возвращает массив значений параметра. Если параметр имеет только одно значение, этот метод возвращает массив с одним элементом. Метод getParameterMap возвращает java.util.Map
Существует несколько методов, поддерживающих определение типа, длины и кодировки содержания HTTP запрос. Метод getContentType возвращает MIME тип содержимого запроса, например как application/x-www-form-urlencoded, application/json, text/plain, или application/zip. Тип содержимого MIME описывает, что данные, которые он отмечает, содержит несколько типов. Например, файлы ZIP архивов имеют тип содержимого MIME application/zip чтобы показать, что они содержат данные архива ZIP.
Методы getContentLength и getContentLengthLong возвращают количество байт в теле
запроса (длина содержимого), причем последний способ является полезным для запросов, содержание которых может превышать 2 гигабайта (необычно, но возможно). Метод getCharacterEncoding возвращает кодировку содержания запроса (например, UTF-8 или ISO-8859-1), когда запрос содержит контент символьного типа. (text/plain, application/json и application/x-www-form-urlencoded - некоторые примеры символьного типа контента MIME). Несмотря на то, эти методы могут пригодиться во многих ситуациях, ни один из них не являются обязательным, если вы получаете переменные POST в теле запроса, используя методы.Методы getInputStream, который возвращает javax.servlet.ServletInputStream, и getReader, который возвращает java.io.BufferedReader, могут быть использованы для чтения содержимого request. Какой из них лучше полностью зависит от контекста, в котором читается содержание request. Если ожидается, что содержимое - данные в символьной кодировке, такой как текст UTF-8 или ISO-8859-1, использование BufferedReader, как правило, самый простой способ, потому что он позволяет легко читать символьные данные. Если, однако, данные request в двоичной форме по природе, вы должны использовать ServletInputStream, поскольку таким образом можно получить доступ к содержимому request в байтовом формате. Никогда не следует использовать оба класса для одного request. После вызова любого метода, вызов другого приведет к исключению IllegalStateException.
Получение характеристик Request таких как URL, URI и Headers Они легко получаются из объекта request: getRequestURL: Возвращает полный URL, который клиент использовал, чтобы сделать запрос, в том числе протокол (HTTP или HTTPS), имя сервера, номер порта и путь на сервере, но не включая строку запроса.
getRequestURI: Немного отличается от getRequestURL в том, что он возвращает только часть пути URL.
getServletPath: Аналогично getRequestURI, и возвращает еще меньше чем в URL. Если request /hello-world/greeting?foo=world, приложение развертывается как /hello-world на сервере, и обращение к сервлету /greeting , то getServletPath возвращает только часть адреса, используемого для запуска сервлета: /greeting. getHeader: Возвращает значение заголовка с заданным именем. Вариант в заголовке не должен совпадать с вариантом строки, переданной в метод, так getHeader ("ContentType") может соответствовать заголовку Content-Type. Если существует несколько заголовков с тем же именем, он возвращает только первое значение. В таких случаях, лучше использовать метод getHeaderNames для возвращения enumeration всех значений.
getHeaderNames: Возвращает enumeration имен всех заголовков в запросе - отличный способ для перебора доступных заголовков. getIntHeader: Если у вас есть конкретный заголовок, который вы знаете, всегда число, его можно вызвать, чтобы возвращалось значение уже преобразованное в число. Он выбрасывает NumberFormatException, если заголовок не может быть преобразован в целое число.
getDateHeader: Вы можете вызвать его для возвращения (в миллисекундах) Unix timestampequivalent из значения заголовка, который представляет собой действительную метку. Метод выбрасывет IllegalArgumentException, если значение заголовка не распознается как тип Data.
Ниже представлен сервлет ShowRequestHeaders, демонстрирующий использование методов request для вывода клиенту некоторых заголовков. Попробуйте создатт, запустить и проанализировать вывод этого сервлета.
import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class ShowRequestHeaders */ @WebServlet("/ShowRequestHeaders") public class ShowRequestHeaders extends HttpServlet { private static final long serialVersionUID = 1L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); String title = "Servlet Example: Showing Request Headers"; out.println("\n" + "" + title +"
\n" + "Request Method: " + request.getMethod() + "
\n" + "Request URI: " + request.getRequestURI() + "
\n" + "Request Protocol: " + request.getProtocol() + "
\n" + "
Header Name | Header Value");
Enumeration" + headerName);
out.println(" | " + request.getHeader(headerName)); }
out.println(" | |
---|