EasyExcel的使用方法

一、导入依赖

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>easyexcel</artifactId>
	<version>2.2.7</version>
</dependency>

二、编写实体类

@Data
public class DemoData {
    @ExcelProperty(value = "学生编号", index = 0)
    private Integer sno;
    @ExcelProperty(value = "学生姓名", index = 1)
    private String sname;
}

三、写入Excel

@Test
public void writeExcel() {
    //实现excel写操作
    // 写法1 JDK8+
    // since: 3.0.0-beta1
    String fileName = "F:\\online-education/student.xlsx";
    // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
    // 如果这里想使用03 则 传入excelType参数即可
    EasyExcel.write(fileName, DemoData.class).sheet("Sheet1").doWrite(getData());
}
private static List<DemoData> getData(){
    List<DemoData> list=new ArrayList<>();
    for (int i=0;i<10;i++){
        DemoData demoData = new DemoData();
        demoData.setSno(i);
        demoData.setSname("liming"+i);
        list.add(demoData);
     }
    return list;
}

四、写入Excel并以流的方式发送给前端并下载

1.编辑响应体参数

	/**
     * 导出
     *
     * @param response
     * @param data
     * @param fileName
     * @param sheetName
     * @param clazz
     * @throws Exception
     */
    public static void writeExcel(HttpServletResponse response, List<? extends Object> data, String fileName, String sheetName, Class clazz) throws Exception {
        //表头样式
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        //设置表头居中对齐
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        //内容样式
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        //设置内容靠左对齐
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
        EasyExcel.write(getOutputStream(fileName, response), clazz).excelType(ExcelTypeEnum.XLSX).sheet(sheetName).registerWriteHandler(horizontalCellStyleStrategy).doWrite(data);
    }
	
	/**
     * 流方式响应给前端
     *
     * @param fileName
     * @param response
     * @return
     * @throws Exception
     */
    private static OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {
        fileName = URLEncoder.encode(fileName, "UTF-8");
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
        response.setStatus(RESPONSE_SUCCESS_CODE);
        return response.getOutputStream();
    }
@PostMapping("exportExcel")
public void webWriteExcel(HttpServletResponse response) throws IOException {
         ExcelUtil.writeExcel(response, ptPartDetails, fileName, sheetName, PtPartDetail.class);
    }

五、读取Excel

编写监听类并重写所需方法

public class ExcelListener extends AnalysisEventListener<DemoData> {
    //一行一行的读取excel内容
    @Override
    public void invoke(DemoData demoData, AnalysisContext analysisContext) {
        System.out.println("数据:"+demoData);
    }
	
    //读取表头内容
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        System.out.println("表头:"+ headMap);
    }

    //读取完成之后执行
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

    }
}

读取Excel文件

@Test
    public void readExcel(){
        String fileName = "F:\\online-education/student.xlsx";
        EasyExcel.read(fileName,DemoData.class,new ExcelListener()).sheet().doRead();
    }

使用模板写入

1、编辑模板

image
其中{xxxx}表示单个内容,{.xxxx}表示循环遍历内容

2、创建实体类
@Data
public class User implements Comparable<User>{
    private Integer index;
    private String username;
    private String password;
    private Integer age;
    private String hobby;
    private String habit;
    private String phone;
    private Integer num;


    public User(Integer index, String username, String password, Integer age, String hobby, String habit, String phone, Integer num) {
        this.index = index;
        this.username = username;
        this.password = password;
        this.age = age;
        this.hobby = hobby;
        this.habit = habit;
        this.phone = phone;
        this.num = num;
    }

    public User() {
    }

    @Override
    public int compareTo(User o) {
        return this.username.compareTo(o.getUsername());
    }
3、编辑填充方法
String templateFileName =
            TestFileUtil.getPath() + "demo" + File.separator + "fill" + File.separator + "complex.xlsx";

