SpringBoot学习小结之EasyExcel

前言

java处理excel表格常用的框架库有: jxlPOI, EasyExcelEasyPoi, hutool

  • jxl , 韩国人开发的一套解析excel Java库,不支持xlsx。09年后一直没有更新,功能比较少。
  • POI,apache提供的一套java解析office工具,包含excel。我之前有一篇博文介绍了一些POI中关于Excel API使用
  • EasyExcel,阿里开源的JAVA解析Excel工具,对于POI解析耗内存进行了优化
  • EasyPoi,对POI进行封装的一套工具库,简化POI代码编写
  • hutool,国人开发的工具库,其中包含excel的读写

最主要还是POI, 后三个都依赖于它。由于工作中项目重点使用阿里的EasyExcel,以下重点介绍EasyExcel

一、EasyExcel

以一个进销存表格为例子,演示EasyExcel如何导入导出Excel。下面是Excel模板实体,需要先导入pom依赖

@Data
public class InventoryItem {

    @ExcelIgnore
    private Integer id;
    @ExcelProperty(index = 0, value = {"序号", "序号"})
    private String no;
    @ExcelProperty(index = 1, value = { "商品名称","商品名称"})
    private String productName;
    @ExcelProperty(index = 2, value = {"规格", "规格"})
    private String spec;
    @ExcelProperty(index = 3, value = {"单位", "单位"})
    private String unit;

    @ExcelProperty(index = 4, value = {"上月结存","数量"})
    private String lastMonthStoreNum;
    @ExcelProperty(index = 5, value = {"上月结存","单价"})
    private String lastMonthStoreUnitPrice;
    @ExcelProperty(index = 6, value = {"上月结存","金额"})
    private String lastMonthStoreMount;

    @ExcelProperty(index = 7, value = {"本月购入","数量"})
    private String thisMonthPurchaseNum;
    @ExcelProperty(index = 8, value = {"本月购入","单价"})
    private String thisMonthPurchaseUnitPrice;
    @ExcelProperty(index = 9, value = {"本月购入","金额"})
    private String thisMonthPurchaseMount;

    @ExcelProperty(index = 10, value = {"本月发出","数量"})
    private String thisMonthSendNum;
    @ExcelProperty(index = 11, value = {"本月发出","单价"})
    private String thisMonthSendUnitPrice;
    @ExcelProperty(index = 12, value = {"本月发出","金额"})
    private String thisMontSendhMount;

    @ExcelProperty(index = 13, value = {"本月结存","数量"})
    private String thisMonthStoreNum;
    @ExcelProperty(index = 14, value = {"本月结存","单价"})
    private String thisMonthStoreUnitPrice;
    @ExcelProperty(index = 15, value = {"本月结存","金额"})
    private String thisMonthStoreMount;

    @ExcelProperty(index = 16, value = {"月末盘点数量", "月末盘点数量"})
    private String endOfMonthCheckNum;
    @ExcelProperty(index = 17, value = {"差额", "差额"})
    private String diff;
}

1.1 pom依赖

        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>easyexcelartifactId>
            <version>2.2.3version>
        dependency>

1.2 导入

  • 读取Excel需要设置监听器

    public class InventoryItemAnalysis extends AnalysisEventListener<InventoryItem> {
    
        List<InventoryItem> list = new ArrayList<>();
        @Override
        public void invoke(InventoryItem data, AnalysisContext context) {
            list.add(data);
        }
    
        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
        }
    
        public List<InventoryItem> getList() {
            return list;
        }
    
        public void setOtnList(List<InventoryItem> list) {
            this.list = list;
        }
    }
    
  • 本地环境可以根据文件路径读取

    
    InventoryItemAnalysis analysis = new InventoryItemAnalysis();
    EasyExcel.read("C:\\Users\\root\\Desktop\\进销存.xlsx", InventoryItem.class, analysis ).sheet().doRead();
    System.out.println(analysis.getList());
    
  • 在web环境下可以用流读取

    @PostMapping("/upload")
    @ResponseBody
    public Object excelImport(@RequestParam("uploadFile") MultipartFile file
                ) throws Exception {
    	InventoryItemAnalysis analysis = new InventoryItemAnalysis();
    	EasyExcel.read(file.getInputStream(), InventoryItem.class, analysis).sheet().doRead();
    	return analysis.getList();
    }
    
    

