报表数据生成之 Apache POI
介绍
信息:
Apache POI是用Java编写的免费开源的跨平台的Java API,Apache POI提供API给Java程序对Microsoft
Offiffiffice格式档案读和写的功能,其中使用最多的就是使用POI操作Excel文件。
可前往官网一探究竟:
https://poi.apache.org/apidocs/index.html
结构:
- HSSF - 提供读写Microsoft Excel XLS格式档案的功能
- XSSF - 提供读写Microsoft Excel OOXML XLSX格式档案的功能
- HWPF - 提供读写Microsoft Word DOC格式档案的功能
- HSLF - 提供读写Microsoft PowerPoint格式档案的功能
- HDGF - 提供读Microsoft Visio格式档案的功能
- HPBF - 提供读Microsoft Publisher格式档案的功能
- HSMF - 提供读Microsoft Outlook格式档案的功能
maven依赖:
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.14</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.14</version> </dependency>
本文主要用来对Excel进行操作
Excel数据导入
核心对象
- XSSFWorkbook:工作簿
- XSSFSheet:工作表
- Row:行,接口
- XSSFRow:行,实现类。在sheet表中从0开始计数
- Cell:单元格
//遍历工作表获取单元格内容 @Test public void test1() throws IOException { //加载指定文件,创建一个Excel对象 XSSFWorkbook excel = new XSSFWorkbook(new FileInputStream(new File("E:\\aaa\\poi.xlsx"))); //读取Excel文件中第一个sheet标签页 XSSFSheet sheet = excel.getSheetAt(0); //遍历sheet标签页来获得每一行数据 for (Row row : sheet) { //遍历表格中的每一行的每一个单元格,获得单元格数据 for (Cell cell : row) { System.out.println(cell.getStringCellValue()); } } //关闭资源 excel.close(); } //遍历工作表中的有效数据获取单元格内容 @Test public void test2() throws IOException { //加载指定文件,创建一个Excel对象 XSSFWorkbook excel = new XSSFWorkbook(new FileInputStream(new File("E:\\aaa\\poi.xlsx"))); //读取Excel文件中第一个sheet标签页 XSSFSheet sheet = excel.getSheetAt(0); //获得当前工作表中的最后一行的行号,根据行号进行遍历 int lastRowNum = sheet.getLastRowNum(); for (int i = 0; i <= lastRowNum; i++) { XSSFRow row = sheet.getRow(i); short lastCellNum = row.getLastCellNum(); for (int j = 0; j < lastCellNum; j++) { XSSFCell cell = row.getCell(j); System.out.println(cell.getStringCellValue()); } } //关闭资源 excel.close(); }
Excel中导入数据
11
//使用POI向Excel文件中写入数据,并通过输出流将创建的Excel文件保存到磁盘 @Test public void test3() throws Exception{ //在内存中创建一个Excel文件(工作簿) XSSFWorkbook excel = new XSSFWorkbook(); //创建一个工作表对象 XSSFSheet sheet = excel.createSheet("汐海笙歌"); //在工作表中创建行对象 XSSFRow title = sheet.createRow(0); //在行中创建单元格对象 title.createCell(0).setCellValue("姓名"); title.createCell(1).setCellValue("地址"); title.createCell(2).setCellValue("年龄"); XSSFRow dataRow = sheet.createRow(1); dataRow.createCell(0).setCellValue("张三"); dataRow.createCell(1).setCellValue("高安"); dataRow.createCell(2).setCellValue("20"); //创建一个输出流,通过输出流将内存中的文件写入磁盘 FileOutputStream out = new FileOutputStream(new File("E:\\aaa\\hello.xlsx")); excel.write(out); out.flush(); excel.close(); }
web端实战
使用工具类方便对文件的读取和封装
public class POIUtils { private final static String xls = "xls"; private final static String xlsx = "xlsx"; private final static String DATE_FORMAT = "yyyy/MM/dd"; /** * 读入excel文件,解析后返回 * @param file * @throws IOException */ public static List<String[]> readExcel(MultipartFile file) throws IOException { //检查文件 checkFile(file); //获得Workbook工作薄对象 Workbook workbook = getWorkBook(file); //创建返回对象,把每行中的值作为一个数组,所有行作为一个集合返回 List<String[]> list = new ArrayList<String[]>(); if(workbook != null){ for(int sheetNum = 0;sheetNum < workbook.getNumberOfSheets();sheetNum++){ //获得当前sheet工作表 Sheet sheet = workbook.getSheetAt(sheetNum); if(sheet == null){ continue; } //获得当前sheet的开始行 int firstRowNum = sheet.getFirstRowNum(); //获得当前sheet的结束行 int lastRowNum = sheet.getLastRowNum(); //循环除了第一行的所有行 for(int rowNum = firstRowNum+1;rowNum <= lastRowNum;rowNum++){ //获得当前行 Row row = sheet.getRow(rowNum); if(row == null){ continue; } //获得当前行的开始列 int firstCellNum = row.getFirstCellNum(); //获得当前行的列数 int lastCellNum = row.getPhysicalNumberOfCells(); String[] cells = new String[row.getPhysicalNumberOfCells()]; //循环当前行 for(int cellNum = firstCellNum; cellNum < lastCellNum;cellNum++){ Cell cell = row.getCell(cellNum); cells[cellNum] = getCellValue(cell); } list.add(cells); } } workbook.close(); } return list; } //校验文件是否合法 public static void checkFile(MultipartFile file) throws IOException{ //判断文件是否存在 if(null == file){ throw new FileNotFoundException("文件不存在!"); } //获得文件名 String fileName = file.getOriginalFilename(); //判断文件是否是excel文件 if(!fileName.endsWith(xls) && !fileName.endsWith(xlsx)){ throw new IOException(fileName + "不是excel文件"); } } //获取工作簿 public static Workbook getWorkBook(MultipartFile file) { //获得文件名 String fileName = file.getOriginalFilename(); //创建Workbook工作薄对象,表示整个excel Workbook workbook = null; try { //获取excel文件的io流 InputStream is = file.getInputStream(); //根据文件后缀名不同(xls和xlsx)获得不同的Workbook实现类对象 if(fileName.endsWith(xls)){ //2003 workbook = new HSSFWorkbook(is); }else if(fileName.endsWith(xlsx)){ //2007 workbook = new XSSFWorkbook(is); } } catch (IOException e) { e.printStackTrace(); } return workbook; } //获取单元格值 public static String getCellValue(Cell cell){ String cellValue = ""; if(cell == null){ return cellValue; } //如果当前单元格内容为日期类型,需要特殊处理 String dataFormatString = cell.getCellStyle().getDataFormatString(); if(dataFormatString.equals("m/d/yy")){ cellValue = new SimpleDateFormat(DATE_FORMAT).format(cell.getDateCellValue()); return cellValue; } //把数字当成String来读,避免出现1读成1.0的情况 if(cell.getCellType() == NUMERIC){ cell.setCellType(STRING); } //判断数据的类型 switch (cell.getCellType()){ case NUMERIC: //数字 cellValue = String.valueOf(cell.getNumericCellValue()); break; case STRING: //字符串 cellValue = String.valueOf(cell.getStringCellValue()); break; case BOOLEAN: //Boolean cellValue = String.valueOf(cell.getBooleanCellValue()); break; case FORMULA: //公式 cellValue = String.valueOf(cell.getCellFormula()); break; case BLANK: //空值 cellValue = ""; break; case ERROR: //故障 cellValue = "非法字符"; break; default: cellValue = "未知类型"; break; } return cellValue; } }
controller控制层代码
@RequestMapping("ordersetting") public class OrderSettingController { @Autowired private OrderSettingService orderSettingService; //文件上传,实现Excel数据批量导入 @RequestMapping("/upload") public Result upload(@RequestParam("excelFile") MultipartFile excelFile){ try { List<String[]> list = POIUtils.readExcel(excelFile);//使用POI解析表格数据 List<OrderSetting> data = new ArrayList<>(); for (String[] strings : list) { String orderData = strings[0]; String number = strings[1]; //data方式显示已过期,但是还可以用,如有较高要求可使用相关工具类对字符串进行格式转换 OrderSetting orderSetting = new OrderSetting(new Date(orderData),Integer.parseInt(number)); data.add(orderSetting); } //实现数据的批量导入到数据库 orderSettingService.add(data); return new Result(true,MessageConstant.IMPORT_ORDERSETTING_SUCCESS); } catch (IOException e) { e.printStackTrace(); //文件解析失败 return new Result(false, MessageConstant.IMPORT_ORDERSETTING_FAIL); } } }
Service层代码
@Service @Transactional public class OrderSettingServiceImpl implements OrderSettingService { @Autowired private OrderSettingDao orderSettingDao; //批量导入预约设置数据 @Override public void add(List<OrderSetting> list) { if (list != null && list.size() > 0){ for (OrderSetting orderSetting : list) { //判断当前日期是否已经进行了预约设置 long countByOrderDate = orderSettingDao.findCountByOrderDate(orderSetting.getOrderDate()); if (countByOrderDate > 0){ //已经进行了预约设置,执行更新操作 orderSettingDao.editNumberByOrderDate(orderSetting); }else { //没有进行预约设置,执行插入操作 orderSettingDao.add(orderSetting); } } } }
只是一些那数据库插入的语句,此处省略。CRUD也没什么好讲的。
Excel文件下载
//导出运营数据到Excel文件进行下载 @RequestMapping("/exportBusinessReport") public Result exportBusinessReport(HttpServletRequest request, HttpServletResponse response){ Map<String,Object> result = null; try { //查询数据库获取生成Excel中需要展示的数据 result = reportService.getBusinessReportData(); //取出返回结果数据,准备将报表数据写入到Excel文件中 String reportDate = (String) result.get("reportDate"); Integer todayNewMember = (Integer) result.get("todayNewMember"); Integer totalMember = (Integer) result.get("totalMember"); Integer thisWeekNewMember = (Integer) result.get("thisWeekNewMember"); Integer thisMonthNewMember = (Integer) result.get("thisMonthNewMember"); Integer todayOrderNumber = (Integer) result.get("todayOrderNumber"); Integer thisWeekOrderNumber = (Integer) result.get("thisWeekOrderNumber"); Integer thisMonthOrderNumber = (Integer) result.get("thisMonthOrderNumber"); Integer todayVisitsNumber = (Integer) result.get("todayVisitsNumber"); Integer thisWeekVisitsNumber = (Integer) result.get("thisWeekVisitsNumber"); Integer thisMonthVisitsNumber = (Integer) result.get("thisMonthVisitsNumber"); List<Map> hotSetmeal = (List<Map>) result.get("hotSetmeal"); //基于提供的模板文件在内存中创建一个EXCEL表格对象 String filePath = request.getSession().getServletContext().getRealPath("template") + File.separator + "report_template.xlsx"; XSSFWorkbook excel = new XSSFWorkbook(new FileInputStream(new File(filePath))); //读取第一个工作表 XSSFSheet sheet = excel.getSheetAt(0); //获得第三行 XSSFRow row = sheet.getRow(2); XSSFCell cell = row.getCell(5); cell.setCellValue(reportDate);//报表日期 row = sheet.getRow(4); row.getCell(5).setCellValue(todayNewMember);//新增会员数(本日) row.getCell(7).setCellValue(totalMember);//总会员数 row = sheet.getRow(5); row.getCell(5).setCellValue(thisWeekNewMember);//本周新增会员数 row.getCell(7).setCellValue(thisMonthNewMember);//本月新增会员数 row = sheet.getRow(7); row.getCell(5).setCellValue(todayOrderNumber);//今日预约数 row.getCell(7).setCellValue(todayVisitsNumber);//今日到诊数 row = sheet.getRow(8); row.getCell(5).setCellValue(thisWeekOrderNumber);//本周预约数 row.getCell(7).setCellValue(thisWeekVisitsNumber);//本周到诊数 row = sheet.getRow(9); row.getCell(5).setCellValue(thisMonthOrderNumber);//本月预约数 row.getCell(7).setCellValue(thisMonthVisitsNumber);//本月到诊数 int rowNum = 12; for(Map map : hotSetmeal){//热门套餐 String name = (String) map.get("name"); Long setmeal_count = (Long) map.get("setmeal_count"); BigDecimal proportion = (BigDecimal) map.get("proportion"); row = sheet.getRow(rowNum ++); row.getCell(4).setCellValue(name);//套餐名称 row.getCell(5).setCellValue(setmeal_count);//预约数量 row.getCell(6).setCellValue(proportion.doubleValue());//占比 } //使用输出流进行表格下载,基于浏览器作为客户端下载,不能通过new的方式 OutputStream out = response.getOutputStream(); response.setContentType("application/vnd.ms-excel");//代表的就是Excel文件类型 response.setHeader("content-Disposition", "attachment;filename=report.xlsx");//指定以附件的形式下载 excel.write(out); out.flush(); out.close(); excel.close(); return new Result(true,MessageConstant.GET_BUSINESS_REPORT_SUCCESS,result); } catch (Exception e) { e.printStackTrace(); return new Result(false,MessageConstant.GET_BUSINESS_REPORT_FAIL); } }
以上代码你只需要知道,在报表导出时为方便文档的可读性,会在项目目录下添加一个模板文件,格式也是Excel表格的相关格式,你只需要通过查询数据库,在表格的指定位置插入你想要插入的相关信息即可。最重要的是客户端的下载,你需要设置下载格式,在代码中我已经给出了注释,你可以观看,如果你想了解方式更多,请自行百度。
如需将文件下载下来可以查询数据库然后进行Excel创建和下载。我后面会更新一篇使用easyPOI的文章,推荐使用它。