Easy Excel合并单元格情况简单导入导出

需求

实现报表数据的导入导出,表格中部分数据是系统生成,部分数据是甲方填写,录入系统。

批号唯一

Maven

XML 复制代码
<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.3.2</version>
        </dependency>

导出

看到网上都是创建自定义WriteHandler。略麻烦,可以用注解实现。

导出Bean,(bean就不给全了,涉及工艺),合并的单元格是列9,列10

java 复制代码
@Data
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER,verticalAlignment = VerticalAlignmentEnum.CENTER)
@NoArgsConstructor
@AllArgsConstructor
public class ProductOne {


    @ContentLoopMerge(eachRow = 2)
    @ExcelProperty(value = {"批号", "批号", "批号", "批号"},index = 0)
    @ColumnWidth(20)
    private String column1;
    @ContentLoopMerge(eachRow = 2)
    @ExcelProperty(value = {"API放行标准", "API放行标准", "API放行标准", "API放行标准"},index = 1)
    private String column2;
    @ContentLoopMerge(eachRow = 2)
    @ExcelProperty(value = {"盘库月份", "盘库月份", "盘库月份", "盘库月份"},index = 2)
    private String column3;
    @ContentLoopMerge(eachRow = 2)
    @ExcelProperty(value = {"生产进度", "生产进度", "生产进度", "生产进度"},index = 3)
    private String column4;
    @ContentLoopMerge(eachRow = 2)
    @ExcelProperty(value = {"生产偏差/变更", "生产偏差/变更", "生产偏差/变更", "生产偏差/变更"},index = 4)
    private String column5;
    @ContentLoopMerge(eachRow = 2)
    @ExcelProperty(value = {"成品入库数量/kg", "成品入库数量/kg", "成品入库数量/kg", "成品入库数量/kg"},index = 5)
    private String column6;
    @ContentLoopMerge(eachRow = 2)
    @ExcelProperty(value = {"投料开始时间", "投料开始时间", "投料开始时间", "投料开始时间"},index = 6)
    private String column7;


    @ContentLoopMerge(eachRow = 2)
    @ExcelProperty(value = {"工序1:溶解脱色", "投料", "粗品数量(kg)", "M"},index = 7)
    private String column8;
    @ExcelProperty(value = {"工序1:溶解脱色", "投料", "精品二次结晶物数量(kg)", "/"},index = 8)
    private String column9;
    @ExcelProperty(value = {"工序1:溶解脱色", "投料", "精品二次结晶物批号", " / "},index = 9)
    @ColumnWidth(20)
    private String column10;


    public ProductOne(ReportProductOne bean) {

        this.column1 = bean.getColumn1();
        this.column2 = bean.getColumn2();
        this.column3 = bean.getColumn3();
        this.column4 = bean.getColumn4();
        this.column5 = bean.getColumn5();
        this.column6 = bean.getColumn6();
        this.column7 = bean.getColumn7();
        this.column8 = bean.getColumn8();
        this.column9 = bean.getColumn9One();
        this.column10 = bean.getColumn10One();

    }

@ContentLoopMerge(eachRow = 2) ,此注解每2行合并。loop可循环。

@OnceAbsoluteMerge 用于合并一次

下图中每个注解都非常好用

@ContentStyle ,用于正文样式,我这边上下左右都居中

数据库中,存储对象bean

java 复制代码
public class ReportProductOne extends Model<ReportProductOne> {
        
    @TableId(type = IdType.AUTO)
    private Integer id;

    
    private String column1;
    
    private String column2;
    
    private String column3;
    
    private String column4;
    
    private String column5;
    
    private String column6;
    
    private String column7;
    
    private String column8;
    
    private String column9One;
    
    private String column9Two;
    
    private String column10One;
    
    private String column10Two;
    
    private Date createTime;

