文章目录
- Response
- 设置响应消息数据
- 1.设置响应行
- 2.设置响应头
- 3.设置响应体
- 案例
- 1.重定向
- 2.输出字符数据到 Response 对象
- 乱码的问题
- 解决办法一
- 解决办法二
- 3.输出字节数据到 Response 对象
- 4.验证码案例
- 继承与实现体系
Response
该对象的功能就是用来设置响应消息(响应报文)。
程序员将响应数据封装到 Response 对象中,Tomcat 会从 Response 对象中取出程序员设置的响应数据,并将这些响应数据、响应头数据、响应行数据封装成响应报文(即响应数据包)返回给浏览器端。
设置响应消息数据
1.设置响应行
响应行格式:HTTP/1.1 200 OK
设置状态码:void setStatus(int sc)
2.设置响应头
void setHeader(String name, String value)
3.设置响应体
1.获取输出流
获取输出流:PrintWriter getWriter()
获取字节流:ServletOutputStream getOutputStream()
2.使用输出流,将响应数据输出到 ServletResponse 对象中
案例
1.重定向
// 设置重定向的状态码
resp.setStatus(302);
// 设置响应头
resp.setHeader("Location","/servlet_demo/response_demo02");
或者
// 重定向到ResponseDemo02
resp.sendRedirect("/servlet_demo/response_demo02");
2.输出字符数据到 Response 对象
// 获取字符输出流
PrintWriter pw = response.getWriter();
// 输出数据,写入数据。先写入到流对象的缓冲区,再写入到 Response 对象中,服务器再从 Response 对象中读取数据封装成响应报文返回给客户端
pw.write("<h1>hello</h1>");
乱码的问题
乱码的原因分析:
服务端输出数据,需要编码,而浏览器加载解析数据需要解码,乱码的原因就是编码和解码使用的编码格式不同所导致的。
浏览器用于解码的默认字符编码与操作系统有关,中文系统默认的字符编码是 GBK 或者 GB2312,而服务器端获取的输出流对象,是由 Tomcat 创建的,所以使用的字符编码是 ISO-8859-1,所以使用 GBK 或者 GB2312 去解码 ISO-8859-1 编码肯定出现乱码了。
解决办法一
不要使用 ISO-8859-1 进行编码,改为使用 GBK 进行编码。
示例代码如下:
// 在获取输出流之前将Response对象的字符编码设置为GBK,默认的是ISO-8859-1
resp.setCharacterEncoding("GBK");
// 获取字符输出流
PrintWriter pw = resp.getWriter();
// 输出数据
pw.write("<h1>刘德华</h1>");
解决办法二
在解决办法一种,直接将 Response 对象的字符编码设为 GBK,是因为你知道浏览器默认使用的是 GBK,如果你不知道呢?或者用户使用的浏览器默认的编码不是 GBK 呢?所以上述的写法还不够,你还需要告诉客户端响应数据所使用的字符编码,建议浏览器使用该编码进行解码。这样就不要管浏览器默认的字符编码是啥,浏览器在解析数据的时候会使用服务端建议的编码进行解码。
所以完整的示例代码如下:
// 在获取输出流之前将Response对象的字符编码设置为GBK,默认的是 ISO-8859-1
resp.setCharacterEncoding("utf-8");// 告诉浏览器,服务器返回的响应体数据的字符编码,建议浏览器使用该编码进行解码
resp.setHeader("content-type","text/html;charset=utf-8");// 获取字符输出流
PrintWriter pw = resp.getWriter();
// 输出数据
pw.write("<h1>刘德华</h1>");
上述代码中的 resp.setCharacterEncoding("utf-8");
可以去掉,因为 resp.setHeader("content-type","text/html;charset=utf-8");
已经指明输出数据时需要使用什么字符编码,并且还告诉浏览器需要使用什么字符编码进行解码。
另外 resp.setHeader("content-type","text/html;charset=utf-8");
可以替换成另外一个 API 进行简写,如下:
// 简单的写法,设置响应头Content-Type的值
resp.setContentType("text/html;charset=utf-8");
最终的示例代码如下:
// 设置响应头Content-Type的值
resp.setContentType("text/html;charset=utf-8");
// 获取字符输出流
PrintWriter pw = resp.getWriter();
// 输出数据
pw.write("<h1>刘德华</h1>");
3.输出字节数据到 Response 对象
示例代码:
// 设置Response对象的字符编码为utf-8
resp.setContentType("text/html;charset=utf-8");
// 获取字节输出流
ServletOutputStream sos = resp.getOutputStream();
// 获取字符的字节数组作为参数传递,写入到字节输出流中,最后会从字节输出流写入到Response对象中
sos.write("<h1>中国人</h1>".getBytes());
那么将消息头 Content-Type
的值设为 text/html;charset=gbk
行不行呢?
答:不行。设为 gb2312 也不行。因为通过响应消息头 Content-Type
设 置字符编码为 GBK,那么字符输出流会按 GBK 进行编码,而字节输出流是写入字节数据,需要获取字符的字节数组,通过 getBytes 方法获取字节数组,如果没有指定字符编码默认使用的是 UTF-8,所以写入的是 UTF-8 的字节数组,因此浏览器端收到的响应数据的编码格式是 UTF-8,而你又通过消息头Content-Type
告诉浏览器使用 GBK 解码,所以中文字符肯定出现乱码了。
我们知道浏览器在中文操作系统中默认的字符编码是 GBK,如果希望服务端在使用字节输出流输出数据时使用 GBK 编码,必须这样写:
// 获取字节输出流
ServletOutputStream sos = resp.getOutputStream();
// 获取字符的字节数组作为参数传递,写入到字节输出流中,最后会从字节输出流写入到Response对象中
// getBytes方法指定字符编码参数为“GBK”才能得到”GBK“格式的字节数组
sos.write("<h1>中国人</h1>".getBytes("gbk"));
4.验证码案例
package priv.lwx.javaex.servlet_demo.web.servlet.response;import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;/*** 验证码示例代码** @author liaowenxiong* @date 2022/1/10 11:01*/
@WebServlet("/check_code")
public class CheckCodeServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {int width = 100; // 表示图片的宽度,单位像素int height = 50; // 表示图片的高度,单位像素// 1.创建一个图片对象,代表内存中的验证码图片。图片对象创建好之后,就表示在内存中创建了一个图片(内存中存储的是二进制数据),图片背景色默认黑色BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);// 2.美化图片// 2.1.填充背景色// 先获取画笔Graphics graphics = image.getGraphics();// 设置画笔的颜色为粉红色graphics.setColor(Color.PINK);// 填充矩形graphics.fillRect(0, 0, width, height);// 2.2.画边框// 设置画笔的颜色为蓝色graphics.setColor(Color.BLUE);// 画边框graphics.drawRect(0, 0, -1, height - 1);// 画随机字符// 随机字符的来源String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";// 创建随机数对象Random ran = new Random();// 2.3.画随机字符。循环四次,画4个随机的字符for (int i = 1; i <= 4; i++) {// 生成随机的字符串下标int index = ran.nextInt(str.length());// 获取随机字符char c = str.charAt(index);// 画随机字符graphics.drawString(c + "", width / 5 * i, height / 2);}// 2.4.画干扰线// 设置画笔的颜色为绿色的graphics.setColor(Color.GREEN);// 获取随机的for (int i = 0; i < 10; i++) {// 获取两个随机点的坐标值int x1 = ran.nextInt(width);int x2 = ran.nextInt(width);int y1 = ran.nextInt(height);int y2 = ran.nextInt(height);// 画线graphics.drawLine(x1, y1, x2, y2);}// 3.将图片输出到Response对象的字节流中ImageIO.write(image, "jpg", resp.getOutputStream());}
}
继承与实现体系
略