【问题标题】:Spring MVC, Excel file download, corrupts fileSpring MVC,Excel文件下载,文件损坏
【发布时间】:2015-01-17 00:13:52
【问题描述】:

我正在我的一个 web 应用程序中开发 excel 导出功能。我设置了一个小测试用例并开始下载,但 xlsx 文件已损坏,不知道我还能尝试什么。如果我将excel写入文件,它打开没有问题,所以下载时一定会出现错误。

设置:

spring-mvc 3.2.7 poi 3.10.1 雄猫 8.0

控制器方法:

@RequestMapping(value = "/download", method = RequestMethod.GET)
public ModelAndView downloadExcel() {
    // create some sample data
    List<Book> listBooks = new ArrayList<Book>();
    listBooks.add(new Book("Effective Java", "Joshua Bloch", "0321356683",
            "May 28, 2008", 38.11F));
    listBooks.add(new Book("Head First Java", "Kathy Sierra & Bert Bates",
            "0596009208", "February 9, 2005", 30.80F));
    listBooks.add(new Book("Java Generics and Collections",
            "Philip Wadler", "0596527756", "Oct 24, 2006", 29.52F));
    listBooks.add(new Book("Thinking in Java", "Bruce Eckel", "0596527756",
            "February 20, 2006", 43.97F));
    listBooks.add(new Book("Spring in Action", "Craig Walls", "1935182358",
            "June 29, 2011", 31.98F));

    // return a view which will be resolved by an excel view resolver
    return new ModelAndView(new ExcelBuilder(listBooks));
}

抽象自定义视图:

public abstract class AbstractPOIExcelView extends AbstractView {

private static final String CONTENT_TYPE_XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

public AbstractPOIExcelView() {
}

@Override
protected boolean generatesDownloadContent() {
    return true;
}

@Override
protected final void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
        HttpServletResponse response) throws Exception {
    XSSFWorkbook workbook = new XSSFWorkbook();
    buildExcelDocument(model, workbook, request, response);
    ByteArrayOutputStream baos = createTemporaryOutputStream();
    response.setHeader("Content-Disposition", "attachment;filename=filename.xlsx");
    response.setContentType(CONTENT_TYPE_XLSX);
    workbook.write(baos);

    writeToResponse(response, baos);

}

protected abstract void buildExcelDocument(Map<String, Object> model, XSSFWorkbook workbook,
        HttpServletRequest request, HttpServletResponse response) throws Exception;

}

ExcelBuilder:

public class ExcelBuilder extends AbstractPOIExcelView {

private List<Book> listBooks;

public ExcelBuilder(List<Book> books) {
    this.listBooks = books;
}

@Override
protected void buildExcelDocument(Map<String, Object> model, XSSFWorkbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception {
    Sheet sheet = workbook.createSheet("Java Books");
    sheet.setDefaultColumnWidth(30);

    Row header = sheet.createRow(0);
    header.createCell(0).setCellValue("Book Title");
    header.createCell(1).setCellValue("Author");
    header.createCell(2).setCellValue("ISBN");
    header.createCell(3).setCellValue("Published Date");
    header.createCell(4).setCellValue("Price");

    // create data rows
    int rowCount = 1;

    for (Book aBook : listBooks) {
        Row aRow = sheet.createRow(rowCount++);
        aRow.createCell(0).setCellValue(aBook.getTitle());
        aRow.createCell(1).setCellValue(aBook.getAuthor());
        aRow.createCell(2).setCellValue(aBook.getIsbn());
        aRow.createCell(3).setCellValue(aBook.getPublishedDate());
        aRow.createCell(4).setCellValue(aBook.getPrice());
    }
}
}

响应标头:

 Cache-Control:private, must-revalidate
 Content-Disposition:attachment;filename="filename.xlsx"
 Content-Language:de-DE
 Content-Length:3778
 Content-Type:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=ISO-8859-1
 Date:Wed, 19 Nov 2014 12:52:05 GMT
 Expires:Thu, 01 Jan 1970 00:00:00 GMT
 Pragma:private
 Set-Cookie:JSESSIONID=07F50FF2B63D4003311DE222782C4E89; Path=/abc/; HttpOnly
 X-Content-Type-Options:nosniff
 X-Frame-Options:DENY
 X-XSS-Protection:1; mode=block

当这是二进制数据时,将设置字符集让我感到困惑。会不会是这个问题?

【问题讨论】:

    标签: java excel spring spring-mvc


    【解决方案1】:

    我建议使用现有的解决方案,而不是尝试自己处理响应流。

    我会使用AbstractExcelView 而不是您的AbstractPOIExcelView 来完成这项工作。检查this tutorial using AbstractExcelView 以获得灵感。

    对于 Spring 4.2 或更高版本,请使用 AbstractXlsView(或 AbstractXlsxView),因为不推荐使用原始的 AbstractExcelView

    【讨论】:

      【解决方案2】:

      不返回 ModelAndView 而只是将 excel 文件写入响应的 outputStream

      @RequestMapping(value = "/download", method = RequestMethod.GET)
      @ResponseBody
      public Object downloadExcel(HttpServletResponse response) {
              response.setContentType("application/vnd.ms-excel");
              response.setHeader("Content-disposition",
                      "attachment; filename=" + theFileNameString + ".xls");
              try {
                  generateExcel(response.getOutputStream());
              } catch (IOException e) {
                  System.out.println("ERROR: " + e);
              }
          return null;
      }
      

      检查所有已刷新/关闭的流

      【讨论】:

      • 感谢您的回答,StanislavL。我完全按照您发布的方式尝试了您的解决方案,它产生了相同的结果。无法使用 Excel 2010 打开该文件。响应标头看起来也很相似。
      猜你喜欢
      • 1970-01-01
      • 2021-02-15
      • 1970-01-01
      • 2017-09-13
      • 1970-01-01
      • 1970-01-01
      • 2012-02-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多