JavaEE之Response

Response

概述

Servlet 最主要的作用就是处理客户端请求,并向客户端做出响应。为此,针对 Servlet 的每 次请求,Web 服务器在调用 service() 之前,都会创建两个对象,分别是 HttpServletRequest 和 HttpServletResponse,其中,
HttpServletRequest 用于封装 HTTP 请求消息,简称 request 对象。
HttpServletResponse 用于封装 HTTP 响应消息,简称 response 对象。
需要注意的是,在 Web 服务器运行阶段,每个 Servlet 都只会创建一个实例对象。然而, 每次 HTTP 请求,Web 服务器都会调用所请求 Servlet 实例的 service(HttpServletRequest request,HttpServletResponseresponse)方法,重新创建一个 request 对象和一个 response 对 象。

HttpServletResponse 对象

在 ServletAPI 中,定义了一个 HttpServletResponse 接口,它继承自 ServletResponse,专门 用来封装 HTTP 响应消息。
HTTP 响应消息分为三部分:

响应状态行
响应消息头
响应消息体
在 HttpservletResponse 接口中定义了向客户端发送响应状态码、响应消息头、响应消息体 的方法

发送状态码的方法

setStatus(intstatus)方法

该方法用于设置 HTTP 响应消息的状态码
由于响应状态行中的状态描述信息直接与状态码相关,而 HTTP 版本由服务器确定,因此, 只要通过 setStatus(intstatus) 方法设置了状态码,即可实现状态行的发送。
需要注意的是,正常情况下,Web 服务器会默认产生一个状态码为 200 的状态行

setError(intsc)方法

该方法用于发送表示错误信息的状态码,例如 404,状态码表示找不到客户端请求的资源, 在 response 对象中

发送响应消息头的相关方法

当 Servlet 向客户端回送响应消息时,由于 HTTP 的响应头字段有很多种,为此,在 HttpServletResponse 接口中,定义了一系列设置 HTTP 响应头的方法字段的方法。

一个 Key 对应一个 value:

setHeader(String name, String value):用于 value 是字符串的
setIntHeader(String name, int value):用于 value 是整数的

例如:response.setIntHeader(“Content-Length”,888); 表示响应了 888 字节
setHeader(“aa”,“bb”);
setHeader(“aa”,“cc”);
结果:aa:cc 相同的键后赋值的会覆盖先赋值的

一个 Key 对应多个 value:

addHeader(String name, String value):用于 value 是字符串的
addIntHeader(String name, int value):用于 value 是整数的
例如:
addHeader(“aa”,“bb”);
addHeader(“aa”,“cc”);
结果:aa:bb,cc 这个表示添加值

setContentLength(intlen) 设置响应消息的实体内容大小,单位为字节
setContentType(Stringtype) 设置 servlet 输出内容的 MIME 类型,对于 HTTP 来说,就是设置 Content-Type 响应头字 段的值

发送响应消息相关方法

由于在 HTTP 响应消息中,大量的数据都是通过响应消息体传递的,因此 ServletResponse 遵循以 IO 流传递大量数据的设计理念,在发送响应消息体时,定义了两个与输出流相关的 方法
- getOutputStream()方法

该方法所获取的字节输出流对象为 ServletOutputStream 类型。由于 ServletOut putStream 是 OutputStream 的子类,它可以直接输出字节数组中的二进制数据。因此,要 想输出二进制格式的响应正文,就需要使用 getOutputStream() 方法

  • getWriter()方法
    该方法所获取的字符输出流对象为 PrintWriter 类型。由于 PrintWriter 类型的对象可 以直接输出字符文本内容,因此,要想输出内容全为字符文本的网页文档,需要使用 getWriter()方法
代码示例
public class PrintServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        //方式一:专门输出二进制类型的数据
//      String data = "woxihuanni";
//      ServletOutputStream out = response.getOutputStream();
//      out.write(data.getBytes());
        //方式二:专门输出字符文本的类型数据
        //解决中文乱码问题
        String data1 = "我喜欢你";
        PrintWriter writer = response.getWriter();
        writer.write(data1);
    }


    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}
注意:对象的getOutputStream() 和 getWriter() 方法都可以输出数据, 但是两个方法是互斥的。

乱码解决

