Java导出Excel文件合集(easyExcel)

不管现实多么惨不忍睹,都要持之以恒地相信,这只是黎明前短暂的黑暗而已。不要惶恐眼前的难关迈不过去,不要担心此刻的付出没有回报,别再花时间等待天降好运。真诚做人,努力做事!你想要的,岁月都会给你。Java导出Excel文件合集(easyExcel),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

目录

前言

一、EasyExcel简介

1、网站

二、EasyExcel使用

1、相关依赖

2、实现代码

2.1 实体类

2.2 服务层

2.2.1 服务接口类

2.2.2 实现类

2.3 控制层

2.4 相关工具类

2.4.1 导出Util

2.4.2 Excel自定义样式拦截器

2.4.3 Excel单元格拦截器

2.4.4 Excel自定义列宽拦截器

2.4.5 性别转换器

2.4.6 性别枚举

2.5 结果

三、EasyExcel常用注解

1、@ExcelProperty

2、@ColumnWith

3、@ContentFontStyle

4、@ContentLoopMerge和@OnceAbsoluteMerge

4.1 @ContentLoopMerge

4.2 @OnceAbsoluteMerge

5、@ContentRowHeight

6、@ContentStyle

7、@HeadFontStyle

8、@HeadRowHeight

9、@HeadStyle

10、@ExcelIgnore

11、@ExcelIgnoreUnannotated

12、@NumberFormat

13、@DateTimeFormat


前言

        相信在大部分的web项目中都会有导出导入Excel的需求,今天我们就来看看如何用阿里的EasyExcel组件去实现导出Excel文件的需求。之前我也写过几篇使用Apache POI导出Excel的文章,有兴趣的小伙伴可以去瞅瞅,链接也给大家放出来了:

1、Apache POI导出excel(一):单sheet

2、Apache POI导出excel(二):多个sheet

3、JAVA 导出excel(三):导出zip压缩包


一、EasyExcel简介

        Java解析、生成Excel比较有名的框架有Apache POIJXL。但他们都存在一个严重的问题就是非常的耗内存,POI有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。
EasyExcel重写了POI对07版Excel的解析,一个3M的excel用POI sax解析依然需要100M左右内存,改用EasyExcel可以降低到几M,并且再大的excel也不会出现内存溢出;03版依赖POI的sax模式,在上层做了模型转换的封装,让使用者更加简单方便。

1、网站

二、EasyExcel使用

1、相关依赖

pom.xml

        <!-- easyExcel -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.2.1</version>
            <!-- 3+以上版本的easyExcel,使用poi 5+以上版本时,需要手动排除:poi-ooxml-schemas -->
            <exclusions>
                <exclusion>
                    <artifactId>poi-ooxml-schemas</artifactId>
                    <groupId>org.apache.poi</groupId>
                </exclusion>
            </exclusions>
        </dependency>

2、实现代码

2.1 实体类

import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.test.java.converter.GenderConverter;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 学生类
 */
@Data // lombok注解,会生成getter/setter方法
@ExcelIgnoreUnannotated // 没加导出注解的字段,不导出
public class StudentVo implements Serializable {

    /*** 用户ID*/
    private Long userId;

    /*** 姓名*/
    @ExcelProperty(value = "姓名")
    @ColumnWidth(10)
    private String studentName;

    /*** 年龄*/
    @ExcelProperty(value = "年龄")
    private Integer age;

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

    /*** 性别(1男 2女)*/
    @ExcelProperty(value = "性别", converter = GenderConverter.class)
    private Integer gender;

    /*** 生日*/
    @ExcelProperty(value = "生日")
    private String birthday;

    /*** 分数*/
    @ExcelProperty(value = "分数")
    @NumberFormat(value = "###.#") // 数字格式化,保留1位小数
    private BigDecimal score;

    /*** 创建时间*/
    @ExcelProperty(value = "创建时间")
    @DateTimeFormat("yyyy-MM-dd")
    private Date createTime;

}

2.2 服务层

2.2.1 服务接口类

    // 导出学生信息
    List<StudentVo> exportStudent();

