SpringBoot整合EasyExcel实现导入导出

1、EasyExcel是什么

EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。

他能让你在不用考虑性能、内存的等因素的情况下,快速完成Excel的读、写等功能。

2、相关网站

官网https://easyexcel.opensource.alibaba.com/

GitHubhttps://github.com/alibaba/easyexcel

3、实现导入

pom依赖导入

复制代码
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.3.2</version>
</dependency>

excel数据

一共包含姓名,手机号,性别,地址,状态,注册时间6列,共50条数据

数据库表结构

实体类User

复制代码
package com.example.springbootdemo.entity;

import com.baomidou.mybatisplus.annotation.*;
import com.example.springbootdemo.enums.GenderEnum;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * <p>
 *  用户实体类
 * </p>
 *
 * @author yurenwei
 * @since 2023/9/7
 */
@ApiModel(value = "用户参数", description = "用户参数")
@Data
@Accessors(chain = true)
@TableName("user")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 主键id
     */
    @ApiModelProperty(value = "主键id")
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private Long id;

    /**
     * 姓名
     */
    @ApiModelProperty(value = "姓名")
    private String userName;

    /**
     * 手机号
     */
    @ApiModelProperty(value = "手机号")
    private String phone;

    /**
     * 性别
     */
    @ApiModelProperty(value = "性别")
    private GenderEnum gender;

    /**
     * 地址
     */
    @ApiModelProperty(value = "地址")
    private String address;

    /**
     * 状态(0、禁用1、启用)
     */
    @ApiModelProperty(value = "状态(0、禁用1、启用)")
    private Boolean status;

    /**
     * 注册时间
     */
    @ApiModelProperty(value = "注册时间")
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime registerTime;

    /**
     * 创建人
     */
    @ApiModelProperty(value = "创建人")
    private Long createBy;

    /**
     * 创建时间
     */
    @ApiModelProperty(value = "创建时间")
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    /**
     * 修改人
     */
    @ApiModelProperty(value = "修改人")
    private Long updateBy;

    /**
     * 修改时间
     */
    @ApiModelProperty(value = "修改时间")
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    /**
     * 是否删除(0、否1、是)
     */
    @ApiModelProperty(value = "是否删除(0、否1、是)")
    private Boolean isDeleted;
}

controller导入方法

复制代码
@ApiOperation("导入")
@PostMapping("/importUser")
public Result importUser(@RequestParam(value = "file") MultipartFile file){
    userService.importUser(file);
    return Result.ok();
}

service导入方法

复制代码
/**
 * 导入excel
 *
 * @param file excel文件
 */
public void importUser(MultipartFile file) {
    try {
        EasyExcel.read(file.getInputStream(), UserExcelDTO.class, new UserExcelListener(iUserService))
                .sheet(0)
                .headRowNumber(1)
                .doRead();
    } catch (IOException e) {
        log.error("导入用户数据异常:{}",e.getMessage());
        e.printStackTrace();
    }
}

excel对应实体类

复制代码
package com.example.springbootdemo.dto;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import lombok.Data;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * <p>
 *  用户excel实体类
 * </p>
 *
 * @author yurenwei
 * @since 2023/9/7
 */
@Data
public class UserExcelDTO implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 姓名
     */
    @ExcelProperty(value = "姓名",index = 0)
    private String userName;

    /**
     * 手机号
     */
    @ExcelProperty(value = "手机号",index = 1)
    private String phone;

    /**
     * 性别
     */
    @ExcelProperty(value = "性别",index = 2)
    private String gender;

    /**
     * 地址
     */
    @ExcelProperty(value = "地址",index = 3)
    private String address;

    /**
     * 状态(0、禁用1、启用)
     */
    @ExcelProperty(value = "状态",index = 4)
    private String status;

    /**
     * 注册时间
     */
    @ExcelProperty(value = "注册时间",index = 5)
    @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
    private LocalDateTime registerTime;

}

此处注意# @Accessors(chain = true)与EasyExcel不兼容,不要增加此注解,要不导入数据为空

创建读取excel监听类

复制代码
package com.example.springbootdemo.listener;

import cn.hutool.core.util.IdUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson.JSON;
import com.example.springbootdemo.dto.UserExcelDTO;
import com.example.springbootdemo.entity.User;
import com.example.springbootdemo.enums.GenderEnum;
import com.example.springbootdemo.mybatisplus.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  用户excel监听类
 * </p>
 *
 * @author yurenwei
 * @since 2023/9/7
 */
@Slf4j
public class UserExcelListener implements ReadListener<UserExcelDTO> {

    /**
     * 每隔10条数据存储数据库,然后清理List,方便内存回收
     *
     */
    private static final int BATCH_COUNT = 10;

