Servlet -- HttpServletResponse中 OutputStream和PrintWriter的区别

1.response 可以使用OutputStream流向客户端浏览器输出或者PrintWriter输出,但是同一个response只能被一种方式后获取,

如果同时被2中方式获取会报错:

java.lang.IllegalStateException: getWriter() has already been called for this response
	at org.apache.catalina.connector.Response.getOutputStream(Response.java:530)
	at org.apache.catalina.connector.ResponseFacade.getOutputStream(ResponseFacade.java:195)
	at com.snow.www.controller.FilterController.addPost(FilterController.java:62)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

2.response.getOutputStream()向浏览器输出的是二进制数据,是字节流,可以处理任意类型的数据,而response.getWriter()输出的是字符型数据,是字符流。

用例:

1、使用OutputStream流和PrintWriter流向客户端浏览器输出中文数据

      在服务器端,数据的输出码表要和控制客户端浏览器相应的码表一致,比如:outputStream.write("中文".getBytes("UTF-8"));使用OutputStream流向客户端浏览器输出中文,以UTF-8的编码进行输出,此时就要控制客户端浏览器以UTF-8的编码打开,否则显示的时候就会出现中文乱码。

在服务器端如何控制客户端浏览器以以UTF-8的编码显示数据呢?

      可以通过设置响应头控制浏览器的行为,例如:response.setHeader("content-type", "text/html;charset=UTF-8");通过设置响应头控制浏览器以UTF-8的编码显示数据。

1.1使用OutputStream流向浏览器输出中文

复制代码

 1 package controller;
 2 
 3 import java.io.IOException;
 4 import java.io.OutputStream;
 5 import javax.servlet.ServletException;
 6 import javax.servlet.http.HttpServlet;
 7 import javax.servlet.http.HttpServletRequest;
 8 import javax.servlet.http.HttpServletResponse;
 9 
10 public class ServletDemo01 extends HttpServlet {
11     private static final long serialVersionUID = 1L;
12    
13     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
14         this.doPost(request, response);
15     }
16 
17     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
18         
19         String str="使用OutputStream输出中文:我心自在";
20         //在服务器设置响应头,告诉浏览器以utf-8的编码显示数据,如果不写会出现中文乱码
21         response.setHeader("content-type", "text/html;charset=UTF-8");
22         //获取OutputStream输出流
23         OutputStream os=response.getOutputStream();
24         /**
25          * getBytes的作用是将字符转化为字节数组,如果不带参数,默认根据系统环境来进行转化
26          * 这里指定以utf-8的编码进行转换
27          */
28         byte[]b=str.getBytes("utf-8");
29         //想客户端(浏览器)输出数据
30         os.write(b);
31     }
32 }

复制代码

浏览器中输入:http://localhost:8080/servlet_study/ServletDemo01,运行结果如下:

打开浏览器调试工具,可以看到相关编码信息:

 

 

1.2使用PrintWriter流向浏览器输出中文

复制代码

 1 package controller;
 2 
 3 import java.io.IOException;
 4 import java.io.PrintWriter;
 5 import javax.servlet.ServletException;
 6 import javax.servlet.http.HttpServlet;
 7 import javax.servlet.http.HttpServletRequest;
 8 import javax.servlet.http.HttpServletResponse;
 9 
10 public class ServletDemo02 extends HttpServlet {
11     private static final long serialVersionUID = 1L;
12     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
13         this.doPost(request, response);
14     }
15     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
16         String str="使用PrintWriter输出中文:我心自在";
17         //设置中文编码格式
18         response.setCharacterEncoding("utf-8");
19         //获取流
20         PrintWriter pw=response.getWriter();
21         //输出
22         pw.write(str);
23         pw.close();
24     }
25 
26 }

复制代码

浏览器中输入:http://localhost:8080/servlet_study/ServletDemo02,运行结果如下:

这里需要注意的是:  在获取PrintWriter输出流之前首先使用"response.setCharacterEncoding(charset)"设置字符以什么样的编码输出到浏览器,如:response.setCharacterEncoding("UTF-8");设置将字符以"UTF-8"编码输出到客户端浏览器,然后再使用response.getWriter();获取PrintWriter输出流,这两个步骤不能颠倒.如果颠倒,设置将无效,还是会出现中文乱码!

 通过比较可以看出,当需要向浏览器输出字符数据时,使用PrintWriter比较方便,因为不需要将字符转化为字节这一步!

1、使用OutputStream流和PrintWriter流下载文件

最近在做一个项目,涉及到文件的下载,所以特意整理出来做个比较。

文件下载,在实际开发中用到的很多,最近做的项目便是,查看图片的时候,点击图片的时候进行图片下载,这里将这两个下载文件的区别做简要比较。

文件下载,运用的步骤比较固定,大致分为以下几步:

      1.获取要下载的文件的绝对路径(注意是绝对路径)

  2.获取要下载的文件名(获取文件名要注意中文文件名的问题,需进行编码)

  3.设置content-disposition响应头控制浏览器,告诉浏览器以下载的形式打开文件

  4.获取要下载的文件输入流

  5.创建数据缓冲区

  6.通过response对象获取OutputStream流

  7.将FileInputStream流写入到buffer缓冲区

  8.使用OutputStream将缓冲区的数据输出到客户端浏览器

