EasyPoi的基本使用

1. 前言

官方文档:http://doc.wupaas.com/docs/easypoi/

1.1 简介

Easypoi功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员就可以方便的写出Excel导出,Excel模板导出,Excel导入,Word模板导出,通过简单的注解和模板语言(熟悉的表达式语法),完成以前复杂的写法。

1.2 环境搭建

如果使用maven,请使用如下坐标:


<dependency>
    <groupId>cn.afterturngroupId>
    <artifactId>easypoi-baseartifactId>
    <version>4.1.0version>
dependency>

<dependency>
    <groupId>cn.afterturngroupId>
    <artifactId>easypoi-webartifactId>
    <version>4.1.0version>
dependency>

<dependency>
    <groupId>cn.afterturngroupId>
    <artifactId>easypoi-annotationartifactId>
    <version>4.1.0version>
dependency>

2. 使用EasyPOI

2.1 相关注解

easypoi起因就是Excel的导入导出,最初的模板是实体和Excel的对应,model–row,filed–col 这样利用注解我们可以和容易做到excel到导入导出

经过一段时间发展,现在注解有5个类分别是

  • @ExcelTarget 这个是作用于最外层的对象,描述这个对象的id,以便支持一个对象可以针对不同导出做出不同处理
  • @Excel 作用到filed上面,是对Excel一列的一个描述
  • @ExcelCollection 表示一个集合,主要针对一对多的导出,比如一个老师对应多个科目,科目就可以用集合表示
  • @ExcelEntity 表示一个继续深入导出的实体,但他没有太多的实际意义,只是告诉系统这个对象里面同样有导出的字段
  • @ExcelIgnore 和名字一样表示这个字段被忽略跳过这个导出

2.1.1 注解@ExcelTarget

作用于实体类上,同时实体类需要实现序列化接口。value需要给定一个唯一的ID,使用类名即可。

@ExcelTarget("user")
public class User implements Serializable {

2.1.2 注解@Excel

作用于实体类的属性上,每一个属性将会对应Excel上的一列。

属性 类型 默认值 功能
name String null 列名,支持name_id
needMerge boolean fasle 是否需要纵向合并单元格(用于含有list中,单个的单元格,合并list创建的多个row)
orderNum String “0” 列的排序,支持name_id
replace String[] {} 值得替换 导出是{a_id,b_id} 导入反过来
savePath String “upload” 导入文件保存路径,如果是图片可以填写,默认是upload/className/ IconEntity这个类对应的就是upload/Icon/
type int 1 导出类型 1 是文本 2 是图片,3 是函数,10 是数字 默认是文本
width double 10 列宽
height double 10 列高,后期打算统一使用@ExcelTarget的height,这个会被废弃,注意
isStatistics boolean fasle 自动统计数据,在追加一行统计,把所有数据都和输出[这个处理会吞没异常,请注意这一点]
isHyperlink boolean false 超链接,如果是需要实现接口返回对象
isImportField boolean true 校验字段,看看这个字段是不是导入的Excel中有,如果没有说明是错误的Excel,读取失败,支持name_id
exportFormat String “” 导出的时间格式,以这个是否为空来判断是否需要格式化日期
importFormat String “” 导入的时间格式,以这个是否为空来判断是否需要格式化日期
format String “” 时间格式,相当于同时设置了exportFormat 和 importFormat
databaseFormat String “yyyyMMddHHmmss” 导出时间设置,如果字段是Date类型则不需要设置 数据库如果是string 类型,这个需要设置这个数据库格式,用以转换时间格式输出
numFormat String “” 数字格式化,参数是Pattern,使用的对象是DecimalFormat
imageType int 1 导出类型 1 从file读取 2 是从数据库中读取 默认是文件 同样导入也是一样的
suffix String “” 文字后缀,如% 90 变成90%
isWrap boolean true 是否换行 即支持\n
mergeRely int[] {} 合并单元格依赖关系,比如第二列合并是基于第一列 则{0}就可以了
mergeVertical boolean fasle 纵向合并内容相同的单元格
fixedIndex int -1 对应excel的列,忽略名字
isColumnHidden boolean false 导出隐藏列

2.1.3 注解@ExcelCollection

一对多的集合注解,用以标记集合是否被数据以及集合的整体排序。

属性 类型 默认值 功能
id String null 定义ID
name String null 定义集合列名,支持nanm_id
orderNum int 0 排序,支持name_id
type Class ArrayList.class 导入时创建对象使用
@ExcelCollection(name = "订单列表",orderNum = "8")
private List<Order> orders;
@ExcelTarget("orders")
@Data
@AllArgsConstructor
public class Order implements Serializable {