    /**
     * 缓存的数据
     */
    private List<UserExcelDTO> cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);


    private IUserService iUserService;

    public UserExcelListener(IUserService iUserService){
        this.iUserService = iUserService;
    }

    /**
     * 每一条数据解析都会调用
     *
     * @param user
     * @param analysisContext
     */
    @Override
    public void invoke(UserExcelDTO user, AnalysisContext analysisContext) {
        log.info("解析到一条数据user:{}", JSON.toJSONString(user));
        cacheList.add(user);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if(cacheList.size()>=BATCH_COUNT){
            // 保存数据
            saveData();
            // 存储完成清理list
            cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }

    /**
     * 所有数据都解析完了才会调用
     *
     * @param analysisContext
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        saveData();
        log.info("所有数据解析完成!");
    }

    /**
     * 保存数据
     */
    public void saveData(){
        log.info("一共{}条数据,开始存储数据库!",cacheList.size());
        if(CollectionUtils.isNotEmpty(cacheList)){
            List<User> userList = cacheList.stream().map(item -> new User()
                    .setId(IdUtil.getSnowflakeNextId())
                    .setUserName(item.getUserName())
                    .setPhone(item.getPhone())
                    .setGender("男".equals(item.getGender())? GenderEnum.MALE:GenderEnum.FEMALE)
                    .setAddress(item.getAddress())
                    .setRegisterTime(item.getRegisterTime())
                    .setStatus("启用".equals(item.getStatus())))
                    .collect(Collectors.toList());

            // 批量保存
            iUserService.saveBatch(userList);
        }
        log.info("存储数据库成功!");
    }
}

启动项目测试导入

控制台打印信息

查看数据库是否成功导入数据

可见50条都被成功导入到数据库表当中,并且数据都是正确的。

4、接下来实现导出

controller导出方法

复制代码
@ApiOperation("导出")
@PostMapping("/export")
public void export(HttpServletResponse response){
    userService.export(response);
}

service导出方法

复制代码
/**
 * 导出
 *
 * @param response 响应
 */
public void export(HttpServletResponse response) {
    // 查询所有用户
    List<User> list = iUserService.list();
    // 转换数据
    List<UserExcelDTO> excelList = list.stream().map(item ->
            {
                UserExcelDTO user = new UserExcelDTO();
                user.setUserName(item.getUserName());
                user.setPhone(item.getPhone());
                user.setGender(GenderEnum.MALE.equals(item.getGender())?"男":"女");
                user.setAddress(item.getAddress());
                user.setStatus(item.getStatus()?"启用":"禁用");
                user.setRegisterTime(item.getRegisterTime());

                return user;
            })
            .collect(Collectors.toList());
    // 调用工具类导出
    ExcelUtil.exportExcel("用户数据","用户",excelList,UserExcelDTO.class,response);
}

导出excel工具类

复制代码
package com.example.springbootdemo.util;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
 * <p>
 * excel工具类
 * </p>
 *
 * @author yurenwei
 * @since 2023/9/14
 */
@Slf4j
public class ExcelUtil {

    /**
     * 导出excel
     *
     * @param fileName excel文件名称
     * @param sheetName excel sheet名称
     * @param list 数据
     * @param clazz
     * @param response
     */
    public static void exportExcel(String fileName, String sheetName, List list, Class clazz, HttpServletResponse response){
        ServletOutputStream outputStream;
        try {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf8");
            response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".xlsx");
            outputStream = response.getOutputStream();
            EasyExcel.write(outputStream)
                    .head(clazz)
                    .excelType(ExcelTypeEnum.XLSX)
                    .sheet(sheetName)
                    .doWrite(list);
            outputStream.flush();
        } catch (Exception e) {
            log.error("导出excel异常:{}",e.getMessage());
            e.printStackTrace();
        }
    }
}

测试导出

下载excel文件查看

通过测试导出excel 列名和数据都正确

5、总结

至此,SpringBoot整合EasyExcel实现导入导出完成了,通过整合测试发现,使用EasyExcel还是挺方便的。

相关推荐
ssshooter10 分钟前
Tauri 2 iOS 开发避坑指南:文件保存、Dialog 和 Documents 目录的那些坑
前端·后端·ios
追逐时光者23 分钟前
一个基于 .NET Core + Vue3 构建的开源全栈平台 Admin 系统
后端·.net
程序员飞哥29 分钟前
90后大龄程序员失业4个月终于上岸了
后端·面试·程序员
zs宝来了1 小时前
Playwright 自动发布 CSDN 的完整实践
java
彭于晏Yan2 小时前
Redisson分布式锁
spring boot·redis·分布式
吴声子夜歌2 小时前
TypeScript——基础类型(三)
java·linux·typescript
GetcharZp2 小时前
Git 命令行太痛苦?这款 75k Star 的神级工具,让你告别“合并冲突”恐惧症!
后端
Victor3563 小时前
MongoDB(69)如何进行增量备份?
后端
Victor3563 小时前
MongoDB(70)如何使用副本集进行备份?
后端