ServletResponse 接口
|
HttpServletResponse 接口
|
org.apache.catalina.connector.ResponseFacade 实现类(由 Tomcat 厂商提供的实现类)
2 设置 HTTP 响应消息
a. 响应行
格式:协议/版本号 状态码
,例如 HTTP/1.1 200
相关 API:
设置状态码:void setStatus(int ss)
b. 响应头
格式:响应头名称:响应头的值
,例如 Location:https://blog.csdn.net/Regino
相关 API:
设置指定头名称和对应的值:void setHeader(String name, String value)
c. 响应体
相关 API(输出流对象):
获取输出字符流:PrintWriter getWriter()
获取输出字节流:ServletOutputStream getOutputStream()
注意:
在同一个 Servlet 中,二种类型的输出流不能同时存在,互斥。 向浏览器输出文件时用字节流,输出文本内容时用字符流。 3. 案例:响应重定向 a. 主要需求 用户访问 AServlet 后,服务器告诉浏览器重定向到 BServlet。 b. 步骤分析 方式一: 设置状态码(响应行):response.setStatus(302);
设置响应头 Location:response.setHeader("Location","重定向网络地址");
方式二:
Response 封装了专门处理重定向的方法:response.sendRedirect("重定向网络地址");
c. 重定向特点
地址栏会发生改变;
重定向是二次请求;
重定向是客户端(浏览器)行为,可以跳转到服务器外部资源。
不能使用 Request 域共享数据
d. 代码实现
AServlet:
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.io.IOException;
@WebServlet("/AServlet")
public class AServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*System.out.println("AServlet执行了....");
// 1.设置状态码
response.setStatus(302);
// 2.设置响应头
response.setHeader("Location","/webappPractice2/BServlet");*/
// 1.Response封装的专门处理重定向的方法
response.sendRedirect("/webappPractice2/BServlet");
}
}
BServlet:
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.io.IOException;
@WebServlet("/BServlet")
public class BServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
e. 效果展示
访问 http://localhost:8080/webappPractice2/AServlet,页面输出: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.io.IOException;
@WebServlet("/AServlet")
public class AServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//往Request域中存储数据
request.setAttribute("name","Regino");
//请求转发到BServlet
request.getRequestDispatcher("/BServlet").forward(request,response);
}
}
BServlet:
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.io.IOException;
@WebServlet("/BServlet")
public class BServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//解决向浏览器输出中文乱码问题
response.setContentType("text/html;charset=utf-8");
//从Request域中取出数据
String name = (String) request.getAttribute("name");
//向浏览器输出
response.getWriter().write("从Request域中获取到的数据:"+ name);
}
}
访问 http://localhost:8080/webappPractice2/AServlet,页面输出:项目根路径/
,而请求转发是模块内部的跳转,所以不用。
/
在进行资源跳转的时候,如果是给服务器去使用,那么 /
代表了 http://localhost:8080/项目根路径
;如果是给浏览器去使用的时候,那么/
代表了 http://localhost:8080/
。
d. 使用场景
如果需要传递数据(Request域),使用转发;
如果不需要传递数据(Request域),使用重定向。
5. 案例:响应定时刷新
a. 主要需求
在当前页面停留 3 秒钟之后,跳转到个人博客首页。
b. 步骤分析
通过 Response 设置响应头 Refresh:response.setHeader("Refresh","间隔时间(秒);跳转页面");
c. 代码实现
RefreshServlet:
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.io.IOException;
@WebServlet("/refreshServlet")
public class RefreshServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 通过Response设置响应头Refresh
response.setHeader("Refresh", "3;https://blog.csdn.net/Regino");
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("操作成功,3秒后跳转到Regino博客首页...");
}
}
6. 案例:响应中文
a. 主要需求
向页面输出中文数据没有乱码。
b. 步骤分析
通过 Response 获取字符输出流:PrintWriter pw = response.getWriter();
通过字符输出输出文本:pw.write("中文....");
c. 解决中文乱码
指定服务器响应编码方式:response.setCharacterEncoding("GBK");
统一浏览器和服务器编码:response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8");
应该在获取请求参数之前设置,若已获取请求参数,此时还没有设置过编码,Tomcat 会设置默认 Post 请求参数编码为 ISO8859_1,那么再设置成 UTF-8 也无效了。所以应该用 response.setContentType("text/html;charset=utf-8");
。
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.io.IOException;
import java.io.PrintWriter;
@WebServlet("/encodeServlet")
public class EncodeServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 指定服务器响应编码方式
// response.setCharacterEncoding("UTF-8");//出现乱码
// 统一浏览器和服务器编码
response.setContentType("text/html;charset=utf-8");
// 1. 通过response获取字符输出流
PrintWriter pw = response.getWriter();
// 2. 通过字符输出输出文本
pw.write("中文....");
}
}
7. 综合案例:点击切换验证码
a. 主要需求
在页面展示登录验证码,点击此验证码可以更换新的验证码 。
作用:防止表单的恶意提交。
b. 用 Java 制作一个验证码
使用画图工具;
指定宽和高;
指定背景色;
生成四位随机数;
制作干扰线;
通过 Response 响应到浏览器。
CheckcodeServlet:
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;
@WebServlet("/CheckcodeServlet")
public class CheckcodeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 创建画布
int width = 120;
int height = 40;
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 获得画笔
Graphics g = bufferedImage.getGraphics();
// 填充背景颜色
g.setColor(Color.white);
g.fillRect(0, 0, width, height);
// 绘制边框
g.setColor(Color.red);
g.drawRect(0, 0, width - 1, height - 1);
// 生成随机字符
// 准备数据
String data = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
// 准备随机对象
Random r = new Random();
// 声明一个变量 保存验证码
String code = "";
// 书写4个随机字符
for (int i = 0; i < 4; i++) {
// 设置字体
g.setFont(new Font("宋体", Font.BOLD, 28));
// 设置随机颜色
g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
String str = data.charAt(r.nextInt(data.length())) + "";
g.drawString(str, 10 + i * 28, 30);
// 将新的字符 保存到验证码中
code = code + str;
}
// 绘制干扰线
for (int i = 0; i < 6; i++) {
// 设置随机颜色
g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));
}
// 将验证码 打印到控制台
System.out.println(code);
// 将验证码放到session中
request.getSession().setAttribute("code_session", code);
// 将画布显示在浏览器中
ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
c. 前端页面
index.html:
Title
// 给图片绑定一个点击事件
document.getElementById('img1').onclick=function () {
// 重置src路径,重写发送请求
this.src='/webappPractice2/CheckcodeServlet?'+new Date().getTime();
// 后面加一个毫秒值的时间戳来欺骗浏览器,否则因为是同一个请求,验证码不刷新
}
访问 http://localhost:8080/webappPractice2/static/index.html,页面展示:
Download
文件下载
超文本链接下载
word文档
压缩包下载
图片下载
ii. 效果
访问 http://localhost:8080/webappPractice2/static/index.html 后,页面显示:FileInputStream
Response 字节输出流:ServletOutputStream
告知客户端下载文件的 MIME 类型(最新的浏览器此步骤可以省略):Content-Type:MIME类型
告知浏览器以附件的方式保存:Content-Disposition:attachment;filename=文件名
ii. 前端页面
Download
文件下载
超文本链接下载
word文档
压缩包下载
图片下载
Servlet下载
word文档
word文档
图片下载
iii. DownloadServlet
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
@WebServlet("/downloadServlet")
public class DownloadServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.获取请求文件名
String filename = request.getParameter("filename");
// 2.获取文件真实路径,封装到字节输入流
ServletContext servletContext = request.getServletContext();
String realPath = servletContext.getRealPath("/download/" + filename);
FileInputStream in = new FileInputStream(realPath);
// 3.告诉浏览器MIME类型
String mimeType = servletContext.getMimeType(filename);
response.setContentType(mimeType);
// 4.告诉浏览器以附件方式保存
// 解决中文乱码和浏览器兼容性
String userAgent = request.getHeader("user-agent");
// 调用工具类处理
filename = DownLoadUtils.getName(userAgent, filename);
response.setHeader("content-disposition", "attachment;filename=" + filename);
// 5.获取字节输出流
ServletOutputStream out = response.getOutputStream();
// 6.IO流的拷贝
byte[] b = new byte[4096];// 4kb
int len = -1;
while ((len = in.read(b)) != -1) {
out.write(b, 0, len);
}
// 7.释放资源
out.close(); // out流对象,可以交给Tomcat关闭
in.close();
}
}
iv. 解决文件名中文乱码问题
如果该下载文件名是中文的话,会出现乱码。
需要考虑浏览器兼容性问题:
谷歌和绝大多数的浏览器是通过 URL编码,相关方法:URLEncode()
编码URLDecode()
解码
火狐浏览器是 base64编码
判断浏览器不同编码的工具类 DownLoadUtils:
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import sun.misc.BASE64Encoder;
public class DownLoadUtils {
public static String getName(String agent, String filename) throws UnsupportedEncodingException {
if (agent.contains("Firefox")) {
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else {
// 其它浏览器
filename = URLEncoder.encode(filename, "utf-8");
}
return filename;
}
}
v. 效果
访问 http://localhost:8080/webappPractice2/static/index.html 后,页面显示:原文链接:https://qwert.blog.csdn.net/article/details/105556856