Response
文章目录
- Response
-
- 1.概述
- 2.HttpServletResponse 对象
-
- 2.1.发送状态码的方法
-
- 2.1.1. setStatus(int status)方法
- 2.1.2. setError(int sc)方法
- 2.2.发送响应消息头的相关方法
- 2.3.发送响应消息相关方法
- 3.中文输出乱码问题
-
- 3.1.乱码解决
- 4.文件下载
-
- 4.1.文件下载的基本方式
- 4.2. 访问 Servlet 直接进行下载
- 4.3.下载指定文件
- 4.4.中文名字乱码(了解)
- 5.请求重定向
- 6.验证码
-
- 6.1.自己编写代码
- 6.2. 使用第三方组件 kaptcha
1.概述 Servlet 最主要的作用就是处理客户端请求,并向客户端做出响应。为此,针对 Servlet 的每次请求,Web 服务器在调用 service()之前,都会创建两个对象,分别是 HttpServlet Request和HttpServletResponse,
其中,HttpServletRequest 用于封装 HTTP 请求消息,简称 request 对象。
HttpServlet Response 用于封装 HTTP 响应消息,简称 response 对象。
需要注意的是,在 Web 服务器运行阶段,每个 Servlet 都只会创建一个实例对象。然而,每次 HTTP 请求,Web 服务器都会调用所请求 Servlet 实例的 service(HttpServletRequest request, HttpServletResponse response)方法,重新创建一个 request 对象和一个 response 对象。
文章图片
2.HttpServletResponse 对象 在Servlet API 中,定义了一个 HtpServletResponse 接口,它继承自 ServletResponse ,专门用来封装 HTTP 响应消息
HTTP 响应消息分为三部分:
在HttpservletResponse 接口中定义了向客户端发送响应状态码、响应消息头、响应消息体的方法
- 状态行
- 响应消息头
- 消息体
2.1.发送状态码的方法
2.1.1. setStatus(int status)方法 该方法用于设置 HTTP 响应消息的状态码
由于响应状态行中的状态描述信息直接与状态码相关,而 HTTP 版本由服务器确定,因此,只要通过 setStatus( int status)方法设置了状态码,即可实现状态行的发送。
需要注意的是,正常情况下,Web 服务器会默认产生一个状态码为 200 的状态行
2.1.2. setError(int sc)方法 该方法用于发送表示错误信息的状态码,例如 404,状态码表示找不到客户端请求的资源,在response 对象中
2.2.发送响应消息头的相关方法
当Servlet 向客户端回送响应消息时,由于 HTTP 的响应头字段有很多种,为此,在 HttpServletResponse 接口中,定义了一系列设置 HTTP 响应头的方法字段的方法。
addHeader(String name, String value)
addIntHeader(String name, int value)
设置响应头
addIntHeader(String name, String value)
setIntHeader(String name, int value)
设置整数类型的响应头
SetContentLength(int len)
设置响应消息的实体内容大小,单位为字节
setContentType(String type)
设置 servlet 输出内容的 MIME 类型,对于 HTTP 来说,就是设置 Content-Type 响应头字段的值
2.3.发送响应消息相关方法
由于在 HTTP 响应消息中,大量的数据都是通过响应消息体传递的,因此 ServletResponse 遵循以 1O 流传递大量数据的设计理念,在发送响应消息体时,定义了两个与输出流相关的方法
getOutputStream()
方法该方法所获取的字节输出流对象为 ServletOutputStream 类型 。 由于 ServletOut putStream 是 OutputStream 的子类,它可以直接输出字节数组中的二进制数据。因此,要想输出二进制格式的响应正文,就需要使用 getOutputStream() 方法
get Writer()
方法该方法所获取的字符输出流对象为 PrintWriter 类型。由于 PrintWriter 类型的对象可
以直接输出字符文本内容,因此,要想输出内容全为字符文本的网页文档,需要使用getWriter()方法
代码示例
/***演示HttpServletResponse输出流 */public class PrintServlet extends HttpServlet { private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//方式一//String data = "https://www.it610.com/article/jifeng";
//OutputStream stream = response.getOutputStream();
//stream.write(data.getBytes());
//方式二String data = "https://www.it610.com/article/jifeng";
PrintWriter stream = response.getWriter();
stream.write(data);
//注意:对象的getOutputStream() 和 getWriter() 方法都可以输出数据,但是两个方法是互斥的。}}
注意:对象的 getOutputStream() 和 getWriter() 方法都可以输出数据,但是两个方法是互斥的,不可同时使用。
3.中文输出乱码问题 由于计算机中的数据都是以二进制形式存储的,因此,当传输文本时,就会发生字符和字节之间的转换。
字符与字节之间的转换是通过查码表完成的,将字符转换成字节的过程称为编码,将字节转换成字符的过程称为解码,如果编码和解码使用的码表不一致就会导致乱码问题。
3.1.乱码解决
只需要保证响应数据的编码和浏览器解析的编码一致即可
response 缓冲区的默认编码是 iso8859-1,此码表中没有中文,可以通过 response 的 setCharacterEncoding(String charset) 设置 response 的编码
将response 缓冲区的编码设置成 UTF-8,但浏览器的默认编码是本地系统的编码,中文系统默认编码是 GBK,我们可以 手动修改浏览器的编码是 UTF-8。
还可以在代码中指定浏览器解析页面的编码方式,通过 response 的 setContentType(Stringtype)方法指定页面解析时的编码是 UTF-8
response.setContentType(“text/html; charset=UTF-8”);
上面的代码不仅可以指定浏览器解析页面时的编码,同时也内含 setCharacterEncoding 的功能
开发中只要编写 response.setContentType(“text/html; charset=UTF-8”); 就可以解决页面输出中文乱码问题。
4.文件下载 文件下载的实质就是文件拷贝,将文件从服务器端拷贝到浏览器端。
所以文件需要使用到 IO 流将服务器端的文件使用 InputStream 读取到,再使用
ServletOutputStream 写到 response 缓冲区中。
4.1.文件下载的基本方式
使用 a 标签直接指向服务器上的资源 a.xlsx
b.png
c.mp3
d.txt
文件存放截图
文章图片
4.2. 访问 Servlet 直接进行下载
要实现文件下载单独用 a 标签是不那么完美的。那么,究竟该怎样实现文件下载功能呢?此时,就需要使用 Servlet 编码读取要下载的文件,然后写到响应流中以达到用户下载文件的目的。
ServletOutputStream 抽象类。利用这个输出流可以将数据返回到客户端想浏览器直接输出字节流,浏览器会根据对应的格式进行解析
public class ByteServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//使用 response 获得字节输出流
ServletOutputStream out = response.getOutputStream();
//获得服务器上的图片,此时浏览器会直接解析并显示String realPath = this.getServletContext().getRealPath("download/b.png");
//xlsx 文件浏览器并不能解析,所以会以下载的方式进行//String realPath = this.getServletContext().getRealPath("download/a.xlsx");
InputStream in = new FileInputStream(realPath);
int len = 0;
byte[] buffer = new byte[1024];
while ((len = in.read(buffer)) > 0) {out.write(buffer, 0, len);
}in.close();
out.close();
}}
使用上面的代码还是有问题的,浏览器如果能够解析该文件,那么会直接将文件进行解析,并显示,并且不能解析的文件下载后,而且文件名也不对。需要进行如下操作
告诉客户端(浏览器)以下载的方式打开文件
通过文件的 MIME 类型去区分类型(tomcat/conf/web.xml)
文件的名字
//设置文件的类型response.setContentType(this.getServletContext().getMimeType("download/b.png"));
//告诉客户端(浏览器)以下载的方式打开文件,设置 Context-Dispostion 头,并设置文件名字response.setHeader("Content-Disposition", "attachment;
filename=b.png");
设置好两个头后,就可以实现文件下载的功能,并且文件也已经有名字了
4.3.下载指定文件
编写新的 Servlet,访问 Servlet 时传递指定的文件名字,下载指定的文件
HTM L 代码如下(添加多一个中文名字的文件)
给 Servlet 传递参数只需要在 URL 后面加?并且拼接文件名字参数即可(键值对新式)
a.xlsx
b.jpg
c.mp3
d.txt
文本.txt
Servlet 代码,主要改动的代码为:
获取传递过来的文件名,之后以该文件名获取 MIME 类型和读取文件
tring filename="download/"+request.getParameter("filename");
//a.xlsx
主要代码如下
protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
//获得要下载的文件的名称String filename = request.getParameter("filename");
// a.xlsx//设置文件的类型response.setContentType(this.getServletContext().getMimeType("downlo ad/" + filename));
//告诉客户端(浏览器)以下载的方式打开文件,设置 Context-Dispostion 头,并设置文件名字response.setHeader("Content-Disposition", "attachment;
filename=" + filename);
//使用 response 获得字节输出流ServletOutputStream out = response.getOutputStream();
//获得服务器上的图片,此时浏览器会直接解析并显示String realPath = this.getServletContext().getRealPath("download/" + filename);
//xlsx 文件浏览器并不能解析,所以会以下载的方式进行//String realPath =//this.getServletContext().getRealPath("download/a.xlsx");
InputStream in = new FileInputStream(realPath);
int len = 0;
byte[] buffer = new byte[1024];
while ((len = in.read(buffer)) > 0) {out.write(buffer, 0, len);
}in.close();
out.close();
}
4.4.中文名字乱码(了解)
上面的代码,如果下载中文文件,页面在下载时会出现中文乱码或不能显示文件名的情况(也
有可能发生文件找不到 404),对于 GET 请求,参数追加到地址栏,会使用 UTF-8 编码,服务器(Tomcat)接受到请求之后,使用 ISO-8859-1 解码,所以会出现乱码,导致找不到资源。
因此,我们在获取文件名时,必须将文件名用 UTF-8 解码
String filename = new String(request.getParameter(“filename”).getBytes(“iso-8859-1”),“utf-8”);
并且不同的浏览器默认对下载文件的编码方式不同,IE 是 UTF-8 编码方式,而火狐浏览器是
Base64 编码方式。所里这里还需要解决浏览器兼容性问题,解决浏览器兼容性问题的首要
任务是要辨别访问者是 IE 还是火狐(其他),通过 Http 请求体中的一个属性可以辨别
文章图片
代码
//获得请求头中的 User-AgentString agent = request.getHeader("User-Agent");
//根据不同浏览器进行不同的编码String filenameEncoder = "";
if (agent.contains("MSIE")) {//IE 浏览器filenameEncoder = URLEncoder.encode(filename, "utf-8");
filenameEncoder = filenameEncoder.replace("+", " ");
} else if (agent.contains("Firefox")) {//火狐浏览器BASE64Encoder base64Encoder = new BASE64Encoder();
filenameEncoder = "=?utf-8?B?"+base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else {//其它浏览器filenameEncoder = URLEncoder.encode(filename, "utf-8");
}
文件名
//告诉客户端(浏览器)以下载的方式打开文件,设置 Context-Dispostion 头,并设置文件名字
response.setHeader("Content-Disposition", "attachment;
filename=" + filenameEncoder);
完整代码
protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//获得要下载的文件的名称String filename = new String(request.getParameter("filename"));
//设置文件的类型response.setContentType(this.getServletContext().getMimeType("downlo ad/" + filename));
// 获得请求头中的 User-AgentString agent = request.getHeader("User-Agent");
//根据不同浏览器进行不同的编码String filenameEncoder = "";
if (agent.contains("MSIE")) {//IE 浏览器filenameEncoder = URLEncoder.encode(filename, "utf-8");
filenameEncoder = filenameEncoder.replace("+", " ");
} else if (agent.contains("Firefox")) {//火狐浏览器BASE64Encoder base64Encoder = new BASE64Encoder();
filenameEncoder = "=?utf-8?B?" +base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else {//其它浏览器filenameEncoder = URLEncoder.encode(filename, "utf-8");
}//告诉客户端(浏览器)以下载的方式打开文件,设置 Context-Dispostion 头,并设置文件名字response.setHeader("Content-Disposition", "attachment;
filename=" + filenameEncoder);
//使用 response 获得字节输出流ServletOutputStream out = response.getOutputStream();
//获得服务器上的图片,此时浏览器会直接解析并显示String realPath = this.getServletContext().getRealPath("download/" + filename);
//xlsx 文件浏览器并不能解析,所以会以下载的方式进行//String realPath =//this.getServletContext().getRealPath("download/a.xlsx");
InputStream in = new FileInputStream(realPath);
int len = 0;
byte[] buffer = new byte[1024];
while ((len = in.read(buffer)) > 0) {out.write(buffer, 0, len);
}in.close();
out.close();
}
5.请求重定向 在某些情况下,针对客户端的请求,一个 Servlet 类可能无法完成全部工作。这时可以使用请求重定向来完成。
所谓请求重定向,指的是 Web 服务器接受到客户端的请求后,可能由于某些条件限制,不能访问当前请求 URL 所指向的 Web 资源,而是指定了一个新的资源路径,让客户端重新发送请求为了实现请求重定向,在 HttpServletResponse 接口中,定义了一个 sendRedirect() 方法,该方法用于生成 302 响应码和 Location 响应头,从而通知客户端重新访问 Location 响应头中指定的 URL
重定向工作原理
文章图片
当客户端访问 Servlet1 时,由于在 Servlet 中调用了 sendRedirect() 方法将请求重定向到 Servlet2 中,因此,Web 服务器在收到 Servlet1 的响应消息后,立刻向 Servlet2 发送请求 Servlet2 对请求处理完毕后,再将响应消息回送给客户端。
代码示例
访问 Servlet1,会重定向到 Servlet2
public class Servlet1 extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 重定向到Servlet2response.sendRedirect("/Response/servlet2");
}}public class Servlet2 extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.getWriter().write("hello Servlet2");
}}
回忆之前的登陆案例,登陆失败也可以用的对象回到登陆界面,如下代码
文章图片
6.验证码 6.1.自己编写代码
使用 Servlet 完成验证码功能,截图如下
文章图片
绘制验证码图片的 Servlet(了解)
public class ImgServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {BufferedImage bfi = new BufferedImage(68, 22, BufferedImage.TYPE_INT_RGB);
// 图像缓冲区Graphics g = bfi.getGraphics();
StringBuffer sb = new StringBuffer();
/* 画背景框 */Color color = new Color(200, 215, 250);
g.setColor(color);
g.fillRect(0, 0, 68, 30);
/* 第一个数字 */Random r = new Random();
int tmp1 = r.nextInt(20);
g.setColor(new Color(r.nextInt(100), r.nextInt(100), r.nextInt(100)));
// 设置随机颜色g.drawString(tmp1 + "", 3, 18);
/* 加号 */g.setColor(new Color(r.nextInt(100), r.nextInt(100), r.nextInt(100)));
// 设置随机颜色g.drawString("+", 18, 18);
/* 第二个数字 */int tmp2 = r.nextInt(20);
g.setColor(new Color(r.nextInt(100), r.nextInt(100), r.nextInt(100)));
// 设置随机颜色g.drawString(tmp2 + "", 33, 18);
/* 等号 */g.setColor(new Color(r.nextInt(100), r.nextInt(100), r.nextInt(100)));
// 设置随机颜色g.drawString("=", 48, 18);
/* 问号 */g.setColor(new Color(r.nextInt(100), r.nextInt(100), r.nextInt(100)));
// 设置随机颜色g.drawString("?", 57, 18);
/* 保存到 session */int result = tmp1 + tmp2;
request.getSession().setAttribute("verifycode", result + "");
/* 写入 response 输出流 */ImageIO.write(bfi, "JPG", response.getOutputStream());
}}
配置 ImgServlet
>>ImgServlet>com.jf.weidong.ImgServlet >>ImgServlet/imgServlet
表单界面
Insert title here - 锐客网 >function reloadCode() {//浏览器会对同一 url 的图像进行缓存,利用附加一个随机数,来避免客户端浏览器使用缓存(每次请求 url 都不同)document.getElementById("img").src = "https://www.it610.com/VerificationCode/imgServlet?"+ Math.random();
}
登陆的 LoginServlet
public class LoginServlet extends HttpServlet { @Overridepublic void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;
charset=utf-8");
String re = request.getParameter("verifycode");
String answer = (String)request.getSession().getAttribute("verifycode");
PrintWriter out = response.getWriter();
if (re.equals(answer)) {
out.printf("验证成功");
} else {out.printf("验证失败");
}out.flush();
out.close();
}}
6.2. 使用第三方组件 kaptcha
1.添加 kaptcha 的 jar 包到项目 lib 库,下载地址 http://www.java2s.com/Code/Jar/k/Downloadkaptcha23jar.htm
2.配置 web.xml
>>Kaptcha>com.google.code.kaptcha.servlet.KaptchaServlet>>Kaptcha/kaptcha.jpg
表单
>function reloadCode() {//浏览器会对同一 url 的图像进行缓存,利用附加一个随机数,来避免客户端浏览器使用缓存(每次请求 url 都不同)document.getElementById("img").src="https://www.it610.com/VerificationCode/kaptcha.jpg?"+ Math.random();
}
【JavaWeb|JavaWeb——【Response】——一篇文章学会Respose,值得你一看!】LoginServlet_kaptcha
public class LoginServlet_kaptcha extends HttpServlet { @Overridepublic void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;
charset=utf-8");
String re = request.getParameter("verifycode");
/*获取 session 中的验证码*/String captcha = ((String) request.getSession().getAttribute( com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY));
PrintWriter out = response.getWriter();
if (re.equals(captcha)) {out.printf("验证成功");
} else {out.printf("验证失败");
}out.flush();
out.close();
}}
推荐阅读
- #|【蓝桥杯嵌入式】【STM32】12_2020_第十一届_蓝桥杯_嵌入式设计与开发项目_省赛
- #|ClickHouse基础
- #|python opencv 图像像素处理基础
- JavaWeb|基于Java开发的CMS内容管理系统
- #|2020蓝桥杯模拟赛
- Java毕业设计项目实战篇|基于javaweb+springboot的美食菜谱分享平台系统设计和实现(java+springboot+mysql+ssm)
- #|本人寻找泉州地区的iOS开发岗位(简历(欢迎评论留下联系方式))
- #|股票数据分析
- #|数据分析与可视化(四)Pandas学习基础一(统计分析基础)