Оптимизация Java-cервлетов с помощью AsyncContext

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

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

Пример программы:

//Создадим простенький класс. //Дальше поясним зачем он. class Friend { public static void m1() { System.out.println(“Hello Friend!!!”); } } //Также можно увидеть что мы реализуем не только //Runnable но и расширяем Friend. Это преимущество //реализации Runnable перед расширением Thread //так как в Java можно расширять Лишь Один класс //и если бы мы расширили Thread то расширить //какой либо другой класс (например Friend) //уже не имели бы возможности. class MyThread extends Friend implements Runnable { int i=0; public void run() { i++; m1(); } } class RunnableExample { public static void main(String[] args) { //создаем один объект MyThread. MyThread MyThr = new MyThread(); //Можно у одного объекта //в отдельных потоках запускать его метод run //это преимущество Runnable перед Thread. //Подробнее на следующей странице. Thread t1 = new Thread(MyThr);//передается в поток Thread t2 = new Thread(MyThr);//передается в поток 2 раз //run объекта MyThr запускается //в отдельных потоках t1 и t2. t1.start(); t2.start(); //Еще одно преимущество Runnable перед Thread //что код класса реализующего Runnable можно //использовать вне в отдельном потоке. //То есть m1 просто выполнится здесь в потоке метода main MyThr.m1(); //В конце можно увидеть 2. То есть оба потока работали //с одним и тем же объектом. //Все потоки добавили 1 к полю i объекта MyThr. System.out.println(MyThr.i); } }

Вывод:

Слушатели (Listeners) в Java-сервлетах

Часто бывает нужно проследить выполнение каких-то действий в сессии или контексте и т.д.

Для этого используются слушатели.

Например, для прослушивания событий происходящих с аттрибутами реализуется интерфейс ServletContextAttributeListener.

В примере слушателя ниже определены методы, которые будут срабатывать когда в контекст добавляются, удаляются или заменяются аттрибуты. Мы будем уведомлены о событиях с аттрибутами.

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

Интерфейсов слушателей довольно много. Для примера рассмотрим ServletContextAttributeListener.

Пример программы:

import javax.servlet.ServletContextAttributeEvent; import javax.servlet.ServletContextAttributeListener; import javax.servlet.annotation.*; @WebListener //пометим что класс является слушателем public class ServletContextAttributeListenerExample implements ServletContextAttributeListener{ //Этот метод вызывается //при добавлении атрибута в объект ServletContext. public void attributeAdded(ServletContextAttributeEvent scab){ System.out.println(“An attribute was added to the ” + “ServletContext object”); } //Этот метод вызывается, когда атрибут удаляется //из объекта ServletContext. public void attributeRemoved(ServletContextAttributeEvent scab){ System.out.println(“An attribute was removed from ” + “the ServletContext object”); } //Этот метод вызывается при замене атрибута //в объекте ServletContext. public void attributeReplaced(ServletContextAttributeEvent scab){ System.out.println(“An attribute was replaced in ” + “the ServletContext object”); } }

Сервлет вызывающий метод слушателя

Ниже простейший сервлет, в котором просто добавляется аттрибут в контекст. При добавлении аттрибута должен будет вызваться переопределенный нами метод attributeAdded из класса определенного нами выше.

Пример программы:

import java.util.*; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; @WebServlet(“/listenerservlet”) public class MyServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter pw = response.getWriter(); ServletContext scont = request.getServletContext(); scont.setAttribute(“attrName”, “attrVal”); } }

Проверка работы слушателя

Скомпилируем файл сервлета и файл слушателя и в адресной строке перейдем по адресу /listenerservlet.

В консоли запущенного Tomcat можно увидеть сообщение из метода attributeAdded, что значит что слушатель работает.

Что такое Filter в Java-сервлетах

Часто бывает, что нужно чтобы перед вызовом какого-либо сервлета или после вызова выполнялся какой-либо код.

Для этого нужно реализовать интерфейс Filter и реализовать его абстрактный метод doFilter, в котором и пишется код, который будет выполняться до сервлета и после него.

Example

Например:

