1 介绍

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

    <dependency>
      <groupId>cn.afterturn</groupId>
      <artifactId>easypoi-spring-boot-starter</artifactId>
      <version>4.5.0</version>
    </dependency>

2 相关注解

        注解有5类分别是:

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

2.1 @Excel

        这个是必须使用的注解,如果需求简单只使用这一个注解也是可以的,涵盖了常用的Excel需求。

属性类型默认值功能强调说明
nameStringnull列名
groupNameStringnull列名组@Excel(name="语文", groupName="分数")。分数则为一级标题,语文则为二级标题。
needMergebooleanfasle是否需要纵向合并单元格(用于含有list中,单个的单元格,合并list创建的多个row)
orderNumString"0"列的排序
replaceString[]{}值的替换,导出是{"a_1", "b_2"} 导入反过来。1和2是要被替换的值。a和b则是替换后的值。@Excel(replace={"男_1",“女_2”}),当导出时,对象属性值是1则导出的Excel对应单元格为男;导入Excel时,单元格为男则对应的对象属性值为1。如果没有对应的值,则不会进行转换。
savePathString"upload"导入文件保存路径,如果是图片可以填写,默认是upload/className/ IconEntity这个类对应的就是upload/Icon/
typeint1导出类型 1 是文本 2 是图片,3 是函数,10 是数字 默认是文本拥有排名字段时请勿将该值设置成10。这样会导致合计这种无需排名的列也会显式成0。
widthdouble10列宽
heightdouble10列高,后期打算统一使用@ExcelTarget的height,这个会被废弃
isStatisticsbooleanfasle自动统计数据,在追加一行统计,把所有数据都和输出。这个处理会吞没异常,请注意这一点
isHyperlinkbooleanfalse超链接,如果是需要实现接口返回对象
isImportFieldbooleantrue校验字段,看看这个字段是不是导入的Excel中有,如果没有说明是错误的Excel,读取失败
exportFormatString""导出的时间格式,以这个是否为空来判断是否需要格式化日期
importFormatString""导入的时间格式,以这个是否为空来判断是否需要格式化日期Excel时间会固定显示成yyyy/MM/dd格式,需要使用该属性转换成想要的格式。
formatString""时间格式,相当于同时设置了exportFormat 和 importFormat
databaseFormatString"yyyyMMddHHmmss"导出时间设置,如果字段是Date类型则不需要设置 数据库如果是string 类型,这个需要设置这个数据库格式,用以转换时间格式输出
numFormatString""数字格式化,参数是Pattern,使用的对象是DecimalFormat
imageTypeint1导出类型 1 从file读取 2 是从数据库中读取 默认是文件 同样导入也是一样的
suffixString""文字后缀,如% 90 变成90%
isWrapbooleantrue是否换行 即支持\n
mergeRelyint[]{}合并单元格依赖关系,比如第二列合并是基于第一列 则{0}就可以了
mergeVerticalbooleanfasle纵向合并内容相同的单元格
fixedIndexint-1对应excel的列,忽略名字
isColumnHiddenbooleanfalse导出隐藏列

2.2 @ExcelTarget

        限定一个导出实体的注解,以及一些通用设置,作用于最外面的实体。

属性类型默认值功能

value

String

null

定义ID

height

double

10

设置行高

fontSize

short

11

设置文字大小

2.3 @ExcelEntity

        标记是不是导出excel 标记为实体类,标记是否继续穿透,可以自定义内部id。

属性类型默认值功能

id

String

null

定义ID

2.4 @ExcelCollection

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

属性类型默认值功能

id

String

null

定义ID

name

String

null

定义集合列名

orderNum

int

0

排序

type

Class<?>

ArrayList.class

导入时创建对象使用

2.5 @ExcelIgnore

        忽略这个属性,多使用需循环引用中。

3 easypoi提供的类

3.1 ExportParams

        导出参数,主要来定义 Excel的一些信息,在ExcelExportUtil 里面进行文件导出的,都是使用这个参数来作为导出参数。

/**
 * Excel 导出参数
 */
