Java export Excel file collection (easyExcel)

Table of contents

foreword

1. Introduction to EasyExcel

1. Website

2. Use of EasyExcel

1. Related dependencies

2. Realize the code

2.1 Entity class

2.2 Service layer

2.2.1 Service interface class

2.2.2 Implementation class

2.3 Control layer

2.4 Related Tools

2.4.1 Export Util

2.4.2 Excel custom style interceptor

2.4.3 Excel cell interceptor

2.4.4 Excel custom column width interceptor

2.4.5 Gender changer

2.4.6 Gender enumeration

2.5 Results

Three, EasyExcel common annotations

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


foreword

        I believe that most web projects will have the need to export and import Excel files. Today we will take a look at how to use Ali's EasyExcel component to realize the need to export Excel files. I have also written several articles about using Apache POI to export Excel before. Interested friends can go and have a look, and the link is also released for everyone:

1. Apache POI export excel (1): single sheet

2. Apache POI export excel (2): multiple sheets

3. JAVA export excel (3): export zip compressed package


1. Introduction to EasyExcel

        The well-known frameworks for parsing and generating Excel in Java include Apache POI and JXL . But they all have a serious problem that consumes a lot of memory. POI has a SAX mode API that can solve some memory overflow problems to a certain extent, but POI still has some defects, such as Excel version 07 decompression and storage after decompression. It is done in memory, and the memory consumption is still very large.
EasyExcel rewrites POI's analysis of Excel version 07. A 3M excel still needs about 100M memory for POI sax analysis. Using EasyExcel can reduce it to a few M, and no matter how big the excel is, there will be no memory overflow; version 03 relies on POI's sax mode encapsulates the model conversion on the upper layer, making it easier and more convenient for users.

1. Website

2. Use of EasyExcel

1. Related dependencies

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. Realize the code

2.1 Entity class

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 Service layer

2.2.1 Service interface class

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

2.2.2 Implementation class

    @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 Control layer

    /**
     * 导出学生信息
     */
    @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 : I wrote two export methods here. One is to export all normally; the other is to export by specifying columns, you only need to pass in the set of column fields that do not need to be exported, and the export will be filtered when exporting.

2.4 Related Tools

2.4.1 Export 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 custom style interceptor

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 cell interceptor

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 custom column width interceptor

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);
        }
    }

}

The three interceptor classes 2.4.2 , 2.4.3 and 2.4.4 are mainly used to customize some styles of exporting Excel, and small partners can also optimize and modify according to their own needs.

2.4.5 Gender changer

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 Gender enumeration

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 Results

Export all:

Export specified columns:

Three, EasyExcel common annotations

1、@ExcelProperty

A necessary field annotation. There are three parameters in the annotation value, indexwhich converterrespectively represent the column name, column number, and data conversion method. Usually, it is not necessary to set 1. value corresponds to the title text 2. index corresponds to the text line number 3. converter converter, usually Inbound and outbound conversion use, such as gender warehousing 0 and 1, outbound male and femaleconverter


Example :

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

To set the column width, there is only one parameter value, and the unit of value is the character length. The maximum number of characters that can be set is 255 characters, because the maximum number of characters that can be written in an excel cell is 255 characters.

Example :

public class StudentVo implements Serializable {

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

}

3、@ContentFontStyle

Annotation used to format the font of the cell content.

parameter meaning
fontName font name
fontHeightInPoints font height
italic whether italics
strikeout whether to set delete horizontal line
color font color
typeOffset Offset
underline underline
bold Is it bold
charset Encoding format

4、@ContentLoopMerge和@OnceAbsoluteMerge

The same point: These two are annotations for setting merged cells; they are merged according to the specified number of rows and columns, and cannot achieve the same merge.

The difference: @ContentLoopMerge is marked on the field; @OnceAbsoluteMerge is marked on the class.

4.1 @ContentLoopMerge

parameter meaning
eachRow specified number of lines
columnExtend Specify the number of columns

Example :

@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;

}

result

4.2 @OnceAbsoluteMerge

parameter meaning
firstRowIndex Specifies the index of the first row to be merged
lastRowIndex Specifies the index of the last row to be merged
firstColumnIndex Specifies the index of the first column to be merged

Example :

@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;

}

 result

5、@ContentRowHeight

Used to set row height.

parameter meaning
value Row height, -1stands for automatic row height

6、@ContentStyle

Used to format content.

parameter meaning
dataFormat date format
hidden Set the cell to hide using this style
locked Set the cell to lock using this style
quotePrefix Add a ` symbol in front of the cell, and the number or formula will be displayed as a string
horizontalAlignment Set whether to center horizontally
wrapped Sets whether the text should wrap. Set this flag to truemake all content in a cell visible by displaying it on multiple lines
verticalAlignment Set whether to center vertically
rotation Sets the rotation angle of the text in the cell. The rotation angle interval of the Excel version 03 is -90°90°, and the rotation angle interval of the Excel version 07 is 0°180°
indent Sets the number of spaces to indent text in a cell
borderLeft Set the style of the left border
borderRight Set the right border style
borderTop Set the top border style
borderBottom Set the bottom border style
leftBorderColor Set the left border color
rightBorderColor set the right border color
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

Fields not annotated with @ExcelProperty are not converted.

12、@NumberFormat

Used for number formatting.

parameter example result
value

@NumberFormat(value = "###.#")

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

The difference between using #.## and 0.00 for the parameter value is that, for example, if the imported value is 66.80, #.## will ignore the following 0 and become 66.8, while 0.00 will not ignore it, keeping the original 66.80, which I use here It is the practice of retaining 2 decimal places when importing. For the parameter of value in @NumberFormat, please refer to java.text.DecimalFormat .

13、@DateTimeFormat

Used for time formatting.

parameter example result
value @DateTimeFormat(value="yyyy-MM-dd") 2023-07-24

If this article is helpful or inspiring to you, please click three times: like, comment, bookmark ➕ follow, your support is my biggest motivation to keep writing.

Guess you like

Origin blog.csdn.net/weixin_42555014/article/details/131853805