2.2.2 实现类

    @Override
    public List<StudentVo> exportStudent() {

        List<StudentVo> list = new ArrayList<>();
        // 我这里使用for循环 创造了10天测试数据,实际的业务场景肯定是从数据库中查出需要导出的数据
        for (int i = 1; i <= 10; i++) {
            StudentVo student = new StudentVo();
            student.setUserId((long) i);
            student.setStudentName("王" + i);
            student.setAge(18 + i);
            student.setPhone("1305678111" + i);
            if (i % 2 == 0) {
                student.setGender(2);
            } else {
                student.setGender(1);
            }
            student.setBirthday("1997-01-01");
            student.setCreateTime(new Date());
            list.add(student);
        }
        return list;
    }

2.3 控制层

    /**
     * 导出学生信息
     */
    @GetMapping("/exportStudent")
    public void exportStudent(HttpServletResponse response) {
        List<StudentVo> list = userService.exportStudent();

        // 指定列导出
        String column = "studentName,age,phone";// 定义无需导出的列字段
        if (StringUtils.isNotEmpty(column)) {
            List<String> columns = Arrays.asList(column.split(","));
            ExportUtil.exportExcel(response, StudentVo.class, "学生信息", list, columns);
        } else {
            ExportUtil.exportExcel(response, StudentVo.class, "学生信息", list);
        }
    }

PS:我这里写了两个导出方法。一个是正常导出全部;另一个是指定列导出,只需传入无需导出的列字段集合,导出的时候就会进行过滤导出。

2.4 相关工具类

2.4.1 导出Util

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.write.metadata.WriteSheet;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Excel工具类
 */
public class ExportUtil extends EasyExcelFactory {

    public ExportUtil() {
    }

    /**
     * 导入Excel
     */
    public static void importExcel(InputStream inputStream, Class<?> head, ReadListener readListener) {
        read(inputStream, head, readListener).sheet().doRead();
    }

    /**
     * 导出Excel(全部)
     *
     * @param response 响应
     * @param clazz    表头数据
     * @param fileName 文件名
     * @param list     需要导出的数据
     */
    public static void exportExcel(HttpServletResponse response, Class<?> clazz, String fileName, List<?> list) {
        baseExportExcel(response, clazz, fileName, list, new ArrayList<>());
    }

    /**
     * 导出Excel(指定列导出)
     *
     * @param response       响应
     * @param clazz          表头数据
     * @param fileName       文件名
     * @param list           需要导出的数据
     * @param excludeColumns 过滤导出的字段名
     */
    public static void exportExcel(HttpServletResponse response, Class<?> clazz, String fileName, List<?> list, List<String> excludeColumns) {
        baseExportExcel(response, clazz, fileName, list, excludeColumns);
    }

    public static void baseExportExcel(HttpServletResponse response, Class<?> clazz, String fileName, List<?> list, List<String> excludeColumns) {
        try {
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
            String name = format.format(new Date());
            String filename = URLEncoder.encode(name + fileName + ".xlsx", "UTF-8");
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/vnd.ms-excel");
            response.setHeader("Content-disposition", "attachment;filename=" + filename);
            ExcelWriter excelWriter = write(response.getOutputStream()).registerWriteHandler(new ExcelColumnWidthHandler()).registerWriteHandler(new ExcelSheetWriteHandler()).registerWriteHandler(new ExcelStyleHandler()).excludeColumnFieldNames(excludeColumns).build();
            WriteSheet writeSheet = writerSheet(0, fileName).head(clazz).build();
            excelWriter.write(list, writeSheet);
            excelWriter.finish();
        } catch (Exception var8) {
            throw new RuntimeException("导出" + fileName + "失败");
        }
    }

    /**
     * 导出Excel(多个sheet导出)
     *
     * @param response 响应
     * @param fileName 文件名
     */
    public static ExcelWriter exportExcels(HttpServletResponse response, String fileName) {
        try {
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
            String name = format.format(new Date());
            String filename = URLEncoder.encode(name + fileName + ".xlsx", "UTF-8");
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/vnd.ms-excel");
            response.setHeader("Content-disposition", "attachment;filename=" + filename);
            return write(response.getOutputStream()).registerWriteHandler(new ExcelColumnWidthHandler()).registerWriteHandler(new ExcelSheetWriteHandler()).registerWriteHandler(new ExcelStyleHandler()).build();
        } catch (Exception var3) {
            throw new RuntimeException("导出" + fileName + "失败");
        }
    }