    /**
     * 订单编号
     */
    @Excel(name = "订单编号",orderNum = "8",width = 20.0)
    private String num;

    /**
     * 订单名称
     */
    @Excel(name = "订单名称",orderNum = "9",width = 20.0)
    private String name;
}

2.1.4 注解@ExcelEntity

一对一实体对应,作用在实体类里面的属性又是一个实体类的情况。同时被组合的实体类也需要使用ExcelTarget和Excel进行标识。同时实现序列化接口。

@ExcelEntity
private Department department;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ExcelTarget("department")
public class Department implements Serializable {

    /**
     * 部门ID
     */
    private Integer deptId;

    /**
     * 部门名称
     */
    @Excel(name = "部门")
    private String deptName;

    /**
     * 地址
     */
    private String address;

}

2.1.5 注解@ExcelIgnore

忽略这个属性。

2.2. Maven项目整合EasyPOI

2.2.1 引入依赖

<dependencies>
    
    <dependency>
        <groupId>cn.afterturngroupId>
        <artifactId>easypoi-baseartifactId>
        <version>4.1.0version>
    dependency>
    <dependency>
        <groupId>cn.afterturngroupId>
        <artifactId>easypoi-webartifactId>
        <version>4.1.0version>
    dependency>
    <dependency>
        <groupId>cn.afterturngroupId>
        <artifactId>easypoi-annotationartifactId>
        <version>4.1.0version>
    dependency>
    
    <dependency>
        <groupId>junitgroupId>
        <artifactId>junitartifactId>
        <version>4.13.1version>
        <scope>testscope>
    dependency>
    
    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
        <version>1.18.16version>
    dependency>
    <dependency>
        <groupId>org.junit.jupitergroupId>
        <artifactId>junit-jupiterartifactId>
        <version>RELEASEversion>
        <scope>compilescope>
    dependency>
dependencies>

2.2.2 创建实体类

2.2.2.1 用户实体
/**
 * @ClassName: User
 * @Description: 用户实体类,需要实现对象序列化接口
 * @author: 莫提
 * @date 2020/11/27 8:55
 * @Version: 1.0
 */
@Data
@AllArgsConstructor
@Builder
@ExcelTarget("user")
public class User implements Serializable {

    /**
     * 用户 ID
     */
    @Excel(name = "编号",orderNum = "0",suffix = "号")
    private Integer id;
    /**
     * 姓名
     */
    @Excel(name = "姓名",orderNum = "1")
    private String name;
    /**
     * 性别
     */
    @Excel(name = "性别",orderNum = "2",replace = {"男性_男","女性_女"})
    private String sex;
    /**
     * 生日
     */
    @Excel(name = "生日",width = 35.0,format = "yyyy-MM-dd HH:mm:ss",orderNum = "4")
    private Date birthday;

    /**
     * 用户状态:【1:正常】【0:封禁】
     */
    @Excel(name = "用户状态",replace = {"正常_1","封禁_0"},orderNum = "3")
    private Integer status;

    /**
     * 密码
     */
    @ExcelIgnore
    private String password;

    /**
     * 爱好
     */
     @Excel(name = "爱好",orderNum = "5",width = 40.0)
    private List<String> hobbies;

    /**
     * 爱好字符串
     */
    @Excel(name = "爱好",orderNum = "5",width = 40.0)
    private String hobbyStr;

    /**
     * 身份证【一对一】
     */
    @ExcelEntity
    private Card card;

    /**
     * 订单列表【一对多】
     */
    @ExcelCollection(name = "订单列表",orderNum = "8")
    private List<Order> orders;

    /**
     * 头像信息,type = 2表示图片
     */
    @Excel(name = "头像",width = 20,height = 40,type = 2)
    private String photo;

    public String getHobbyStr(){
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < hobbies.size(); i++) {
            sb.append(hobbies.get(i));
            if (i != hobbies.size() -1){
                sb.append(",");
            }
        }
        return sb.toString();
    }
}
2.2.2.2 身份证实体类
/**
 * @ClassName: Card
 * @Description: 身份证
 * @author: 莫提
 * @date 2020/11/27 8:55
 * @Version: 1.0
 */
@ExcelTarget("card")
@Data
@AllArgsConstructor
public class Card implements Serializable {
    /**
     * 身份证号
     */
    @Excel(name = "身份证号码",width = 20.0,orderNum = "6")
    private String number;
    /**
     * 地址
     */
    @Excel(name = "住址",width = 50.0,orderNum = "7")
    private String address;
}