@Data
public class ExportParams extends ExcelBaseParams {
    /**
     * 表格第一行title名称
     */
    private String title;

    /**
     * 表格第一行title高度
     */
    private short titleHeight = 10;

    /**
     * 表格第一行子title名称
     */
    private String secondTitle;

    /**
     * 表格第一行子title高度
     */
    private short secondTitleHeight = 8;

    /**
     * sheetName
     */
    private String sheetName;

    /**
     * 过滤的属性
     */
    private String[] exclusions;

    /**
     * 是否添加index
     */
    private boolean addIndex;

    /**
     * index名称
     */
    private String indexName = "序号";

    /**
     * 冰冻列
     */
    private int freezeCol;

    /**
     * 表头颜色 & 标题颜色
     */
    private short color = HSSFColor.HSSFColorPredefined.WHITE.getIndex();

    /**
     * 第二行标题颜色
     * 属性说明行的颜色 例如:HSSFColor.SKY_BLUE.index 默认
     */
    private short headerColor = HSSFColor.HSSFColorPredefined.SKY_BLUE.getIndex();

    /**
     * Excel 导出版本
     */
    private ExcelType type = ExcelType.HSSF;

    /**
     * Excel 导出style
     */
    private Class<?> style = ExcelExportStylerDefaultImpl.class;

    /**
     * 表头高度
     */
    private double headerHeight = 9D;

    /**
     * 是否创建表头
     */
    private boolean isCreateHeadRows = true;

    /**
     * 是否动态获取数据
     */
    private boolean isDynamicData = false;

    /**
     * 是否追加图形
     */
    private boolean isAppendGraph = true;

    /**
     * 是否固定表头
     */
    private boolean isFixedTitle = true;

    /**
     * 单sheet最大值
     * 03版本默认6W行,07默认100W
     */
    private int maxNum = 0;

    /**
     * 导出时在excel中每个列的高度 单位为字符,一个汉字=2个字符
     * 全局设置,优先使用
     */
    private short height = 0;

    /**
     * 只读
     */
    private boolean readonly = false;

    /**
     * 列宽自适应,如果没有设置width 也自适应宽度
     */
    private boolean autoSize = false;

    public ExportParams() {

    }

    public ExportParams(String title, String sheetName) {
        this.title = title;
        this.sheetName = sheetName;
    }

    public ExportParams(String title, String sheetName, ExcelType type) {
        this.title = title;
        this.sheetName = sheetName;
        this.type = type;
    }

    public ExportParams(String title, String secondTitle, String sheetName) {
        this.title = title;
        this.secondTitle = secondTitle;
        this.sheetName = sheetName;
    }

    public short getSecondTitleHeight() {
        return (short) (secondTitleHeight * 50);
    }

    public short getTitleHeight() {
        return (short) (titleHeight * 50);
    }

    public short getHeight() {
        return height == -1 ? -1 : (short) (height * 50);
    }

    public short getHeaderHeight() {
        return (short) (titleHeight * 50);
    }

}

3.2 ExcelExportUtil

        导出工具类。构造导出需要的参数ExportParams,用该类中的静态方法进行导出指定excel文件。源码中对应的方法与参数含义如下:

/**
 * excel 导出工具类
 */
public final class ExcelExportUtil {

    public static int USE_SXSSF_LIMIT = 1000000;
    public static final String SHEET_NAME = "sheetName";

    private ExcelExportUtil() {
    }
    /**
     * 大数据量导出
     *
     * @param entity    表格标题属性
     * @param pojoClass Excel对象Class
     */
    public static IWriter<Workbook> exportBigExcel(ExportParams entity, Class<?> pojoClass) {
        ExcelBatchExportService batchServer = new ExcelBatchExportService();
        batchServer.init(entity, pojoClass);
        return batchServer;
    }

    /**
     * 大数据量导出
     *
     * @param entity 表格标题属性
     * @param excelParams cell映射类参数list
     * @return
     */
    public static IWriter<Workbook> exportBigExcel(ExportParams entity, List<ExcelExportEntity> excelParams) {
        ExcelBatchExportService batchServer = new ExcelBatchExportService();
        batchServer.init(entity, excelParams);
        return batchServer;
    }