        String fileName = TestFileUtil.getPath() + "complexFill" + System.currentTimeMillis() + ".xlsx";
        try (ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build()) {
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            // 这里注意 入参用了forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行,然后下面的数据往后移动。默认 是false,会直接使用下一行,如果没有则创建。
            // forceNewRow 如果设置了true,有个缺点 就是他会把所有的数据都放到内存了,所以慎用
            // 简单的说 如果你的模板有list,且list不是最后一行,下面还有数据需要填充 就必须设置 forceNewRow=true 但是这个就会把所有数据放到内存 会很耗内存
            // 如果数据量大 list不是最后一行 参照下一个
            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            excelWriter.fill(data(), fillConfig, writeSheet);
            excelWriter.fill(data(), fillConfig, writeSheet);
            Map<String, Object> map = MapUtils.newHashMap();
            map.put("obj", 需要填充到表头的对象);
            excelWriter.fill(map, writeSheet);
        }

合并单元格(根据上一行的内容进行判断是否进行合并)

1、同填充方法使用同一个实体
2、编辑方法(测试数据+写出方法)
List<User> list=new ArrayList<>();
        list.add(new User(1,"张三","1234567",13,"篮球1","学习0","123456",112));
        list.add(new User(2,"李四","12456",15,"篮球1","学习","123456",12));
        list.add(new User(3,"张三","1234567",13,"篮球3","学习2","123456",112));
        list.add(new User(4,"赵六","13456",17,"篮球1","学习","123456",12));
        list.add(new User(5,"李四","12456",15,"篮球2","学习","123456",12));
        list.add(new User(6,"王武","12346",16,"篮球1","学习","123456",12));
        list.add(new User(7,"张三","1234567",13,"篮球2","学习1","123456",112));
        list.add(new User(8,"王武","12346",16,"篮球2","学习2","123456",12));
        list.add(new User(9,"赵六","13456",17,"篮球2","学习","123456",12));
        list.add(new User(10,"嘿嘿","1456",17,"篮球1","学习","123456",12));
        List<User> collect = list.stream().sorted(Comparator.comparing(User::getUsername)).collect(Collectors.toList());
        // 查询数据
        String fileName = TestController.class.getResource("/").getPath()+"导出文件名.xlsx" ;
        //需要合并的列
        int[] mergeColumeIndex = {1,2,3};
        // 从第二行后开始合并
        int mergeRowIndex = 2;
//        LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 1,4);
        EasyExcel.write(fileName,User.class).registerWriteHandler(new ExcelMergeHandler(mergeRowIndex, mergeColumeIndex)).sheet("Sheet1").doWrite(collect);

3、合并工具类
public class ExcelMergeHandler implements CellWriteHandler {
    private int[] mergeColumnIndex;
    private int mergeRowIndex;

    public ExcelMergeHandler() {
    }

    public ExcelMergeHandler(int mergeRowIndex, int[] mergeColumnIndex) {
        this.mergeRowIndex = mergeRowIndex;
        this.mergeColumnIndex = mergeColumnIndex;
    }


    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {

        //当前行
        int curRowIndex = cell.getRowIndex();
        //当前列
        int curColIndex = cell.getColumnIndex();

        if (curRowIndex > mergeRowIndex) {
            for (int i = 0; i < mergeColumnIndex.length; i++) {
                if (curColIndex == mergeColumnIndex[i]) {
                    mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
                    break;
                }
            }
        }
    }


    /**
     * 当前单元格向上合并
     *
     * @param writeSheetHolder
     * @param cell             当前单元格
     * @param curRowIndex      当前行
     * @param curColIndex      当前列
     */
    private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
        //获取当前行的当前列的数据和上一行的当前列数据,通过上一行数据是否相同进行合并
        Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();
        Cell preCell = cell.getSheet().getRow(curRowIndex - 1 ).getCell(curColIndex);
        Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();

        //比较当前行的第一列的单元格与上一行是否相同,相同合并当前单元格与上一行
        if (curData.equals(preData)){
            Sheet sheet = writeSheetHolder.getSheet();
            List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();
            boolean isMerged = false;
            for (int i = 0; i < mergedRegions.size() && !isMerged; i++) {
                CellRangeAddress cellAddresses = mergedRegions.get(i);
                //若上 一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
                if (cellAddresses.isInRange(curRowIndex - 1 , curColIndex)){
                    sheet.removeMergedRegion(i);
                    cellAddresses.setLastRow(curRowIndex);
                    sheet.addMergedRegion(cellAddresses);
                    isMerged = true;
                }
            }
            //若上一个单元格未被合并,则新增合并单元
            if (!isMerged){
                CellRangeAddress cellAddresses = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);
                sheet.addMergedRegion(cellAddresses);
            }
        }
    }
}

posted @ 2021-09-27 16:43  __先森  阅读(956)  评论(0编辑  收藏  举报