2.2.2.3 订单实体类
/**
 * @ClassName: Order
 * @Description: 订单
 * @author: 莫提
 * @date 2020/11/27 8:55
 * @Version: 1.0
 */
@ExcelTarget("orders")
@Data
@AllArgsConstructor
public class Order implements Serializable {

    /**
     * 订单编号
     */
    @Excel(name = "订单编号",orderNum = "8",width = 20.0)
    private String num;

    /**
     * 订单名称
     */
    @Excel(name = "订单名称",orderNum = "9",width = 20.0)
    private String name;
}
2.2.2.4 员工实体类
/**
 * @ClassName: Employee
 * @Description: 导入的员工实体
 * @author: 莫提
 * @date 2020/11/27 8:55
 * @Version: 1.0
 */
@ExcelTarget("employee")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {

    /**
     * 用户 ID
     */
    @Excel(name = "编号",suffix = "号")
    private Integer id;
    /**
     * 姓名
     */
    @Excel(name = "姓名")
    private String name;
    /**
     * 性别
     */
    @Excel(name = "性别")
    private String sex;
    /**
     * 生日
     */
    @Excel(name = "生日",format = "yyyy-MM-dd HH:mm:ss")
    private Date birthday;

    /**
     * 用户状态:【1:正常】【0:封禁】
     */
    @Excel(name = "用户状态",replace = {"正常_1","封禁_0"})
    private Integer status;
}

2.2.3 创建测试类

2.2.3.1 导出测试
public class TestExport {

    /**
     * 获取全部用户
     */
    public List<User> getAllUsers(){
        List<User> list = new ArrayList<>();
        // 创建身份证信息
        Card card1 = new Card("11111","江西省南昌市");
        Card card2 = new Card("22222","四川省成都市");
        Card card3 = new Card("33333","河北省唐山市");
        // 创建订单信息
        Order order1 = new Order("1","泡面");
        Order order2 = new Order("2","外套");
        Order order3 = new Order("3","裤子");
        Order order4 = new Order("4","AJ1");
        Order order5 = new Order("5","NICK");
        Order order6 = new Order("6","笔记本");
        Order order7 = new Order("7","键盘");
        Order order8 = new Order("8","鼠标");

        list.add(User.builder()
                .id(1).name("张三").sex("男").status(0).password("123456").birthday(new Date())
                .hobbies(Arrays.asList("唱歌", "跳舞")).card(card1).orders(Arrays.asList(order1,order2))
                .photo("E:\\头像\\avatar.jpg")
                .build());
        list.add(User.builder()
                .id(2).name("李四").sex("男").status(1).password("123456").birthday(new Date())
                .hobbies(Arrays.asList("睡觉", "游戏")).card(card2).orders(Arrays.asList(order3,order4,order5))
                .photo("E:\\头像\\1.jpg")
                .build());
        list.add(User.builder()
                .id(3).name("丽丽").sex("女").status(0).password("123456").birthday(new Date())
                .hobbies(Arrays.asList("技术", "代码")).card(card3).orders(Arrays.asList(order6,order7,order8))
                .photo("E:\\头像\\2.jpg")
                .build());
        return list;
    }

    /**
     * 导出Excel表格
     */
    @Test
    public void testExport() throws IOException {
        // 获取全部用户
        List<User> users = getAllUsers();

        // 导出到文件
        FileOutputStream outputStream = new FileOutputStream("E:\\导出.xls");

        // 配置Excel文件信息
        ExportParams params = new ExportParams();
        params.setTitle("用户信息");
        params.setSheetName("用户信息1表");

        // 导出Excel表格
        Workbook workbook = ExcelExportUtil.exportExcel(params, User.class, users);
        workbook.write(outputStream);

        // 关闭资源
        outputStream.close();
        workbook.close();
    }
}
2.2.3.2 导入测试
public class TestImport {
    /**
     * 导入
     */
    @Test
    public void testImport() throws Exception {
        // 参数1:文件流
        FileInputStream stream = new FileInputStream("E:\\导入.xls");
        // 参数2:导入类型
        ImportParams params = new ImportParams();
        // 标题占用多少行
        params.setTitleRows(1);
        // 头部属性占用多少行
        params.setHeadRows(1);
        // 从指定的sheet的下标开始读取
        // params.setStartSheetIndex(1);
        // 读取sheet的数量,需要和上面的配合
        // params.setSheetNum(1);

        // 对Excle进行合法参数校验
        params.setImportFields(new String[]{"编号"});

        // 参数3:导出的数据结合
        List<Employee> employees = ExcelImportUtil.importExcel(stream, Employee.class, params);
        for (Employee employee : employees) {
            System.out.println("employee = " + employee);
        }
    }
}