    /**
     * 创建工作表sheet
     *
     * @param sheetNo   工作表编号
     * @param sheetName 工作表名称
     * @param clazz     表头数据
     */
    public static WriteSheet createSheet(Integer sheetNo, String sheetName, Class<?> clazz) {
        return writerSheet(sheetNo, sheetName).head(clazz).build();
    }

}

2.4.2 Excel自定义样式拦截器

import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.AbstractVerticalCellStyleStrategy;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;

/**
 * Excel自定义样式拦截器
 */
public class ExcelStyleHandler extends AbstractVerticalCellStyleStrategy {

    private static final String FONT_NAME = "等线";
    private static final Integer[] COLUMN_INDEX = new Integer[]{1, 2, 3, 4, 7, 8, 9};


    @Override
    protected WriteCellStyle contentCellStyle(Head head) {
        // 内容的策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        // 背景白色
        contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
        contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
        contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
        contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
        WriteFont contentWriteFont = new WriteFont();
        // 字体大小
        contentWriteFont.setFontHeightInPoints((short) 12);
        // 字体样式
        contentWriteFont.setFontName(FONT_NAME);
        contentWriteCellStyle.setWriteFont(contentWriteFont);
        return contentWriteCellStyle;
    }

}

2.4.3 Excel单元格拦截器

import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.xssf.streaming.SXSSFSheet;

/**
 * Excel单元格拦截器
 */
public class ExcelSheetWriteHandler implements SheetWriteHandler {

    // 设置100列column
    private static final Integer COLUMN = 100;

    @Override
    public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
    }

    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        for(int i = 0; i < COLUMN; ++i) {
            // 设置为文本格式
            SXSSFSheet sxssfSheet = (SXSSFSheet)writeSheetHolder.getSheet();
            CellStyle cellStyle = writeWorkbookHolder.getCachedWorkbook().createCellStyle();
            // 49为文本格式
            cellStyle.setDataFormat((short)49);
            // i为列,一整列设置为文本格式
            sxssfSheet.setDefaultColumnStyle(i, cellStyle);
        }
    }
}

2.4.4 Excel自定义列宽拦截器

import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import org.apache.poi.ss.usermodel.Cell;

import java.util.List;

/**
 * Excel自定义列宽拦截器
 */
public class ExcelColumnWidthHandler extends AbstractColumnWidthStyleStrategy {


    @Override
    protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        if (Boolean.TRUE.equals(isHead)) {
            int columnWidth = cell.getStringCellValue().length();
            columnWidth = Math.max(columnWidth * 2, 20);
            if (columnWidth > 255) {
                columnWidth = 255;
            }
            writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 256);
        }
    }

}

2.4.22.4.32.4.4这三个拦截器类,主要是用于自定义导出Excel的一些样式,小伙伴也可以根据自己的需求,进行优化修改。

2.4.5 性别转换器

import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ReadConverterContext;
import com.alibaba.excel.converters.WriteConverterContext;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.test.java.base.GenderEnum;

/**
 * 性别转换器
 */
public class GenderConverter implements Converter<Integer> {

    @Override
    public Class<?> supportJavaTypeKey() {
        return Integer.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    // 读取Excel文件时将string转换为integer(导入)
    @Override
    public Integer convertToJavaData(ReadConverterContext<?> context) {
        return GenderEnum.convert(context.getReadCellData().getStringValue()).getValue();
    }

    // 写入Excel文件时将integer转换为string(导出)
    @Override
    public WriteCellData<?> convertToExcelData(WriteConverterContext<Integer> context) {
        return new WriteCellData<>(GenderEnum.convert(context.getValue()).getDescription());
    }

}

2.4.6 性别枚举

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.stream.Stream;

/**
 * 性别枚举
 */
@Getter
@AllArgsConstructor
public enum GenderEnum {

