将大型 HSSFWorkbook 写入 ServletOutputStream
write large HSSFWorkbook into ServletOutputStream
我有以下代码。当我尝试使用少量记录(大约 200 条记录)将记录列表导出到 excel 时,这工作正常:
@Path("/toExcel")
@GET
public Response excelCustomersReport(@QueryParam("page") Integer page, @QueryParam("start") Integer start, @QueryParam("limit") Integer limit, @QueryParam("filter") FilterWrapper filter, @QueryParam("sort") SortWrapper sort) throws Exception {
response.setContentType("application/octet-stream");
DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss");
String currentDateTime = dateFormatter.format(new Date());
String headerKey = "Content-Disposition";
String headerValue = "attachment; filename=report_" + currentDateTime + ".xlsx";
response.setHeader(headerKey, headerValue);
HSSFWorkbook workbook=userService.export(page,start,limit,filter,sort);
ServletOutputStream outputStream=response.getOutputStream();
workbook.write(outputStream);
workbook.close();
outputStream.close();
return ResponseHelper.ok(response);
}
当列表变大时悲剧就开始了(例如超过 200 条记录)。它给出以下错误:
<An I/O error has occurred while writing a response message entity to the container output stream.
org.glassfish.jersey.server.internal.process.MappableException: java.io.IOException: CLOSED
我搜索了很多,最后找到了这个解决方案:
public Response excelCustomersReport(@QueryParam("page") Integer page, @QueryParam("start") Integer start, @QueryParam("limit") Integer limit, @QueryParam("filter") FilterWrapper filter, @QueryParam("sort") SortWrapper sort) throws Exception {
response.setContentType("application/octet-stream");
DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss");
String currentDateTime = dateFormatter.format(new Date());
String headerKey = "Content-Disposition";
String headerValue = "attachment; filename=report_" + currentDateTime + ".xlsx";
response.setHeader(headerKey, headerValue);
HSSFWorkbook workbook=userService.export(page,start,limit,filter,sort);
response.setHeader("Content-Length", String.valueOf(workbook.getBytes().length));
InputStream is=new ByteArrayInputStream(workbook.getBytes());
ServletOutputStream sos = response.getOutputStream();
long byteRead = 0;
try {
byte[] buf = new byte[1000];
while (true) {
int r = is.read(buf);
if (r == -1)
break;
sos.write(buf, 0, r);
byteRead +=r;
if(byteRead > 1024*1024){ //flushes after 1mb
byteRead = 0;
sos.flush();
}
}
}catch (Exception e) {
e.printStackTrace();
}finally{
if(sos != null){
sos.flush();
}
try{is.close();}catch(Exception e){}
try{sos.close();}catch(Exception e){}
}
return ResponseHelper.ok(response);
}
冲洗流是大多数人所指的唯一方式。现在这个解决方案不仅适用于大数据而且也适用于较小的数据(不适用于这两种情况)。它给出了这个错误:
An I/O error has occurred while writing a response message entity to the container output stream.
org.glassfish.jersey.server.internal.process.MappableException: com.fasterxml.jackson.databind.JsonMappingException: Direct self-reference leading to cycle
我试过 XSSFWorkbook
而不是 HSSFWorkbook
。但是 weblogic 甚至没有构建项目并抛出了与 meta-model
.
有关的错误
无论如何,这段代码有什么问题。如何将更大的文件写入流中?我的 apache poi 版本是 3.11.
正如 S.O link 评论的 Paul Samsotha
所说,我应该使用 StreamingOutput
而不是 ServletOutputStream
。所以该方法应该重写为:
@Path("/toExcel")
@GET
public Response excelCustomersReport(@QueryParam("page") Integer page, @QueryParam("start") Integer start, @QueryParam("limit") Integer limit, @QueryParam("filter") FilterWrapper filter, @QueryParam("sort") SortWrapper sort) throws Exception {
response.setContentType("application/octet-stream");
DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss");
String currentDateTime = dateFormatter.format(new Date());
String headerKey = "Content-Disposition";
String headerValue = "attachment; filename=report_" + currentDateTime + ".xlsx";
response.setHeader(headerKey, headerValue);
HSSFWorkbook workbook=userService.export(page,start,limit,filter,sort);
StreamingOutput output = new StreamingOutput() {
@Override
public void write(OutputStream out)
throws IOException, WebApplicationException {
workbook.write(out);
out.flush();
}
};
return Response.ok(output)
.build();
}
我有以下代码。当我尝试使用少量记录(大约 200 条记录)将记录列表导出到 excel 时,这工作正常:
@Path("/toExcel")
@GET
public Response excelCustomersReport(@QueryParam("page") Integer page, @QueryParam("start") Integer start, @QueryParam("limit") Integer limit, @QueryParam("filter") FilterWrapper filter, @QueryParam("sort") SortWrapper sort) throws Exception {
response.setContentType("application/octet-stream");
DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss");
String currentDateTime = dateFormatter.format(new Date());
String headerKey = "Content-Disposition";
String headerValue = "attachment; filename=report_" + currentDateTime + ".xlsx";
response.setHeader(headerKey, headerValue);
HSSFWorkbook workbook=userService.export(page,start,limit,filter,sort);
ServletOutputStream outputStream=response.getOutputStream();
workbook.write(outputStream);
workbook.close();
outputStream.close();
return ResponseHelper.ok(response);
}
当列表变大时悲剧就开始了(例如超过 200 条记录)。它给出以下错误:
<An I/O error has occurred while writing a response message entity to the container output stream.
org.glassfish.jersey.server.internal.process.MappableException: java.io.IOException: CLOSED
我搜索了很多,最后找到了这个解决方案:
public Response excelCustomersReport(@QueryParam("page") Integer page, @QueryParam("start") Integer start, @QueryParam("limit") Integer limit, @QueryParam("filter") FilterWrapper filter, @QueryParam("sort") SortWrapper sort) throws Exception {
response.setContentType("application/octet-stream");
DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss");
String currentDateTime = dateFormatter.format(new Date());
String headerKey = "Content-Disposition";
String headerValue = "attachment; filename=report_" + currentDateTime + ".xlsx";
response.setHeader(headerKey, headerValue);
HSSFWorkbook workbook=userService.export(page,start,limit,filter,sort);
response.setHeader("Content-Length", String.valueOf(workbook.getBytes().length));
InputStream is=new ByteArrayInputStream(workbook.getBytes());
ServletOutputStream sos = response.getOutputStream();
long byteRead = 0;
try {
byte[] buf = new byte[1000];
while (true) {
int r = is.read(buf);
if (r == -1)
break;
sos.write(buf, 0, r);
byteRead +=r;
if(byteRead > 1024*1024){ //flushes after 1mb
byteRead = 0;
sos.flush();
}
}
}catch (Exception e) {
e.printStackTrace();
}finally{
if(sos != null){
sos.flush();
}
try{is.close();}catch(Exception e){}
try{sos.close();}catch(Exception e){}
}
return ResponseHelper.ok(response);
}
冲洗流是大多数人所指的唯一方式。现在这个解决方案不仅适用于大数据而且也适用于较小的数据(不适用于这两种情况)。它给出了这个错误:
An I/O error has occurred while writing a response message entity to the container output stream.
org.glassfish.jersey.server.internal.process.MappableException: com.fasterxml.jackson.databind.JsonMappingException: Direct self-reference leading to cycle
我试过 XSSFWorkbook
而不是 HSSFWorkbook
。但是 weblogic 甚至没有构建项目并抛出了与 meta-model
.
无论如何,这段代码有什么问题。如何将更大的文件写入流中?我的 apache poi 版本是 3.11.
正如 S.O link 评论的 Paul Samsotha
所说,我应该使用 StreamingOutput
而不是 ServletOutputStream
。所以该方法应该重写为:
@Path("/toExcel")
@GET
public Response excelCustomersReport(@QueryParam("page") Integer page, @QueryParam("start") Integer start, @QueryParam("limit") Integer limit, @QueryParam("filter") FilterWrapper filter, @QueryParam("sort") SortWrapper sort) throws Exception {
response.setContentType("application/octet-stream");
DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss");
String currentDateTime = dateFormatter.format(new Date());
String headerKey = "Content-Disposition";
String headerValue = "attachment; filename=report_" + currentDateTime + ".xlsx";
response.setHeader(headerKey, headerValue);
HSSFWorkbook workbook=userService.export(page,start,limit,filter,sort);
StreamingOutput output = new StreamingOutput() {
@Override
public void write(OutputStream out)
throws IOException, WebApplicationException {
workbook.write(out);
out.flush();
}
};
return Response.ok(output)
.build();
}