JavaRush /Курсы /JSP & Servlets /Формирование ответов сервлета

Формирование ответов сервлета

JSP & Servlets
12 уровень , 2 лекция
Открыта

3.1 Класс HttpServletResponse

После вызова метода service() твоего сервлета веб-контейнер сформирует ответ клиенту на основе объекта HttpServletResponse. Так что если хочешь как-то повлиять на ответ клиенту, то стоит модифицировать этот объект.

Ответ сервера состоит из трех частей:

  • Строка статуса (например: 200 OK)
  • Заголовки (headers)
  • Тело ответа (response body)

И методы класса HttpServletResponse тоже делятся на 3 группы? Ну почти:

Методы Описание
1 void setStatus(int sc) Устанавливает код статуса ответа.
2 void sendError(int sc) Отправляет клиенту ошибку с указанным кодом.
3 void sendError(int sc, String msg) Отправляет клиенту ошибку с указанным кодом и сообщение.
4 void addHeader(String name, String value) Добавляет заголовок в список заголовков ответа.
5 void setHeader(String name, String value) Меняет заголовок в списке заголовков ответа.
6 boolean containsHeader(String name) Проверяет, есть ли уже такой заголовок.
7 void addCookie(Cookie cookie) Добавляет Cookie к ответу.
8 void sendRedirect(String location) Перенаправляет клиента на другой URL.
9 String encodeRedirectURL(String url) Кодирует указанный URL для его использования в методе sendRedirect.
10 String encodeURL(String url) Кодирует указанный URL, включая в него идентификатор сессии.
11 void setContentType(String type) Устанавливает MimeType результата.
12 void setContentLength(int len) Устанавливает длину тела ответа.
13 void setCharacterEncoding(String charset) Устанавливает набор кодировок ответа.
14 void setBufferSize(int size) Устанавливает размер буфера для тела ответа.
15 boolean isCommitted() Проверяет, записан ли уже буфер в ответ.
16 void flushBuffer() Записывает содержимое буфера в ответ.
17 void reset() Сбрасывает все данные, которые хранятся в буфере, заголовки и коды ответа.
18 void resetBuffer() Очищает буфер ответа.

Методы тут достаточно тривиальны. Но расскажу ниже несколько нюансов.

Буфер. Ответ твоего сервлета пишется в буфер, а не сразу отправляется пользователю. Поэтому на каком-то этапе (если, например произошла ошибка), ты можешь сбросить (стереть) все, что записано в буфер. Можно даже вызвать метод reset() и стереть не только содержимое буфера, но и заголовки с кодом ответа.

3.2 redirect()

Второй важный момент — это редирект. Если твой сервлет примет решение перенаправить клиента на другой URL, то тебе нужно как-то этот URL отправить клиенту. Это можно сделать с помощью метода sendRedirect.

Но есть важный нюанс. URI может содержать более широкий диапазон символов, чем разрешено в response body. Поэтому URL перед вызовом метода sendRedirect() нужно сначала перекодировать в допустимый набор символов. Для этого и есть специальный метод encodeRedirectURL(String url). Воспользуйся им.

Пример редиректа:


public class RedirectServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String newUrl = "http://google.com?q=Учись гуглить!";
        String redirectUrl = response.encodeRedirectURL(newUrl);
        response.sendRedirect(redirectUrl);
    }
}

3.3 Метод getWriter()

А теперь мы научимся писать свой текст в качестве response body. Для этого у класса HttpServletResponse есть специальный метод getWriter(), который возвращает объект PrintStream. Если кто забыл, именно такой тип имеет поле с именем System.out.

Для того, чтобы написать какой-то текст в качестве ответа сервлета, нужно:

  • Получить объект PrintStream, вызвав метод response.getWriter().
  • Записать в объект PrintStream все, что считаешь нужным (все данные запишутся в буфер).
  • Отправить буфер пользователю, вызвав метод close() у PrintStream.

Давай напишем сервлет, который складывает два числа a и b и возвращает пользователю результат:



public class CalculatorServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws Exception {
         // Получаем параметр “a” и “b” из запроса
        String a = request.getParameter("a");
        String b = request.getParameter("b");
 
        try {
            // Преобразовываем строки в числа и считаем сумму
            int sum = Integer.parseInt(a) + Integer.parseInt(b);
 
            // Печатаем HTML в качестве ответа для браузера
            response.setContentType("text/html;charset=UTF-8");
            PrintWriter out = response.getWriter();
 
            out.println("<html>");
            out.println("<head> <title> CalculatorServlet </title> </head>");
            out.println("<body>");
            out.println("<h1> Sum == " + sum + "</h1>");
            out.println("</body>");
            out.println("</html>");
        } finally {
            out.close();
        }
    }
}
Комментарии (19)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Дмитрий Саргаев Уровень 76 Expert
1 октября 2023
Зачем нужен