    /**
     * 未知
     */
    UNKNOWN(0, "未知"),

    /**
     * 男性
     */
    MALE(1, "男性"),

    /**
     * 女性
     */
    FEMALE(2, "女性");

    private final Integer value;

    @JsonFormat
    private final String description;

    public static GenderEnum convert(Integer value) {
        return Stream.of(values())
                .filter(bean -> bean.value.equals(value))
                .findAny()
                .orElse(UNKNOWN);
    }

    public static GenderEnum convert(String description) {
        return Stream.of(values())
                .filter(bean -> bean.description.equals(description))
                .findAny()
                .orElse(UNKNOWN);
    }
}

2.5 结果

导出全部:

Java导出Excel文件合集(easyExcel)

导出指定列:

Java导出Excel文件合集(easyExcel)

三、EasyExcel常用注解

1、@ExcelProperty

必要的一个字段注解,注解中有三个参数value,index,converter分别代表列名,列序号,数据转换方式,通常不用设置converter
1.value 通过标题文本对应
2.index 通过文本行号对应
3.converter 转换器,通常入库和出库转换使用,如性别入库0和1,出库男和女

示例

public class StudentVo {

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

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

    /*** 性别(1男 2女)*/
    @ExcelProperty(value = "性别", index = 3,converter = GenderConverter.class)
    private Integer gender;

}

2、@ColumnWith

设置列宽度,只有一个参数value,value的单位是字符长度,最大可以设置255个字符,因为一个excel单元格最大可以写入的字符个数就是255个字符。

示例

public class StudentVo implements Serializable {

    /*** 姓名*/
    @ExcelProperty(value = "姓名")
    @ColumnWidth(10)
    private String studentName;

}

3、@ContentFontStyle

用于设置单元格内容字体格式的注解。

参数 含义
fontName 字体名称
fontHeightInPoints 字体高度
italic 是否斜体
strikeout 是否设置删除水平线
color 字体颜色
typeOffset 偏移量
underline 下划线
bold 是否加粗
charset 编码格式

4、@ContentLoopMerge和@OnceAbsoluteMerge

相同点:这两个都是用于设置合并单元格的注解;它们都是按指定行数和指定列数去合并,并不能实现内容相同的合并。

不同点:@ContentLoopMerge是标注在字段上;@OnceAbsoluteMerge是标注在类上。

4.1 @ContentLoopMerge

参数 含义
eachRow 指定行数
columnExtend 指定列数

示例

@Data
public class Demo implements Serializable {

    @ExcelProperty(value = "商户名称", index = 0)
    private String appName;

    @ExcelProperty(value = "城市名称", index = 1)
    @ContentLoopMerge(eachRow = 2, columnExtend = 3)
    private String cityName;

    @ExcelProperty(value = "区域名称", index = 2)
    private String regionName;

    @ExcelProperty(value = "商圈名称", index = 3)
    private String businessAreaName;

    @ExcelProperty(value = "楼盘名称", index = 4)
    private String gardenName;

    @ExcelProperty(value = "楼栋名称", index = 5)
    private String buildingName;

    @ExcelProperty(value = "单元名称", index = 6)
    private String unitName;

    @ExcelProperty(value = "价格", index = 7)
    private Integer price;

}

结果: Java导出Excel文件合集(easyExcel)

4.2 @OnceAbsoluteMerge

参数 含义
firstRowIndex 指定合并的第一行索引
lastRowIndex 指定合并的最后一行索引
firstColumnIndex 指定合并的第一列索引

示例

@Data
@OnceAbsoluteMerge(firstRowIndex = 1, lastRowIndex = 3 , firstColumnIndex = 1 , lastColumnIndex = 3)
public class Demo implements Serializable {

    @ExcelProperty(value = "商户名称", index = 0)
    private String appName;

    @ExcelProperty(value = "城市名称", index = 1)
    private String cityName;

    @ExcelProperty(value = "区域名称", index = 2)
    private String regionName;

    @ExcelProperty(value = "商圈名称", index = 3)
    private String businessAreaName;

    @ExcelProperty(value = "楼盘名称", index = 4)
    private String gardenName;

