当前位置: 首页 > news >正文

easyExcel实现分批导入,动态表头分批导出,以及导出表格样式设置

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

一,分批导入

1.首先配置表格头映射类
@Getter
@Setter
@EqualsAndHashCode
public class IndexOrNameData {
    /**
     * 强制读取第三个 这里不建议 index 和 name 同时用,要么一个对象只用index,要么一个对象只用name去匹配
     */
    @ExcelProperty(index = 2)
    private Double doubleData;
    /**
     * 用名字去匹配,这里需要注意,如果名字重复,会导致只有一个字段读取到数据
     */
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private Date date;
}
2.编写excel数据读监听器
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class DemoDataListener implements ReadListener<IndexOrNameData > {

    /**
     * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 100;
    /**
     * 缓存的数据
     */
    private List<IndexOrNameData> 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(IndexOrNameData  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("存储数据库成功!");
    }
}

分批插入的实现是在invoke方法中,当读取缓存数达到我们预期的插入数量时就进行插入,然后重新更新list,原本的list就会被回收,达到方式内存溢出的效果,可以在这个方法中进行行参数校验,有异常抛出即可

3.编写读入方法
 // 写法1:
        fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
        // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
        EasyExcel.read(fileName, IndexOrNameData.class, new DemoDataListener()).sheet().doRead();

        // 写法2
        fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
        // 一个文件一个reader
        try (ExcelReader excelReader = EasyExcel.read(fileName, IndexOrNameData.class, new DemoDataListener()).build()) {
            // 构建一个sheet 这里可以指定名字或者no
            ReadSheet readSheet = EasyExcel.readSheet(0).build();
            // 读取一个sheet
            excelReader.read(readSheet);
        }

二,动态表头分批导出

1.构建表头和数据
//获取表头    
private static List<String> makeHeads() {
        List<String> heads = new ArrayList<>(); //表头信息
        heads.add("唯一标识");
        heads.add("名称");
        heads.add("类型");
        return heads;
    }

//获取数据
    private static List<Map<String, Object>> makeData() {
        List<Map<String, Object>> list = new ArrayList<>();
        //
        Map<String,Object> test1 = new LinkedHashMap<>(); //手动添加测试数据(可根据需要从数据库查询)
        test1.put("id", 1);
        test1.put("name", 2);
        test1.put("str", 3);
        list.add(test1);
        //
        Map<String,Object> test2 = new LinkedHashMap<>();
        test2.put("id", 11);
        test2.put("name", 22);
        test2.put("str", 33);
        list.add(test2);

        return list;
    }
