SpringBoot整合EasyExcel实现导入导出

EasyExcel是什么

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

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

相关网站

官网 easyexcel.opensource.alibaba.com/

GitHub github.com/alibaba/eas...

实现

pom依赖导入

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

excel数据

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

数据库表结构

实体类User

kotlin 复制代码
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导入方法

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

service导入方法

scss 复制代码
/**
 * 导入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对应实体类

kotlin 复制代码
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监听类

scss 复制代码
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条都被成功导入到数据库表当中,并且数据都是正确的。

接下来实现导出

controller导出方法

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

service导出方法

scss 复制代码
/**
 * 导出
 *
 * @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工具类

java 复制代码
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 列名和数据都正确

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

相关推荐
IT_陈寒2 分钟前
Python开发者都在偷偷用的5个高效技巧,你竟然还不知道?
前端·人工智能·后端
kevinzeng3 分钟前
mysql和redis数据一致性的策略
后端
小码哥_常4 分钟前
一文搞懂双Token、SSO与第三方权限打通,附实战代码
后端
SimonKing7 分钟前
5分钟学会!把代码从本地推送到 GitHub,就是这么简单
java·后端·程序员
灵境空间10 分钟前
企业微信 AI 机器人 PHP SDK —— 免回调地址,三行代码接入,支持流式回复
后端
陈随易17 分钟前
Vite 8正式发布,内置devtool,Wasm SSR 支持
前端·后端·程序员
CodeSheep24 分钟前
首个OpenClaw龙虾大模型排行榜来了,国产AI霸榜了!
前端·后端·程序员
Moment27 分钟前
想转 AI 全栈?这些 Agent 开发面试题你能答出来吗
前端·后端·面试
parafeeee9 小时前
程序人生-Hello’s P2P
数据库·后端·asp.net
bug攻城狮10 小时前
Spring Boot应用内存占用分析与优化
java·jvm·spring boot·后端