只需要保证响应数据的编码和浏览器解析的编码一致即可 response 缓冲区的默认编码是 iso8859-1,此码表中没有中文,可以通过 response 的 setCharacterEncoding(Stringcharset) 设置 response 的编码 将 response 缓冲区的编码设置成 UTF-8,但浏览器的默认编码是本地系统的编码,中文系统 默认编码是 GBK,我们可以手动修改浏览器的编码是 UTF-8。 还可以在代码中指定浏览器解析页面的编码方式,通过 response 的 setContentType(String type)方法指定页面解析时的编码是 UTF-8

response.setContentType(“text/html;charset=UTF-8”);

上面的代码不仅可以指定浏览器解析页面时的编码,同时也内含 setCharacterEncoding 的功 能 开发中只要编写 response.setContentType(“text/html;charset=UTF-8”);就可以解决页面输出中 文乱码问题。
代码示例
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");

文件下载

文件下载的实质就是文件拷贝,将文件从服务器端拷贝到浏览器端。 所以文件需要使用到 IO 流将服务器端的文件使用 InputStream 读取到,再使用 ServletOutputStream 写到 response 缓冲区中

文件下载的基本方式

示例代码
<body>
    <h1>使用a标签直接指向服务器上的资源</h1>
    <a href="/ResponseDemo/download/1.jfif">1.jfif</a><br>
    <a href="/ResponseDemo/download/2.txt">2.txt</a><br>
    <a href="/ResponseDemo/download/3.pdf">3.pdf</a><br>
    <a href="/ResponseDemo/download/4.zip">4.zip</a>
</body>
- 文件存放结构图 ![](https://i.imgur.com/EC93fEZ.png)

访问 Servlet 直接进行下载

要实现文件下载单独用 a 标签是不那么完美的。那么,究竟该怎样实现文件下载功能呢? 此时,就需要使用 Servlet 编码读取要下载的文件,然后写到响应流中以达到用户下载文件 的目的。 ServletOutputStream 抽象类。利用这个输出流可以将数据返回到客户端 想浏览器直接输出字节流,浏览器会根据对应的格式进行解析 。
示例代码
public class DownloadServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //使用respnse获得字节输出流
        ServletOutputStream out = response.getOutputStream();
        //获得服务器上的图片,此时浏览器会直接解析并显示
        String realpath = this.getServletContext().getRealPath("download/2.txt");
        InputStream in = new FileInputStream(realpath);
        int ch =0;
        byte[] b = new byte[1024];
        while((ch = in.read(b))!=-1){
            out.write(b,0,ch);
        }
        in.close();
        out.close();
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}
使用上面的代码还是有问题的,浏览器如果能够解析该文件,那么会直接将文件进行解析, 并显示,并且不能解析的文件下载后,而且文件名也不对。需要进行如下操作 - 告诉客户端(浏览器)以下载的方式打开文件

通过文件的 MIME 类型去区分类型(tomcat/conf/web.xml)

  • 文件的名字

    // 设置文件的类型
    response.setContentType(this.getServletContext().getMimeType(“download/ b.png”));
    //告诉客户端(浏览器)以下载的方式打开文件,设置 Context-Dispostion 头,并设置 文件名字
    response.setHeader(“Content-Disposition”, “attachment;filename=b.png”);
    设置好两个头后,就可以实现文件下载的功能,并且文件也已经有名字了

下载指定文件

编写新的 Servlet,访问 Servlet 时传递指定的文件名字,下载指定的文件
- HTML 代码如下(添加多一个中文名字的文件)
给Servlet传递参数只需要在URL后面加?并且拼接文件名字参数即可(键值对新式)

示例代码
<body>
    <h1>使用a标签直接指向服务器上的资源</h1>
    <a href="/ResponseDemo/download2servlet?filename=1.jfif">1.jfif</a><br>
    <a href="/ResponseDemo/download2servlet?filename=2.txt">2.txt</a><br>
    <a href="/ResponseDemo/download2servlet?filename=3.pdf">3.pdf</a><br>
    <a href="/ResponseDemo/download2servlet?filename=4.zip">4.zip</a><br>
</body>
  • Servlet 代码,主要改动的代码为:
    获取传递过来的文件名,之后以该文件名获取 MIME 类型和读取文件
主要代码
public class Download2Servlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String filepath = "download/"+request.getParameter("filename");
        response.setContentType(this.getServletContext().getMimeType("download/"+filepath));
        response.setHeader("Content-Disposition", "attachment;filename="+filepath);
        ServletOutputStream out = response.getOutputStream();
        String file = this.getServletContext().getRealPath(filepath);
        InputStream in = new FileInputStream(file);
        int ch = 0;
        byte[] b = new byte[1024];
        while((ch = in.read(b)) !=-1){
            out.write(b, 0, ch);
        }
        in.close();
        out.close();
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

