无法使用Spring Boot和Apache POI正确生成Excel文件

时间:2019-03-13 18:48:51

标签: excel spring-boot spring-mvc apache-poi thymeleaf

我有一个非常基本的基于SpringBootThymeleaf的应用程序,并与Oracle DB绑定。

我的应用程序当前正在读取一个表,并通过ControllerThymeleaf UI模板将其显示在页面上。我在此表底部还有一个链接,上面写着"Export to Excel",该链接调用服务层中的方法,并成功生成甚至下载该.XLS文档。

但是,问题是生成的excel是页面上内容的精确副本(右侧有一些额外的空列),即使我通过编写代码手动创建了工作表也添加了额外的列,另一个标题。

不确定为什么我的代码没有被调用,为什么我的HTML表数据只是按原样导出到excel工作表中。

ExcelReportController.java

@Controller
@Log4j2
public class ExcelReportController {

    private static final String EXCEL_FILE_NAME = "applications.xls";
    @Autowired
    private LinkApplService linkApplService;

    @GetMapping("/excel")
    public ModelAndView showPage() {
        return new ModelAndView("applications", "linkAppls", linkApplService.getAllLinkAppls());
    }

    @GetMapping("/download")
    public ModelAndView download(HttpServletResponse response) {
        response.setHeader("Content-disposition", "attachment; filename=" + EXCEL_FILE_NAME);
        return new ModelAndView("applications", "linkAppls", linkApplService.getAllLinkAppls());
    }

}

ExcelBuilderService.java

@Service
public class ExcelBuilderService extends AbstractXlsView {

    @Override
    protected void buildExcelDocument(Map<String, Object> model, Workbook workbook, HttpServletRequest request,
                                      HttpServletResponse response) {
        Iterable<LinkAppl> linkAppls = (Iterable<LinkAppl>) model.get("linkAppls");
        //THIS SHEET WITH TITLE NOT GETTING SHOWN
        Sheet sheet = workbook.createSheet("All Applications List");
        Row header = sheet.createRow(0);
        header.createCell(0).setCellValue("ID");
        header.createCell(1).setCellValue("DESC");
        header.createCell(2).setCellValue("DESC");
        header.createCell(3).setCellValue("LINK_NOTES"); //THIS COLUMN NOT GETTING DISPLAYED
        int rowNum = 1;
        for (LinkAppl la : linkAppls) {
            Row row = sheet.createRow(rowNum++);
            row.createCell(0).setCellValue(la.getApplId());
            row.createCell(1).setCellValue(la.getApplDeTx());
            row.createCell(2).setCellValue(la.getApplActvCd());
            row.createCell(3).setCellValue(la.getLinkNotesTx());
        }
    }

}

LinkAppl.java

@Entity
@Table(name = "LINK_APPL")
public class LinkAppl {
    private String applId;
    private String applDeTx;
    private String seqNbResetCd;
    private String intfMsgFrmtCd;
    private String sndRcvCd;
    private String applAcptMsgFrmtCd;
    private String applActvCd;
    private String sodEodIn;
    private String linkNotesTx;
    private String lastModByUsrId;
    private Timestamp lastModTs;
    private String sndCnctStsCd;
    private Long maxSeqNb;
    private String batIntfIn;
    private String gfpSrcSiteCd;
    private String rcvRterAckmentIn;
    private String rcvMqCodIn;
    private String fxApplIn;
    private String rcvEodpAckmentIn;

    //getters and setters go here

}

applications.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="x-ua-compatible" content="ie=edge">
        <title>Link Statistics Report</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>
        <h4>Excel Generation Demo</h4>
        <table border="1">
            <thead>
                <tr>
                    <td>App ID</td>
                    <td>Name</td>
                    <td>Active</td>
                </tr>
            </thead>
            <tbody>
                <tr th:each="a : ${linkAppls}">
                    <td th:text="${a.applId}">App ID</td>
                    <td th:text="${a.getApplDeTx()}">Description</td>
                    <td th:text="${a.applActvCd}">Active</td>
                </tr>
            </tbody>
            <tfoot>
                <tr>
                    <td colspan="7">
                        <a href="/download">Export to Excel</a>
                    </td>
                </tr>
            </tfoot>
        </table>
    </body>
</html>

pom.xml

