EasyExcel的基本使用
本文最后更新于108 天前,其中的信息可能已经过时,如有错误请发送邮件到1770087309@qq.com

1、EasyExcel介绍

传统操作Excel大多都是利用Apach POI进行操作的,但是POI框架并不完善,使用过程非常繁琐且有较多的缺陷:

  • 动态操作Excel非常繁琐,对于新手来说,很难在短时间内上手;
  • 读写时需要占用较大的内存,当数据量大时容易发生内存溢出问题(OOM);

基于上述原因,阿里开源出一款易于上手,且比较节省内存的Excel框架:EasyExcel

注意:easyExcel底层也是使用POI实现的;

2、EasyExcel导出数据快速入门

2.1 依赖引入

<!--引入easyexcel-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.3.4</version>
</dependency>

2.2 构建测试实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User implements Serializable {
    private String userName;
    private Integer age;
    private String address;
    private Date birthday;
}

2.3 数据导出到excel

@SpringBootTest
class EasyexcelApplicationTests {

    public List<User> init() {
        //组装数据
        ArrayList<User> users = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setAddress("上海" + i);
            user.setUserName("张三" + i);
            user.setBirthday(new Date());
            user.setAge(10 + i);
            users.add(user);
        }
        return users;
    }


    /**
     * 直接导出后,表头名称默认是实体类中的属性名称
     */
    @Test
    void contextLoads() {
        List<User> users = init();
        //不做任何注解处理时,表头名称与实体类属性名称一致
        EasyExcel.write("C:\\Users\\KCH\\Desktop\\ex\\用户.xls", User.class).sheet("用户信息").doWrite(users);
    }
}

2.4 自定义表头

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
/**
 * 通过注解自定义表头名称 注解添加排序规则,值越大 越靠近右边
 */
public class User implements Serializable {
    @ExcelProperty(value = {"用户名"},index = 0)
    private String userName;
    @ExcelProperty(value = {"年龄"},index = 1)
    private Integer age;
    @ExcelProperty(value = {"地址"} ,index = 3)
    private String address;
    @ExcelProperty(value = {"生日"},index = 2)
    private Date birthday;
}

3、EasyExcel导出数据高级设置

3.1 自定义日期格式

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User implements Serializable {
    @ExcelProperty(value = {"用户名"},index = 1)
    private String userName;
    @ExcelProperty(value = {"年龄"},index = 2)
    private Integer age;
    @ExcelProperty(value = {"地址"} ,index = 4)
    private String address;
    @ExcelProperty(value = {"生日"},index = 3)
    //注意:日期格式注解由alibaba.excel提供
    @DateTimeFormat("yyyy/MM/dd HH:mm")
    private Date birthday;
}

3.2 合并表头

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User implements Serializable {
    @ExcelProperty(value = {"用户基本信息","用户名"},index = 1)
    private String userName;
    @ExcelProperty(value = {"用户基本信息","年龄"},index = 2)
    private Integer age;
    @ExcelProperty(value = {"用户基本信息","地址"} ,index = 4)
    private String address;
    @ExcelProperty(value = {"用户基本信息","生日"},index = 3)
    //注意:日期格式注解由alibaba.excel提供
    @DateTimeFormat("yyyy/MM/dd HH:mm")
    private Date birthday;
}

3.3 忽略指定表头信息

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User implements Serializable {
    @ExcelProperty(value = {"用户基本信息","用户名"},index = 1)
    @ExcelIgnore
    private String userName;
    @ExcelProperty(value = {"用户基本信息","年龄"},index = 2)
    private Integer age;
    @ExcelProperty(value = {"用户基本信息","地址"} ,index = 4)
    private String address;
    @ExcelProperty(value = {"用户基本信息","生日"},index = 3)
    //注意:日期格式注解由alibaba.excel提供
    @DateTimeFormat("yyyy/MM/dd HH:mm")
    private Date birthday;
}

3.4 设置单元格大小

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@HeadRowHeight(value = 35) // 表头行高
@ContentRowHeight(value = 25) // 内容行高
@ColumnWidth(value = 50) // 列宽
public class User implements Serializable {
    @ExcelProperty(value = {"用户基本信息","用户名"},index = 1)
    @ExcelIgnore
    private String userName;
    @ExcelProperty(value = {"用户基本信息","年龄"},index = 2)
    private Integer age;
    @ExcelProperty(value = {"用户基本信息","地址"} ,index = 4)
    private String address;
    @ExcelProperty(value = {"用户基本信息","生日"},index = 3)
    //注意:日期格式注解由alibaba.excel提供
    @DateTimeFormat("yyyy/MM/dd HH:mm")
    private Date birthday;
}

