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行在合并单元格列都能读取到数据。

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

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

相关推荐
西电研梦8 小时前
考研倒计时30天丨和西电一起向前!再向前!
人工智能·考研·1024程序员节·西电·西安电子科技大学
惜.己9 小时前
Jmeter中的断言(四)
测试工具·jmeter·1024程序员节
·云扬·16 小时前
Java IO 与 BIO、NIO、AIO 详解
java·开发语言·笔记·学习·nio·1024程序员节
网安_秋刀鱼20 小时前
PHP代码审计 --MVC模型开发框架&rce示例
开发语言·web安全·网络安全·php·mvc·1024程序员节
HUODUNYUN1 天前
小程序免备案:快速部署与优化的全攻略
服务器·网络·web安全·小程序·1024程序员节
惜.己1 天前
Jmeter的后置处理器(二)
测试工具·github·1024程序员节
惜.己2 天前
Jmeter中的断言(一)
测试工具·jmeter·1024程序员节
cainiao0806052 天前
《物理学进展》
1024程序员节·核心期刊·知网期刊·职称评审
FFDUST2 天前
C++ —— string类(上)
c语言·开发语言·数据结构·c++·stl·1024程序员节
惜.己2 天前
Jmeter中的断言(三)
测试工具·jmeter·1024程序员节