EasyExcel动态映射Excel数据到任意实体类教程

🌟一、文前说明

在使用EasyExcel进行Excel导入时,我们经常需要将Excel中的数据映射到Java实体类中。如果Excel的列名是固定的,我们可以通过@ExcelProperty("列名")注解直接在实体类中指定列名。但如果Excel的列名不固定,或者我们希望根据Excel的第一行来动态确定映射关系,我们就需要一种更灵活的方法。本教程将介绍如何使用EasyExcel创建一个工具类,以支持动态映射Excel数据到任意实体类。

🌟二、方案实现

✏️步骤1:添加EasyExcel依赖

首先,确保你的项目中已经添加了EasyExcel的依赖。如果使用Maven,可以在pom.xml中添加如下依赖:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.x.x</version> <!-- 使用最新版本 -->
</dependency>

✏️步骤2:创建动态映射工具类

创建一个工具类DynamicExcelUtil,它将负责读取Excel文件,并根据第一行的列名动态映射数据到实体类。

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import lombok.var;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class ExcelUtil {

    /**
     * 读取 Excel 文件并返回数据模型列表。
     *
     * @param fileName Excel 文件的路径。
     * @param clazz    数据模型类。
     * @param <T>      数据模型的类型。
     * @return 数据模型列表。
     */
    public static <T> List<T> readExcel(String fileName, Class<T> clazz) {
        ExcelDataListener<T> listener = new ExcelDataListener<>();
        List<T> dataModels = new ArrayList<>();

        try {
            EasyExcel.read(fileName, clazz, listener).sheet().doRead();
            dataModels = listener.getDataModels();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return dataModels;
    }

    /**
     * Excel 数据读取监听器。
     *
     * @param <T> 数据模型的类型。
     */
    public static class ExcelDataListener<T> implements ReadListener<T> {
        private List<T> dataModels = new ArrayList<>();

        @Override
        public void invoke(T dataModel, AnalysisContext context) {
            dataModels.add(dataModel);
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            // 所有数据解析完成后的操作
        }

        public List<T> getDataModels() {
            return dataModels;
        }
    }



    /**
     * 将 MultipartFile 转换为 File 对象。
     *
     * @param file MultipartFile 对象。
     * @return 转换后的 File 对象。
     * @throws IOException 如果文件写入失败。
     */
    public static File convert(MultipartFile file) throws IOException {
        if (!file.isEmpty()) {
            File convFile = new File(Objects.requireNonNull(file.getOriginalFilename()));
            try (var fos = new FileOutputStream(convFile)) {
                fos.write(file.getBytes());
            }
            return convFile;
        }
        throw new IOException("Could not convert the uploaded file.");
    }

}

定义了一个名为ExcelUtil的工具类,它包含两个静态方法用于处理Excel文件。第一个方法readExcel使用阿里巴巴的EasyExcel库来读取指定路径的Excel文件,并将数据映射到给定的数据模型类中,返回一个包含所有数据模型的列表。它使用了内部定义的ExcelDataListener类作为读取监听器来收集解析后的数据。第二个方法convert用于将Spring的MultipartFile对象转换为Java的File对象,这通常用于处理上传的文件。如果转换过程中出现错误,会抛出IOException。这个工具类为处理Excel文件的读取和文件类型的转换提供了便利。 

如果我们现在有一个实体类,如下:

package com.xiaobai.easyexceldemo.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import lombok.Data;

/**
 * 
 * @TableName easy_demo
 */
@TableName(value ="easy_demo")
@Data
public class EasyDemo implements Serializable {
    /**
     * 
     */
    @TableId
    private Integer id;

    /**
     * 
     */
    private String name;

    /**
     * 
     */
    private String password;

    /**
     * 
     */
    private String email;

    /**
     * 
     */
    private String qq;

    /**
     * 
     */
    private String address;

    /**
     * 
     */
    private String nameSpace;

    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
}

 此时我们我们有一个表格,数据如下:

🌟三、测试 

✏️测试:方式一,直接映射

此时我们映射的时候,需要按照表格的列新创建一个中间类。

@Data
public class EasyDemoDto {

    /**
     *
     */
    private String name;

    /**
     *
     */
    private String password;

    /**
     *
     */
    private String email;

    /**
     *
     */
    private String qq;

    /**
     *
     */
    private String address;

    /**
     *
     */
    private String nameSpace;
}

这个类需要按照表格的列进行按照顺序排列,才可以映射上。

现在我们调换一下(name,password)字段的顺序,看一下结果:

所以直接映射的时候一定要注意,字段和excel表格列顺序一致

✏️测试:方式二,注解映射

在实体中添加注解@ExcelProperty("列名"),映射excel表中的列名,进行映射数据。

@Data
public class EasyDemoDto {

    /**
     *
     */
    @ExcelProperty("密码")
    private String password;

    /**
     *
     */
    @ExcelProperty("名称")
    private String name;



    /**
     *
     */
    @ExcelProperty("邮箱")
    private String email;

    /**
     *
     */
    @ExcelProperty("qq")
    private String qq;

    /**
     *
     */
    @ExcelProperty("地址")
    private String address;

    /**
     *
     */
    @ExcelProperty("空间")
    private String nameSpace;
}

🌟四、EasyExcel中注解说明 

@ExcelProperty: 用于指定实体类属性与 Excel 列的映射关系。

public class Student {
    @ExcelProperty("学生姓名")
    private String name;
    // 其他属性和getter/setter方法
}

@DateTimeFormat: 用于指定日期时间格式,与@ExcelProperty一起使用。

@ExcelProperty("出生日期")
@DateTimeFormat("yyyy-MM-dd")
private Date birthDate;

@NumberFormat: 用于指定数字格式,与@ExcelProperty一起使用。

@ExcelProperty("分数")
@NumberFormat("#.##")
private double score;

@ColumnWidth: 用于指定列宽。

public class Product {
    @ExcelProperty("产品名称")
    @ColumnWidth(20)
    private String name;
    // 其他属性和getter/setter方法
}

@ContentFontStyle: 用于定义内容单元格的字体样式。

@ExcelProperty("备注")
@ContentFontStyle(name = "微软雅黑", size = 12, isBold = true)
private String comment;

@ContentLoopMerge: 用于在循环写入时合并单元格。

public class SalesRecord {
    @ExcelProperty("产品名称")
    @ContentLoopMerge(startRow = 1, endRow = 3)
    private String productName;
    // 其他属性和getter/setter方法
}

@ContentRowHeight: 用于设置内容行高。

@ExcelProperty("详细描述")
@ContentRowHeight(value = 50)
private String description;

@ContentStyle: 用于定义内容单元格的样式。

@ExcelProperty("数值")
@ContentStyle(fillForegroundColor = 3, fillPatternType = FillPatternType.SOLID_FOREGROUND)
private double value;

@HeadFontStyle: 用于定义表头单元格的字体样式。

public class Employee {
    @ExcelProperty("工号")
    @HeadFontStyle(name = "宋体", size = 14, isBold = true)
    private String employeeId;
    // 其他属性和getter/setter方法
}

@HeadRowHeight: 用于设置表头行高。

@ExcelProperty("姓名")
@HeadRowHeight(value = 30)
private String name;

@HeadStyle: 用于定义表头单元格的样式。

@ExcelProperty("部门")
@HeadStyle(fillForegroundColor = 4, fillPatternType = FillPatternType.SOLID_FOREGROUND)
private String department;

@OnceAbsoluteMerge: 用于绝对合并单元格一次。

public class Summary {
    @ExcelProperty("总计")
    @OnceAbsoluteMerge(merge = {@ExcelColIndex(1), @ExcelColIndex(2)}, row = 1)
    private double total;
    // 其他属性和getter/setter方法
}

@ExcelIgnore: 用于忽略不映射到 Excel 的实体类属性。

private String internalUseOnly;

@ExcelIgnoreUnannotated: 类级别的注解,指定只有使用了@ExcelProperty注解的字段才会写入 Excel。

@ExcelIgnoreUnannotated
public class Product {
    private String id;
    @ExcelProperty("产品名称")
    private String name;
    // 只有name属性会写入Excel
}

@ExcelColIndex: 用于指定列的索引。

@ExcelProperty("价格")
@ExcelColIndex(2)
private double price;

至此,已经结束啦,获取有不对的地方,还请提出,共勉。

这篇文章就到这里了,下次见!

🥇原创不易,还希望各位大佬支持一下!

👍点赞,你的认可是我创作的动力 !

🌟收藏,你的青睐是我努力的方向!

✏️评论,你的意见是我进步的财富!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

许舒雅的宝贝

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值