解决springmvc中文件下载功能中使用javax.servlet.ServletOutputStream out = response.getOutputStream();后运行出异常但结果正确的问题

问题描述:

  在springmvc中实现文件下载功能一般都会使用javax.servlet.ServletOutputStream out = response.getOutputStream();封装下载的工具类,稍后我会分享该工具类。

当使用了response.getOutputStream()后,由于在同一个请求中JSP或Servlet中同时调用了Response的getWriter和getOutputStream就会抛此异常,异常部分代码如下:

严重: Servlet.service() for servlet jsp threw exception
java.lang.IllegalStateException: getOutputStream() has already been called for this response
    at org.apache.catalina.connector.Response.getWriter(Response.java:678)
    at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:213)
    at javax.servlet.ServletResponseWrapper.getWriter(ServletResponseWrapper.java:104)
    at org.apache.jasper.runtime.JspWriterImpl.initOut(JspWriterImpl.java:125)
    at org.apache.jasper.runtime.JspWriterImpl.flushBuffer(JspWriterImpl.java:118)
    at org.apache.jasper.runtime.PageContextImpl.release(PageContextImpl.java:186)
    at org.apache.jasper.runtime.JspFactoryImpl.internalReleasePageContext(JspFactoryImpl.java:126)
    at org.apache.jasper.runtime.JspFactoryImpl.releasePageContext(JspFactoryImpl.java:80)
    at org.apache.jsp.download_jsp._jspService(download_jsp.java:103)
    at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
    at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:395)
    at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:339)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)

网上有的解决办法都是基于jsp中有java代码的,但是如果想在springmvc的controller中使用时难免不太对应,经过我的摸索,由于下载文件大多数情况况下都是留在原页面,那么我试了一下将返回值设为void,结果巧妙解决了以上问题,特以此记录。

测试的下载工具类如下:;


import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

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

public class DownloadFile {
    /**
     * 下载文件,file 为文件位置
     */
    public static void downloadFile(String file, HttpServletRequest request,
            HttpServletResponse response) {
        try {
            File tempFile = new File(file.trim());
            String fileName = tempFile.getName();
            InputStream is = new FileInputStream(file);
            response.reset(); // 必要地清除response中的缓存信息
            request.setCharacterEncoding("UTF-8");
            response.setContentType("application/octet-stream; charset=utf-8");
            response.setHeader("Content-disposition", 
                               "attachment;" + UserAgentUtil.encodeFileName(request, fileName));
            //response.setHeader("Content-Length", String.valueOf(fileLength));
            /*response.setHeader("Content-Disposition", "attachment; filename="
                    + java.net.URLEncoder.encode(fileName, "UTF-8"));*/
            javax.servlet.ServletOutputStream out = response.getOutputStream();
            byte[] content = new byte[1024];
            int length = 0;
            while ((length = is.read(content)) != -1) {
                out.write(content, 0, length);
            }
            out.flush();
            out.close();
       is.close(); }
catch (Exception e) { e.printStackTrace(); } } }

测试的controller层代码如下:

@RequestMapping(value = "/download.do")    
    public void downloadDetailPrice(//@RequestParam String id, 
            HttpServletRequest request, HttpServletResponse response) {
        String file = "D:\\a.txt";
        DownloadFile.downloadFile(file,request,response);
            
    } 

 浏览器客户端防乱码工具类:

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import javax.mail.internet.MimeUtility;
import javax.servlet.http.HttpServletRequest;


/** @author  pangchao E-mail: pangchao620@163.com
 * @date : 2016年2月24日 上午11:27:26 
 * @Description : 文件下载时浏览器端防乱码编码工具类
 * @version 1.0 
 */
public class UserAgentUtil {

    public static String encodeFileName(HttpServletRequest request, String fileName) {
        String userAgent = request.getHeader("User-Agent");
        String rtn = "";
        try {
            String new_filename = URLEncoder.encode(fileName, "UTF8");
            // 如果没有UA,则默认使用IE的方式进行编码,因为毕竟IE还是占多数的
            rtn = "filename=\"" + new_filename + "\"";
            if (userAgent != null) {
                userAgent = userAgent.toLowerCase();
                // IE浏览器,只能采用URLEncoder编码
                if (userAgent.indexOf("msie") != -1) {
                    rtn = "filename=\"" + new_filename + "\"";
                }
                // Opera浏览器只能采用filename*
                else if (userAgent.indexOf("opera") != -1) {
                    rtn = "filename*=UTF-8''" + new_filename;
                }
                // Safari浏览器,只能采用ISO编码的中文输出
                else if (userAgent.indexOf("safari") != -1) {
                    rtn = "filename=\"" + new String(fileName.getBytes("UTF-8"), "ISO8859-1") + "\"";
                }
                // Chrome浏览器,只能采用MimeUtility编码或ISO编码的中文输出
                else if (userAgent.indexOf("applewebkit") != -1) {
                    new_filename = MimeUtility.encodeText(fileName, "UTF8", "B");
                    rtn = "filename=\"" + new_filename + "\"";
                }
                // FireFox浏览器,可以使用MimeUtility或filename*或ISO编码的中文输出
                else if (userAgent.indexOf("mozilla") != -1) {
                    rtn = "filename*=UTF-8''" + new_filename;
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return rtn;
    }
}

 

posted @ 2016-02-23 20:59  庞超SuperPang  阅读(32755)  评论(0编辑  收藏  举报