文章目录
- 异常日志
- 源码位置
- 异常原因
- 异常前代码
- 调整后代码
异常日志
java.lang.IllegalStateException: getOutputStream() has already been called for this responseat org.apache.catalina.connector.Response.getWriter(Response.java:582) ~[tomcat-embed-core-9.0.17.jar!/:9.0.17]at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:227) ~[tomcat-embed-core-9.0.17.jar!/:9.0.17]at javax.servlet.ServletResponseWrapper.getWriter(ServletResponseWrapper.java:152) ~[javax.servlet-api-3.1.0.jar!/:3.1.0]
源码位置
看起来是,output流使用标志生效导致异常。
异常原因
一句话总结:同一个请求中:调用了两次response.getOutputStream()方法。或者先进行了respose的头等信息设置后调用response.getOutputStream()
异常前代码
控制层:
@RequestMapping(value ="/detailExport" ,method = RequestMethod.POST)@BusiResponseBodypublic void detailExport(@RequestBody IdReqBO queryBO, HttpServletRequest request,HttpServletResponse response ) {//获取导出的元数据(转换器、格式控制器、导出内容等)ExcelExportContent excelExportContent = excelExportStrategy.exportDetailExcelContent(request.getRequestURI(), queryBO);EasyExcelUtils.ExportResponse(excelExportContent,response);}
工具类:
public class EasyExcelUtils {public static void ExportResponse(ExcelExportContent excelExportContent,HttpServletResponse response){try {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");String fileName = URLEncoder.encode(excelExportContent.getFileName(), "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");//这里先设置的response的头、编码等信息,导致response.getOutputStream()时异常ExcelWriterBuilder excelWriterBuilder = EasyExcel.write(response.getOutputStream(), excelExportContent.getAccountDataClass()).registerConverter(new BigDecimalStringConverter()).registerConverter(new DateStringConverter());List<WriteHandler> writeHandler = excelExportContent.getWriteHandler();for (WriteHandler handler : writeHandler) {excelWriterBuilder.registerWriteHandler(handler);}excelWriterBuilder.sheet(excelExportContent.getSheetName()).doWrite(excelExportContent.getAccountData());} catch (Exception e){e.printStackTrace();throw new ZTBusinessException(e.getMessage());}}
}
调整后代码
控制层不变:
@RequestMapping(value ="/detailExport" ,method = RequestMethod.POST)@BusiResponseBodypublic void detailExport(@RequestBody IdReqBO queryBO, HttpServletRequest request,HttpServletResponse response ) {//获取导出的元数据(转换器、格式控制器、导出内容等),可忽略ExcelExportContent excelExportContent = excelExportStrategy.exportDetailExcelContent(request.getRequestURI(), queryBO);EasyExcelUtils.ExportResponse(excelExportContent,response);}
工具类:
这里格式化response的动作只能在response.getOutputStream()之后,在EasyExcel的doWrite之前。
在response.getOutputStream()之前会出现getOutputStream() has already been called for this response异常。在EasyExcel的doWrite之后,流已经被写回了,格式化response不会生效,写回的内容是txt格式。
public class EasyExcelUtils {protected static Logger logger = LoggerFactory.getLogger(EasyExcelUtils.class);public static void ExportResponse(ExcelExportContent excelExportContent, HttpServletResponse response) {try {ExcelWriterBuilder excelWriterBuilder = EasyExcel.write(response.getOutputStream());//这里格式化response内容只能在这个位置FormatResponse(response, excelExportContent.getFileName());ExcelWriterSheetBuilder(excelWriterBuilder, excelExportContent).doWrite(excelExportContent.getDetailData());} catch (Exception e) {e.printStackTrace();throw new ZTBusinessException("ExportResponse exception:" + e.getMessage());}}public static void FormatResponse(HttpServletResponse response, String fileName) {try {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");String exportFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + exportFileName + ".xlsx");} catch (UnsupportedEncodingException e) {e.printStackTrace();throw new ZTBusinessException("FormatResponse exception:" + e.getMessage());}}private static ExcelWriterSheetBuilder ExcelWriterSheetBuilder(ExcelWriterBuilder excelWriterBuilder, ExcelExportContent excelExportContent) {List<Converter> converterList = Optional.ofNullable(excelExportContent.getConverter()).orElseGet(ArrayList::new);for (Converter converter : converterList) {excelWriterBuilder.registerConverter(converter);}List<WriteHandler> writeHandlerList = Optional.ofNullable(excelExportContent.getWriteHandler()).orElseGet(ArrayList::new);for (WriteHandler writeHandler : writeHandlerList) {excelWriterBuilder.registerWriteHandler(writeHandler);}ExcelWriterSheetBuilder excelWriterSheetBuilder = excelWriterBuilder.sheet(excelExportContent.getSheetName());return excelWriterSheetBuilder;}}