ServletResponse

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处理完毕之后,跳转至一个页面。
  • 不同点:
    1. 转发是request介导的,刷新、重定向是response介导的
    2. 转发的两个组件之间可以共享request域,刷新、重定向是不可以的
    3. 转发是一次请求,刷新、重定向会发送多次请求
    4. 转发、刷新的状态码是200,重定向状态码是302、307
    5. 刷新可以设置跳转的时间,转发、重定向做不到
    6. 转发只可以在当前应用内部跳转,刷新、重定向不受限制,可以跳转到当前应用之外的任意网络资源
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处理多个网页请求,尤其是类似显示资源和下载资源的具有高相似度的请求或功能,通常有如下几种方法
    1. 设置不同的请求url后缀,在Servlet实现类上进行字符串匹配,并做出相应处理
    2. 在注解中添加多个urlpattern,添加格式为@webServlet({"/download", “/stream”})
    3. 在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方法关闭该输出流对象。
上一篇:2020-12-8 Filter过滤器


下一篇:springboot 集成 shiro 前后端分离 返回认证鉴权JSON数据