2.写出代码
    public void exportExcel(HttpServletResponse httpServletResponse,@RequestParam(required = false) String fileName,@RequestParam(required = false) List<String> heads, @RequestParam(required = false) List<Map<String, Object>> list) throws IOException {
         if (StringUtils.isEmpty(fileName)){ //文件名称也可以动态获取
            fileName = System.currentTimeMillis() + ".xlsx";
        } else {
            fileName = fileName + ".xlsx";
        }

        if(heads == null || heads.size() == 0){
            heads = makeHeads();
        }
        if(list == null || list.size() == 0){
            list = makeData();
        }
           OutputStream os= responseInfo(httpServletResponse, fileName); // 调用responseInfo方法
       List<List<String>> hs = new ArrayList<>();
        for (String s : heads) {
            hs.add(Arrays.asList(s));
        }
        List<List<Object>> list2 = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            List<Object> objects = new ArrayList<>();
            Collection<Object> values = list.get(i).values();
            for (Object value : values) {
                objects.add(value.toString());
            }
            list2.add(objects);
        }

 // 头的策略
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        // 背景设置为红色
        headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short)20);
        headWriteCellStyle.setWriteFont(headWriteFont);
        // 内容的策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
        contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
        // 背景绿色
        contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex());
        WriteFont contentWriteFont = new WriteFont();
        // 字体大小
        contentWriteFont.setFontHeightInPoints((short)20);
        contentWriteCellStyle.setWriteFont(contentWriteFont);
        // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
        HorizontalCellStyleStrategy horizontalCellStyleStrategy =
            new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);

        //创建一个行高设置处理器,我这里直接用匿名内部类类了
               AbstractRowHeightStyleStrategy abstractRowHeightStyleStrategy = new AbstractRowHeightStyleStrategy() {
            @Override
            protected void setHeadColumnHeight(Row row, int relativeRowIndex) {
                if (relativeRowIndex==0){
                    row.setHeightInPoints(50);
                }else {
                    row.setHeightInPoints(10);
                }
            }

            @Override
            protected void setContentColumnHeight(Row row, int relativeRowIndex) {
                //默认主体的高度
                row.setHeightInPoints(10);
            }
        };
        
     //创建列宽设置处理器

             AbstractHeadColumnWidthStyleStrategy abstractHeadColumnWidthStyleStrategy = new AbstractHeadColumnWidthStyleStrategy() {

            @Override
            protected Integer columnWidth(Head head, Integer columnIndex) {
                switch (columnIndex) {
                    case 0:
                        return 6;
                    case 1:
                        return 20;
                    case 2:
                        return 20;
                    default:
                        return 13;
                }
            }
        };

        WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
         

          //开始写出
          ExcelWriter build = EasyExcel
                .write(os)
                .head(hs)
                //注册内容以及表头处理器
                .registerWriteHandler(new HorizontalCellStyleStrategy(headWriteCellStyle ,contentWriteCellStyle))
                   //注册行高处理器
                .registerWriteHandler(abstractRowHeightStyleStrategy)
                   //注册列宽处理器
                .registerWriteHandler(abstractHeadColumnWidthStyleStrategy)
                .build();

           //然后就可以用上边的buid对象往指定的sheet中写入数据了,当数据量大的时候,我们就可以
           分批写入,伪代码如下
          for(a a:list){
           build.write(list2,writeSheet);
          }

}



        /**
     * 功能:公用方法,写回浏览器
     * [response, fileName]
     * @return {@link OutputStream}
     * @throws
     */
    public static OutputStream responseInfo(HttpServletResponse response, String fileName) throws IOException {
        // 这里注意有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment; filename*=utf-8''" + fileName);
        OutputStream os=response.getOutputStream();
        return os;
    }

    /**
     * 如果要兼容swagger用这个,上面的注释掉
     * 功能:公用方法
     * 参数:fileName 文件名称, 如:123.xlsx

     public static OutputStream responseInfo(HttpServletResponse response, String fileName) throws IOException {
     response.setCharacterEncoding("utf-8");
     response.setContentType("APPLICATION/OCTET-STREAM");
     response.addHeader("Content-Disposition", "attachment;filename=" + fileName);

     OutputStream os=response.getOutputStream();
     return os;
     }
     */




       
        
        

相关文章:

  • python趣味编程-5分钟实现一个石头剪刀布游戏(含源码、步骤讲解)
  • 【FLink】水位线(Watermark)
  • 使用wxPython和PyMuPDF合并PDF文档并自动复制到剪贴板
  • Stable Diffusion XL网络结构-超详细原创
  • 【C++进阶之路】第十篇:C++的类型转换
  • 环境配置|GitHub——如何在github上搭建自己写的网站
  • ClickHouse查看执行计划
  • Caché for UNIX®, Linux及macOS的安装及配置
  • mysql 设置远程登录
  • 力扣-414.第三大的数(两种解法)
  • Linux难学?大神告诉你,Linux到底该怎么自学!
  • golang opt-in transparent telemetry
  • 1.什么是Angular?
  • 【CSS】各百分比透明度 opacity 对应的 16 进制颜色值(例如:#FFFFFF80)
  • 网络爬虫|Selenium——find_element_by_xpath()的几种方法
  • 【Python】给出n个数,找出这n个数的最大值,最小值,和。
  • 矿区安全检查VR模拟仿真培训系统更全面、生动有效
  • 【nlp】2.5(gpu version)人名分类器实战项目(对比RNN、LSTM、GRU模型)工程管理方式
  • 算法笔记-第九章-树的遍历(未完成-待整理)
  • 红队攻防之Goby反杀
  • 科技部等七部门:优先支持取得关键核心技术突破的科技型企业上市融资
  • 乌总统:若与普京会谈,全面停火和交换战俘是主要议题
  • 孙卫东会见巴基斯坦驻华大使:支持巴印两国实现全面持久停火
  • “80后”德州市接待事务中心副主任刘巍“拟进一步使用”
  • 金正恩观摩朝鲜人民军各兵种战术综合训练
  • 广东省中医院脾胃病科大科主任张北平病逝,年仅52岁