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

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

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

相关推荐
写点什么呢7 小时前
Word使用记录
word·1024程序员节
开开心心就好9 小时前
内存清理工具点击清理,自动间隔自启
linux·运维·服务器·安全·硬件架构·材料工程·1024程序员节
开开心心就好1 天前
内存清理工具开源免费,自动优化清理项
linux·运维·服务器·python·django·pdf·1024程序员节
张萌杰4 天前
深度学习的基础知识(常见名词解释)
人工智能·深度学习·机器学习·1024程序员节
开开心心就好5 天前
免费无广告卸载工具,轻便安全适配全用户
linux·运维·服务器·网络·安全·启发式算法·1024程序员节
开开心心就好6 天前
图片格式转换工具,右键菜单一键转换简化
linux·运维·服务器·python·django·pdf·1024程序员节
徐子童8 天前
网络协议---TCP协议
网络·网络协议·tcp/ip·面试题·1024程序员节
扫地的小何尚10 天前
NVIDIA RTX PC开源AI工具升级:加速LLM和扩散模型的性能革命
人工智能·python·算法·开源·nvidia·1024程序员节
数据皮皮侠AI11 天前
上市公司股票名称相似度(1990-2025)
大数据·人工智能·笔记·区块链·能源·1024程序员节
开开心心就好11 天前
系统清理工具清理缓存日志,启动卸载管理
linux·运维·服务器·神经网络·cnn·pdf·1024程序员节