• 解决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;
        }
    }
  • 相关阅读:
    权限设计 【数据库和代码】 GO
    sql读取指定字符前的字符 GO
    C#编码建议 GO
    网页鼠标提示 GO
    ASP.NET设置ie打印两法 GO
    正则表达式入门教程 GO
    一个初学者对ArrayAdapter的简单理解
    泛型的简单理解
    SQL Server死锁详解
    .NET代理模式
  • 原文地址:https://www.cnblogs.com/superpang/p/5211224.html
Copyright © 2020-2023  润新知