2.3 SpringBoot整合EasyPOI

2.3.1 导入依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-thymeleafartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
            <groupId>org.mybatis.spring.bootgroupId>
            <artifactId>mybatis-spring-boot-starterartifactId>
            <version>2.1.4version>
        dependency>

        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <scope>runtimescope>
        dependency>
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>druidartifactId>
            <version>1.1.20version>
        dependency>
        
        <dependency>
            <groupId>org.mybatis.cachesgroupId>
            <artifactId>mybatis-ehcacheartifactId>
            <version>1.0.3version>
        dependency>
        
        <dependency>
            <groupId>com.github.pagehelpergroupId>
            <artifactId>pagehelperartifactId>
            <version>5.1.10version>
        dependency>
        
        <dependency>
            <groupId>cn.afterturngroupId>
            <artifactId>easypoi-baseartifactId>
            <version>4.1.0version>
        dependency>
        <dependency>
            <groupId>cn.afterturngroupId>
            <artifactId>easypoi-webartifactId>
            <version>4.1.0version>
        dependency>
        <dependency>
            <groupId>cn.afterturngroupId>
            <artifactId>easypoi-annotationartifactId>
            <version>4.1.0version>
        dependency>
    dependencies>

2.3.2 修改配置文件

# 配置应用相关
server:
  servlet:
    context-path: /
    session:
      timeout: 60m
  tomcat:
    uri-encoding: UTF-8

# 配置MyBatis相关
mybatis:
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml

spring:
  # 禁用ThymeLeaf缓存
  thymeleaf:
    cache: false
  # 配置数据源
  datasource:
    username: root
    password: 983934
    url: jdbc:mysql://127.0.0.1:3306/learn?serverTimezone=Hongkong&useAffectedRows=true
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB

2.3.3 创建数据表