Если нужно чтобы сначала пользователь авторизировался, и только если данные авторизации правильные запустился какой-либо сервлет.

Создадим сервлет, перед которым и после которого будет выполняться код.

Это простой сервлет, ничего нового здесь нет.

Пример программы:

import java.util.*; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; @WebServlet(“/filterservlet”) public class MyServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter pw = response.getWriter(); pw.println(“servlet”); } }

Класс реализующий Filter

Теперь создаем класс, который реализовывает Filter и в котором пишется код, который выполняется перед сервлетом и после сервлета.

Аннотацией WebFilter в urlPatterns указываем адрес сервлета, к которому будет применен данный фильтр. То есть адрес /filterservlet – сервлета выше.

urlPatterns, initParams,… можно задать и не через аннотацию, а и через web.xml, но здесь это демонстрировать не будем, также можно задать параметры инициализации в фильтре с помощью аннотации WebInitParam вместо тега <init-param> в web.xml (аннотацию WebInitParam можно использовать не только в фильтре).

Пример программы:

import java.io.IOException; import java.io.PrintWriter; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; @WebFilter(urlPatterns = “/filterservlet”, initParams=@WebInitParam(name = “Name”,value = “Value”))) public class FilterClass implements Filter { public void init(FilterConfig fConf) throws ServletException { //здесь использовать заданные параметры инициализации System.out.println(fConf.getInitParameter(“name”)); } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { //этот код выполнится до вызова сервлета PrintWriter pw=resp.getWriter(); pw.println(“invoked before”); //так вызывается сам сервлет по адресу //который был указан в urlPatterns chain.doFilter(req, resp); //этот код выполнится после вызова сервлета pw.println(“invoked after”); } public void destroy() {} }

Проверка работы сервлета и класса фильтра

Скомпилируем файл сервлета и файл класса реализующего Filter и в адресной строке перейдем по адресу /filterservlet.

Как видим, выполнился код в методе doFilter, который до вызова сервлета (вывелось invoked before), код самого сервлета (вывелось servlet) и вывелся код в методе doFilter, который после вызова сервлета (вывелось invoked after).

Синхронизация в Java-сервлете

По умолчанию все клиенты обращаются к одному созданному объекту сервлета.

Каждое обращение клиента к этому объекту создает отдельный поток, в котором обрабатываться запрос клиента используя этот объект.

Поэтому необходимо заботиться о потокобезопасности.

Чтобы для каждого запроса клиента создавался отдельный объект, а не производилась работа с одним в отдельных потоках можно наследовать SingleThreadModel, но это не рекомендуется, SingleThreadModel объявлен устаревшим (deprecated) вместо этого лучше использовать стандартные средства синхронизации изученные в прошлых уроках о многопоточности.

Пример программы:

import java.util.*; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.servlet.annotation.*; @WebServlet(“/SynchroServlet”) //Можно было бы //ниже дописать implements SingleThreadModel { //тогда бы при каждом обращении клиента к этому //сервлету создавался бы отдельный объект MyServlet. //Но мы не будем дописывать. Он deprecated. public class MyServlet extends HttpServlet{ int j = 0; protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //Если придет запрос к этому сервлету одновременно //от 100 клиентов то создастся 100 потоков //и в каждом из них параллельно //будет выполняться код doGet synchronized(this){ for(int i=0;i<5000000;i++){ //и в таком случае если бы цикл //не был обернут в synchronized то //при одновременном обращении //к сервлету от множества клиентов //содержимое переменной j в итоге //не будет корректным. j++; } } PrintWriter pw = resp.getWriter(); pw.print(j); } }

encodeURL и encodeRedirectURL в Java-сервлетах

Часто так бывает, что клиент отключил cookies в браузере, а id сессии храниться в cookies, а как-то поддерживать сессию надо.

Выход есть. Для этого нужно закодировать URL-адрес с добавлением идентификатора сессии и прикрепленный к адресу id будет тем же самым, как если бы он хранился в cookies, только здесь в ссылке. То есть теперь клиент будет отправлять JSESIONID не из Cookies, а в ссылке при обращении к серверу.

Для этого применяется метод encodeURL. Он перекодирует адрес добавляя в него JSESSIONID. Используется в ссылках в самом сервлете.

encodeRedirectURL делает то же самое, только применяется при перенаправлении.

Как пример использования encodeURL, создадим программу, в которой при каждом нажатии на ссылку в аттрибут сессии будет добавляться строка.

В программе ниже используем в ссылке в сервлете метод encodeURL.

Если бы в приведённой ниже программе не использовался encodeURL, то при нажатии на ссылку EncUrlServlet к адресу http://localhost:8080/helloservlet добавлялся бы EncUrlServlet, и происходил бы переход на http://localhost:8080/helloservlet/EncUrlServlet.

Благодаря encodeURL в этот адрес еще будет добавляться и JSESSIONID.

Вот так:

http://localhost:8080/helloservlet/EncUrlServlet;jsessionid=83A1405652DB65133B5EFE68FFBB30F5

Пример программы:

import java.util.*; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.servlet.annotation.*; @WebServlet(“/EncUrlServlet”) public class MyServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter pw = response.getWriter(); HttpSession sess = request.getSession(); //Извлекаем аттрибут someattr из сессии. //Далее будем добавлять к нему строку. String someattr = (String) sess.getAttribute(“someattr”); //По нажатию на ссылку обновляем аттрибут someattr. //К старому содержимому аттрибута someattr будет //добавляться _sessionIsWorking! что значит что сессия //работает. request.getSession().setAttribute(“someattr”,someattr+”_sessionIsWorking!”); //Используем в ссылке в сервлете метод encodeURL //чтобы в адрес добавлялся JSESSIONID pw.println(“someattr=”+someattr +”
EncUrlServlet“); } }