out.close
если PrintWriter использует AutoClosable?
Бегемот Уровень 31
4 января 2024
Так объект создан не через try-with-resources. Чтобы оно автоматом освобождало ресурсы нужно именно так создавать, тогда да, close() будет вызван автоматически.
Rolik Уровень 41
19 августа 2023
HttpServletResponse - интерфейс. sendRedirect() - переадресация клиента (ф-ция HttpClientResponse). Перенаправление клиента - forward() (ф-ция RequestDispatcher). • forward() работает на стороне сервера - sendRedirect() на стороне клиента; • forward() перенаправляет те же request и response объекты - sendRedirect() переадресует новый request() объект.
jvatechs Уровень 111 Expert
22 июня 2023
Очень полезно для наглядности использовать представленные тут сервлеты в связке с программой Postman (все действия проделываются после запуска сервера Tomcat с данным сервлетом): 1) вставляете url (у меня http://localhost:8080/calculator ) 2) выбираете команду GET 3) снизу во вкладке Params прописываете: key value a 10 b 20 4) Жмете кнопку SEND и получаете внизу ответ (для наглядности выбрать вкладку Preview) скрин ниже
Anonymous #3322801 Уровень 2 Expert
23 августа 2023
Крутяк, спасибо) Мой ручной вариант через браузер:

http://localhost:8080/calculator?a=10&b=5
jvatechs Уровень 111 Expert
23 августа 2023
Тоже интересно, в принципе одно и то же в конечном счете)
Dima Makarov Уровень 42
24 августа 2023
Извиняюсь за нубский вопрос но могли бы Вы хотя бы кратко описать, как этот код сервлета запихнуть в томкэт, чтобы его протестить (без IDEA Ultimate) ?
Anonymous #3322801 Уровень 2 Expert
24 августа 2023
Я думаю что без IDEA Ultimate никак не обойтись, НО... я находила пару рабочих ключей к платной идее методом длительного гугления.
Justinian Уровень 41 Master
28 августа 2023
Intellij IDEA это просто графический интерфейс поверх командной строки, все что делает Идея в плане запуска кода или операций с ним - она делает консольными командами, просто для удобства пользователя предоставляет графический интерфейс для этого. Что умеет Идея, чего нельзя сделат в консоли, это функции Ворда - всякие автозамены, автопредложения, анализ кода, красивое подсвечивание и тд. Чтобы запустить сервлет без Идеи, нужно установить томкат локально, нужно в командной строке сбилдить и сгенерировать war и отправить его в Томкат. По запросу в гугле war tomcat deploy будет много способов как это можно сделать
Dima Makarov Уровень 42
16 сентября 2023
Не знаю то ли я сделал или нет, но сбилдил через Мавен варник и задеплоил через томкэт. Все работает.
Justinian Уровень 41 Master
18 сентября 2023
Проверить легко - работает или нет ) Если работает, все ок. Это тоже один из путей, но я такое видел очень редко, на этапе обучения так точно. Идея делает тоже самое только через консоль и интеграцию с консолью. Проще делать через Идею, обычная Идея - https://jayasundeep.medium.com/running-servlets-on-tomcat-in-intellij-community-edition-using-smart-tomcat-plugin-7a0370a9548f - https://stefancosma.xyz/2018/10/01/how-to-use-tomcat-intellij-idea-community/ если погуглить очень много вариантов. Если у кого будет рабочий вариант, зафиксируйте ссылку на решение или напишите сами шаги и бросьте отдельным комментарием в эту тему, многим будет актуально. При работе над веб-приложением постоянно приходится его перегружать, передеплоить/рестартовать, делать это одной кнопкой в Идее очень удобно. При работе с веб конечно стоит заморочиться Ультимейт Идеей, если нет лицензии, то всегда можно погуглить что делать или раз в месяц переустанавливать или другие варианты. Переустановка там тоже нестрашна, поскольку на ваши проекты это не будет влиять, а кастомных настроек которые теряются почти нету либо быстро восстанавливаются.
overbf bf Уровень 42
30 октября 2024
У меня "постман" не устанавливается, пришлось воспользоваться материалом прошлой лекции про HttpClient: public class RequestToMyServlet implements Requestable { @Override public HttpRequest getRequest() { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://localhost:8080/MyProject_1_war/test/?secret=MySuperPuperSecretInfo!!!!!")) .version(HttpClient.Version.HTTP_2) .timeout( Duration.of(1000, MILLIS) ) .GET() .build(); return request; } }
kv0ut Уровень 51
4 января 2023
В приведенном коде переменная out имеет тип PrintWriter, метод getWriter возвращает объект Print Stream. Данный код не скомпилируется.
JavaCoder Уровень 51
12 января 2023
На самом деле метод getWriter() возвращает именно PrintWriter, поэтому ошибки не будет.
Артем Уровень 2
23 ноября 2022
Класс RedirectServlet перекидывает на страницу Google, но вместо русских символов знаки ?. Как победить такую проблему? Нашел ответ, вдруг кому понадобится: String query = "q=" + URLEncoder.encode("Учись гуглить!", "UTF-8"); String url = "http://google.com?" + query; String redirectUrl = response.encodeRedirectURL(url);
Anonymous #3145256 Уровень 3
23 августа 2022
В последнем примере 13 строку нужно вынести из блока try, потому что в finally объект out недоступен, область видимости и всё такое
Александр Ц. Уровень 108 Expert
5 октября 2022
... и внести в try-with-resources, избавившись от finally
Антон Уровень 108 Expert
6 октября 2022
Скорее всего, finally и close() тут указали в учебных целях, чтобы использование метода было наглядно. В try-with-resources этот момент не так очевиден.
finedefinition Уровень 28
21 января 2023
в чем суть таких целей и такой наглядности если я код запускаю, а он не компилится?