問題描述:html
在springmvc中實現文件下載功能通常都會使用javax.servlet.ServletOutputStream out = response.getOutputStream();封裝下載的工具類,稍後我會分享該工具類。java
當使用了response.getOutputStream()後,因爲在同一個請求中JSP或Servlet中同時調用了Response的getWriter和getOutputStream就會拋此異常,異常部分代碼以下:web
嚴重: 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,結果巧妙解決了以上問題,特以此記錄。spring
測試的下載工具類以下:;apache
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; } }