Проверка работы сервлета с encodeURL

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

Скомпилируем файл сервлета и в адресной строке перейдем по адресу /EncUrlServlet.

Теперь нажмем на ссылку и посмотрим добавиться ли к адресу http://localhost:8080/helloservlet/EncUrlServlet хранящийся в куках JSESSIONID.

Видим, что в адрес добавился JSESSIONID.

Также видим, что к аттрибуту добавилась строка _sessionIsWorking!. Что значит, что сессия работает и в нее можно добавлять и извлекать из нее аттрибуты.

И это, ясное дело, благодаря методу encodeURL, который отправляет на сервер JSESSIONID в ссылке, благодаря чему сессия поддерживается.

Если бы мы убрали метод encodeURL, то ничего бы не происходило, так как сервер не смог бы получить JSESSIONID клиента.

Для примера также можем еще понажимать на ссылку и в адресе всё еще будет добавлен JSESSIONID, а к строке продолжит добавляться строка _sessionIsWorking!. То есть сессия всё еще работает.

Интерфейс ServletConfig

ServletConfig – можно сказать, что то же самое, что и ServletContext, но в отличии от него хранит данные касающиеся только конкретного сервлета.

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

В основном, он нужен для извлечения параметров инициализации.

Параметры инициализации (прописываются в web.xml) – это какие-то данные, которые доступны сервлету или сервлетам сразу с начала его работы.


Определение параметров инициализации в web.xml

В web.xml можно определить параметры инициализации как на уровне контекста, так и только для конкретного сервлета.  

Web.xml:

MyServlet MyServlet name firstParamName MyServlet1 MyServlet1 name secondParamName name commonName

Как можно увидеть, мы задали три параметра инициализации.

Задали один общий для всех сервлетов параметр с именем name и задали параметры с именем name, доступные только конкретному сервлету. Эти все параметры потом можно будет достать с помощью getInitParameter().


Параметры инициализации в первом сервлете MyServlet.

С помощью getInitParameter извлекаем параметры инициализации, которые были определены в web.xml.