<!-- for handling .xls files (older format) -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.0.1</version>
</dependency>
<!-- for handling .xlsx files (newer format) -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.0.1</version>
</dependency>

enter image description here

2 个答案:

答案 0 :(得分:1)

控制器中的两个ModelAndView完全相同。

return new ModelAndView("applications", "linkAppls", linkApplService.getAllLinkAppls());

在下载控制器中完全相同:

return new ModelAndView("applications", "linkAppls", linkApplService.getAllLinkAppls());

设置content-disposition不会改变spring处理请求的方式,如果您在文本编辑器中打开applications.xls,您会发现您刚刚下载了html页面重命名为.xls文件。您需要弄清楚如何正确连接并使用您创建的AbstractXlsView


下载文件:

@GetMapping("/download")
public void download(HttpServletResponse response) throws Exception {
    Iterable<LinkAppl> linkAppls = linkApplService.getAllLinkAppls();

    Workbook workbook = new HSSFWorkbook();
    Sheet sheet = workbook.createSheet("All Applications List");
    Row header = sheet.createRow(0);
    header.createCell(0).setCellValue("ID");
    header.createCell(1).setCellValue("DESC");
    header.createCell(2).setCellValue("DESC");
    header.createCell(3).setCellValue("LINK_NOTES");
    int rowNum = 1;
    for (LinkAppl la : linkAppls) {
        Row row = sheet.createRow(rowNum++);
        row.createCell(0).setCellValue(la.getApplId());
        row.createCell(1).setCellValue(la.getApplDeTx());
        row.createCell(2).setCellValue(la.getApplActvCd());
        row.createCell(3).setCellValue(la.getLinkNotesTx());
    }

    response.setHeader("Content-disposition", "attachment; filename=" + EXCEL_FILE_NAME);
    workbook.write(response.getOutputStream());
}

答案 1 :(得分:0)

因此,在@Metroids的大力帮助下,我终于能够通过控制器下载Excel文件。我还尝试下载src / main / resources文件夹中的现有文件。这是用于更好理解的源代码。

applications.html

 <a href="/download">Export to Excel</a>&nbsp;
 <a href="/buildNDownload">Export to Excel 2</a>

ExcelReportController.java

@Controller
@Log4j2
public class ExcelReportController {

    private static final String EXCEL_FILE_NAME = "applications.xls";
    @Autowired
    private LinkApplService linkApplService;

    @GetMapping("/excel")
    public ModelAndView showPage() {
        return new ModelAndView("applications", "linkAppls", linkApplService.getAllLinkAppls());
    }

    @GetMapping(value = "/download")
    public void download(HttpServletResponse response) {
        response.addHeader("Content-Disposition", "attachment; filename=" + EXCEL_FILE_NAME);
        try {
            //download an existing file located in src/main/resources folder
            File file = ResourceUtils.getFile("classpath:" + EXCEL_FILE_NAME);
            InputStream inputStream = new FileInputStream(file);
            IOUtils.copy(inputStream, response.getOutputStream());
            response.flushBuffer();
            inputStream.close();
        } catch (IOException e) {
            log.error("Error while locating file", e);
        }
    }

    @GetMapping(value = "/buildNDownload")
    public void buildNDownload(HttpServletResponse response) throws IOException {
        response.setHeader("Content-disposition", "attachment; filename=applications_new.xlsx");
        Iterable<LinkAppl> linkAppls = linkApplService.getAllLinkAppls();
        //build a file from scratch and then download
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("All Applications List");
        Row header = sheet.createRow(0);
        header.createCell(0).setCellValue("ID");
        header.createCell(1).setCellValue("DESC");
        header.createCell(2).setCellValue("ACTIVE");
        header.createCell(3).setCellValue("LINK_NOTES");
        int rowNum = 1;
        for (LinkAppl la : linkAppls) {
            Row row = sheet.createRow(rowNum++);
            row.createCell(0).setCellValue(la.getApplId());
            row.createCell(1).setCellValue(la.getApplDeTx());
            row.createCell(2).setCellValue(la.getApplActvCd());
            row.createCell(3).setCellValue(la.getLinkNotesTx());
        }
        workbook.write(response.getOutputStream());
    }

}

pom.xml

<!-- for handling .xls files (older format) -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.0.1</version>
</dependency>
<!-- for handling .xlsx files (newer format) -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.0.1</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>