前言:
今天写Day12的内容。也是最后一天的课程内容。
今日所学:
- Apache POI
- 导出运营数据Excel报表
1. Apache POI
1.1 介绍
Apache POI(Poor Obfuscation Implementation的递归缩写)是一个开源的Java API,用于处理Microsoft Office格式文件。它允许Java程序读取、写入和操作Microsoft Office文档,包括Excel、Word和PowerPoint文件。
一句话总结:
Apache POI是一个用于读写Microsoft Office格式文件(如Excel、Word、PPT)的Java开源库。
1.2 如何在Java项目中使用
这里以读写excel表格为例
1.2.1. 引入相关的依赖
先是基础依赖
另外还有excel支持依赖
1.2.2. 对excel表格进行读写操作
导入相应的坐标就可以对excel表格进行读写操作了
这里我们先讲写操作
1. 内存中创建一个Excel文件
2.在excel文件中创建一个sheet页
3.在sheet页中指定行,并且给指定行的指定单元格赋值(这里注意行和单元格的索引都是从零开始的,也就是零是第一行)
4.通过数据流fileout将excel表格写入到磁盘,并关闭相应操作
具体代码
/** * 通过POI去写Excel文件 * @throws IOException */ public static void write() throws IOException { // 在内存张创建一个Excel文件 XSSFWorkbook workbook = new XSSFWorkbook(); // 在excel文件中创建一个sheet页 XSSFSheet sheet = workbook.createSheet("info"); // sheet中创建对象,Row编号从零开始 XSSFRow row = sheet.createRow(0); row.createCell(0).setCellValue("姓名"); row.createCell(1).setCellValue("城市"); row = sheet.createRow(1); row.createCell(0).setCellValue("张三"); row.createCell(1).setCellValue("南京"); row = sheet.createRow(2); row.createCell(0).setCellValue("李四"); row.createCell(1).setCellValue("芜湖"); // 通过数据流将内存中的ECcel文件给它写入到磁盘 FileOutputStream fileOut = new FileOutputStream("D:\\ExcelData\\info.xlsx"); workbook.write(fileOut); fileOut.close(); workbook.close(); } public static void main(String[] args) throws Exception { //read(); write(); }
接下来是读操作
1. 通过输入流传入相应的文件给excel对象
2.获得想读取数据的那一页sheet,并获得载有数据的最后一行
3. 从第一行开始遍历row,获得每一行的数据并输出
4.关闭相应操作
具体代码:
/** * 通过POI去读取Excel文件 * @throws IOException */ public static void read() throws IOException { // 创建excel对象,找到相应的excel表格 FileInputStream fileIn = new FileInputStream("D:\\ExcelData\\info.xlsx"); XSSFWorkbook workbook = new XSSFWorkbook(fileIn); XSSFSheet sheet = workbook.getSheetAt(0); // 获得最后一行 int lastRowNum = sheet.getLastRowNum(); // 遍历 for (int i = 0; i <= lastRowNum; i++) { XSSFRow row = sheet.getRow(i); if (row != null) { String stringCellValue = row.getCell(0).getStringCellValue(); String stringCellValue1 = row.getCell(1).getStringCellValue(); System.out.println(stringCellValue + " " + stringCellValue1); } } fileIn.close(); workbook.close(); } public static void main(String[] args) throws Exception { read(); // write(); }
运行效果:
2.导出运营数据Excel报表
需求分析:
业务规则:
- 导出Excel形式的报表文件
- 导出最近30天的运营数据
- 导出最近30天每日的明细数据
需要注意的是这个接口功能不传入和返回任何数据
代码展示:
admin包下的ReportController类下(Controller层)写入以下代码:
/** * 导出运营数据报表 * @param response * @return */ @GetMapping("/export") @ApiOperation("导出运营数据报表") public void export(HttpServletResponse response){ reportService.exportBusinessData(response); }
要注意的是虽然接口不传入任何参数,但是我们可以传入一个httpServletResponse用于将excel文件下载到客户端浏览器
service层:
具体的代码逻辑:
1. 将时间回溯到30天前,查看30天前到现在的营业数据(营业额,订单完成率,新增用户数,有效订单,平均客单价,这些都是封装到BusinessDataVo的数据)
2. 通过POI写入到Excel文件中(填充概览数据->30天的总数据)
先是通过输入流传入相应的文件给excel对象(这边输入流加载文件用的是类加载器),调用workspaceService.getBusinessData方法,最后获取sheet->row->填充相应的ceil单元格
3.通过POI写入到Excel文件中(填充明细数据->30天内每天的数据)
在前一步excel对象的基础上,for循环得到30天内每天的日期,将其依次调用workspaceService.getBusinessData方法,获取sheet->row->填充相应的ceik单元格
4.通过输出流将Excel文件下载到相应的客户端浏览器
5.关闭相应资源
/** * 导出运营数据报表 * @param response */ @Override public void exportBusinessData(HttpServletResponse response) { // 1, 查询数据库,获取营业数据 ... 查询30天的运营数据 // 前面30天 LocalDate begin = LocalDate.now().minusDays(30); LocalDate end = LocalDate.now().minusDays(1); LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN); LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX); BusinessDataVO businessData = workspaceService.getBusinessData(beginTime, endTime); // 2.通过POI写入到Excel文件中 InputStream in = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx"); try { // 基于模板文件创建一个新的Excel文件 XSSFWorkbook workbook = new XSSFWorkbook(in); // 获取表格的sheet页面 XSSFSheet sheet = workbook.getSheetAt(0); // 填充数据--时间 sheet.getRow(1).getCell(1).setCellValue("时间" + beginTime + "至" + endTime); // 获得第4行 XSSFRow row = sheet.getRow(3); row.getCell(2).setCellValue(businessData.getTurnover()); row.getCell(4).setCellValue(businessData.getOrderCompletionRate()); row.getCell(6).setCellValue(businessData.getNewUsers()); // 获得第5行 XSSFRow row1 = sheet.getRow(4); row1.getCell(2).setCellValue(businessData.getValidOrderCount()); row1.getCell(4).setCellValue(businessData.getUnitPrice()); // 填充我们的明细数据 for (int i = 0; i < 30; i++) { begin = begin.plusDays(i); BusinessDataVO businessDataVO = workspaceService.getBusinessData(LocalDateTime.of(begin, LocalTime.MIN), LocalDateTime.of(begin, LocalTime.MAX)); // 接收每一行的数据 XSSFRow row2 = sheet.getRow(7 + i); // 获取单元格 row2.getCell(1).setCellValue(begin.toString()); row2.getCell(2).setCellValue(businessDataVO.getTurnover()); row2.getCell(3).setCellValue(businessDataVO.getValidOrderCount()); row2.getCell(4).setCellValue(businessDataVO.getOrderCompletionRate()); row2.getCell(5).setCellValue(businessDataVO.getUnitPrice()); row2.getCell(6).setCellValue(businessDataVO.getNewUsers()); } // 3.通过输出流将Excel文件下载到客户端浏览器 ServletOutputStream outputStream = response.getOutputStream(); workbook.write(outputStream); // 关闭资源 outputStream.flush(); outputStream.close(); workbook.close(); }catch (Exception e) { e.printStackTrace(); } }
这里都是调用写好的方法,所以没有用到mapper层
问题:
1.在Controller层我将result.success()作为了返回数据
导致生成的excel文件是这样的
2.在关闭输出流outputStream时,没有使用flush强制将缓冲区的数据写入目标
导致生成的excel文件是空的
最后:
今天的分享就到这里。如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!(๑`・ᴗ・´๑)