1 Response对象概述
方向: 服务器 -> 浏览器
负责对浏览器进行响应的对象
什么是响应: 服务器接收到请求需要进行处理,将处理以后的结果显示回浏览器端(将这个过程称为是响应Response)。
- 查看Servlet中的service方法得知, Servlet中使用的ServletResponse接口, 而我们使用的是ServletResponse的子接口HttpServletResponse, 它继承自ServletResponse, 是与HTTP协议相关的Response响应对象
- 我们使用的子接口HttpServletResponse, 此接口对象由Tomcat引擎提供
- 可以实现对客户端的响应, 响应内容包括: 响应行,响应头,响应体
其中设置响应行可以设置返回的状态码
而设置返回头就可以设置给浏览器的指导信息,而通过响应头和响应体的组合可以设置重定向的操作(当然也有直接的命令可以使用)
而设置响应体则是设置给浏览器显示的内容
2 Response设置响应行
方法 | 返回值 | 描述 |
setStatus(int sc) | void | 设置响应的状态码 |
- 设置响应的状态码
- 200 正确
- 302 重定向
- 304 查找本地缓存
- 404 请求资源不存在
- 500 服务器内部错误
response.setStatus(500);
3 Response设置响应头
HTTP协议的响应头,数据格式键值对 k:v
包含指导性信息,指导客户端
方法 | 返回值 | 描述 |
addHeader(String key,String value) | void | 添加响应头,值为String类型 |
addIntHeader(String key,int value) | void | 添加响应头,值为int类型 |
addDateHeader(String key,long l) | void | 添加响应头,值为日期类型 |
setHeader(String key,String value) | void | 更改响应头,值为String类型 |
setIntHeader(String key,int value) | void | 更改响应头,值为int类型 |
setDateHeader(String key,long l) | void | 更改响应头,值为日期类型 |
- add开头的方法:针对一个key对应多个value的情况。
比如已有一个响应头 heima:java
然后执行 addHeader(“heima”,”java2222”);
最终得到响应头的结果:heima:java,java2222
- set开头的方法:针对一个key对应一个value的情况。
比如已有一个响应头 heima:java
然后执行 setHeader(“heima”,”java2222”);
最终得到响应头的结果:heima:java2222
演示:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* response对象设置响应头
*/
response.addHeader("heima","java");
/* response.addIntHeader("heima2",5);
response.addDateHeader("date",System.currentTimeMillis());*/
/*
* addHeader() 添加,实现一个键对应多个值
* setHeader() 设置,原来的键覆盖
*/
response.setHeader("heima","java2222");
}
4 重定向
HTTP中的重定向和请求转发的区别
一、调用方式我们知道,在servlet中调用转发、重定向的语句如下:
request.getRequestDispatcher("new.jsp").forward(request, response);//转发到new.jsp response.sendRedirect("new.jsp");//重定向到new.jsp
在jsp页面中你也会看到通过下面的方式实现转发:
<jsp:forward page="apage.jsp" />
当然也可以在jsp页面中实现重定向:
<%response.sendRedirect("new.jsp");//重定向到new.jsp%>
二、本质区别
解释一一句话,转发是服务器行为,重定向是客户端行为。为什么这样说呢,这就要看两个动作的工作流程:
转发过程:客户浏览器发送http请求----》web服务器接受此请求–》调用内部的一个方法在容器内部完成请求处理和转发动作----》将目标资源发送给客户;在这里,转发的路径必须是同一个web容器下的url,其不能转向到其他的web路径上去,中间传递的是自己的容器内的request。在客户浏览器路径栏显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了转发的。转发行为是浏览器只做了一次访问请求。
重定向过程:客户浏览器发送http请求----》web服务器接受后发送302状态码响应及对应新的location给客户浏览器–》客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location地址----》服务器根据此请求寻找资源并发送给客户。在这里location可以重定向到任意URL,既然是浏览器重新发出了请求,则就没有什么request传递的概念了。在客户浏览器路径栏显示的是其重定向的路径,客户可以观察到地址的变化的。重定向行为是浏览器做了至少两次的访问请求的。
解释二
重定向,其实是两次request,
第一次,客户端request A,服务器响应,并response回来,告诉浏览器,你应该去B。这个时候IE可以看到地址变了,而且历史的回退按钮也亮了。重定向可以访问自己web应用以外的资源。在重定向的过程中,传输的信息会被丢失。请求转发是服务器内部把对一个request/response的处理权,移交给另外一个
对于客户端而言,它只知道自己最早请求的那个A,而不知道中间的B,甚至C、D。 传输的信息不会丢失。解释三
假设你去办理某个执照,
重定向:你先去了A局,A局的人说:“这个事情不归我们管,去B局”,然后,你就从A退了出来,自己乘车去了B局。
转发:你先去了A局,A局看了以后,知道这个事情其实应该B局来管,但是他没有把你退回来,而是让你坐一会儿,自己到后面办公室联系了B的人,让他们办好后,送了过来。
4.1 重定向的写法
浏览器进行重新的定向:
- 设置302状态码: setStatus(302)
- 设置重定向资源的地址: setHeader(“location”,“资源”)
通过HttpServletResponse对象中的以下方法实现重定向
方法 | 返回值 | 描述 |
sendRedirect(String location) | void | 重定向 |
4.2 重定向的代码实现
package cn.itcast.web;
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("/demo07")
public class ServletDemo07 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 解决服务器给浏览器的数据中文乱码问题
response.setContentType("text/html;charset=utf-8");
System.out.println("77777777777777777777777");
// 需求: 演示重定向: 访问 demo07 跳转到 demo08
// 方式一: 分解式
// 1 设置状态码 为 302 , 通知浏览器访问新资源
// response.setStatus(302);
// 2 设置响应头 location, 通知浏览器访问新资源的路径
// 新资源的路径 可以使 项目内的资源,也可以是项目外的资源
// response.setHeader("location", "/web0201/demo08");
// 方式二: 合并式
response.sendRedirect("/web0201/demo08");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
5 Response设置响应体
HTTP的响应体,就是页面的正文部分
不能同时使用字符流和字节流,二者只能选其一,否则程序会报错
5.1 字符流向浏览器写数据
方法 | 返回值 | 描述 |
write() | PrintWriter | 使用字符串数据,没有差别, 输出是整数,查询编码表 |
print() | PrintWriter | 无论是什么,原样打印 |
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* response对象方法getWriter()
* 打印流的响应体
* write() 使用字符串数据,没有差别, 输出是整数,查询编码表
* print() 无论是什么,原样打印
*/
PrintWriter pw = response.getWriter();
pw.write(100);
pw.print(100);
}
5.2 字符流的中文乱码问题
产生乱码原因: 编码和解码不一致
提问:在Servlet中编写以下代码,向页面输出中文是否会产生乱码?
response.getWriter().print("中文");
会乱码:
- 原因:
- 字符流是有缓冲区的,response获得字符流,response设计默认的缓冲区编码是ISO-8859-1。这个字符集不支持中文的。
- 解决:
- 设置response获得字符流缓冲区的编码 与 设置浏览器默认打开时候采用的字符集一致即可。
方法 | 放回值 | 描述 |
setHeader(“Content-Type”, “text/html;charset=UTF-8”) | void | 设置浏览器打开页面时采用的字符集 |
setContextType(String type) | void | 设置浏览器打开页面时采用的字符集 |
// 设置浏览器默认打开的时候采用的字符集:
// response.setHeader("Content-Type", "text/html;charset=UTF-8");
// 简化代码
response.setContentType("text/html;charset=UTF-8");
// 输出中文汉字
response.getWriter().println("中文");
5.3 字节流向浏览器写数据
方法 | 返回值 | 描述 |
getOutputStream() | OutputStream | 返回字节输出流OutputStream,响应非文本类型的数据 |
5.3.1 案例 验证码
验证码的本质是个图片,图片里面是个随机生成字符串
随机字符串的思想:
String str ="abcdefABCDE1234567890";
Random.nextInt( str.length() )产生整数随机数
str.charAt(索引)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
function changeImg(){
// 1 获取验证码图片对象
var codeImgObj = document.getElementById("codeImg");
// 2 修改图片的路径
// ?key=val 目的: 欺骗浏览器这是一个新资源
codeImgObj.src = "/web0202/demo11?r=" + Math.random();
}
</script>
</head>
<body>
<form action="xx" method="post">
<table>
<tr>
<td>用户名</td>
<td><input type="text" name="username"/></td>
</tr>
<tr>
<td>密码</td>
<td><input type="password" name="password"/></td>
</tr>
<tr>
<td>验证码</td>
<td>
<input type="text" name="code_form"/>
<img src="/web0202/demo11" onclick="changeImg()" id="codeImg"/>
</td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="提交"/></td>
</tr>
</table>
</form>
</body>
</html>
package cn.itcast.web;
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("/demo11")
public class ServletDemo11 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 解决服务器给浏览器的数据中文乱码问题
// response.setContentType("text/html;charset=utf-8");
// 1 创建画布对象
int width = 120;
int height = 40;
BufferedImage bufi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 3 获取画笔
Graphics g = bufi.getGraphics();
// 4 修改背景色
g.fillRect(0, 0, width, height);
// 5 绘制边框
g.setColor(Color.red);
g.drawRect(0, 0, width-1, height-1);
// 6 生成随机字符 且 显示
// 6.1 准备数据
String data = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz123456789";
// 6.2 创建随机对象
Random r = new Random();
// 7.1 准备变量保存 生成的 随机字符
String code = "";
// 6.3 循环输出
for (int i = 0; i < 4; i++) {
// 6.3.2 设置字体
g.setFont(new Font("楷体", Font.BOLD, 30));
// 6.3.3 设置随机颜色
g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
// 6.3.1 绘制字符
char c = data.charAt(r.nextInt(data.length()));
g.drawString(c + "", 10 + i * 30, 30);
// 7.1 将生成的随机字符 保存到 随机字符串中
code += c +"";
}
// 7 将生成的字符输出到控制台
System.out.println(code);
// 8 绘制干扰线
for (int i = 0; i < 10; i++) {
// 8.2 设置随机颜色
g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
// 8.1 绘制干扰线
g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));
}
// 2 将画布输出到浏览器中
ImageIO.write(bufi, "jpg", response.getOutputStream());
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}