    /**
     * 大数据量导出
     *
     * @param entity      表格标题属性
     * @param pojoClass   Excel对象Class
     * @param server      查询数据的接口
     * @param queryParams 查询数据的参数
     */
    public static Workbook exportBigExcel(ExportParams entity, Class<?> pojoClass,
                                          IExcelExportServer server, Object queryParams) {
        ExcelBatchExportService batchServer = new ExcelBatchExportService();
        batchServer.init(entity, pojoClass);
        return batchServer.exportBigExcel(server, queryParams);
    }

    /**
     * 大数据量导出
     * @param entity 表格标题属性
     * @param excelParams 表格标题属性
     * @param server      查询数据的接口
     * @param queryParams 查询数据的参数
     * @return
     */
    public static Workbook exportBigExcel(ExportParams entity, List<ExcelExportEntity> excelParams,
                                          IExcelExportServer server, Object queryParams) {
        ExcelBatchExportService batchServer = new ExcelBatchExportService();
        batchServer.init(entity, excelParams);
        return batchServer.exportBigExcel(server, queryParams);
    }


    /**
     * @param entity    表格标题属性
     * @param pojoClass Excel对象Class
     * @param dataSet   Excel对象数据List
     */
    public static Workbook exportExcel(ExportParams entity, Class<?> pojoClass,
                                       Collection<?> dataSet) {
        Workbook workbook = getWorkbook(entity.getType(), dataSet.size());
        new ExcelExportService().createSheet(workbook, entity, pojoClass, dataSet);
        return workbook;
    }

    private static Workbook getWorkbook(ExcelType type, int size) {
        if (ExcelType.HSSF.equals(type)) {
            return new HSSFWorkbook();
        } else {
            return new XSSFWorkbook();
        }
    }

    /**
     * 根据Map创建对应的Excel
     *
     * @param entity     表格标题属性
     * @param entityList Map对象列表
     * @param dataSet    Excel对象数据List
     */
    public static Workbook exportExcel(ExportParams entity, List<ExcelExportEntity> entityList,
                                       Collection<?> dataSet) {
        Workbook workbook = getWorkbook(entity.getType(), dataSet.size());
        ;
        new ExcelExportService().createSheetForMap(workbook, entity, entityList, dataSet);
        return workbook;
    }

    /**
     * 根据Map创建对应的Excel(一个excel 创建多个sheet)
     *
     * @param list 多个Map key title 对应表格Title key entity 对应表格对应实体 key data
     *             Collection 数据
     */
    public static Workbook exportExcel(List<Map<String, Object>> list, ExcelType type) {
        Workbook workbook = getWorkbook(type, 0);
        for (Map<String, Object> map : list) {
            ExcelExportService service = new ExcelExportService();
            ExportParams params = (ExportParams) map.get("title");
            params.setType(type);
            service.createSheet(workbook,params,
                    (Class<?>) map.get("entity"), (Collection<?>) map.get("data"));
        }
        return workbook;
    }

    /**
     * 导出文件通过模板解析,不推荐这个了,推荐全部通过模板来执行处理
     * @param params    导出参数类
     * @param pojoClass 对应实体
     * @param dataSet   实体集合
     * @param map       模板集合
     * @return
     */
    @Deprecated
    public static Workbook exportExcel(TemplateExportParams params, Class<?> pojoClass,
                                       Collection<?> dataSet, Map<String, Object> map) {
        return new ExcelExportOfTemplateUtil().createExcelByTemplate(params, pojoClass, dataSet,
                map);
    }

    /**
     * 导出文件通过模板解析只有模板,没有集合
     *
     * @param params 导出参数类
     * @param map    模板集合
     * @return
     */
    public static Workbook exportExcel(TemplateExportParams params, Map<String, Object> map) {
        return new ExcelExportOfTemplateUtil().createExcelByTemplate(params, null, null, map);
    }

