📚 目录(点击跳转对应章节)
1. 什么是Apache POI
2. Apache POI的在实际工作中的用途
3. 如何使用Apache POI(springboot项目)
4. 苍穹外卖项目中的实际使用
1. 什么是Apache POI {#1-什么是apache-poi}
Apache POI是Apache软件基金会的一套完整的开源java类库,用于操作Microsoft Office文件。
2. Apache POI的在实际工作中的用途 {#2-apache-poi的在实际工作中的用途}
2.1 银行导出交易明细 {#21-银行导出交易明细}
2.2 各种业务系统导出Excel报表 {#22-各种业务系统导出excel报表}
2.3 批量导入业务系统数据 {#23-批量导入业务系统数据}
3. 如何使用Apache POI(springboot项目) {#3-如何使用apache-poispringboot项目}
3.1 添加依赖 {#31-添加依赖}
<!-- poi --><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId></dependency>
3.2 读写excel示例{#32-读写excel示例}
3.2.1 写 {#321-写}
packagecom.sky.test;importorg.apache.poi.xssf.usermodel.XSSFCell;importorg.apache.poi.xssf.usermodel.XSSFRow;importorg.apache.poi.xssf.usermodel.XSSFSheet;importorg.apache.poi.xssf.usermodel.XSSFWorkbook;importjava.io.File;importjava.io.FileInputStream;importjava.io.FileOutputStream;publicclassPOITest{/** * 基于POI向Excel文件写入数据 * @throws Exception */publicstaticvoidwrite()throwsException{//在内存中创建一个Excel文件对象XSSFWorkbookexcel=newXSSFWorkbook();//创建Sheet页XSSFSheetsheet=excel.createSheet("itcast");//在Sheet页中创建行,0表示第1行XSSFRowrow1=sheet.createRow(0);//创建单元格并在单元格中设置值,单元格编号也是从0开始,1表示第2个单元格row1.createCell(1).setCellValue("姓名");row1.createCell(2).setCellValue("城市");XSSFRowrow2=sheet.createRow(1);row2.createCell(1).setCellValue("张三");row2.createCell(2).setCellValue("北京");XSSFRowrow3=sheet.createRow(2);row3.createCell(1).setCellValue("李四");row3.createCell(2).setCellValue("上海");FileOutputStreamout=newFileOutputStream(newFile("D:\\itcast.xlsx"));//通过输出流将内存中的Excel文件写入到磁盘上excel.write(out);//关闭资源out.flush();out.close();excel.close();}publicstaticvoidmain(String[]args)throwsException{write();}}效果如下:
3.2.2 读 {#322-读}
packagecom.sky.test;importorg.apache.poi.xssf.usermodel.XSSFCell;importorg.apache.poi.xssf.usermodel.XSSFRow;importorg.apache.poi.xssf.usermodel.XSSFSheet;importorg.apache.poi.xssf.usermodel.XSSFWorkbook;importjava.io.File;importjava.io.FileInputStream;importjava.io.FileOutputStream;publicclassPOITest{/** * 基于POI读取Excel文件 * @throws Exception */publicstaticvoidread()throwsException{FileInputStreamin=newFileInputStream(newFile("D:\\itcast.xlsx"));//通过输入流读取指定的Excel文件XSSFWorkbookexcel=newXSSFWorkbook(in);//获取Excel文件的第1个Sheet页XSSFSheetsheet=excel.getSheetAt(0);//获取Sheet页中的最后一行的行号intlastRowNum=sheet.getLastRowNum();for(inti=0;i<=lastRowNum;i++){//获取Sheet页中的行XSSFRowtitleRow=sheet.getRow(i);//获取行的第2个单元格XSSFCellcell1=titleRow.getCell(1);//获取单元格中的文本内容StringcellValue1=cell1.getStringCellValue();//获取行的第3个单元格XSSFCellcell2=titleRow.getCell(2);//获取单元格中的文本内容StringcellValue2=cell2.getStringCellValue();System.out.println(cellValue1+" "+cellValue2);}//关闭资源in.close();excel.close();}publicstaticvoidmain(String[]args)throwsException{read();}}效果如下:
4. 苍穹外卖项目中的实际使用 {#4-苍穹外卖项目中的实际使用}
前置准备:
- 在如图所示的位置导入模板excel文件
路径:sky-take-out\sky-server\src\main\resources\template
实际代码:
- 课程中代码:
//controller层/** * 导出运营数据报表 * @param response */@GetMapping("/export")@ApiOperation("导出运营数据报表")publicvoidexport(HttpServletResponseresponse){reportService.exportBusinessData(response);}//service层/** * 导出近30天的运营数据报表 * @param response **/voidexportBusinessData(HttpServletResponseresponse);//serviceImpl层/**导出近30天的运营数据报表 * @param response **/publicvoidexportBusinessData(HttpServletResponseresponse){LocalDatebegin=LocalDate.now().minusDays(30);LocalDateend=LocalDate.now().minusDays(1);//查询概览运营数据,提供给Excel模板文件BusinessDataVObusinessData=workspaceService.getBusinessData(LocalDateTime.of(begin,LocalTime.MIN),LocalDateTime.of(end,LocalTime.MAX));InputStreaminputStream=this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");try{//基于提供好的模板文件创建一个新的Excel表格对象XSSFWorkbookexcel=newXSSFWorkbook(inputStream);//获得Excel文件中的一个Sheet页XSSFSheetsheet=excel.getSheet("Sheet1");sheet.getRow(1).getCell(1).setCellValue(begin+"至"+end);//获得第4行XSSFRowrow=sheet.getRow(3);//获取单元格row.getCell(2).setCellValue(businessData.getTurnover());row.getCell(4).setCellValue(businessData.getOrderCompletionRate());row.getCell(6).setCellValue(businessData.getNewUsers());row=sheet.getRow(4);row.getCell(2).setCellValue(businessData.getValidOrderCount());row.getCell(4).setCellValue(businessData.getUnitPrice());for(inti=0;i<30;i++){LocalDatedate=begin.plusDays(i);//准备明细数据businessData=workspaceService.getBusinessData(LocalDateTime.of(date,LocalTime.MIN),LocalDateTime.of(date,LocalTime.MAX));row=sheet.getRow(7+i);row.getCell(1).setCellValue(date.toString());row.getCell(2).setCellValue(businessData.getTurnover());row.getCell(3).setCellValue(businessData.getValidOrderCount());row.getCell(4).setCellValue(businessData.getOrderCompletionRate());row.getCell(5).setCellValue(businessData.getUnitPrice());row.getCell(6).setCellValue(businessData.getNewUsers());}//通过输出流将文件下载到客户端浏览器中ServletOutputStreamout=response.getOutputStream();excel.write(out);//关闭资源out.flush();out.close();excel.close();}catch(IOExceptione){e.printStackTrace();}}- 本人优化后的impl层代码:
/** * 导出近三十天的营业额数据 * @param response */@OverridepublicvoidexportBusinessData(HttpServletResponseresponse)throwsIOException{LocalDatebegin=LocalDate.now().minusDays(30);LocalDateend=LocalDate.now().minusDays(1);//查询概览运营数据,提供给Excel模板文件BusinessDataVObusinessData=workspaceService.getBusinessData(LocalDateTime.of(begin,LocalTime.MIN),LocalDateTime.of(end,LocalTime.MAX));InputStreaminputStream=this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");// 添加详细的错误信息,帮助定位问题if(inputStream==null){thrownewIOException("无法找到Excel模板文件: template/运营数据报表模板.xlsx,请确认文件是否存在!"+"请在sky-server/src/main/resources/template/目录下放置名为'运营数据报表模板.xlsx'的Excel模板文件。");}//基于提供好的模板文件创建一个Excel表格对象XSSFWorkbookexcel=newXSSFWorkbook(inputStream);//获取Excel文件中第一个sheet页XSSFSheetsheet=excel.getSheet("Sheet1");//设置报表标题和时间范围XSSFRowtitleRow=sheet.getRow(1);titleRow.getCell(1).setCellValue("运营数据统计报表("+begin+"至"+end+")");//填充汇总数据XSSFRowsummaryRow=sheet.getRow(3);//设置汇总行标题summaryRow.getCell(1).setCellValue("总营业额(元)");summaryRow.getCell(3).setCellValue("订单完成率(%)");summaryRow.getCell(5).setCellValue("新增用户数");//填充汇总数据值summaryRow.getCell(2).setCellValue(businessData.getTurnover());summaryRow.getCell(4).setCellValue(businessData.getOrderCompletionRate()*100);//转换为百分比summaryRow.getCell(6).setCellValue(businessData.getNewUsers());//创建表头行XSSFRowheaderRow=sheet.getRow(5);//设置各列标题String[]headers={"日期","营业额(元)","有效订单数","订单完成率(%)","平均客单价(元)","新增用户数"};for(inti=0;i<headers.length;i++){headerRow.getCell(i+1).setCellValue(headers[i]);}//填充详细数据for(inti=0;i<30;i++){LocalDatedate=begin.plusDays(i);//准备明细数据businessData=workspaceService.getBusinessData(LocalDateTime.of(date,LocalTime.MIN),LocalDateTime.of(date,LocalTime.MAX));XSSFRowdetailRow=sheet.getRow(6+i);// 日期detailRow.getCell(1).setCellValue(date.toString());// 营业额detailRow.getCell(2).setCellValue(businessData.getTurnover());// 有效订单数detailRow.getCell(3).setCellValue(businessData.getValidOrderCount());// 订单完成率detailRow.getCell(4).setCellValue(businessData.getOrderCompletionRate()*100);//转换为百分比// 平均客单价detailRow.getCell(5).setCellValue(businessData.getUnitPrice());// 新用户数detailRow.getCell(6).setCellValue(businessData.getNewUsers());}//通过输出流将文件下载到客户端浏览器中ServletOutputStreamout=response.getOutputStream();excel.write(out);//关闭资源out.flush();out.close();excel.close();}- 与原版的区别
优化版代码相对于课程原版代码的主要区别和改进点如下:
异常处理与资源检查:增加了对模板文件输入流的空值检查(
if (inputStream == null),并抛出详细的IOException异常信息,明确提示文件路径和放置位置,便于调试和定位"模板文件找不到"的常见问题。原版无此检查,容易导致空指针异常。报表标题更丰富:原版仅设置时间范围(如"begin 至 end"),优化版改为"运营数据统计报表(begin至end)",标题更完整、专业,提升报表可读性。
汇总数据行优化:
- 明确设置汇总行的标题(如"总营业额(元)"、“订单完成率(%)”、“新增用户数”),原版直接填充值而无标题说明。
- 订单完成率转换为百分比显示(
* 100),更符合实际报表习惯(原版保持小数形式)。
明细数据表头动态设置:原版假设模板中明细表头已预设好,直接从第7行开始填充数据。优化版新增代码在第5行(或对应行)动态设置详细表头数组(“日期”、"营业额(元)"等),使报表更清晰、灵活,即使模板表头不完整也能正确显示。
数据填充位置调整:明细数据从第6行开始填充(对应30天数据),并调整了汇总行和表头的行号/列号,使布局更规范(原版从第7行开始,汇总在第3-4行)。
代码结构与可读性:使用了更多注释、变量命名更清晰(如
titleRow、summaryRow、headerRow、detailRow),并将表头设置为数组循环填充,代码更易维护和扩展。
总体而言,优化版更注重健壮性(错误提示)、用户体验(百分比、标题清晰)和灵活性(动态表头),生成的Excel报表更专业、美观,适合实际生产环境使用。
- 最终实现的效果: