javaweb入门(一)——servlet-05-Response学习

HttpServletResponse

web服务器接收到客户端的http请求之后,针对于这个请求,web服务器会创建两个类HttpServletRequest以及HtppServletResponse,其中HttpServletRequest来代表请求HttpServletResponse用来代表响应
对于这两个类我们要记住:

  • 如果我们想要获取客户端传来的请求参数,我们需要找的类是HttpServletRequest
  • 如果我们想要给客户端响应信息,我们需要找的类是HttpServletResponse

对于HttpServletResponse类,我们习惯于称之为Response,也即响应类

对HttpServletResponse类中方法的一些简单分类

我们学习一个类最直接有效的方法就是先看他的代码,查看其中具体都有哪些方法,搞明白这些方法的功能都是什么。
首先我们看HttpServletResponse类,我们可以发现它继承的是ServletResponse接口。

我们可以发现,这些方法大多都是get、set以及add方法。那么我们可以将这些方法做一个简单的归类。

负责向服务器发送数据的方法

//	只可以输出字符流数据,即只可以输出字符串
    PrintWriter getWriter() throws IOException;
//	可以输出字符流数据和字节流数据,即字符串和二进制字节流
    ServletOutputStream getOutputStream() throws IOException;

这两个类都是用于获取向服务器输出数据的输出流
我们需要注意的是:
1.getWriter()方法用于输出字符流数据getOutputStream()方法用于输出字节流数据
在这里和大家解释一下什么是字节流数据字符流数据
字节流数据其实就是二进制数据,它是以字节为单位,即在很多类中都有的getBytes()方法便是将此类转换为字节流。
字符流数据其实就是我们常用的字符串,它是以字符为单位,例如我们经常使用的String类。

为了更好地理解这两个类,我们可以编写一个案例。

测试getWriter()的Servlet:

package com.kuang.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;

public class WriterServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
//        由于我们的message中有中文,为了防止乱码,所以要对ContentType进行设置
        resp.setContentType("text/html;charset=UTF-8");
//        获取Writer输出流
        PrintWriter writer = resp.getWriter();
        String message = "你好,我是BugMaker2000";
//      将数据使用输出流输出
        writer.write(message);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        doGet(req, resp);
    }
}

测试getOutputStream()的Servlet:

package com.kuang.servlet;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class OutputStreamServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
//        对resp的ContextType设置
        resp.setContentType("text/html;charset=UTF-8");
//      获取输出流
        ServletOutputStream os = resp.getOutputStream();
        String message = "大家好,我是BugMaker2000 ";
//      这里在测试时,我发现resp中设置的字符字符标准对outputStream无效
        os.write(message.getBytes());
//      当我们需要outputsStream输出数据时候,我们需要在此设置字节流的标准
        os.write(message.getBytes(StandardCharsets.UTF_8));
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        doGet(req, resp);
    }
}

测试结果:
getWriter()的测试结果
在这里插入图片描述
getOutputStream()的测试结果
在这里插入图片描述
通过本次案例我们可以更加直观的了解到两个输出流之间功能上的差别:Writer更加注重字符的输出,OutputStream更加注重对字节的输出。

OutputStreamServlet类中尽管我们在输出流输出之前对response的ContextType中的字符进行了设置,但是outputStream输出的字节流依然是乱码。只用我们在os.write()中设置好字节流的编码格式输出的中文字符才不会变成乱码。

  1. 一个serlvet中的输出流可以选择Writer或者outputStream两者其中一种
    在一个输出流创建完毕之后,它就会随着response发送到客户端,在客户端接收之后,服务器就会自动关闭response中没有关闭的输出流