1.3 导出

  • 本地导出

    EasyExcel.write("C:\\Users\\root\\Desktop\\进销存导出.xlsx", InventoryItem.class).sheet().doWrite(analysis.getList());
    
  • web导出

    @GetMapping("/download")
    public void download(HttpServletResponse response) {
    	String fileName = "进销存数据.xlsx";
    	List<InventoryItem> list = new ArrayList<>();
    	setResponseHeader(response, fileName);
    	try {
    	EasyExcel.write(response.getOutputStream(), InventoryItem.class)
    	                    .sheet("总表").doWrite(list);
    	} catch (IOException e) {
    	e.printStackTrace();
    	}
    }
    private void setResponseHeader(HttpServletResponse response, String fileName) {
    	try {
        	response.setContentType("application/octet-stream;charset=ISO8859-1");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName,"UTF-8"));
            response.addHeader("Pargam", "no-cache");
            response.addHeader("Cache-Control", "no-cache");
         } catch (Exception ex) {
                ex.printStackTrace();
        }
    }
    

    SpringBoot学习小结之EasyExcel_第1张图片

1.4 自定义样式或内容

  • EasyExcel默认样式不美观,需要自定义样式。EasyExcel提供一个类HorizontalCellStyleStrategy,可用来配置一些表头和内容样式。

    public static WriteHandler headStyle() {
    		// 头部样式策略
            WriteCellStyle headWriteCellStyle = new WriteCellStyle();
            headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE1.getIndex());
            WriteFont headWriteFont = new WriteFont();
            headWriteFont.setFontHeightInPoints((short) 12);
            headWriteFont.setBold(false);
            headWriteCellStyle.setWriteFont(headWriteFont);
    
            // 内容样式策略
            WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
            contentWriteCellStyle.setWrapped(true);
            contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            // 设置内容边框样式
            contentWriteCellStyle.setBorderLeft(THIN);
            contentWriteCellStyle.setBorderTop(THIN);
            contentWriteCellStyle.setBorderRight(THIN);
            contentWriteCellStyle.setBorderBottom(THIN);
    
            HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle,
                    contentWriteCellStyle);
            return horizontalCellStyleStrategy;
        }
    
  • 更细粒度控制可以通过实现com.alibaba.excel.write.handler.WriteHandler的四个子接口来自定义样式或者内容。注意:多个Handler如果作用在同一个单元格,后面会覆盖前面的样式。

    • com.alibaba.excel.write.handler.CellWriteHandler单元格处理器

      • beforeCellCreate
      • afterCellCreate
      • afterCellDataConverted 一个单元格数据转换后
      • afterCellDispose一个单元格所有操作完成后调用这个方法
    • com.alibaba.excel.write.handler.RowWriteHandler 行处理器

      • beforeRowCreate
      • afterRowCreate
      • afterRowDispose 一行所有操作完成后调用这个方法
    • com.alibaba.excel.write.handler.SheetWriteHandlerSheet处理器

      • beforeSheetCreateSheet
      • afterSheetCreateSheet
    • com.alibaba.excel.write.handler.WorkbookWriteHandler 工作簿处理器

      • beforeWorkbookCreate
      • afterWorkbookCreate
      • afterWorkbookDispose 工作簿所有操作完成后调用这个方法
  • 自定义案例

    • 案例1:在表格表头前添加标题等信息

      public class CustomWriteHandler implements SheetWriteHandler {
      
          @Override
          public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
          }
      
          @Override
          public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
              Workbook workbook = writeWorkbookHolder.getWorkbook();
              Sheet sheet = workbook.getSheetAt(0);
              //设置标题
              Row row1 = sheet.createRow(0);
              row1.setHeight((short) 800);
              Cell cell1 = row1.createCell(0);
              cell1.setCellValue("某某公司进销存报表");
              CellStyle cellStyle = workbook.createCellStyle();
              cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
              cellStyle.setAlignment(HorizontalAlignment.CENTER);
              Font font = workbook.createFont();
              font.setBold(true);
              font.setFontHeight((short) 400);
              cellStyle.setFont(font);
              cell1.setCellStyle(cellStyle);
              sheet.addMergedRegionUnsafe(new CellRangeAddress(0, 0, 0, 17));
              //设置填表日期,填报人,联系方式
              Row row2 = sheet.createRow(1);
              row2.setHeight((short) 500);
              row2.createCell(1).setCellValue("填表日期");
              row2.createCell(11).setCellValue("填表人");
              row2.createCell(15).setCellValue("联系方式");
          }
      }
      
      EasyExcel.write(response.getOutputStream(), InventoryItem.class)
                          .sheet("总表").registerWriteHandler(headStyle())
                          .registerWriteHandler(new CustomWriteHandler())
                          .relativeHeadRowIndex(2).doWrite(list);
      

      最终样式

      SpringBoot学习小结之EasyExcel_第2张图片

  • 案例二:报表标颜色
    进销存中上月库存数量小于10字体变红,否则变绿

     public class ColorWriteHandler implements CellWriteHandler {
    
      @Override
      public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
    
      }
    
      @Override
      public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
    
      }
    
      @Override
      public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
    
      }
    
      @Override
      public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
          if (!isHead) {
              if (cell.getColumnIndex() == 4) {
                  String val = cell.getStringCellValue();
                  int num = 0;
                  try {
                      num = Integer.parseInt(val);
                  } catch (NumberFormatException e) {
                      e.printStackTrace();
                  }
                  if (num > 10) {
                      setColor(cell, writeSheetHolder, IndexedColors.RED);
                  } else {
                      setColor(cell, writeSheetHolder, IndexedColors.GREEN);
                  }
              }
          }
      }
      private void setColor(Cell cell, WriteSheetHolder writeSheetHolder, IndexedColors color) {
          Sheet sheet = writeSheetHolder.getSheet();
          Workbook workbook = sheet.getWorkbook();
          Font font = workbook.createFont();
          font.setColor(color.getIndex());
          CellStyle cellStyle = workbook.createCellStyle();
          cellStyle.setFont(font);
          cellStyle.setBorderTop(BorderStyle.THIN);
          cellStyle.setBorderBottom(BorderStyle.THIN);
          cellStyle.setBorderLeft(BorderStyle.THIN);
          cellStyle.setBorderRight(BorderStyle.THIN);
          cell.setCellStyle(cellStyle);
      }
    }
    
    
    public static void main(String[] args) {
    	        List<InventoryItem> list = data();
    	        EasyExcel.write("C:\\Users\\supre\\Desktop\\进销存导出.xlsx", InventoryItem.class)
    	                .registerWriteHandler(normalStyle())
    	                .registerWriteHandler(new ColorWriteHandler())
    	                .sheet().doWrite(list);
    }
    public static List<InventoryItem> data() {
    	List<InventoryItem> list = new ArrayList<>();
    	for (int i = 0; i < 50; i++) {
    		String s = Integer.valueOf(i).toString();
    		InventoryItem inventoryItem = new InventoryItem();
    		inventoryItem.setId(i);
    		inventoryItem.setNo(s);
    		inventoryItem.setLastMonthStoreNum(s);
    		inventoryItem.setProductName("上衣+" + i);
    		list.add(inventoryItem);
    	}
    	return list;
    }
    public static WriteHandler normalStyle() {
    	        // 头部样式策略
    		WriteCellStyle headWriteCellStyle = new WriteCellStyle();
    	    headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE1.getIndex());
    		WriteFont headWriteFont = new WriteFont();
    		headWriteFont.setFontHeightInPoints((short) 12);
    		headWriteFont.setBold(false);
    		headWriteCellStyle.setWriteFont(headWriteFont);
    	
    		// 内容样式策略
    		WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
    		contentWriteCellStyle.setWrapped(true);
    	    contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
    		// 设置内容边框样式
    		contentWriteCellStyle.setBorderLeft(THIN);
    		contentWriteCellStyle.setBorderTop(THIN);
    		contentWriteCellStyle.setBorderRight(THIN);
    		contentWriteCellStyle.setBorderBottom(THIN);
    	
    		HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle,
    		contentWriteCellStyle);
    		return horizontalCellStyleStrategy;
    }
    

    最终样式
    SpringBoot学习小结之EasyExcel_第3张图片

1.5 模板填充

EasyExcel自2.1.1后提供了更强大的表格填充功能,提供一个模板文件,写一些模板参数,就可以快速生成表格

  • 模板

    将Excel实体类的属性用{.属性名}填入模板文件,样式也会被复制。注意:填充List时需要带个点,如果单个就不需要。

    SpringBoot学习小结之EasyExcel_第4张图片

  • 填充

    EasyExcel.write("C:\\Users\\root\\Desktop\\进销存.xlsx")
                    .withTemplate("C:\\Users\\root\\Desktop\\进销存模板.xlsx").sheet().doFill(analysis.getList());
    

    SpringBoot学习小结之EasyExcel_第5张图片

  • 更复杂的填充

    EasyExcel不仅支持竖向填充,还支持横向填充,多列表填充,详细信息可以查看官方文档

参考

  1. https://www.yuque.com/easyexcel/doc/easyexcel
  2. https://www.yuque.com/easyexcel/doc/fill
  3. https://blog.csdn.net/qq_41514643/article/details/106993760

你可能感兴趣的:(springboot,java,excel,java,easyexcel,poi,writeHandler)