中文名字乱码

上面的代码,如果下载中文文件,页面在下载时会出现中文乱码或不能显示文件名的情况(也 有可能发生文件找不到 404),对于 GET 请求,参数追加到地址栏,会使用 UTF-8 编码, 服务器(Tomcat)接受到请求之后,使用 ISO-8859-1 解码,所以会出现乱码,导致找不到 资源。
因此,我们在获取文件名时,必须将文件名用 UTF-8 解码 String filename = new String(request.getParameter(“filename”).getBytes(“iso-8859-1”), “utf-8”);
并且不同的浏览器默认对下载文件的编码方式不同, IE 是 UTF-8 编码方式,而火狐浏览器是 Base64 编码方式。所里这里还需要解决浏览器兼容性问题,解决浏览器兼容性问题的首要 任务是要辨别访问者是 IE 还是火狐(其他),通过 Http 请求体中的一个属性可以辨别

示例代码
    //获得请求头中的 User-Agent 
    String agent = request.getHeader("User-Agent"); //根据不同浏览器进行不同的编码 
    String filenameEncoder = ""; 
    if (agent.contains("MSIE")) { 
        // IE 浏览器 
        filenameEncoder = URLEncoder.encode(filename, "utf-8"); 
        filenameEncoder = filenameEncoder.replace("+", " "); 
    } else if (agent.contains("Firefox")) { 
        // 火狐浏览器
        BASE64Encoder base64Encoder = new BASE64Encoder(); 
        filenameEncoder = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?="; 
    } else { 
        // 其它浏览器 
        filenameEncoder = URLEncoder.encode(filename, "utf-8");
    }

- 文件名

> // 告诉客户端(浏览器)以下载的方式打开文件,设置 Context-Dispostion 头,并设置 文件名字 

response.setHeader(“Content-Disposition”, “attachment;filename=” + filenameEncoder);

完整代码
public class Download3Servlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        String filename = new String(request.getParameter("filename"));
        response.setContentType(this.getServletContext().getMimeType("download/"+filename));
        //获得请求头中的 User-Agent 
        String agent = request.getHeader("User-Agent"); //根据不同浏览器进行不同的编码 
        String filenameEncoder = ""; 
        if (agent.contains("MSIE")) { 
            // IE 浏览器 
            filenameEncoder = URLEncoder.encode(filename, "utf-8"); 
            filenameEncoder = filenameEncoder.replace("+", " "); 
        } else if (agent.contains("Firefox")) { 
            // 火狐浏览器
            BASE64Encoder base64Encoder = new BASE64Encoder(); 
            filenameEncoder = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?="; 
        } else { 
            // 其它浏览器 
            filenameEncoder = URLEncoder.encode(filename, "utf-8");
        }
        response.setHeader("Content-Disposition", "attachment;filename"+filenameEncoder);

        ServletOutputStream out = response.getOutputStream();
        String file = this.getServletContext().getRealPath("download/"+filename);
        InputStream in = new FileInputStream(file);
        int ch = 0;
        byte[] b = new byte[1024];
        while((ch = in.read(b)) !=-1){
            out.write(b, 0, ch);
        }
        in.close();
        out.close();


    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

请求重定向

在某些情况下,针对客户端的请求,一个 Servlet 类可能无法完成全部工作。这时可以使用 请求重定向来完成。 所谓请求重定向,指的是 Web 服务器接受到客户端的请求后,可能由于某些条件限制,不 能访问当前请求 URL 所指向的 Web 资源,而是指定了一个新的资源路径,让客户端重新发 送请求。为了实现请求重定向,在 HttpServletResponse 接口中,定义了一个 sendRedirect() 方法,该方法用于生成 302 响应码和 Location 响应头,从而通知客户端重新访问 Location 响应头中指定的 URL。
- 重定向工作原理

当客户端访问 Servlet1 时,由于在 Servlet 中调用了 sendRedirect() 方法将请求重定向到 Servlet2 中,因此,Web 服务器在收到 Servlet1 的响应消息后,立刻向 Servlet2 发送请求 Servlet2 对请求处理完毕后,再将响应消息回送给客户端。

代码示例
public class Servlet1 extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // 重定向到
    Servlet2 response.sendRedirect("/Response/servlet2");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值