    public ReportProductOne(ProductOne productOne, String column9, String column10) {
        this.column1 = productOne.getColumn1();
        this.column2 = productOne.getColumn2();
        this.column3 = productOne.getColumn3();
        this.column4 = productOne.getColumn4();
        this.column5 = productOne.getColumn5();
        this.column6 = productOne.getColumn6();
        this.column7 = productOne.getColumn7();
        this.column8 = productOne.getColumn8();
        this.column9One = productOne.getColumn9();
        this.column10One = productOne.getColumn10();
        this.column9Two = column9;
        this.column10Two = column10;

    }

由此可以看出,对于批号,列9,列10。拆分的单元格也是一对一关系。

导出Controller

java 复制代码
    @Operation(summary = "导出")
    @GetMapping("export2")
    public void export2(HttpServletResponse response) {


        List<ReportProductOne> list = reportProductOneService.list();
        List<ProductOne> result = new ArrayList<>(32);

        for (ReportProductOne reportProductOne : list) {
            ProductOne bean1 = new ProductOne(reportProductOne);
            ProductOne bean2 = BeanUtil.copyProperties(bean1, ProductOne.class);
            bean2.setColumn9(reportProductOne.getColumn9Two());
            bean2.setColumn10(reportProductOne.getColumn10Two());

            result.add(bean1);
            result.add(bean2);
        }


        try {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename=test.xlsx");
            EasyExcel.write(response.getOutputStream(), ProductOne.class).autoCloseStream(Boolean.FALSE).sheet("Sheet 0")
                    .doWrite(result);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

以上bean2,其实也可以new一个,然后set列9 和列10。在导出的情况下根本没有区别,但是导入的时候会有。

导入

导入demo

导入Controller

java 复制代码
    @Operation(summary = "批量导入")
    @PostMapping("import")
    public R userBatchImport(MultipartFile file){
        String originalFilename = file.getOriginalFilename();
        String suffixName = originalFilename.substring(originalFilename.lastIndexOf("."));
        if(!AuthConstant.SUFFIX_FILE_NAME.equals(suffixName)){
            return failed("文件格式不符合");
        }
        try {
            EasyExcel.read(file.getInputStream(),ProductOne.class,productOneImportBatchListener).headRowNumber(4).sheet().doRead();
        } catch (Exception e) {
            productOneImportBatchListener.clear();
            return failed(e.getMessage());
        }
        return success("success");
    }

ReadListener

java 复制代码
public class ProductOneImportBatchListener extends AnalysisEventListener<ProductOne> {

    List<ProductOne> cache = new ArrayList<>(16);



    @Override
    public void invoke(ProductOne bean, AnalysisContext analysisContext) {

        if(cache.size() % 2 == 0 && StrUtil.isEmpty(bean.getColumn1())) {
            throw new ExcelAnalysisException("批号必填或格式有误");
        }

        if(cache.size() % 2 == 0) {
            //判断批号是否存在,不存在throw
        }

        System.out.println(bean);
        cache.add(bean);
    }


    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        if(cache.size() % 2 != 0) {
            throw new ExcelAnalysisException("文档格式有误");
        }


        List<ReportProductOne> list = new ArrayList<>(32);

        //奇数行,都有批号
        for (int i = 0; i < cache.size(); i+=2) {
            ReportProductOne temp = new ReportProductOne(cache.get(i),cache.get(i+1).getColumn9(),cache.get(i+1).getColumn10());
            list.add(temp);
        }


        log.info("插入完成:共"+ list.size()+"条");
        clear();
    }


    public void clear(){
        cache.clear();
    }
}

解析数据

总结

虽然合并单元格,但是读取还是有2行。

如果是上面导出模板,那么导入的时候,2行在合并单元格列都能读取到数据。

如果是新增的情况,那么只有在首行能读取到导入的合并单元格数据。介于一对一关系这边忽略。非一对一可参考

如果在导出的情况下修改,那么合并单元格也只能首行能读取到数据。

相关推荐
u0103055275 小时前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝1 天前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u0103055272 天前
Java图像处理实战指南
人工智能·1024程序员节
u0103055272 天前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u0103055274 天前
Java实用类应用精讲
人工智能·1024程序员节
u0103055275 天前
Java I/O核心操作实战
人工智能·1024程序员节
u0103055276 天前
ArrayList操作详解与实战应用
人工智能·1024程序员节
u0103055277 天前
Java模块化编程实战指南
人工智能·笔记·1024程序员节
u0103055278 天前
使用BufferedReader读取控制台输入
人工智能·1024程序员节
u0103055278 天前
泛型类与类型安全详解
人工智能·1024程序员节