EasyPoi的基本使用_第1张图片

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `user_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `user_name` varchar(50) DEFAULT NULL COMMENT '用户名',
  `work_age` int(2) DEFAULT NULL COMMENT '工龄',
  `sex` int(1) DEFAULT NULL COMMENT '性别',
  `birthday` date DEFAULT NULL COMMENT '生日',
  `dept_id` int(11) DEFAULT NULL COMMENT '部门ID',
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=18433 DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `department`
-- ----------------------------
DROP TABLE IF EXISTS `department`;
CREATE TABLE `department` (
  `dept_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '部门ID',
  `dept_name` varchar(20) DEFAULT NULL,
  `address` varchar(100) DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`dept_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

2.3.4 逆向工程生成文件

  • 生成Mapper.Java
  • 生成Mapper.xml
  • 生成Service.java
  • 生成ServiceImpl.java
  • 生成Entity.java

生成基本的增删查改方法

2.3.5 修改实体类

/**
 * (User)实体类
 *
 * @author 莫提
 * @since 2020-12-13 20:39:36
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ExcelTarget("user")
public class User implements Serializable {

    private static final long serialVersionUID = 587947964930607265L;

    /**
     * 用户ID
     */
    @Excel(name = "ID",suffix = "号")
    private Integer userId;

    /**
     * 用户名
     */
    @Excel(name = "姓名")
    private String userName;

    /**
     * 工龄
     */
    @Excel(name = "工龄",suffix = "年")
    private Integer workAge;

    /**
     * 性别
     */
    @Excel(name = "性别",replace = {"男_1","女_0"})
    private Integer sex;

    /**
     * 生日
     */
    @Excel(name = "生日",format = "yyyy年MM月dd日",width = 20)
    private Date birthday;

    /**
     * 部门ID
     */
    @ExcelIgnore
    private Integer deptId;

    /**
     * 所属部门
     */
    @ExcelEntity
    private Department department;

}
package com.moti.entity;

import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * (Department)实体类
 *
 * @author 莫提
 * @since 2020-12-13 20:39:38
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ExcelTarget("department")
public class Department implements Serializable {

    private static final long serialVersionUID = 164895400081727426L;

    /**
     * 部门ID
     */
    private Integer deptId;

    /**
     * 部门名称
     */
    @Excel(name = "部门")
    private String deptName;

    /**
     * 地址
     */
    private String address;

}

2.3.6 编写前端页面

DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>主页title>
    
    <link rel="stylesheet" href="boot/css/bootstrap.min.css">
    
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="js/jquery-3.4.1.js">script>
head>
<body>
<hr>
<div class="container">
    <div class="row">
        <div class="col-12">
            <h3>选择Excle文件导入h3>
            <form class="form-inline" method="post" action="importExcel" enctype="multipart/form-data">
                <input type="file" class="form-control" name="file">
                <input type="submit" class="btn btn-danger" value="导入">
            form>
        div>
        <br>
        <div class="col-12">
            <table class="table table-bordered">
                <thead>
                <tr>
                    <th>IDth>
                    <th>姓名th>
                    <th>部门th>
                    <th>性别th>
                    <th>工龄th>
                    <th>出生日期th>
                tr>
                thead>
                <tbody>
                <tr th:each="user:${users}">
                    <td th:text="${user.userId}">td>
                    <td th:text="${user.userName}">td>
                    <td th:text="${user.department.deptName}">td>
                    <td th:if="${user.sex == 1}">td>
                    <td th:if="${user.sex == 0}">td>
                    <td th:text="${user.workAge}">td>
                    <td th:text="${#dates.format(user.birthday,'yyyy-MM-dd')}">td>
                tr>
                tbody>
            table>
            <br>
            <a href="exportExcel" class="btn btn-success btn-sm">导出a>
        div>
    div>
div>
body>
html>

2.3.7 编写控制层

/**
 * @ClassName: HelloController
 * @Description:
 * @author: 莫提
 * @date 2020/11/27 8:55
 * @Version: 1.0
 */
@Controller
@Slf4j
public class HelloController {

    @Autowired
    private UserService userService;
    @Autowired
    private DepartmentService departmentService;

    @GetMapping("/")
    public String hello(Map<String,Object> map){
        // 获取全部用户
        List<User> users = userService.listUsers();
        users.forEach(user -> {
            Department department = departmentService.getById(user.getDeptId());
            user.setDepartment(department);
        });
        map.put("users",users);
        return "index";
    }

    /**
     * 导入
     */
    @PostMapping("/importExcel")
    public String importExcel(MultipartFile file) throws Exception {
        if (ObjectUtils.isEmpty(file) || file.getSize() == 0){
            return "redirect:/";
        }
        log.info("接收到文件:{}",file.getOriginalFilename());
        // 参数1:文件流
        InputStream stream = file.getInputStream();

        // 参数2:导入类型
        ImportParams params = new ImportParams();

        // 标题占用多少行
        params.setTitleRows(1);

        // 头部属性占用多少行
        params.setHeadRows(1);

        // 从指定的sheet的下标开始读取
        // params.setStartSheetIndex(1);

        // 读取sheet的数量,需要和上面的配合
        // params.setSheetNum(1);

        // 对Excle进行合法参数校验
        params.setImportFields(new String[]{"姓名","部门"});

        List<User> users  = ExcelImportUtil.importExcel(stream, User.class,params);
        // 遍历结果,插入到数据库
        users.forEach(user -> {
            Department build = Department.builder().deptName(user.getDepartment().getDeptName()).build();
            List<Department> departments = departmentService.listDepartments(build);
            if (departments.size() > 0){
                user.setDeptId(departments.get(0).getDeptId());
            }
            userService.insert(user);
        });
        log.info("导入用户:{}",users);
        return "redirect:/";
    }

    /**
     * 导出Excel
     */
    @GetMapping("/exportExcel")
    public void exportExcel(HttpServletResponse response) throws IOException {
        response.setHeader("content-disposition",
                "attachment;fileName="+ URLEncoder.encode("用户列表.xls","UTF-8"));
        ServletOutputStream outputStream = response.getOutputStream();
        // 查询所有用户
        List<User> users = userService.listUsers();
        users.forEach(user -> {
            Department department = departmentService.getById(user.getDeptId());
            user.setDepartment(department);
        });
        // 生成文件的信息
        ExportParams params = new ExportParams();
        params.setTitle("导出的用户信息");
        params.setSheetName("用户信息");

        Workbook workbook = ExcelExportUtil.exportExcel(params, User.class, users);

        // 输出
        workbook.write(outputStream);

        // 关闭资源
        outputStream.close();
        workbook.close();
    }
}

EasyPoi的基本使用_第2张图片

EasyPoi的基本使用_第3张图片

EasyPoi的基本使用_第4张图片

导入之后

EasyPoi的基本使用_第5张图片

你可能感兴趣的:(SpringBoot,java,poi)