response对象的概念
HttpServletResponse对象封装了向客户端发送数据,发送三响应头,响应状态码的方法
因此,必须学会HttpServletResponse,才能给浏览器发送数据
response操作相应行
组成
响应行,响应头,响应体
响应行是http响应内容的第一行。
响应行一般数据为:
HTTP/1.1 200(tomcat8.5)
HTTP/1.1 200 OK(tomcat7)
响应行分为三个部分: HTTP/1.1:协议版本
200:响应状态码
OK:对响应状态码的解释
常见的响应状态码:
200 OK 请求已成功,请求所希望的响应头或数据体将随此响应返回。出现此状态码是表示正常状态。
302 Move temporarily 重定向,请求的资源临时从不同的 URI响应请求。
304 Not Modified 从缓存中读取数据,不从服务器重新获取数据。
403 Forbidden 服务器已经理解请求,但是拒绝执行它,一般在权限不够的时候常见。
404 Not Found 请求失败,请求所希望得到的资源未被在服务器上发现。
405 Method Not Allowed 请求行中指定的请求方法不能被用于请求相应的资源。
500 Internal Server Error 服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。
了解了http协议有关响应行的部分,对于response对象来说 , 只有响应状态码可以操作 , 并且我们一般也不操作状态码 。
API介绍
void setStatus(int sc) 设置响应的状态代码(一般用来设置 1xx 2xx 3xx)
void setError(int sc) 设置响应的状态代码(一般用来设置 4xx 5xx)
注意 : 状态码的一般不需要我们手动设置
操作响应头
常见的响应头介绍
1. location :
重定向操作:通常告知浏览器马上向该地址发送请求,通常和响应码302一起使用
两次请求,一次手动,一次自动
- refresh :
定时刷新操作 , 指定时间后跳转到指定页面 - content-encoding :
设置当前数据的压缩格式,告知浏览器以何种压缩格式解压数据 content-disposition :
通知浏览器以何种方式获取数据(直接解析数据(网页,图片文本),或者以附件方式attachment(下载文件))content-type :
实体头部用于指示资源的MIME类型(MIME类型:用于提示当前文件的媒体类型,例如图片为 : image/png、音频为:audio/ogg)。它的作用与传统上Windows上的文件扩展名相同。该名称源于最初用于电子邮件的
MIME标准。)
setContentType(“text/html;charset=UTF-8”);
底层是如下
setHeader(“content-type”,”text/html;charset=UTF-8”);
注意:我们content‐type常用的设置一般都是“text/html;charset=utf‐8”
“text/html”用来设置浏览器以指定文件格式解析数据;
“charset=utf‐8”用来响应数据的编码表,若不需要设置编码可以不写。
方法
设置头
setHeader(String 名字,String 值) –> 都是字符串
setIntHeader(String 名字, int 值)
setDataHeader(String 名字,long 值)
添加头
addHeader(String 名字, String 值) –> 字符串
操作响应体
API介绍(字符+字符串)
ServletOutputStream getOutputStream() 获取字节输出流
PrintWriter getWriter() 获取字符输出流
注意:两个流不能同时使用(互斥),这两个流使用完成后如果没有关闭,Servlet容器会帮我们将其关闭
代码实例
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//字符流的方式写数据
response.getWriter().write(“hello response…”);
//字节流的方式写数据
response.getOutputStream().write(“hahhahaha”.getBytes());
}
1.向浏览器输出中文数据(无乱码)
以字符流输出
–> response.getWriter().write(“..”);
//中文乱码
//字符流的方式写数据
//此处写出去的文字,默认使用的是ISO-8859-1,我们可以指定写出去的时候所使用的编码
//1.指定输出到客户端的时候,这些文字使用UTF-8码
response.setCharacterEncoding(“UTF-8”);
//2.直接规定浏览器看这份数据的时候,使用的编码
response.setHeader(“Content-Type”, “text/html; charset=UTF-8”);
response.getWriter().write(“你好”);
以字节流输出
//设置相应的数据类型是html文本,并且告知浏览器,使用UTF-8来编码
response.setContentType(“text/html;charset=UTF-8”);
–> 不管字节流还是字符流, 一行代码即可
//字节流的方式写数据
//如果想让服务器端出去的中文,在客户端正常显示
//那么,只要保证客户端看的编码和这数据的编码相同即可
//默认情况下,字节输出流,输出使用的是UTF-8编码
//如果想要获取具体的编码,可以在byte数组的时候
//1.指定浏览器看这份数据使用的码表
response.setHeader("Content-Type", "text/html;charset=UTF-8");
//2.指定输出的中文用的码表
response.getOutputStream().write("你好".getBytes("UTF-8"));
字符串的String里面的getByte方法使用的码表是UTF-8,与tomcat没关系
实际开发时
//设置response使用的码表,以控制response以什么码表向浏览器写出数据
response.setCharacterEncoding(“码表”);
//指定浏览器以什么码表打开服务器发送的数据
response.setContentType(“text/html;charset=UTF-8”);
2.以附件形式下载文件
tomcat8.5之前需要设置2个响应头
1.设置下载文件的媒体;自行MIMEType
让浏览器知道下载格式
String mimgtype = this.getServletContext.getMIMEType(filename);
content-type:mimetype
2.设置下载头
按照附件的形式打开
content-dispositon:attachment; filename = "名字";
tomcat8.5之后只要2即可
1.直接以连接的形式下载
让tomcat的默认servlet去提供下载<br/>
<a href="download/aa.jpg">aa.jpg</a><br/>
<a href="download/bb.txt">bb.jpg</a><br/>
<a href="download/cc.rar">cc.jpg</a><br/>
原因是tomcat里有一个默认的Servlet—DefaultServlet
–>专门用于处理放在tomcat服务器上的静态资源
2.手动模式下载
String filename = “xjj.jpg”;
//设置响应头
response.setHeader(“Content-Disposition”,”attachmenet;filename=” + “xjj.jpg”);
//获取文件的真实路径
String realPath = this.getServletContext().getRealPath(filename);
//需要字节输入流
FileInputStream fis = new FileInputStream(realPath);
//将字节数据写给浏览器
ServletOutputStream out = response.getOutputStream();
//边读边写
int len;
byte[] buffer = new byte[8*1204];
while ((len = fis.read(buffer) )!= -1){
out.write(buffer,0,len);
}
out.close();
fis.close();
3.多种类型通用下载
在下载链接上加上?的操作,即是完成请求携带参数的操作
小姐姐
aaa.txt
String filename = request.getParameter(“filename”);
//设置响应头
response.setHeader(“Content-Disposition”,”attachmenet;filename=” + filename);
//获取文件的真实路径
String realPath = this.getServletContext().getRealPath(“download/”+ filename);
//需要字节输入流
FileInputStream fis = new FileInputStream(realPath);
//将字节数据写给浏览器
ServletOutputStream out = response.getOutputStream();
//边读边写
int len;
byte[] buffer = new byte[8*1204];
while ((len = fis.read(buffer) )!= -1){
out.write(buffer,0,len);
}
out.close();
fis.close();
4.下载带有中文名字的资源
响应头的编码只能通过转码进行传递
–> 需要进行编码处理
如果是IE或者Chrome,使用URLEncoding编码
如果是Firefox,使用Base64编码
代码案例
String filename = request.getParameter(“filename”);
//获取文件的真实路径
String realPath = this.getServletContext().getRealPath(“download/”+ filename);
String agent = request.getHeader("User-Agent");
if (agent.contains("Firefox")){
filename = util.base64EncodeFileName(filename);
}else{
filename = URLEncoder.encode(filename,"UTF-8");
}
//设置响应头
response.setHeader("Content-Disposition","attachmenet;filename=" + filename);
//需要字节输入流
FileInputStream fis = new FileInputStream(realPath);
//将字节数据写给浏览器
ServletOutputStream out = response.getOutputStream();
//边读边写
int len;
byte[] buffer = new byte[8*1204];
while ((len = fis.read(buffer) )!= -1){
out.write(buffer,0,len);
}
out.close();
fis.close();
}
Base64编码 –> 可以做成工具类
public static String base64EncodeFileName(String fileName) {
BASE64Encoder base64Encoder = new BASE64Encoder();
try {
return “=?UTF-8?B?” + new String(base64Encoder.encode(fileName.getBytes(“UTF-8”))) + “?=”;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
3.请求转发和重定向
API 介绍(设置)
void setHeader(String name, String value) 用给定名称和值设置响应头
void sendRedirect(String location) 用类设置重定向
使用location响应头实现跳转(重定向)
设置重定向响应头
resp.setHeader(“location”,”http://ntlias-stu.boxuegu.com/#/index“);
//设置状态码
resp.setStatus(302);
//简化模式
// resp.sendRedirect(“http://ntlias-stu.boxuegu.com/#/index“);
//设置编码方式
response.setContentType(“text/html;charset=UTF-8”);
String userName = request.getParameter("username");
String password = request.getParameter("password");
if("admin".equals(userName)&&"123".equals(password)) {
// response.getWriter().write(“登录成功”);
//之前的写法
/* response.setStatus(302);
response.setHeader(“Location”,”login_sucess.html”);*/
//重定向写法:重新定向,参数即为跳转的位置
response.sendRedirect(“login_sucess.html”);
1.地址上显示的是最后的哪个资源的路径地址
请求转发模式:参数即跳转的位置
response.getRequestDispatcher(“login_sucess.html”).forward(request,response);
2.地址上显示的是请求servlet的地址
}else {
response.getWriter().write(“登录失败”);
}
请求转发和重定向区别
- 转发在一次请求中完成,重定向是两次请求
- 转发操作发生在服务器内部,重定向是浏览器执行操作
- 转发地址栏不变(只有一次请求,一个地址–服务器执行后续操作),重定向,地址栏变化(两次请求,两个地址 –第一次请求后,会返回302,以及一个地址,浏览器再根据此地址执行第二次访问)
- 转发可以在一次请求中共享数据,重定向不行(重定向两次请求)。
- 转发只能跳转自己项目的资源路径,重定向可以跳转其他资源路径
6.转发效率高一些(1次请求),重定向效率低一些(2次请求) 转发可以使用上一次request对象,重定向不能使用上次的request对象,因为是两次不同的请求
3秒钟之后跳转到其他页面
案例分析- 创建RefreshServlet
- 调用setHeader,设置消息头(”Refresh”,” 3;url=网址”)
resp.setHeader(“Refresh”,”3;url=http://ntlias-stu.boxuegu.com/#/index“);
在访问登录页面时,需要生产验证码。从而防止用户使用程序恶意登录。
验证码
需求:
在访问登录页面时,需要生产验证码。从而防止用户使用程序恶意登录。
分析
3.4.3 代码实现
页面代码
用户名密码
验证码
function changeImg(obj){ //修改修改src obj.src = "/day15/checkcode?xx="+new Date().getTime(); }
Servlet代码
@WebServlet(name = “CheckcodeServlet”,urlPatterns = “/checkcode”)
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);
}
}