负责向浏览器发送响应头的方法

	//这些是 SerlvetResponse的方法
	void setCharacterEncoding(String var1);

    void setContentLength(int var1);

    void setContentLengthLong(long var1);

    void setContentType(String var1);

	//这些是HttpServletResponse的方法
	void setDateHeader(String var1, long var2);

    void addDateHeader(String var1, long var2);

    void setHeader(String var1, String var2);

    void addHeader(String var1, String var2);

    void setIntHeader(String var1, int var2);

    void addIntHeader(String var1, int var2);

设置响应的状态码

	void setStatus(int var1);

关于状态码,我们只需要记住:

  • 200表示响应成功
  • 3XX表示请求重定向
  • 4XX表示找不到资源
  • 5XX表示服务器代码错误

Response常见的应用——下载文件

一般来说我们使用response应用为:向客户端输出消息,客户端下载文件。其实这两个应用的本质都是客户端通过response类获取服务器传来的数据
我们此处详细讲解一下response完成下载文件的功能。
客户端下载文件,我们需要完成一下几步:
1.设置响应头,使得客户端可以接收下载文件
2.获取文件输入流
3.获取servlet的输出流
4.创建缓冲区,通过缓冲区将文件输出流写入输出流(返回给客户端)
(5.关闭流,我们十分提倡我们自己关闭输入/输出流
完成的类:

package com.kuang.servlet;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class FileDownServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    

//        1.设置浏览器可以接收下载的文件
        resp.setHeader("Content-Disposition","attachment;filename=1.png");
//        2.获取文件作为输入流
        InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/1.jpeg");
//        3.获取输出流
        ServletOutputStream os = resp.getOutputStream();
//        4.创建缓冲区,通过缓冲区将文件输入流写入响应输出
        byte[] buffer = new byte[1024];
        int len = 0;
        while((len = is.read(buffer)) > 0){
    
    
//            将文件输出给客户端
            os.write(buffer,0,len);
        }
//        关闭流
        is.close();
        os.close();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        doGet(req, resp);
    }
}

实现结果:
当我们运行下载文件的serlvet之后,浏览器就会新建下载任务
在这里插入图片描述
关于这个案例,我们需要知道这些知识点:
1.关于设置浏览器下载文件的语句

        resp.setHeader("Content-Disposition","attachment;filename=1.png");

只有在我们设置了响应头之后,浏览器才会出现新建下载任务的窗口,否则浏览器只会展示图片。要注意其中的filename=1.pngfilename=之后的内容是根据我们需要下载的文件名而改变的。
2.获取文件作为输入流
我们需要知道,获取文件作为输入流不仅仅可以通过ServletContext.getResourceAsStream来完成。我们也可通过new一个FileInputStream来完成。

FileInputStream fis = new FileInputStream(filepath);//参数是文件路径

3.关于文件输入流的输入方法inputStream.read()
我们把文件输入流通过缓冲区写入输出流的代码:

        int len = 0;
        while((len = is.read(buffer)) > 0){
    
    
//            将文件输出给客户端
            os.write(buffer,0,len);
        }

这段代码可以说是将文件输入流转换为输出流的固定格式,在服务器文件下载中经常使用,需要我们记住。
其中的is.read()方法的作用是:如果参数是byte[],那么将从输入流中获取下一段最多长度是byte[].length的字节(也有可能不够这么多),将其存放在byte[]中,将实际读取的字节数作为int类型返回,如果输入流之后没有字节,那么返回值为-1
4.我们一定要养成在使用完流之后手动将它关闭的好习惯。
5.如果我们想要下载的文件名称是中文的话,我们下载的文件名会是乱码,这个时候需要我们将响应头的设置修改一下:

        String filename = "中文名字.jpeg";
        resp.setHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode(filename,"UTF-8"));

需要注意的是,SerlvetContext.getResource()中的路径是可以带有中文的,所以在将中文名称的文件作为文件流导入时直接将filename输入进去就可以了。

InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/" + filename);

在这里插入图片描述
而且我们需要知道,就算我们没有对response的响应头做处理中文乱码的设置,文件也是可以正常下载的,仅仅只是名字是乱码