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

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

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

相关推荐
kangaroo.10 天前
基于EasyExcel、FastExcel封装spring boot starter
spring boot·easyexcel·fastexcel
小咪一会25 天前
JVM 基础
jvm·1024程序员节
FenceRain1 个月前
EasyExcel 实现国际化导入导出
java·spring boot·easyexcel
空灵之海1 个月前
Ubuntu系统安全合规配置
linux·ubuntu·系统安全·1024程序员节
阿啄debugIT1 个月前
装饰(Decorator)模式可以在不修改对象外观和功能的情况下添加或者删除对象功能
软件工程·1024程序员节
带刺的坐椅1 个月前
老码农教你:Solon + EasyExcel 导出工具
java·excel·solon·easyexcel
lzb_kkk2 个月前
【实习总结】Qt通过Qt Linguist(语言家)实现多语言支持
开发语言·c++·qt·1024程序员节·qt linguist·qt 语言家
Yangy_Jiaojiao2 个月前
三维手眼标定
1024程序员节
guozhetao2 个月前
【图论,拓扑排序】P1347 排序
数据结构·c++·python·算法·leetcode·图论·1024程序员节
lzb_kkk3 个月前
【C++】C++四种类型转换操作符详解
开发语言·c++·windows·1024程序员节