2.1使用OutputStream流下载中文文件

复制代码

package controller;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ServletDemo03 extends HttpServlet {
    private static final long serialVersionUID = 1L;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取文件的下载绝对路径
        String downloadPath=this.getServletContext().getRealPath("/download/阳光海滩.jpg");
        //获取文件名
        String fileName=downloadPath.substring(downloadPath.lastIndexOf("\\")+1);
        //设置响应头,告诉浏览器以下载的方式打来文件,设置中文编码,如果不设置会出现乱码
         response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(fileName, "UTF-8"));
        //获取文件流
         InputStream is=new FileInputStream(downloadPath);
         int len=0;
         byte[]b=new byte[1024];
         OutputStream os=response.getOutputStream();
         while((len=is.read(b))!=-1){
             //将缓冲区数据输出到浏览器
             os.write(b,0,len);
         }
         is.close();
    }

}

复制代码

浏览器中输入:http://localhost:8080/servlet_study/ServletDemo03可以成功下载图片并且可以顺利打开,

2.1使用PrintWriter流下载中文文件

复制代码

package controller;

import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ServletDemo03 extends HttpServlet {
    private static final long serialVersionUID = 1L;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取文件的下载绝对路径
        String downloadPath=this.getServletContext().getRealPath("/download/阳光海滩.jpg");
        //获取文件名
        String fileName=downloadPath.substring(downloadPath.lastIndexOf("\\")+1);
        //设置响应头,告诉浏览器以下载的方式打来文件,设置中文编码,如果不设置会出现乱码
         response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(fileName, "UTF-8"));
        //获取文件流
         FileReader fr=new FileReader(downloadPath);
         int len=0;
         char[] b=new char[1024];
         PrintWriter os=response.getWriter();
         while((len=fr.read(b))!=-1){
             //将缓冲区数据输出到浏览器
             os.write(b,0,len);
         }
         fr.close();
    }

}

复制代码

浏览器中输入:http://localhost:8080/servlet_study/ServletDemo03可以成功下载,但是打开的过程中却出现了一下情况:

 

这是什么原因造成的呢?

     PrintWriter流处理节数据,会导致数据丢失,因此在编写下载文件功能时,要使用OutputStream流,避免使用PrintWriter流,因为OutputStream流是字节流,可以处理任意类型的数据,而PrintWriter流是字符流,只能处理字符数据,如果用字符流处理字节数据,会导致数据丢失。

以下是文件上传和下载的完整代码,包括JSP和Servlet: 上传文件的JSP页面(upload.jsp): ``` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>文件上传</title> </head> <body> <h2>文件上传</h2> <form action="UploadServlet" method="post" enctype="multipart/form-data"> <label>请选择文件:</label> <input type="file" name="file"><br/><br/> <input type="submit" value="上传"> </form> </body> </html> ``` 上传文件的Servlet(UploadServlet.java): ``` import java.io.File; import java.io.IOException; import java.io.PrintWriter; 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 javax.servlet.http.Part; @WebServlet("/UploadServlet") public class UploadServlet extends HttpServlet { private static final long serialVersionUID = 1L; public UploadServlet() { super(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); // 上传文件保存路径 String savePath = this.getServletContext().getRealPath("/WEB-INF/upload"); // 创建保存路径的文件夹 File file = new File(savePath); if (!file.exists() && !file.isDirectory()) { System.out.println(savePath + "目录不存在,需要创建"); file.mkdir(); } // 获取上传的文件 Part part = request.getPart("file"); // 获取上传的文件名 String fileName = part.getSubmittedFileName(); // 上传的文件保存到服务器的完整路径 String filePath = savePath + File.separator + fileName; // 将上传的文件保存到服务器指定的路径 part.write(filePath); out.println("文件上传成功!"); } } ``` 下载文件的Servlet(DownloadServlet.java): ``` import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/DownloadServlet") public class DownloadServlet extends HttpServlet { private static final long serialVersionUID = 1L; public DownloadServlet() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取要下载的文件名 String fileName = request.getParameter("filename"); // 设置文件MIME类型 response.setContentType(getServletContext().getMimeType(fileName)); // 设置Content-Disposition response.setHeader("Content-Disposition", "attachment;filename=" + fileName); // 读取目标文件,通过response将目标文件写到客户端 // 获取目标文件的绝对路径 String fullFileName = getServletContext().getRealPath("/WEB-INF/upload/" + fileName); // 读取文件 FileInputStream in = new FileInputStream(fullFileName); OutputStream out = response.getOutputStream(); // 写文件 int len = 0; byte[] buffer = new byte[1024]; while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } in.close(); out.close(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } ``` 在web.xml文件添加以下配置: ``` <servlet> <servlet-name>DownloadServlet</servlet-name> <servlet-class>DownloadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>DownloadServlet</servlet-name> <url-pattern>/DownloadServlet</url-pattern> </servlet-mapping> ``` 在JSP页面,可以通过以下方式链接到下载Servlet: ``` <a href="DownloadServlet?filename=xxx.txt">下载xxx.txt文件</a> ``` 其,xxx.txt是要下载的文件名。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值