import java.util.*; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletExcept1on; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.ServletContext; import javax.servlet.ServletConfig; import javax.servlet.annotation.*; @WebServlet(“/configservlet”) public class MyServlet extends HttpServlet{ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ PrintWriter pw = resp.getWriter(); //получаем контекст всего приложения ServletContext scont = getServletContext(); //получаем значение параметра name контекста //(будет commonName) pw.println(scont.getInitParameter(“name”)); //получаем конфиг сервлета ServletConfig sconf = getServletConfig(); //получаем значение параметра name конфига //(будет firstParamName) pw.println(sconf.getInitParameter(“name”)); } }

Параметры инициализации во втором сервлете MyServlet1.

С помощью getInitParameter извлекаем параметры инициализации во втором сервлете, которые были определены в web.xml.

import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.annotation.*; import javax.servlet.ServletContext; import javax.servlet.ServletConfig; import javax.servlet.http.Cookie; @WebServlet(“/myservlet”) public class MyServlet1 extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ PrintWriter pw = resp.getWriter(); //получаем контекст всего приложения ServletContext scont = getServletContext(); //получаем значение параметра name контекста //(также как и в другом сервлете будет CommonName) pw.println(scont.getInitParameter(“name”)); //получаем конфиг сервлета ServletConfig sconf = getServletConfig(); //получаем значение параметра name конфига //(будет secondParamName) pw.println(sconf.getInitParameter(“name”)); } }

Проверка работы сервлетов

Скомпилируем файлы сервлетов и в адресной строке перейдем по адресу /configservlet.

Видим, что клиенту был отправлен параметр инициализации уровня контекста и параметр инициализации, который принадлежит только MyServlet и нигде больше не виден.

Если перейдем по пути /myservlet, то можно увидеть параметр инициализации уровня контекста (это тот же самый параметр, что и на картинке выше), который доступен всем сервлетам и параметр инициализации, который принадлежит только сервлету MyServlet1 и нигде больше не виден.

Интерфейс ServletContext

ServletContext – контекст является объектом общим для всего приложения.

В объекте ServletContext можно хранить какие-либо данные общие для всех сервлетов приложения. И потом эти данные можно извлекать из этого объекта в сервлетах приложения.

Например, из него получать параметры инициализации прописанные в web.xml или сохранять в него какие-то аттрибуты с помощью метода setAttribute, и потом получать их с помощью getAttribute.

Аттрибуты это какие-то данные для внутренней коммуникации сервлетов. Сервлеты могут обмениваться ими в пределах контекста или сессии.

Положим аттрибут в ServletContext в сервлете MyServlet

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

Пример программы:

import java.util.*; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.ServletContext; import javax.servlet.annotation.*; @WebServlet(“/contextservlet”) public class MyServlet extends HttpServlet{ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException{ PrintWriter pw = resp.getWriter(); //Получаем контекст всего приложения. ServletContext scont = getServletContext(); //Создадим аттрибут с именем attrName //и положим туда какие-то данные //В данном случае просто строку “attrVal”. scont.setAttribute(“attrName”, “attrVal”); //getAttributeNames – получаем имена атрибутов. //Вот таким образом можем просмотреть //все атрибуты сервлета. Enumeration attrNames=scont.getAttributeNames(); while(attrNames.hasMoreElements()) { String attrName = attrNames.nextElement(); //выводим значение атрибута pw.println(attrName+”: “+scont.getAttribute(attrName)); pw.println(“-------------“); } //Ниже также несколько полезных методов контекста. //с помощью getRealPath можно вернуть полный путь //сервлета засунув аргументом относительный. pw.println(getServletContext().getRealPath(req.getServletPath())); //Можно получить некоторую информацию о сервере. pw.println(getServletContext().getServerInfo()); } }

Прием этого аттрибута в другом сервлете MyServlet1.

С помощью getAttribute получаем аттрибут из контекста, ранее положенный туда в другом сервлете.

import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.annotation.*; import javax.servlet.ServletContext; import javax.servlet.http.Cookie; @WebServlet(“/myservlet”) public class MyServlet1 extends HttpServlet{ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ PrintWriter pw = resp.getWriter(); //здесь получаем значение атрибута attrName (будет attrVal) ServletContext scont = getServletContext(); String str = scont.getAttribute(“attrName”).toString(); pw.write(str); } }

Скомпилируем файлы сервлетов и в адресной строке перейдем по адресу /contextservlet.

Видим содержимое контекста приложения. Это все аттрибуты, которые в нем хранятся. Внизу можно увидеть тот, который был создан в MyServlet.

Также, как можно увидеть, последние две строки это результат методов getRealPath и getServerInfo.

Если перейдем по пути /myservlet, то можно увидеть значение аттрибута, который был создан в MyServlet.

То есть, очевидно, что аттрибут attrName доступен не в одном сервлете приложения. Он доступен всем сервлетам на уровне контекста.

Работа с сессиями (Session) в Java-cервлетах

Если выбрать все cookies нашего веб-ресурса, то там всегда будет кук с именем SESSIONID и значением идентификатором.

Этот идентификатор уникален для каждого клиента и он отправляется на сервер при запросах клиента и сервер ассоциирует этот уникльный ID с сессией конкретного клиента.

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

Example

Например:

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

Search Icon

Сессия обычно живет какой-то промежуток времени и его зачастую можно настроить.

Как простой пример давайте что-нибудь положим в сессию клиента и отправим ее содержимое на страницу клиента.

Пример программы:

import java.util.*; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.servlet.annotation.*; @WebServlet(“/sessionsservlet”) public class MyServlet extends HttpServlet{ int i = 0; protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter pw = resp.getWriter(); //getSession – получаем сессию клиента HttpSession sess = req.getSession(); //допустим клиент положил какойто товар в корзину String someProductName = “Refrigerator”; //и можем положить его имя в сессию sess.setAttribute(“product”, someProductName); //getAttributeNames – получаем имена аттрибутов Enumeration attrNames = sess.getAttributeNames(); while(attrNames.hasMoreElements()) { String attrName = attrNames.nextElement(); //выводим имя аттрибута pw.println(attrName); //выводим значение аттрибута pw.println(sess.getAttribute(attrName)); pw.println(“-------------“); } } }

Проверим работу программы с Session

Скомпилируем файл сервлета и в адресной строке перейдем по адресу /sessionsservlet.

Видим содержимое сессии клиента.

Работа с Cookies в Java-cервлетах

Cookies это данные, которые генерируются сервером и хранятся в браузере клиента.

Браузер клиента возвращает эти данные обратно на сервер когда клиент делает запрос из того же веб-ресурса.

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

Example

Раскроем этот пример получше:

  • Когда клиент вводит логин и пароль на каком-то веб-ресурсе они отправляются на сервер и там сохраняются.
  • Сервер генерирует некий номер, который будет принадлежать только конкретно этому клиенту и отправляет сгенерированный номер клиенту, который сохраняется у него в браузере (в куках) и когда клиент повторно заходит на этот веб-ресурс браузер отправляет сохраненные куки с номером в них на сервер.
  • Сервер проверяет этот номер и по этому номеру отправляет клиенту его логин и пароль, и клиент не должен самостоятельно их опять вводить.

Как простой пример, давайте отправим клиенту какой-нибудь куки, чтобы он сохранился у него в браузере, и клиент отправит этот куки обратно на сервер, и сервер отправит клиенту эти куки для вывода на странице у клиента.

Пример программы:

import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Cookie; import javax.servlet.annotation.*; @WebServlet(“/cookieservlet”) public class MyServlet extends HttpServlet{ int i = 0; protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter pw = resp.getWriter(); //Также можем создать куки передав имя и значение //кука как параметры конструктора класса Cookie. Cookie cookie=new Cookie(“someCookieName”,”someCookieValue”); //Довольно важный метод setPath, который следует упомянуть. //Делает так чтобы этот куки был доступен только //указанной аргументом странице нашего веб ресурса. //То есть получить данный куки другой сервлет не сможет. cookie.setPath(“/cookieservlet”); //и отправить его клиенту в браузер resp.addCookie(cookie); //с помощью метода getCookies можем получить все куки, //которые отправляем на клиент при запросах //к нашему веб ресурсу. Cookie[] allcookies = req.getCookies(); for(Cookie somecookie : allcookies){ //с помощью методов getName(), getValue() //можем получить имя и значение куков веб-ресурса. //Отправляем клиенту его куки для вывода. pw.println(somecookie.getName()+” = ” +somecookie.getValue()); } } }

Проверка работы программы с Cookies

Скомпилируем файл сервлета и в адресной строке перейдем по адресу /cookiesservlet.

Как видим, куки клиента были успешно отправлены сервером клиенту для вывода.

Search Icon

Можно также увидеть кук JSESSIONID. Что это за кук разберем в следующем уроке.

Также справа можно увидеть, что отправленный кук someCookieName храниться у клиента в браузере. Чтобы посмотреть хранящиеся куки в браузере Chrome нужно нажать на кнопку F12.    

Эти куки клиент теперь может всегда посмотреть в браузере когда заходит на страницу данного сервлета и он будет там существовать пока клиент не очистит куки браузера.

Redirect, forward, include в Java-сервлетах

Рассмотрим переход на другую страницу с помощью sendRedirect()

sendRedirect()перенаправляет на любой указанный аргументом адрес.

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

Пример программы:

import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.annotation.*; @WebServlet(“/redirservlet”) public class MyServlet extends HttpServlet{ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ //сервер указывает браузеру клиента перейти по ссылке resp.sendRedirect(“https://google.com”); } }

Скомпилируем файл и в адресной строке перейдем по адрусу /redirservlet.

Как видим сервлет сказал браузеру клиента перейти по ссылке https://google.com и он перешел.


Переход на другую страницу с помощью forward()

forward()вызывает любой другой ресурс (другой сервлет, jsp) на этом же сервере.

Адресная строка браузера клиента при таком переходе не меняется. У клиента может поменяться страница, но клиент понятия не имеет куда его перенаправило в плане адреса, так как перенаправление произошло на сервере.

Также этот метод полезен тем, что аргументами ему передаются req и resp ресурса, из которого происходит перенаправление forward(req, resp).

То есть между сервлетами сервера можно передавать одни и те же req и resp.

Также forward понятное дело быстрее чем sendRedirect, так как он не передает никаких адресов клиенту чтобы он по ним переходил.

Все переходы происходят на сервере.

Давайте создадим еще один простенький сервлет MyServlet1.java, к которому будет происходить переход.

Этот сервлет выглядит так:

import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.RequestDispatcher; import javax.servlet.annotation.*; @WebServlet(“/forwardservlet”) public class MyServlet extends HttpServlet{ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ //В getRequestDispatcher передаем адрес сервлета //на этом сервере куда будет происходить переход //из текущего сервлета. RequestDispatcher rd = req.getRequestDispatcher(“/myservlet”); //передаем в сервлет myservlet req и resp //текущего сервлета и вызываем его. rd.forward(req, resp); } }

Сервлет же, из которого будет совершаться переход, выглядит так:

import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.annotation.*; @WebServlet(“/myservlet”) public class MyServlet1 extends HttpServlet{ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ PrintWriter pw = resp.getWriter(); pw.write(“Hello World!!!”); } }

Скомпилируем файлы сервлетов и в адресной строке перейдем по адрусу /forwardservlet.

Как видим, клиенту был отправлен текст Hello World!!!. И передал его клиенту очевидно сервлет MyServlet1.

Браузер клиента при этом не знает, что его куда-то перенаправили и даже адресная строка, как уже было сказано, не меняется (forwardservlet не измениться на myservlet).


Включение другой страницы в текущую с помощью include()

include – буквально просто включение кода другого сервлета на сервере в текущий сервлет с передачей req и resp текущего сервлета во включаемый сервлет.

Код сервлета MyServlet, в который будет включаться MyServlet1:

import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.RequestDispatcher; import javax.servlet.annotation.*; @WebServlet(“/includeservlet”) public class MyServlet extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter pw = resp.getWriter(); pw.println(“” + “” + “” + “

Hello world form includeservlet

” + “” + ““); RequestDispatcher rd = req.getRequestDispatcher(“/myservlet”); //передаем в сервлет myservlet req и resp //текущего сервлета и вставляем его в текущий сервлет rd.include(req, resp); } }

Скомпилируем файлы сервлетов и в адресной строке перейдем по адресу /includeservlet.

На странице можно увидеть и “Hello world form includeservlet” из текущего сервлета и “Hello World!!!” из MyServlet1.