    /**
     * 导出文件通过模板解析只有模板,没有集合
     * 每个sheet对应一个map,导出到处,key是sheet的NUM
     *
     * @param params 导出参数类
     * @param map    模板集合
     * @return
     */
    public static Workbook exportExcel(Map<Integer, Map<String, Object>> map,
                                       TemplateExportParams params) {
        return new ExcelExportOfTemplateUtil().createExcelByTemplate(params, map);
    }

    /**
     * 导出文件通过模板解析只有模板,没有集合
     * 每个sheet对应一个list,按照数量进行导出排序,key是sheet的NUM
     *
     * @param params 导出参数类
     * @param map    模板集合
     * @return
     */
    public static Workbook exportExcelClone(Map<Integer, List<Map<String, Object>>> map,
                                            TemplateExportParams params) {
        return new ExcelExportOfTemplateUtil().createExcelCloneByTemplate(params, map);
    }

}

3.3 ImportParams

        导入的参数设置,主要根据你文件里面的内容的格式来进行设置。

/**
 * 导入参数设置
 */
@Data
public class ImportParams extends ExcelBaseParams {

    public static final String SAVE_URL = "/excel/upload/excelUpload";

    /**
     * 表格标题行数,默认0
     */
    private int titleRows = 0;
    /**
     * 表头行数,默认1
     */
    private int headRows = 1;
    /**
     * 字段真正值和列标题之间的距离 默认0
     */
    private int startRows = 0;

    /**
     * 主键设置,如何这个cell没有值,就跳过 或者认为这个是list的下面的值
     * 大家不理解,去掉这个
     */
    private Integer keyIndex = null;
    /**
     * 开始读取的sheet位置,默认为0
     */
    private int startSheetIndex = 0;
    /**
     * 上传表格需要读取的sheet 数量,默认为1
     */
    private int sheetNum = 1;
    /**
     * 是否需要保存上传的Excel,默认为false
     */
    private boolean needSave = false;
    /**
     * 校验组
     */
    private Class[] verifyGroup = null;
    /**
     * 是否需要校验上传的Excel,默认为false
     */
    private boolean needVerify = false;
    /**
     * 返回文件是否分割,默认是分割
     */
    private boolean verifyFileSplit = true;
    /**
     * 校验处理接口
     */
    private IExcelVerifyHandler verifyHandler;
    /**
     * 保存上传的Excel目录,默认是 如 TestEntity这个类保存路径就是
     * upload/excelUpload/Test/yyyyMMddHHmss_***** 保存名称上传时间_五位随机数
     */
    private String saveUrl = SAVE_URL;
    /**
     * 最后的无效行数
     */
    private int lastOfInvalidRow = 0;
    /**
     * 手动控制读取的行数
     */
    private int readRows = 0;
    /**
     * 导入时校验数据模板,是不是正确的Excel
     */
    private String[] importFields;
    /**
     * 导入时校验excel的标题列顺序。依赖于importFields的配置顺序
    */
    private boolean needCheckOrder = false;
    /**
     * Key-Value 读取标记,以这个为Key,后面一个Cell 为Value,多个改为ArrayList
     */
    private String keyMark = ":";
    /**
     * 按照Key-Value 规则读取全局扫描Excel,但是跳过List读取范围提升性能
     * 仅仅支持titleRows + headRows + startRows 以及 lastOfInvalidRow
     */
    private boolean readSingleCell = false;
    /**
     * 是否并行计算
     */
    private boolean concurrentTask = false;
    /**
     * 最小截取大小
     */
    private Integer critical = 1000;
}

3.4 ExcelImportUtil

        导入工具。传入的文件、导出的entity的类,对应的import的参数来进行文件的导入。

/**
 * Excel 导入工具
 */
@SuppressWarnings({ "unchecked" })
public class ExcelImportUtil {

    private ExcelImportUtil() {
    }

    private static final Logger LOGGER = LoggerFactory.getLogger(ExcelImportUtil.class);