    @ExcelProperty(value = "楼栋名称", index = 5)
    private String buildingName;

    @ExcelProperty(value = "单元名称", index = 6)
    private String unitName;

    @ExcelProperty(value = "价格", index = 7)
    private Integer price;

}

 结果: 

Java导出Excel文件合集(easyExcel)

5、@ContentRowHeight

用于设置行高。

参数 含义
value 行高,-1代表自动行高

6、@ContentStyle

用于设置内容格式。

参数 含义
dataFormat 日期格式
hidden 设置单元格使用此样式隐藏
locked 设置单元格使用此样式锁定
quotePrefix 在单元格前面增加`符号,数字或公式将以字符串形式展示
horizontalAlignment 设置是否水平居中
wrapped 设置文本是否应换行。将此标志设置为true通过在多行上显示使单元格中的所有内容可见
verticalAlignment 设置是否垂直居中
rotation 设置单元格中文本旋转角度。03版本的Excel旋转角度区间为-90°90°,07版本的Excel旋转角度区间为0°180°
indent 设置单元格中缩进文本的空格数
borderLeft 设置左边框的样式
borderRight 设置右边框样式
borderTop 设置上边框样式
borderBottom 设置下边框样式
leftBorderColor 设置左边框颜色
rightBorderColor 设置右边框颜色
topBorderColor 设置上边框颜色
bottomBorderColor 设置下边框颜色
fillPatternType 设置填充类型
fillBackgroundColor 设置背景色
fillForegroundColor 设置前景色
shrinkToFit 设置自动单元格自动大小

7、@HeadFontStyle

用于定制标题字体格式。

参数 含义
fontName 设置字体名称
fontHeightInPoints 设置字体高度
italic 设置字体是否斜体
strikeout 是否设置删除线
color 设置字体颜色
typeOffset 设置偏移量
underline 设置下划线
charset 设置字体编码
bold 设置字体是否加粗

8、@HeadRowHeight

用于设置标题行行高。

参数 含义
value 设置行高,-1代表自动行高

9、@HeadStyle

用于设置标题样式。

参数 含义
dataFormat 日期格式
hidden 设置单元格使用此样式隐藏
locked 设置单元格使用此样式锁定
quotePrefix 在单元格前面增加`符号,数字或公式将以字符串形式展示
horizontalAlignment 设置是否水平居中
wrapped 设置文本是否应换行。将此标志设置为true通过在多行上显示使单元格中的所有内容可见
verticalAlignment 设置是否垂直居中
rotation 设置单元格中文本旋转角度。03版本的Excel旋转角度区间为-90°90°,07版本的Excel旋转角度区间为0°180°
indent 设置单元格中缩进文本的空格数
borderLeft 设置左边框的样式
borderRight 设置右边框样式
borderTop 设置上边框样式
borderBottom 设置下边框样式
leftBorderColor 设置左边框颜色
rightBorderColor 设置右边框颜色
topBorderColor 设置上边框颜色
bottomBorderColor 设置下边框颜色
fillPatternType 设置填充类型
fillBackgroundColor 设置背景色
fillForegroundColor 设置前景色
shrinkToFit 设置自动单元格自动大小

10、@ExcelIgnore

不将该字段转换成Excel。

11、@ExcelIgnoreUnannotated

没有添加@ExcelProperty注解的字段都不转换。

12、@NumberFormat

用于数字格式化。

参数 示例 结果
value

@NumberFormat(value = “###.#”)

66.8
@NumberFormat(value = “#.##%”) 66.8%
@NumberFormat(value = “0.00”) 66.80

参数value用#.##0.00的区别就是,比如导入的数值是66.80,#.##会忽略掉后面的0变成66.8,而0.00则不会忽略,保持原来的66.80,我这里用的是导入时保留2位小数的做法,关于@NumberFormat里面value的参数可以参照java.text.DecimalFormat

13、@DateTimeFormat

用于时间格式化。

参数 示例 结果
value @DateTimeFormat(value=”yyyy-MM-dd”) 2023-07-24

如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、评论、收藏➕关注,您的支持是我坚持写作最大的动力。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/161424.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!