4、EasyExcel导入数据

   /**
     * excel数据格式必须与实体类定义一致,否则数据读取不到
     */
    @Test
    public void readExcel() {
        ArrayList<User> users = new ArrayList<>();
        //读取数据
        EasyExcel.read("C:\\Users\\KCH\\Desktop\\ex\\用户.xls", User.class, new AnalysisEventListener<User>() {
            //解析excel中的每条数据
            @Override
            public void invoke(User o, AnalysisContext analysisContext) {
                System.out.println(o);
                users.add(o);
            }

            //解析完成后执行的操作
            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                System.out.println("完成。。。。");
            }
        }).sheet().doRead();
        System.out.println(users);
    }

5、结合阿里云上传保存导出

5.1 阿里云OSS配置

5.1.1 配置文件

sky:
  alioss:
    endpoint: oss-cn-beijing.aliyuncs.com
    access-key-id: LTAI5tPZCZvadQUz5VVqWdSF
    access-key-secret: cqrELWRwTQF6uoCUhU7R1enkmL2ppZ
    bucket-name: kch-file

5.1.2 配置文件加载

@Component
@ConfigurationProperties(prefix = "sky.alioss")
@Data
public class AliOssProperties {

    private String endpoint;
    private String accessKeyId;
    private String accessKeySecret;
    private String bucketName;

}

5.1.3 上传工具类AliOssUtil

@Data
@AllArgsConstructor
@Slf4j
public class AliOssUtil {

    private String endpoint;
    private String accessKeyId;
    private String accessKeySecret;
    private String bucketName;

    /**
     * 文件上传
     *
     * @param bytes
     * @param objectName
     * @return
     */
    public String upload(byte[] bytes, String objectName) {

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            // 创建PutObject请求。(上传文件)
            ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
        } catch (OSSException oe) {
            System.out.println("捕获到 OSSException,这意味着您的请求已发送到 OSS, 但由于某种原因被拒绝并显示错误响应");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("捕获到 ClientException,这意味着客户端在尝试与 OSS 通信时遇到了严重的内部问题,例如无法访问网络");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }

        //文件访问路径规则 https://BucketName.Endpoint/ObjectName
        StringBuilder stringBuilder = new StringBuilder("https://");
        stringBuilder
                .append(bucketName)
                .append(".")
                .append(endpoint)
                .append("/")
                .append(objectName);

        log.info("文件上传到:{}", stringBuilder.toString());

        return stringBuilder.toString();
    }
}

5.1.4 配置类

@Configuration
@Slf4j
public class OssConfiguration {