    /**
     * Excel 导入 数据源本地文件,不返回校验结果 导入 字 段类型 Integer,Long,Double,Date,String,Boolean
     * 
     * @param file 导入的文件
     * @param pojoClass 需要导入数据成的entity类
     * @param params 导入的参数
     * @return
     */
    public static <T> List<T> importExcel(File file, Class<?> pojoClass, ImportParams params) {
        FileInputStream in = null;
        try {
            in = new FileInputStream(file);
            return new ExcelImportService().importExcelByIs(in, pojoClass, params, false).getList();
        } catch (ExcelImportException e) {
            throw new ExcelImportException(e.getType(), e);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            throw new ExcelImportException(e.getMessage(), e);
        } finally {
            IOUtils.closeQuietly(in);
        }
    }

    /**
     * Excel 导入 数据源IO流,不返回校验结果 导入 字段类型 Integer,Long,Double,Date,String,Boolean
     * 
     * @param inputstream 文件流
     * @param pojoClass 需要导入数据成的entity类
     * @param params 导入的参数
     */
    public static <T> List<T> importExcel(InputStream inputstream, Class<?> pojoClass,
                                          ImportParams params) throws Exception {
        return new ExcelImportService().importExcelByIs(inputstream, pojoClass, params, false).getList();
    }

    /**
     * Excel 导入 数据源IO流 字段类型 Integer,Long,Double,Date,String,Boolean
     * 支持校验,支持Key-Value
     * 
     * @param inputstream 文件流
     * @param pojoClass 需要导入数据成的entity类
     * @param params 导入的参数
     */
    public static <T> ExcelImportResult<T> importExcelMore(InputStream inputstream,
                                                             Class<?> pojoClass,
                                                             ImportParams params) throws Exception {
        return new ExcelImportService().importExcelByIs(inputstream, pojoClass, params, true);
    }

    /**
     * Excel 导入 数据源本地文件 字段类型 Integer,Long,Double,Date,String,Boolean
     * 支持校验,支持Key-Value
      * @param inputstream 文件流
     * @param pojoClass 需要导入数据成的entity类
     * @param params 导入的参数
     */
    public static <T> ExcelImportResult<T> importExcelMore(File file, Class<?> pojoClass,
                                                             ImportParams params) {
        FileInputStream in = null;
        try {
            in = new FileInputStream(file);
            return new ExcelImportService().importExcelByIs(in, pojoClass, params, true);
        } catch (ExcelImportException e) {
            throw new ExcelImportException(e.getType(), e);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            throw new ExcelImportException(e.getMessage(), e);
        } finally {
            IOUtils.closeQuietly(in);
        }
    }

    /**
     * Excel 通过SAX解析方法,适合大数据导入,不支持图片
     * 导入 数据源本地文件,不返回校验结果 导入字段类型 Integer,Long,Double,Date,String,Boolean
     * 
      * @param inputstream 文件流
     * @param pojoClass 需要导入数据成的entity类
     * @param params 导入的参数
     * @param handler 接口自定义处理类,用来解析对象
     */
    public static void importExcelBySax(InputStream inputstream, Class<?> pojoClass,
                                        ImportParams params, IReadHandler handler) {
        new SaxReadExcel().readExcel(inputstream, pojoClass, params, handler);
    }

}

4 使用案例

4.1 自定义easypoi工具类

package com.ywz.utils;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;


/**
 * 类描述 -> EasyPoi工具类
 *
 * @Author: ywz
 * @Date: 2024/08/20
 */
@Slf4j
public class EasyPoiUtils {

