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

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

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

相关推荐
yaosheng_VALVE6 小时前
探究全金属硬密封蝶阀的奥秘-耀圣控制
运维·eclipse·自动化·pyqt·1024程序员节
dami_king6 小时前
SSH特性|组成|SSH是什么?
运维·ssh·1024程序员节
一个通信老学姐5 天前
专业125+总分400+南京理工大学818考研经验南理工电子信息与通信工程,真题,大纲,参考书。
考研·信息与通信·信号处理·1024程序员节
sheng12345678rui5 天前
mfc140.dll文件缺失的修复方法分享,全面分析mfc140.dll的几种解决方法
游戏·电脑·dll文件·dll修复工具·1024程序员节
谈谈的心情6 天前
EasyExcel 动态设置表格的背景颜色和排列
java·easyexcel·导出表格
huipeng9266 天前
第十章 类和对象(二)
java·开发语言·学习·1024程序员节
earthzhang20216 天前
《深入浅出HTTPS》读书笔记(19):密钥
开发语言·网络协议·算法·https·1024程序员节
爱吃生蚝的于勒7 天前
计算机基础 原码反码补码问题
经验分享·笔记·计算机网络·其他·1024程序员节
earthzhang20217 天前
《深入浅出HTTPS》读书笔记(20):口令和PEB算法
开发语言·网络协议·算法·https·1024程序员节
一个通信老学姐7 天前
专业140+总分410+浙江大学842信号系统与数字电路考研经验浙大电子信息与通信工程,真题,大纲,参考书。
考研·信息与通信·信号处理·1024程序员节