    /**
     * 返回阿里云OSS文件上传工具类对象
     *
     * @param aliOssProperties
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    public AliOssUtil aliOssUtil(AliOssProperties aliOssProperties) {
        log.info("开始创建阿里云文件上传工具类对象:{}", aliOssProperties);
        return new AliOssUtil(
                aliOssProperties.getEndpoint(),
                aliOssProperties.getAccessKeyId(),
                aliOssProperties.getAccessKeySecret(),
                aliOssProperties.getBucketName());
    }
}

5.1.5 上传测试

@RestController
@RequestMapping("/admin/upload")
@Slf4j
@Api(tags = "上传接口")
public class UploadController {

    @Autowired
    private AliOssUtil aliOssUtil;

    @PostMapping("/upload")
    @ApiOperation("文件上传")
    public String upload(MultipartFile file) {
        log.info("文件上传:{}", file);

        try {
            // 前端传过来的文件名
            String originalFilename = file.getOriginalFilename();

            // 截取文件名的后缀
            String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));

            // 重命文件名
            String newName = UUID.randomUUID().toString() + suffix;

            // 文件的请求路径
            return aliOssUtil.upload(file.getBytes(), newName);
        } catch (IOException e) {
            log.error("文件上传失败:{}", e);
        }
        return "文件上传失败";
    }
}

5.2 简单导出

@GetMapping("/easy-export")
@ApiOperation("简单导出")
public String export() {
    // 获取数据
    List<GlobalExpressCompany> list = globalExpressCompanyService.list();

    // 生成 Excel 文件路径
    String rootDir = System.getProperty("user.dir"); // 获取项目根目录
    String filePath = rootDir + File.separator + "ex" + File.separator + "公司正则.xls";
    File dir = new File(rootDir + File.separator + "ex");
    if (!dir.exists()) {
        dir.mkdirs();  // 确保目录存在
    }

    // 写入 Excel 文件
    EasyExcel.write(filePath).sheet("快递公司").doWrite(list);

    // 上传文件至阿里云 OSS
    File file = new File(filePath);
    try (FileInputStream fis = new FileInputStream(file)) {
        byte[] fileBytes = fis.readAllBytes();  // 获取文件字节数组

        String uploadUrl = aliOssUtil.upload(fileBytes, "公司正则.xls");// 上传文件

        // 判断上传是否成功
        if (uploadUrl != null && !uploadUrl.isEmpty()) {
            // 上传成功后删除本地文件
            boolean isFileDeleted = file.delete();
            if (isFileDeleted) {
                System.out.println("本地文件删除成功");
            } else {
                System.out.println("本地文件删除失败");
            }
        } else {
            System.out.println("文件上传失败");
        }

        return uploadUrl;
    } catch (IOException e) {
        e.printStackTrace();
        return "上传失败";  // 处理文件读取和上传异常
    }
}

5.3 模板填充

@GetMapping("/template-fill")
@ApiOperation("模板填充")
public String exportWithTemplate() {

    // 生成 Excel 文件路径
    String rootDir = System.getProperty("user.dir"); // 获取项目根目录
    String filePath = rootDir + File.separator + "ex" + File.separator + "模板填充.xlsx";
    File dir = new File(rootDir + File.separator + "ex");
    if (!dir.exists()) {
        dir.mkdirs();  // 确保目录存在
    }

    // 读取模板文件
    ClassPathResource classPathResource = new ClassPathResource("template/fillSimple.xlsx");
    try (
            InputStream inputStream = classPathResource.getInputStream();
            ByteArrayOutputStream os = new ByteArrayOutputStream()
    ) {

        // 配置填充的数据(填充 map 和 list)
        Map<String, String> map = Map.of("year", "2022");
        List<FillSimpleDTO> list = List.of(
                new FillSimpleDTO("老张", 1),
                new FillSimpleDTO("老李", 2)
        );
        // 配置填充配置
        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();

        // 使用 EasyExcel 进行模板填充
        ExcelWriter excelWriter = EasyExcel.write(os).withTemplate(inputStream).build(); // 读取模板
        WriteSheet writeSheet = EasyExcel.writerSheet().build(); // 写到第一个工作表

        // 填充模板
        excelWriter.fill(map, writeSheet);  // 填充单一变量
        excelWriter.fill(list, fillConfig, writeSheet);  // 填充列表
        excelWriter.finish();  // 完成填充

        // 获取填充后的字节数组
        byte[] fileBytes = os.toByteArray();

        // 保存到本地
        try (FileOutputStream fos = new FileOutputStream(filePath)) {
//                fos.write(fileBytes);  // 第一种写入方式,直接写入
            EasyExcel.write(fos).sheet("模板填充").doWrite(list); // 第二种写入方式,使用EasyExcel进行写入,write传参可以是输出流,也可以是文件路径
        }

        // 上传文件至阿里云 OSS
        String uploadUrl = aliOssUtil.upload(fileBytes, "模板填充.xlsx");

        // 判断上传是否成功
        if (uploadUrl != null && !uploadUrl.isEmpty()) {
            // 上传成功后删除本地文件
            File file = new File(filePath);
            boolean isFileDeleted = file.delete();
            if (isFileDeleted) {
                System.out.println("本地文件删除成功");
            } else {
                System.out.println("本地文件删除失败");
            }
            return uploadUrl;  // 返回上传的 URL
        } else {
            System.out.println("文件上传失败");
            return "上传失败";
        }
    } catch (IOException e) {
        e.printStackTrace();
        return "上传失败";  // 处理文件读取和上传异常
    }
}
觉得有帮助可以投喂下博主哦~感谢!
作者:KCH
版权声明: 转载请注明文章地址及作者哦~
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