13.ServletResponse
13.1.介绍
-
用途:用于设置响应消息
-
同样,ServletResponse是*父接口,因为我们常用Http协议,所以我们只介绍HttpServletReponse。
-
ServletResponse接口
| 继承
HttpServletResponse接口| 实现
org.apache.catalina.connector.ResponseFacade 类(tomcat)
13.2.常用API
- public void setStatus(int sc) : 设置此响应的状态代码。
- public void setHeader(String name,String value) : 用给定的名称和值设置响应头
- public PrintWriter getWriter() : 返回可以向客户端发送字符文本的PrintWriter对象设置响应体,继承于ServletResponse。
- public ServletOutputStream getOutputStream() : 返回适合在响应中写入二进制数据的ServletOutputStream。servlet容器不编码二进制数据。
@WebServlet("/response1")
public class ResponseServlet1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置响应状态码
response.setStatus(404);
//设置响应头
response.setHeader("Content-Type", "text/html");
response.setHeader("Server", "Tomcat 8.5");
//设置响应体
response.getWriter().println("<h1 style='color:red'>File Not Found</h1>");
}
}
13.3.定时刷新
- 使用refresh实现页面的定时刷新
@WebServlet("/refresh")
public class RefreshServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//refresh用法一共有两种
//用法一:值只有一个数字,表示每隔多少秒刷新当前页面,实现页面时时刻刻刷新当前的时间
//转成YYYY-MM-dd HH:mm:ss
String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
response.getWriter().println(time);
//response.setHeader("refresh", "1");
//用法二:值里面有一个数字,并且还有一个url,表示的是经过多少秒之后跳转至url,然后结束
//response.setHeader("refresh", "3;url=" + request.getContextPath() + "/1.html");
response.setHeader("refresh", "3;url=http://www.cskaoyan.com");
}
}
13.4.重定向
- 使用Location实现页面重定向,状态码为302或307
- refresh、重定向,浏览器默认使用get方式,而请求转发前后请求方法不变。
- Servlet源组件生成的响应结果不会被发送到客户端
- response.sendRedirect(String location) 方法一律返回状态码为302的响应结果。
- 如果源组件在进行重定向之前,已经提交了响应结果,会抛出IllegalStateException。为了避免异常,不应该在源组件中提交响应结果。
- //Cannot call sendRedirect() after the response has been committed
- 在Servlet源组件重定向语句后面的代码也会执行。
- 源组件和目标组件不共享同一个ServletRequest对象。
- 对于sendRedirect(String location)方法的参数,如果以“/”开头,表示相对于当前服务器根路径的URL (不是当前应用的根目录)。以“http"//”开头,表示一个完整路径。
http://localhost/
- 目标组件不必是同一服务器上的同一个web应用的组件,它可以是任意一个有效网页。
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//response.setStatus(302);
//第一种写法
//response.setHeader("Location", request.getContextPath() + "/1.html");
//第二种写法
//response.setHeader("Location", "http://www.cskaoyan.com");
//我们上面是根据重定向的定义,自己去写了对应的实现
//服务器给我们提供了一个更为简便的API
//第三种写法
response.sendRedirect(request.getContextPath() + "/1.html");
}
}
13.5.几种页面跳转方式的比较
- 转发、刷新、重定向都可以用在servlet处理完毕之后,跳转至一个页面。
- 不同点:
- 转发是request介导的,刷新、重定向是response介导的
- 转发的两个组件之间可以共享request域,刷新、重定向是不可以的
- 转发是一次请求,刷新、重定向会发送多次请求
- 转发、刷新的状态码是200,重定向状态码是302、307
- 刷新可以设置跳转的时间,转发、重定向做不到
- 转发只可以在当前应用内部跳转,刷新、重定向不受限制,可以跳转到当前应用之外的任意网络资源
13.6.乱码的解决
//响应体设置一个编码格式,同时将编码格式告诉给浏览器,两边统一即可
//1.可以通过响应头告知
@WebServlet("/response1")
public class ResponseServlet1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置响应状态码
response.setStatus(404);
//设置响应头
//response.setHeader("Content-Type", "text/html");
response.setHeader("Server", "Tomcat 8.5");
//设置响应体
//response.getWriter().println(new Date());
//response.setCharacterEncoding("gbk");
//因为该行代码由两层含义:1.设置响应体编码格式2.发送一个含有编码格式的响应头
response.setHeader("Content-Type", "text/html;charset=utf-8");
response.getWriter().println("<h1 style='color:red'>File Not Found</h1>");
response.getWriter().println("<h1 style='color:red'>文件未找到</h1>");
}
}
//2.发送一个含有编码格式的响应头
@WebServlet("/response1")
public class ResponseServlet1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置响应状态码
response.setStatus(404);
//设置响应头
//response.setHeader("Content-Type", "text/html");
response.setHeader("Server", "Tomcat 8.5");
//设置响应体
//response.getWriter().println(new Date());
//response.setCharacterEncoding("gbk");
//因为该行代码由两层含义:1.设置响应体编码格式2.发送一个含有编码格式的响应头
//response.setHeader("Content-Type", "text/html;charset=utf-8");
response.setContentType("text/html;charset=utf-8");
response.getWriter().println("<h1 style='color:red'>File Not Found</h1>");
response.getWriter().println("<h1 style='color:red'>文件未找到</h1>");
}
}
//3.通过响应体告知
//3.1.设置编码格式 3.2.告知对方我使用的编码格式
@WebServlet("/response2")
public class ResponseServlet2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置响应状态码
response.setStatus(404);
//设置响应头
response.setHeader("Server", "Tomcat 8.5");
//设置响应体
response.setCharacterEncoding("utf-8");
response.getWriter().println("<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>Title</title>\n" +
"</head>\n" +
"<body>");
response.getWriter().println("<h1 style='color:red'>File Not Found</h1>");
response.getWriter().println("<h1 style='color:red'>文件未找到</h1>");
response.getWriter().println("\n" +
"</body>\n" +
"</html>");
}
}
13.7.输出字节数据
- 利用字节数据其实也是可以输出字符的。但是字节数据最常见的使用场景还是去处理文件,去响应文件资源、二进制文件资源
@WebServlet("/stream")
public class OutputStreamServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//可以设置,也可以不设置,如果不设置的话浏览器会自动帮我们设置好。
response.setContentType("image/jpg");
ServletOutputStream outputStream = response.getOutputStream();
//可以把这个当作FileOutputStram来看待,但是呢,行为应该是相同的,输出的目的地不同
//需要你将本地部署根目录下面的1.jpg 输出到客户端
//硬盘上面的文件,读取到内存中 FileInputStream来处理这一个过程
//部署根目录下面1.jpg的输入流拿到
//先拿到文件的绝对路径
String realPath = getServletContext().getRealPath("1.jpg");
FileInputStream fileInputStream = new FileInputStream(realPath);
//输出到response的响应体即可
int length = 0;
byte[] bytes = new byte[1024];
while ((length = fileInputStream.read(bytes)) != -1){
outputStream.write(bytes, 0, length);
}
fileInputStream.close();
//输出流可以关闭,也可以不关闭,如果不关闭,那么tomcat会在响应的时候关闭他们
outputStream.flush();
outputStream.close();
}
}
13.8.下载
- 下载网页中的资源,与显示资源的代码基本一致,只需要添加一个响应头就可以了
@WebServlet("/download")
public class DownloadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置响应头
response.setHeader("Content-Disposition","attachment;filename=1.jpg");
response.setContentType("image/jpg");
ServletOutputStream outputStream = response.getOutputStream();
//可以把这个当作FileOutputStram来看待,但是行为应该是相同的,输出的目的地不同
//需要你将本地部署根目录下面的1.jpg 输出到客户端
//硬盘上面的文件,读取到内存种 FileInputStream来处理这一个过程
//部署根目录下面1.jpg的输入流拿到
//先拿到文件的绝对路径
String realPath = getServletContext().getRealPath("1.jpg");
FileInputStream fileInputStream = new FileInputStream(realPath);
//输出到response的响应体即可
int length = 0;
byte[] bytes = new byte[1024];
while ((length = fileInputStream.read(bytes)) != -1){
outputStream.write(bytes, 0, length);
}
fileInputStream.close();
//输出流可以关闭,也可以不关闭,如果不关闭,那么tomcat会在响应的时候关闭
outputStream.flush();
outputStream.close();
}
}
13.9.同一个Servlet响应多个请求
- 在开发中,一个网站通常会有很多子网页,同时带来很多请求,我们不能一个子网页写一个实现类,那样可能会产生成千上万个Servlet类
- 因此,我们应该用一个Servlet处理多个网页请求,尤其是类似显示资源和下载资源的具有高相似度的请求或功能,通常有如下几种方法
- 设置不同的请求url后缀,在Servlet实现类上进行字符串匹配,并做出相应处理
- 在注解中添加多个urlpattern,添加格式为@webServlet({"/download", “/stream”})
- 在web.xml中配置多个urlpattern
13.10.Response的一些细节
- getOutputStream和getWriter方法分别用于得到输出二进制数据、输出文本数据的ServletOuputStream、Printwriter对象。
- getOutputStream和getWriter这两个方法互相排斥,调用了其中的任何一个方法后,就不能再调用另一方法。 会抛异常。
- Servlet程序向ServletOutputStream或PrintWriter对象中写入的数据将被Servlet引擎从response里面获取,Servlet引擎将这些数据当作响应消息的正文,然后再与响应状态行和各响应头组合后输出到客户端。
- Serlvet的service方法结束后,Servlet引擎将检查getWriter或getOutputStream方法返回的输出流对象是否已经调用过close方法,如果没有,Servlet引擎将调用close方法关闭该输出流对象。