Response对象
1.1 Response概述
什么是Response
开发的软件是B/S结构的软件,可以通过浏览器访问服务器的软件。
- 从浏览器输入一个地址访问服务器(将这个过程称为是请求)。
- 服务器接收到请求,需要进行处理,处理以后需要将处理结果显示回浏览器端(将这个过程称为是响应Response)。
1.2 Response对象的API
关于响应行的方法
方法 | 返回值 | 描述 |
---|---|---|
setStatus(int sc) | void | 设置响应的状态码 |
- 设置响应的状态码
- 200 正确
- 302 重定向
- 304 查找本地缓存
- 404 请求资源部存在
- 500 服务器内部错误
代码演示:
//设置响应的状态码
public class ResponseDemo1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置响应的状态码:
response.setStatus(404);
//response.setStatus(500);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
关于响应头的方法
响应头里放的都是键值对(键值对 k:v)
方法 | 返回值 | 描述 |
---|---|---|
setDateHeader(String name, long date) | void | 设置响应头 |
setHeader(String name, String value) | void | 设置响应头 |
setIntHeader(String name, int value) | void | 设置响应头 |
- set开头的方法:针对一个key对应一个value的情况。
- 举例:比如已有一个响应头
content-Type:text/html
,然后执行setHeader(“content-Type”,”text/plain”);
- 最终得到响应头的结果:
content-Type:text/plain
- 举例:比如已有一个响应头
方法 | 返回值 | 描述 |
---|---|---|
addDateHeader(String name, long date) | void | 设置响应头 |
addHeader(String name, String value) | void | 设置响应头 |
addIntHeader(String name, int value) | void | 设置响应头 |
- add开头的方法:针对一个key对应多个value的情况(一键多值)。但需要多次设置,一次只能设置一个键值对。
- 举例:比如已有一个响应头
content-Type:text/html
,然后执行addHeader(“content-Type”,”text/plain”);
- 最终得到响应头的结果:
content-Type:text/html,text/plain
- 举例:比如已有一个响应头
代码演示:
/*
* 使用状态码和Location头完成重定向
*/
public class ResponseDemo1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 完成重定向
response.setStatus(302);
// 设置响应头
response.setHeader("Location", "/web01/ResponseDemo2");
//实际开发中可以使用下面的代码,替换重定向两句写法
//response.sendRedirect("/web01/ResponseDemo2");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
关于响应体的方法
方法 | 返回值 | 描述 |
---|---|---|
getOutputStream() | ServletOutputStream | 返回一个字节流,用于向浏览器发送数据 |
getWriter() | PrintWriter | 放回一个字符流,用于向浏览器发送数据 |
- Response设置响应体:页面中显示正文(body中显示内容)
- 字符流:只能读写文本文件–>使用记事本打开能看懂
getWriter() 返回值是打印流PrintWrite - 字节流:可以读写任意文件(文本,图片,音乐,文件…)
getOutputStream() 返回字节输出流OutputStream
- 字符流:只能读写文本文件–>使用记事本打开能看懂
字符流:response对象获取到字符流PrintWriter(字符打印流)
-
继承自父类Wirter中的方法
write() : 写的数据会查询编码表 100–>d -
自己特有的方法
print(): 写数据原样输出 100–>100
println(): 写数据原样输出,带换行 100–>100
代码演示:
@WebServlet(urlPatterns = "/body")
public class Demo03BodyServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取字符打印流
PrintWriter pw = response.getWriter();
pw.write(100); //d
pw.println(100);
pw.println("aaa");
pw.println('#');
pw.println(5.5);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
使用字节输出流:响应非文本文件
getOutputStream() 返回字节输出流OutputStream
案例:文件复制:一读(本地流)一写(网络流,给客户端写)
客户端/服务器:读写本地文件(硬盘中)必须使用自己创建的流对象(本地流)
客户端/服务器:之间进行交互必须使用response或者request中提供的流对象(网络流)
package com.ccc.demo03Response;
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(urlPatterns = "/img")
public class Demo05InputStreamServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取要读取的文件的绝对路径
String realPath = getServletContext().getRealPath("1.jpg");
//创建一个字节输入流对象
FileInputStream fis = new FileInputStream(realPath);
//获取response对象中提供的字节输出流对象
ServletOutputStream sos = response.getOutputStream();
//一读一写复制文件
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fis.read(bytes))!=-1){
sos.write(bytes,0,len);
}
fis.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
其他常用的API
方法 | 放回值 | 描述 |
---|---|---|
sendRedirect(String location) | void | 重定向方法 |
setContextType(String type) | void | 设置浏览器打分页面时采用的字符集 |
setCharacterEncoding(String charset) | void | 设置响应字符流的缓冲区字符集 |
代码演示:
/**
* 定时刷新
*/
public class ResponseDemo1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 定时刷新
response.setContentType("text/html;charset=UTF-8");
response.getWriter().println("5秒以后页面跳转!");
response.setHeader("Refresh", "5;url=/web01/ResponseDemo2");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
/**
3. 重定向后的页面
*/
public class ResponseDemo2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println("ResponseDemo2...");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
重定向:让客户端浏览器重新再请求一次服务器(客户端会请求两次服务器)
- 设置响应行中状态码为:302
- 指导浏览器再次请求服务器的地址:设置响应头
key:“location” value:"/day12_web/servlet2"
最终,Apache很善良,把两个方法合二为一
下面是重定向的最终版代码:response.sendRedirect("/day12_web/servlet2");
注意:重定向的地址可以是外网。
重定向案例:
代码演示:
package com.ccc.demo04redirect;
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(urlPatterns = "/servlet1")
public class Servlet1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Servlet1 我是刘备");
//response.setStatus(302);
//response.setHeader("location","/day12_web/servlet2");
//上面两可以用下面这一行简化
response.sendRedirect("/day12_web/servlet2");
//也可以不把项目名称写成一个固定的地址,如下面所示
//response.sendRedirect(getServletContext().getContextPath()+"/servlet2");
//重定向的地址可以是外网地址
response.sendRedirect("http://www.baidu.com");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
package com.ccc.demo04redirect;
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(urlPatterns = "/servlet2")
public class Servlet2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Servlet2 我是关羽");
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("二哥借你500");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
注意事项:
- 重定向之后不要再写代码,没有意义,因为后面的代码浏览器读取不到(地址已经跳转了)
- 只能重定向一次
- getWriter()字符流和getOutputStream()字节流,互斥,只能选择一个使用。因为写数据是把数据写在response对象的缓冲区中,缓冲区中的数据不能既是字符又是字节。
1.3 Response对象响应中文乱码处理
提问:在Servlet中编写以下代码,向页面输出中文是否会产生乱码?
response.getWriter().println("中文");
会乱码:
- 原因:编码和解码不一致
- 给客户端使用response响应数据(通过IO流),不是直接把数据写给浏览器,而是存储到response对象的缓冲区中,response设计默认的缓冲区编码是ISO-8859-1。这个字符集不支持中文的。
- 解决:
- 设置response获得字符流缓冲区的编码和设置浏览器默认打开时候采用的字符集一致即可。
1.设置response对象的缓冲区的编码为UTF-8格式编码
2.通知浏览器以utf-8编码格式读取数据response.setCharacterEncoding("utf-8"); pw.write("你好"); //输出的是 浣犲ソ 此时还有问题,因为浏览器默认使用GBK解码
<meta charset="UTF-8">
最终,Apache很善良,把两个方法合二为一
下面是解决中文乱码的最终版代码:respons.setContextType("text/html;charset=utf-8");
- 设置response获得字符流缓冲区的编码和设置浏览器默认打开时候采用的字符集一致即可。
使用字节流响应中文
/**
* Response响应中文的处理
*/
public class ResponseDemo3 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
test1(response);
}
/**
* 使用字节流输出中文
*/
private void test1(HttpServletResponse response) throws IOException, UnsupportedEncodingException {
// 使用字节流的方式输出中文:
ServletOutputStream outputStream = response.getOutputStream();
// 设置浏览器默认打开的时候采用的字符集
response.setHeader("Content-Type", "text/html;charset=UTF-8");
// 设置中文转成字节数组字符集编码
outputStream.write("中文".getBytes("UTF-8"));
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
使用字符流响应中文
/**
* Response响应中文的处理
*/
public class ResponseDemo3 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
test2(response);
}
/**
* 使用字符流输出中文
*/
private void test2(HttpServletResponse response) throws IOException, UnsupportedEncodingException {
// 设置浏览器默认打开的时候采用的字符集:
// response.setHeader("Content-Type", "text/html;charset=UTF-8");
// 设置response获得字符流的缓冲区的编码:
// response.setCharacterEncoding("UTF-8");
// 简化代码
response.setContentType("text/html;charset=UTF-8");
// 会不会产生乱码
response.getWriter().println("中文");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}