EasyExcel读写及填充 |
您所在的位置:网站首页 › 填充表格的英语 › EasyExcel读写及填充 |
EasyExcel官方文档:https://www.yuque.com/easyexcel/doc/easyexcel. 初识EasyExcel 传统POI的内存消耗较大特点 功能强大代码书写冗余繁杂读写大文件耗费内存较大,容易OOM EasyExcel重写了POI对07版Excel的解析 EasyExcel重写了POI对07版Excel的解析,可以把内存消耗从100M左右降低到10M以内,并且再大的Excel不会出现内存溢出,03版仍依赖POI的SAX模式。 下图为64M内存1分钟内读取75M(46W行25列)的Excel(当然还有急速模式能更快,但是内存占用会在100M多一点)![]() pom.xml 4.0.0 org.springframework.boot spring-boot-starter-parent 2.2.1.RELEASE com.jxsl exceldemo 0.0.1-SNAPSHOT exceldemo Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-thymeleaf org.springframework.boot spring-boot-starter-web org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test com.alibaba druid-spring-boot-starter 1.2.3 mysql mysql-connector-java 8.0.27 org.mybatis.spring.boot mybatis-spring-boot-starter 2.1.4 com.alibaba easyexcel 3.0.5 com.alibaba fastjson 1.2.78 org.springframework.boot spring-boot-maven-plugin org.projectlombok lombokapplication.yml server: port: 8887 #\u6570\u636E\u6E90 spring: datasource: druid: url: jdbc:mysql://localhost:3306/excel?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT driver-class-name: com.mysql.cj.jdbc.Driver username: root password: 123456 initial-size: 10 max-active: 50 min-idle: 10 max-wait: 60000 pool-prepared-statements: true max-pool-prepared-statement-per-connection-size: 20 # mysql \u6570\u636E\u5E93\u7684\u7279\u5F81 \u4F1A\u5173\u95ED\u5DF2\u7ECF\u8FDE\u63A5\u4E868\u4E2A\u5C0F\u65F6\u7684\u8FDE\u63A5 validation-query: SELECT 1 FROM DUAL # mybatis 配置 mybatis: # 扫描映射文件 mapper-locations: classpath:mapper/*.xml configuration: # 开启驼峰映射配置 map-underscore-to-camel-case: true # log # 整个工程只答应info 以及以上级别的日志 logging: level: root: info com.jsxl.mapper: debug
TestWrite @Test public void simpleWrite() { //jdk1.8 EasyExcel.write(path, DemoData.class) .sheet("模板") .doWrite(() -> { // 分页查询数据 return demoDataMapper.selectByExample(null); }); // // 写法2 // // 这里 需要指定写用哪个class去写 // ExcelWriter excelWriter = null; // try { // excelWriter = EasyExcel.write(path, DemoData.class).build(); // WriteSheet writeSheet = EasyExcel.writerSheet("模板").build(); // excelWriter.write(data(), writeSheet); // } finally { // // 千万别忘记finish 会帮忙关闭流 // if (excelWriter != null) { // excelWriter.finish(); // } // } /** * 根据参数只导出指定列 * 1. 创建excel对应的实体对象 参照{@link DemoData} * 2. 根据自己或者排除自己需要的列 * 3. 直接写即可 */ @Test void excludeOrIncludeWrite() { String fileName = path + "excludeOrIncludeWrite" + System.currentTimeMillis() + ".xlsx"; // 这里需要注意 在使用ExcelProperty注解的使用,如果想不空列则需要加入order字段,而不是index,order会忽略空列,然后继续往后,而index,不会忽略空列,在第几列就是第几列。 // 根据用户传入字段 假设我们要忽略 date Set excludeColumnFiledNames = new HashSet(); excludeColumnFiledNames.add("date"); // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName, DemoData.class).excludeColumnFiledNames(excludeColumnFiledNames).sheet("模板") .doWrite(demoDataMapper.selectByExample(null)); fileName = path + "excludeOrIncludeWrite" + System.currentTimeMillis() + ".xlsx"; // 根据用户传入字段 假设我们只要导出 date Set includeColumnFiledNames = new HashSet(); includeColumnFiledNames.add("date"); // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName, DemoData.class).includeColumnFiledNames(includeColumnFiledNames).sheet("模板") .doWrite(demoDataMapper.selectByExample(null)); }
复杂头写入 注解ColumnWidth() /** * Set the width of the table * * @author Jiaju Zhuang */ @Target({ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited//@Inherited修饰的注解的@Retention是RetentionPolicy.RUNTIME,则增强了继承性,在反射中可以获取得到 public @interface ColumnWidth { /** * Column width * 默认返回-1 * -1 means the default co */ // 返回列的宽度 int value() default -1; }注解ExcelProperty @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface ExcelProperty { /** * 工作表标题的名称。 * write: 当你有多个头时,它会自动合并 * read: 当你有多个头时,选最后一个 * @return The name of the sheet header */ String[] value() default {""}; /** * 返回当前列的索引 *读取或写入列的索引,如果它等于-1,它是按Java类排序。 * priority: index ; order ; default sort * * @return Index of column */ int index() default -1; /** * 定义列的排序顺序。 * priority: index ; order ; default sort * @return Order of column */ int order() default Integer.MAX_VALUE; /** * 强制当前字段使用这个转换器 * @return Converter */ Class converter() default AutoConverter.class; /** * 如果默认格式不满足,可以设置格式 * @return Format string * @deprecated please use {@link com.alibaba.excel.annotation.format.DateTimeFormat} */ @Deprecated //若某类或某方法加上该注解之后,表示此方法或类不再建议使用,调用时也会出现删除线,但并不代表不能用,只是说,不推荐使用,因为还有更好的方法可以调用。 String format() default ""; }注解ExcelIgnore /** * 忽略将该字段 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface ExcelIgnore {} 二、使用EasyExcel读出新增一个接口 int save(@Param("list") List list);Mapper.xml insert into excel.demo_data (string,date,double_data) values (#{item.string}, #{item.date},#{item.doubleData})这里需要一个监听器,注解这个监听器不能被spring管理 package com.jsxl.read; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.util.ListUtils; import com.jsxl.mapper.DemoDataMapper; import com.jsxl.pojo.DemoData; import lombok.extern.slf4j.Slf4j; import java.util.List; @Slf4j // 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去 public class DemoDataListener implements ReadListener { /** * 引入接口 */ DemoDataMapper demoDataMapper; /** * 我们通过构造函数从外部传入接口 * @param demoDataMapper */ public DemoDataListener(DemoDataMapper demoDataMapper){ this.demoDataMapper = demoDataMapper; } /** * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收 */ private static final int BATCH_COUNT = 100; /** * 缓存的数据 */ private List cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); /** * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。 */ /** * 这个每一条数据解析都会来调用 */ @Override public void invoke(DemoData data, AnalysisContext context) { // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM cachedDataList.add(data); System.out.println(cachedDataList.size()); 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()); demoDataMapper.save(cachedDataList); log.info("存储数据库成功!"); } } 三、填充 Excel表格中用{} 来表示包裹要填充的变量,如果单元格文本中本来就有{,}左右大括号,需要在括号前面使用斜杠转义{,}。 代码中被填充数据的实体对象的成员变量名或被填充map集合的key需要和Excel中被{}包裹的变量名称一致。 3.1 简单填充
测试 // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替 private static final String templateFileName1 = "D:\\github\\exceldemo\\模板1.xlsx"; private static final String fileName1="D:\\github\\exceldemo\\simpleFill1.xlsx"; /** * 最简单的填充 */ @Test public void simpleFill() { // 方案1 根据对象填充 // 这里 会填充到第一个sheet, 然后文件流会自动关闭 FillData fillData = new FillData(); fillData.setName("张三"); fillData.setNumber(5.2); EasyExcel.write(fileName1).withTemplate(templateFileName1).sheet().doFill(fillData); // 方案2 根据Map填充 // 这里 会填充到第一个sheet, 然后文件流会自动关闭 // Map map = new HashMap(); // map.put("name", "张三"); // map.put("number", 5.2); // EasyExcel.write(fileName1).withTemplate(templateFileName1).sheet().doFill(map); } 3.2 填充列表
FillConfig类 @Getter @Setter @EqualsAndHashCode @Builder @NoArgsConstructor @AllArgsConstructor public class FillConfig { private WriteDirectionEnum direction; /** * 每次使用list参数时创建一个新行。如果需要,默认创建。 ** Warnning:If you use forceNewRow set true, will not be able to use asynchronous write file, simply * say the whole file will be stored in memory. */ private Boolean forceNewRow; /** * Automatically inherit style * default true. */ private Boolean autoStyle; private boolean hasInit; public void init() { if (hasInit) { return; } if (direction == null) { direction = WriteDirectionEnum.VERTICAL; } if (forceNewRow == null) { forceNewRow = Boolean.FALSE; } if (autoStyle == null) { autoStyle = Boolean.TRUE; } hasInit = true; } } |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |