20. Введение в сервлет — введение и использование ответа
Обзор ответов
В предыдущих главах мы уже знали соответствующие функции запроса-запроса, поэтому давайте продолжим разбираться в ответе-ответе.
Обзор HttpServletResponse
В Servlet API определен интерфейс HttpServletResponse (параметры методов doGet, doPost), который наследуется от интерфейса ServletResponse и специально используется для инкапсуляции ответных сообщений HTTP. Поскольку сообщение ответа HTTP разделено на три части: строка ответа, заголовок ответа и тело ответа, методы отправки кода состояния ответа, заголовка ответа и тела ответа клиенту определяются в интерфейсе HttpServletResponse.
эффект
-
Три части ответа операции (строка ответа, заголовок ответа, тело ответа)
краткое содержание
-
Response представляет объект ответа, прототипом является HttpServletResponse, созданный сервером, и есть методы doGet()/doPost() в виде формальных параметров
-
Роль ответа
-
Три части ответа операции (строка, заголовок, тело)
Response задает код состояния ответа (строка ответа операции)
Когда сервлет возвращает информацию об ответе в браузер, вы можете установить код состояния ответа, возвращаемый в браузер.
Например:
HTTP/1.1 200
Вы можете использовать метод setStatus(int sc) для установки кода состояния ответа:
Обычно используемые коды состояния:
200: успех
302: перенаправление
304: доступ к кешу
404: Ошибка клиента
500: Ошибка сервера
Давайте напишем демо, чтобы продемонстрировать это.
1. Создайте демонстрационную программу сервлета и установите код состояния ответа 403.
@WebServlet("/ResponseDemo1")
public class ResponseDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("访问 ResponseDemo1 ....");
//设置响应状态码: 403 forbidden
response.setStatus(403);
}
}
2. Проверить доступ в браузере
3. Резюме
-
Установить API: response.setStatus(int code);
-
Как правило, никаких настроек не требуется, возможно, необходимо установить перенаправление 302.
-
Общие коды состояния ответа
-
200 успешных
-
302 редирект
-
304 кэш чтения
-
404 ошибка клиента
-
500 ошибка сервера
Ответ устанавливает заголовок ответа обновления для выполнения временного перехода (заголовок ответа операции).
Мы узнали, как использовать Response для установки кода состояния ответа выше, поэтому давайте поработаем с заголовком ответа.
1. Введение в API для управления заголовками ответов
Заголовок ответа: указывает ли сервер браузеру, что делать
Ключ соответствует значению
Один ключ соответствует нескольким значениям
Рассматриваемый метод: setHeader (имя строки, значение строки);
Общие заголовки ответов
Обновить: скачок по времени (например, сервер сообщает браузеру перейти к Baidu через 5 секунд)
Местоположение: адрес перенаправления (например, сервер указывает браузеру перейти на xxx)
Content-Disposition: Скажите браузеру загрузить
Content-Type: Установите MIME-тип содержимого ответа (сервер сообщает браузеру тип содержимого)
Давайте продемонстрируем, как Refresh выполняет временные скачки.
2. Создайте демонстрационную программу сервлета и настройте заголовок ответа так, чтобы он регулярно переходил
@WebServlet("/ResponseDemo2")
public class ResponseDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//目标: 让浏览器在访问ResponseDemo2后三秒,跳转到百度首页
System.out.println("ResponseDemo2收到了请求。。。");
//通过"Refresh"响应头
response.setHeader("Refresh","3;url=https://www.baidu.com");
}
}
3. Тестовый доступ в браузере
Подождав 3 секунды, он автоматически перейдет к Baidu следующим образом:
Ответ инициирует перенаправление (заголовок ответа операции)
Выше мы реализовали временной скачок, установив заголовок ответа, поэтому давайте теперь рассмотрим перенаправление.
1. Ответ устанавливает заголовок ответа Location для перенаправления (немедленный переход).
Сначала создайте программу сервлета для демонстрации перенаправления следующим образом:
@WebServlet("/ResponseDemo3")
public class ResponseDemo3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("ResponseDemo3收到了一个请求...");
//目标1:浏览器访问ResponseDemo3,会跳转到百度首页
//重定向跳转的步骤:1. 设置响应状态码为302 2. 设置响应头Location的值为要跳转到的地址
response.setStatus(302);
response.setHeader("Location","https://www.baidu.com");
}
}
2. Тестовый доступ браузера, обнаружил, что браузер работает успешно и сразу переходит на Baidu.
Посетите http://localhost:8080/ResponseDemo3
В этом тесте мы можем убедиться, что перенаправления могут быть перенаправлены на ресурсы вне проекта. Итак, давайте направим его на ресурсы в проекте, чтобы увидеть.
3. Установите перенаправление на ресурсы в проекте
3.1 Создайте index.html в WEB-INF
3.2 Установите перенаправление на index.html в сервлете следующим образом:
@WebServlet("/ResponseDemo3")
public class ResponseDemo3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("ResponseDemo3收到了一个请求...");
//目标1:浏览器访问ResponseDemo3,会跳转到百度首页
//重定向跳转的步骤:1. 设置响应状态码为302 2. 设置响应头Location的值为要跳转到的地址
// response.setStatus(302);
// response.setHeader("Location","https://www.baidu.com");
//目标2:浏览器访问ResponseDemo3,会跳转到本项目的index.html页面
response.setStatus(302);
response.setHeader("Location","/index.html"); // 路径设置: /项目部署路径/文件在webapp下的路径
}
}
Используйте браузер для доступа к http://localhost:8080/ResponseDemo3 следующим образом:
Могу ли я получить доступ к ресурсам в WEB-INF?
3.3 Попытка перенаправления на ресурсы в WEB-INF
Видно, что браузер не может получить доступ к ресурсам в WEB-INF, поэтому на него нельзя перенаправить.
3.4 Сокращенное перенаправление с помощью sendRedirect
В приведенном выше, поскольку мы перенаправляем, чтобы установить код ответа или установить заголовок запроса, есть ли сокращенный метод? Конечно есть, см. ниже.
// 重定向的简写方法
response.sendRedirect("/index.html");
Протестируйте его в браузере следующим образом:
Видно, что эффекта перенаправления можно добиться, поэтому нам просто нужно запомнить этот способ написания.
4. Резюме
-
Перенаправления заставляют браузер делать два запроса
-
Путь перенаправленной адресной строки меняется
-
Напишите абсолютный путь для перенаправленного пути (с доменным именем/ip-адресом, если он находится в том же проекте, доменное имя/ip-адрес можно не указывать)
-
Путь перенаправления может быть как внутри проекта, так и за его пределами (например, Baidu).
-
Перенаправления не могут перенаправлять на ресурсы в WEB-INF
-
Хранить данные в запросе, перенаправление недоступно
//方式一: 重定向
//1.设置状态码
//response.setStatus(302);
//2.设置重定向的路径(绝对路径,带域名/ip地址的,如果是同一个项目里面的,域名/ip地址可以省略)
//response.setHeader("Location","https://www.baidu.com");
//response.setHeader("Location","/index.html");
//方式二: 直接调用sendRedirect方法, 内部封装了上面两行
response.sendRedirect("/index.html");
-
перенаправить
response.sendRedirect("重定向的路径");
Сравнение перенаправления и переадресации запроса
1. Особенности перенаправления:
-
Переход с перенаправлением инициируется браузером, и во время этого процесса браузер инициирует два запроса.
-
Переходы перенаправления могут переходить к ресурсам любого сервера, но не могут переходить к ресурсам в WEB-INF.
-
Переходы перенаправления нельзя использовать с объектами домена запроса.
-
Адрес в адресной строке браузера станет путем перенаправления
2. Особенности переадресации запросов:
1. 请求转发的跳转是由服务器发起的,在这个过程中浏览器只会发起一次请求
2. 请求转发只能跳转到本项目的资源,但是可以跳转到WEB-INF中的资源
3. 请求转发可以和request域对象一起使用
Используйте поток вывода символов Response для вывода текстового содержимого тела ответа в браузер (тело ответа операции).
1. API для управления телом ответа
Вывод страницы может быть достигнут только с использованием одного из потоков, и эти два потока являются взаимоисключающими.
Общее использование:
-
Если вы выводите текстовое содержимое в браузер, то вам нужно вывести символы в браузер, используйте
getWriter()
-
Если это для загрузки ресурсов, таких как картинки, то вам нужно вывести поток байтов в браузер, используйте
getOutputStream()
Давайте сначала продемонстрируем ситуацию вывода текстового контента.
2. Используйте getWriter() для вывода текстового содержимого в браузер
2.1 Метод response.getWriter().writer() может выводить только строки, если он выводит int, float и т.д., то будут проблемы
@WebServlet("/ResponseDemo4")
public class ResponseDemo4 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//要向浏览器输出响应体的信息,需要通过流来进行操作
//第一种:字符串,输出文本内容
PrintWriter writer = response.getWriter();
//使用字符流往浏览器输出文本
//1. writer()方法,只能输出字符串,如果输出int、float等等类型的话,则会有问题
writer.write("hello world");
}
}
Если выводятся типы int и float, об ошибке будет сообщено следующим образом:
Видно, что цифры не могут нормально отображаться, так зачем же нужно отображать цифры? В настоящее время он обычно выводится в виде строки следующим образом:
Но если вы не хотите этого делать, что вы можете сделать, если хотите напрямую выводить int, float и т. д.? можно использовать writer.print()
метод .
2.2 Метод response.getWriter().print() может выводить числа и строки
//2. print()方法,可以输出数字、字符串
writer.print(123456);
Можно видеть, что использование print()
метода действительно может выводить числа, но обычно нам нужно только помнить writer()
, что метод должен использоваться для вывода строк.
2.3 Вывод строк китайских символов, появляются искаженные символы
Можно вывести английские строки и числа выше, но когда мы попытаемся вывести китайский контент, будут искажены символы, как показано ниже:
Итак, почему появляются искаженные символы, конечно, это вызвано несовместимыми форматами кодирования. Итак, давайте посмотрим, как решить искаженную проблему.
3. Решить проблему искаженных символов китайского ответа
Проблема искажения китайских символов вызвана несоответствием между форматом кодировки сервера и форматом кодировки браузера. Затем нам нужно только установить формат кодировки сервера на UTF8, а затем сообщить браузеру, чтобы он также установил формат кодировки на UTF8.
Так что, если браузер уведомлен о необходимости установить формат кодировки UTF8? Он может быть установлен следующим образом при ответе:
-
Решить проблему вывода потока символов с искаженными китайскими символами.
response.setContentType("text/html;charset=utf-8");
/*
* 这句代码底层做了什么?
* 1. 设置服务器响应的字符集为UTF-8
* 2. 设置Content-Type响应头的信息为 "text/html;charset=UTF-8"
* 让浏览器知道了服务器的响应字符集UTF-8,那么浏览器也会使用UTF-8解码
*/
3.1 Демонстрация решения проблемы вывода искаженных китайских символов
@WebServlet("/ResponseDemo4")
public class ResponseDemo4 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//解决响应中文乱码
response.setContentType("text/html;charset=utf-8");
//要向浏览器输出响应体的信息,需要通过流来进行操作
//第一种:字符串,输出文本内容
PrintWriter writer = response.getWriter();
//使用字符流往浏览器输出文本
//1. writer()方法,只能输出字符串,如果输出int、float等等类型的话,则会有问题
writer.write("你好,世界...");
//2. print()方法,可以输出数字、字符串
// writer.print(123456);
}
}
3.2 Ярлыки для настройки формата кодирования ответа
Хотя для решения искаженных китайских символов в ответе требуется всего одна строка кода, запоминать каждый раз довольно сложно. Таким образом, мы можем установить его как ярлык для входа.
Файл | Настройки | Редактор | Живые шаблоны
//解决响应中文乱码
response.setContentType("text/html;charset=utf-8");
Результаты теста следующие:
Используйте поток байтов ответа getOutputStream() для вывода содержимого изображения в браузер (тело ответа операции)
Выше мы реализовали вывод содержимого строки в браузер, поэтому, конечно, нам также нужно подумать о том, как вывести содержимое изображения в браузер.
Во-первых, давайте посмотрим, как DefaultServlet по умолчанию обрабатывает статические ресурсы.
DefaultServlet обрабатывает статические ресурсы
1. Скопируйте изображение в каталог веб-приложения
2. Запустите службу tomcat и используйте путь проекта для доступа к ресурсам изображения.
Итак, если вы сами пишете программу сервлета, как реализовать эту функцию?
Напишите свой собственный сервлет и используйте getOutputStream() для вывода ресурсов изображения в браузер.
@WebServlet("/ResponseDemo5")
public class ResponseDemo5 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 读取b.jpg图片,将其转换成字节输入流,使用ServletContext
ServletContext servletContext = getServletContext();
InputStream is = servletContext.getResourceAsStream("1.jpeg");
//2. 使用字节输出流,将is中的字节都输出到浏览器
//2.1 获取响应字节流
ServletOutputStream os = response.getOutputStream();
//2.2 读取文件输入流 拷贝到 响应输出字节流
byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != -1){
os.write(buffer,0,len);
}
//3.关闭流
os.close();
is.close();
}
}
В приведенном выше коде мы добились эффекта вывода ресурса изображения в браузер, но мы можем его найти.
Каждый раз, когда мы работаем с потоком байтов, нам приходится писать строку буферов потока байтов для копирования в другой выходной поток, что громоздко:
//2.2 读取文件输入流 拷贝到 响应输出字节流
byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != -1){
os.write(buffer,0,len);
}
Есть ли более простой способ? Конечно есть, то есть он может быть инкапсулирован как публичный метод, и этот публичный метод был предоставлен третьей стороной, и мы можем использовать его напрямую.
Использование инструментов потока ввода-вывода: упростите операцию копирования байтовых потоков.
-
Представляем jar-пакет commons-io
-
Используйте commons-io для упрощения операции копирования потока байтов.
1. Используйте Maven для импорта зависимостей пакета jar от commons-io.
1.1 Посетите склад Maven и найдите зависимости commons-io
Посетите https://mvnrepository.com и найдите commons-io следующим образом:
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
1.2 Импорт зависимостей координат commons-io в pom.xml проекта
<!-- 导入 commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
2. Используйте метод IOUtils.copy(is,os); в commons-io, чтобы скопировать поток
import org.apache.commons.io.IOUtils;
//2.2 使用 commons-io 中的 IOUtils.copy(is,os); 方法来拷贝流
IOUtils.copy(is, os);
3. Просмотр исходного кода IOUtils.copy(is, os)
Видно, что, по сути, этот метод копирования копирует и байтовый поток, но лучше пакетный, которым удобно пользоваться всем нам.
Резюме ответов
-
Установите код состояния ответа: setStatus()
-
Установите заголовок ответа: setHeader (имя, значение)
-
Заголовок ответа на обновление используется для перехода на определенную страницу через несколько секунд.
-
заголовок ответа местоположения, используемый для перенаправления на определенную страницу
-
-
Написание перенаправления: sendRedirect(адрес)
-
Установить содержимое тела ответа
-
response.getOutputStream() получает поток вывода байтов
-
response.getWriter() получает поток вывода символов
-
строка вывода Writer.write()/print()
-
Устраните искаженные китайские символы данных ответа: response.setContentType("text/html;charset=UTF-8")
-
Вывод текстового содержимого с использованием потока вывода символов
-
выходной файл с использованием байтового потока вывода
-
-
Используйте структуру потока ввода-вывода для чтения и записи