EasyExcel工具 Java导出Excel表数据

官网:https://easyexcel.opensource.alibaba.com/

EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。
他能让你在不用考虑性能、内存的等因素的情况下,快速完成Excel的读、写等功能。
在这里插入图片描述

优点

gitee地址:https://gitee.com/easyexcel/easyexcel
在这里插入图片描述

坐标依赖

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

读Excel

官方参考:https://easyexcel.opensource.alibaba.com/docs/current/quickstart/read

PS:@Data相当于@Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode这5个注解的合集

最简单的读的对象

在这里插入图片描述

// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class DemoDataListener implements ReadListener {

/**
 * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
 */
private static final int BATCH_COUNT = 100;
/**
 * 缓存的数据
 */
private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
/**
 * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
 */
private DemoDAO demoDAO;

public DemoDataListener() {
    // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
    demoDAO = new DemoDAO();
}

/**
 * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
 *
 * @param demoDAO
 */
public DemoDataListener(DemoDAO demoDAO) {
    this.demoDAO = demoDAO;
}

/**
 * 这个每一条数据解析都会来调用
 *
 * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
 * @param context
 */
@Override
public void invoke(DemoData data, AnalysisContext context) {
    log.info("解析到一条数据:{}", JSON.toJSONString(data));
    cachedDataList.add(data);
    // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
    if (cachedDataList.size() >= BATCH_COUNT) {
        saveData();
        // 存储完成清理 list
        cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    }
}

/**
 * 所有数据解析完成了 都会来调用
 *
 * @param context
 */
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
    // 这里也要保存数据,确保最后遗留的数据也存储到数据库
    saveData();
    log.info("所有数据解析完成!");
}

/**
 * 加上存储数据库
 */
private void saveData() {
    log.info("{}条数据,开始存储数据库!", cachedDataList.size());
    demoDAO.save(cachedDataList);
    log.info("存储数据库成功!");
}

}

写Excel

https://easyexcel.opensource.alibaba.com/docs/current/quickstart/write

扫描二维码关注公众号,回复: 17274453 查看本文章

最简单的写的对象

在这里插入图片描述

最简单的读的监听器

@Getter
@Setter
@EqualsAndHashCode
public class DemoData {
    
    
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private Date date;
    @ExcelProperty("数字标题")
    private Double doubleData;
    /**
     * 忽略这个字段
     */
    @ExcelIgnore
    private String ignore;
}
/**
 * 最简单的写
 * <p>
 * 1. 创建excel对应的实体对象 参照{@link DemoData}
 * <p>
 * 2. 直接写即可
 */
@Test
public void simpleWrite() {
    // 注意 simpleWrite在数据量不大的情况下可以使用(5000以内,具体也要看实际情况),数据量大参照 重复多次写入

    // 写法1 JDK8+
    // since: 3.0.0-beta1
    String fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
    // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
    // 如果这里想使用03 则 传入excelType参数即可
    EasyExcel.write(fileName, DemoData.class)
        .sheet("模板")
        .doWrite(() -> {
            // 分页查询数据
            return data();
        });

    // 写法2
    fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
    // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
    // 如果这里想使用03 则 传入excelType参数即可
    EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());

    // 写法3
    fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
    // 这里 需要指定写用哪个class去写
    try (ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build()) {
        WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
        excelWriter.write(data(), writeSheet);
    }
}

填充Excel

https://easyexcel.opensource.alibaba.com/docs/current/quickstart/fill

简单填充(对象)

参考官网:
/**
* 填充列表
*
* @since 2.1.1
*/
@Test
public void listFill() {
// 模板注意 用{} 来表示你要用的变量 如果本来就有"{“,”}" 特殊字符 用"{“,”}"代替
// 填充list 的时候还要注意 模板中{.} 多了个点 表示list
// 如果填充list的对象是map,必须包涵所有list的key,哪怕数据为null,必须使用map.put(key,null)
String templateFileName =
TestFileUtil.getPath() + “demo” + File.separator + “fill” + File.separator + “list.xlsx”;

    // 方案1 一下子全部放到内存里面 并填充
    String fileName = TestFileUtil.getPath() + "listFill" + System.currentTimeMillis() + ".xlsx";
    // 这里 会填充到第一个sheet, 然后文件流会自动关闭
    EasyExcel.write(fileName).withTemplate(templateFileName).sheet().doFill(data());

    // 方案2 分多次 填充 会使用文件缓存(省内存)
    fileName = TestFileUtil.getPath() + "listFill" + System.currentTimeMillis() + ".xlsx";
    try (ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build()) {
        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        excelWriter.fill(data(), writeSheet);
        excelWriter.fill(data(), writeSheet);
    }
}

复杂填充(对象和列表)

在这里插入图片描述

    @GetMapping("/export")
    public void export(HttpServletResponse response) throws IOException {
    
    

       Map<String,Object> map =  this.reportService.export();

        BusinessDataVO vo = (BusinessDataVO) map.get("vo");
        List<BusinessDataVO> voList  = (List<BusinessDataVO>) map.get("list");

            File templateFile = new ClassPathResource("运营数据报表模板.xlsx").getFile();

            ServletOutputStream responseOutputStream = response.getOutputStream();

            // 以字节流的形式写回前端
            try (ExcelWriter excelWriter = EasyExcel.write(responseOutputStream).withTemplate(templateFile).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(vo,fillConfig, writeSheet);

                //填充多条数据
                excelWriter.fill(voList, fillConfig, writeSheet);

//                excelWriter.fill(map,fillConfig, writeSheet);
            }


    }
    @Override
    public Map<String, Object> export() {
    
    

        LocalDate beginTime = LocalDate.now().minusDays(30);
        LocalDate endTime = LocalDate.now().minusDays(1);

        BigDecimal turnover = new BigDecimal("0");
        Integer validOrderCount = 0;
        Integer newUsers = 0;
        Integer total = 0;

        Double unitPrice = 0D;
        Double orderCompletionRate = 0D;

        List<BusinessDataVO> voList = new ArrayList<>();

        for (int i = 0; i < 30; i++) {
    
    
            LocalDate date = beginTime.plusDays(i);
            BusinessDataVO businessDataVO = workSpaceService.businessData(date);
            voList.add(businessDataVO);
            businessDataVO.setDate(date);

            turnover = turnover.add(BigDecimal.valueOf(businessDataVO.getTurnover()));
            validOrderCount += businessDataVO.getValidOrderCount();
            newUsers += businessDataVO.getNewUsers();
            total += businessDataVO.getTotal();
        }

        if (total>0) {
    
    
            orderCompletionRate = BigDecimal.valueOf(validOrderCount)
                    .divide(BigDecimal.valueOf(total.doubleValue()),2,RoundingMode.HALF_UP).doubleValue();
        }

        if (validOrderCount > 0) {
    
    
            unitPrice = turnover.divide(BigDecimal.valueOf(validOrderCount),2,RoundingMode.HALF_UP).doubleValue();
        }

        BusinessDataVO vo = BusinessDataVO.builder()
                .unitPrice(unitPrice)
                .orderCompletionRate(orderCompletionRate)
                .turnover(turnover.doubleValue())
                .newUsers(newUsers)
                .beginTime(beginTime)
                .endTime(endTime)
                .validOrderCount(validOrderCount)
                .total(voList.size())
                .build();

        Map<String, Object> map = new HashMap<>();

        map.put("vo",vo);
        map.put("list",voList);

        return map;
    }

猜你喜欢

转载自blog.csdn.net/PY_XAT_SFZL/article/details/132415631