    /**
     * 方法描述 -> 复杂导出Excel,包括文件名以及表名,不创建表头
     *
     * @param list      数据源
     * @param title     表头名称
     * @param sheetName sheet表名
     * @param pojoClass 映射的实体类
     * @param fileName  导出的文件名
     * @param tailInfo 尾部信息,可以为null
     * @Author: ywz
     * @Date: 2024/08/20
     */
    public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName, HttpServletResponse response, String tailInfo) {
        defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName), tailInfo);
    }

    /**
     * 方法描述 -> 动态表头导出
     *
     * @param list 数据源
     * @param fileName 文件名
     * @param exportParams 导出参数
     * @param titleList 标题集合
     * @param response 响应
     * @param tailInfo 尾部信息,可以为null
     * @Author: ywz
     * @Date: 2024/11/02
     */
    public static void dynamicExportExcel(List<?> list, String fileName, ExportParams exportParams, List<ExcelExportEntity> titleList, HttpServletResponse response, String tailInfo) {
        Workbook sheets = ExcelExportUtil.exportExcel(exportParams, titleList, list);
        downLoadExcel(fileName, response, sheets, tailInfo);
    }

    /**
     * 方法描述 -> 导出数据源属性不为空的列。
     *  <p>
     *    此方法会根据数据源中第一个对象的属性进行导出表头统计。
     *    对象的属性为null则不会作为表单的表头进行导出。
     *    数据源类型必须要有@Excel注解且存在name值。
     *  </p>
     * @param list 数据源
     * @param pojoClass 数据源类型
     * @param fileName 文件名
     * @param exportParams 导出参数
     * @param response 响应
     * @param tailInfo 尾部信息,可以为null
     * @Author: ywz
     * @Date: 2024/11/03
     */
    public static <T> void exportExcelByPropertyNotNull(List<T> list, Class<T> pojoClass, String fileName, ExportParams exportParams, HttpServletResponse response, String tailInfo) {
        if (list == null || list.isEmpty()) {
            throw new RuntimeException("数据源为空!");
        }
        // 创建需要导出的标题集合
        List<ExcelExportEntity> entityList = new ArrayList<>();
        // 获取第一个对象
        T t = list.get(0);
        // 获取数据源对象所有属性
        Field[] declaredFields = pojoClass.getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            Object o = null;
            try {
                o = field.get(t);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
            if (o != null) {
                // 获取Excel注解
                Excel annotation = field.getAnnotation(Excel.class);
                if (annotation != null) {
                    ExcelExportEntity excelExportEntity = new ExcelExportEntity(annotation.name(), field.getName());
                    excelExportEntity.setGroupName(annotation.groupName());
                    excelExportEntity.setOrderNum(Integer.parseInt(annotation.orderNum()));
                    excelExportEntity.setWidth(annotation.width());
                    entityList.add(excelExportEntity);
                }
            }
        }
        // 动态导出
        dynamicExportExcel(list, fileName, exportParams, entityList, response, tailInfo);
    }


    /**
     * 方法描述 -> 默认导出方法
     *
     * @param list         数据源
     * @param pojoClass    pojo实体
     * @param fileName     导出的文件名
     * @param exportParams ExportParams封装实体
     * @param tailInfo     尾部信息,可以为null
     * @Author: ywz
     * @Date: 2024/08/20
     */
    public static void defaultExport(List<?> list, Class<?> pojoClass, String fileName, HttpServletResponse response, ExportParams exportParams, String tailInfo) {
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list);
        if (workbook != null) {
            downLoadExcel(fileName, response, workbook, tailInfo);
        }
    }

    /**
     * 方法描述 -> Excel下载
     *
     * @param fileName 文件名称
     * @param workbook Excel对象
     * @param tailInfo 尾部信息,可以为null
     * @Author: ywz
     * @Date: 2024/08/20
     */
    private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook, String tailInfo) {
        Workbook responseWorkbook = setWorkbookTailInfo(workbook, tailInfo);
        if (!fileName.endsWith(".xlsx"))
            fileName += ".xlsx";
        try {
            response.setCharacterEncoding("UTF-8");
            response.setHeader("content-Type", "application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            responseWorkbook.write(response.getOutputStream());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 方法描述 -> 根据文件路径来导入Excel
     *
     * @param filePath   文件路径
     * @param titleRows  表标题的行数
     * @param headerRows 表头行数
     * @param pojoClass  Excel实体类
     * @Author: ywz
     * @Date: 2024/08/20
     */
    public static <T> List<T> importExcel(String filePath, Integer titleRows, Integer headerRows, Class<T> pojoClass) {
        //判断文件是否存在
        if (StringUtils.isBlank(filePath)) {
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        List<T> list = null;
        try {
            list = ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);
        } catch (NoSuchElementException e) {
            throw new RuntimeException("模板不能为空");
        } catch (Exception e) {
            log.error(e.getMessage());

        }
        return list;
    }

    /**
     * 方法描述 -> 根据接收的Excel文件来导入Excel,并封装成实体类
     *
     * @param file       上传的文件
     * @param titleRows  表标题的行数
     * @param headerRows 表头行数
     * @param pojoClass  Excel实体类
     * @Author: ywz
     * @Date: 2024/08/20
     */
    public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass) {
        if (file == null) {
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        List<T> list = null;
        InputStream is = null;
        try {
            is = file.getInputStream();
            list = ExcelImportUtil.importExcel(is, pojoClass, params);
        } catch (NoSuchElementException e) {
            throw new RuntimeException("excel文件不能为空");
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        } finally {
            try {
                if (is != null)
                    is.close();
            } catch (IOException e) {
                log.error(e.getMessage());
            }
        }
        return list;
    }

    /**
     * 方法描述 -> 导出表格设置自定义尾部信息
     *
     * @param workbook 工作簿
     * @param tailInfo 尾部信息
     * @Author: ywz
     * @Date: 2024/11/03
     */
    private static Workbook setWorkbookTailInfo(Workbook workbook, String tailInfo) {
        if (tailInfo == null)
            return workbook;
        // 获取最后一页
        Sheet sheetAt = workbook.getSheetAt(workbook.getNumberOfSheets() - 1);
        // 获取最后一行
        Row tailRow = sheetAt.createRow(sheetAt.getLastRowNum() + 1);
        tailRow.createCell(0);
        tailRow.getCell(0).setCellValue(tailInfo);
        return workbook;
    }
}

4.2 简单的导入导出

4.2.1 定义实体类

package com.ywz.entity;

import cn.afterturn.easypoi.excel.annotation.Excel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.time.LocalDateTime;

@ApiModel("用户实体类")
@Data
public class User {
    @ApiModelProperty("用户id")
    @Excel(name = "用户id", orderNum = "0")
    private Integer id;

    @ApiModelProperty("用户名")
    @Excel(name = "用户名", orderNum = "1")
    private String name;

    @ApiModelProperty("密码")
    @Excel(name = "密码", orderNum = "2")
    private String password;

    @ApiModelProperty("年龄")
    @Excel(name = "年龄", orderNum = "3")
    private Integer age;

    @ApiModelProperty("状态")
    @Excel(name = "状态", orderNum = "6", replace = {"正常_1", "禁用_0"})
    private Integer status;

    @ApiModelProperty("创建时间")
    @Excel(name = "创建时间", orderNum = "4", exportFormat = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
}

4.2.2 测试

        准备个excel文件进行导入:

        测试方法: 

package com.ywz;

import com.ywz.entity.User;
import com.ywz.utils.EasyPoiUtil;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
public class EasyPoiTest {
    @Test
    public void importExcel() {

        // 导入测试
        String file = "D:\\用户表.xlsx";
        List<User> users = EasyPoiUtil.importExcel(file, 0, 1, User.class);
        System.out.println(users);
        // 导出假代码
        List<User> list = new ArrayList<>();
        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setPassword("123456");
        user.setAge(18);
        user.setStatus(1);
        user.setCreateTime(LocalDateTime.now());
        list.add(user);
        User user2 = new User();
        user2.setId(2);
        user2.setName("李四");
        user2.setPassword("111111");
        user2.setAge(20);
        user2.setStatus(1);
        user2.setCreateTime(LocalDateTime.now());
        list.add(user2);
    }
}

        在控制台查看导入成功:

5 注意事项

        导入时,被@Excel标记的对象属性最好使用String类型,这样可以避免在导入时因为Excel内容不标准导致出现对象属性赋值异常。更复杂的Excel操作请查看Springboot与easypoi(2):合并单元格、二级表头、动态导出_easypoi合并单元格-CSDN博客

点击阅读全文
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