EasyExcel学习总结

1、什么事EasyExcel?

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

2、EasyExcel特点

➢ 使用简单
➢ 高性能
➢ 低消耗

3、EasyExcel读数据

3.1、少量数据读取

➢ 读操作

    /**
     * 读取指定路径文件
     *
     * @param filePath 文件路径
     * @param clazz 映射实体类型
     * @param <T> 实体
     * @return
     */
    public static <T> List<T> read(String filePath, final Class<T> clazz) {

        if (ObjectUtils.isNotEmpty(filePath)) {
            throw new ServiceException("路径文件出错了,为空");
        }

        // DataListAnalysis 不能被spring管理
        DataListAnalysis<T> listener = new DataListAnalysis<>();

        // 默认第一个sheet 文件流会自动关闭
        EasyExcel.read(filePath, clazz, listener).sheet().doRead();

        return listener.getData();
    }
    /**
     * 读取excel流,数据量不是很大,可一次全量读取
     *
     * @param inputStream 文件流
     * @param clazz 映射实体类型
     * @param <T> 实体
     * @return
     */
    public static <T> List<T> read(InputStream inputStream, final Class<T> clazz) {
        if (inputStream == null) {
            throw new ServiceException("解析出错了,文件流是null");
        }

        // DataListAnalysis 不能被spring管理
        DataListAnalysis<T> listener = new DataListAnalysis<>();

        // 默认第一个sheet 文件流会自动关闭
        EasyExcel.read(inputStream, clazz, listener).sheet().doRead();
        return listener.getData();
    }

➢ 读取监听器

	/**
     * 读取文件的解析器
     *
     * @param <T>
     */
    public class DataListAnalysis<T> extends AnalysisEventListener<T> {

        private List<T> data = new ArrayList<>();

        /**
         * 每解析一行数据事件调度中心都会通知到这个方法, 订阅者1
         *
         * @param t               解析的每行数据
         * @param analysisContext
         */
        @Override
        public void invoke(T t, AnalysisContext analysisContext) {
            data.add(t);
        }

        /**
         * excel文件解析完成后,事件调度中心会通知到该方法, 订阅者2
         *
         * @param analysisContext
         */
        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
            log.info("文件读取完成");
        }

        public List<T> getData() {
            return data;
        }
    }

3.2、大流数据读取

大量数据读取时,为防止OOM,需要分批将读取的数据先处理,一般进行临时性持久化操作


	/**
     * 读取大数据文件的解析器
     *
     * @param <T>
     */
    public class BigDataListAnalysis<T> extends AnalysisEventListener<T> {

        private List<T> data = new ArrayList<>();

        /**
         * 默认每10000条数据处理一次
         */
        private int batchCount = 10000;

        /**
         * 数据处理器,一般进行临时性持久化操作
         */
        private BigDataListHandle handle;

        /**
         * 构造器1
         */
        public BigDataListAnalysis(BigDataListHandle handle) {
            this.handle = handle;
        }

        /**
         * 构造器2
         */
        public BigDataListAnalysis(BigDataListHandle handle, Integer batchCount) {
            this.handle = handle;

            if (ObjectUtils.isNotEmpty(batchCount) && batchCount > 0) {
                this.batchCount = batchCount;
            }
        }

        /**
         * 每解析一行数据事件调度中心都会通知到这个方法, 订阅者1
         *
         * @param t               解析的每行数据
         * @param analysisContext
         */
        @Override
        public void invoke(T t, AnalysisContext analysisContext) {

            data.add(t);

            // 达到batchCount了,需要处理
            // 注意,如果最后一次未达到batchCount需到doAfterAllAnalysed方法中进行处理
            if (data.size() >= batchCount) {

                // 处理数据
                handle.handle(data);

                // 处理完成清空 list
                data.clear();
            }
        }

        /**
         * excel文件解析完成后,事件调度中心会通知到该方法, 订阅者2
         *
         * @param analysisContext
         */
        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {

            // 处理最后一批数据
            if (ObjectUtils.isNotEmpty(data)) {
                handle.handle(data);
            }

            log.info("文件读取完成");
        }

        public List<T> getData() {
            return data;
        }

    }

监听器可以进一步优化,更方便使用

	/**
     * 获取读取Excel的监听器对象
     * 为了解耦及减少每个数据模型bean都要创建一个监听器的臃肿, 使用泛型指定数据模型类型
     * 使用jdk8新特性中的函数式接口 Consumer
     * 可以实现任何数据模型bean的数据解析, 不用重复定义监听器
     *
     * @param consumer  处理解析数据的函数, 一般可以是数据入库逻辑的函数
     * @param threshold 阈值,达到阈值就处理一次存储的数据
     * @param <T>       数据模型泛型
     * @return 返回监听器
     */
    public static <T> AnalysisEventListener<T> getReadListener(Consumer<List<T>> consumer, int threshold) {

        return new AnalysisEventListener<T>() {

            /**
             * 存储解析的数据 T t
             * LinkedList基于双向链表实现, 插入和删除更快
             */
            List<T> dataList = new LinkedList<>();

            /**
             * 每解析一行数据事件调度中心都会通知到这个方法, 订阅者1
             * @param data 解析的每行数据
             * @param context
             */
            @Override
            public void invoke(T data, AnalysisContext context) {
                dataList.add(data);
                // 达到阈值就处理一次存储的数据
                if (dataList.size() >= threshold) {
                    consumer.accept(dataList);
                    dataList.clear();
                }
            }

            /**
             * excel文件解析完成后,事件调度中心会通知到该方法, 订阅者2
             * @param context
             */
            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                // 最后阈值外的数据做处理
                if (dataList.size() > 0) {
                    consumer.accept(dataList);
                }
            }
        };
    }

4、EasyExcel写数据

➢ 向一个sheet中写入

    /**
     * 写出list到指定文件文,sheet默认为0
     *
     * @param outFile
     * @param list
     */
    public static<T> void write(String outFile, List<T> list) {
        Class clazz = list.get(0).getClass();

        // 新版本会自动关闭流,不需要自己操作
        EasyExcel.write(outFile, clazz).sheet().doWrite(list);
    }

    /**
     * 写出list到流中,并指定sheet名
     *
     * @param outputStream
     * @param list
     * @param sheetName
     */
    public static void write(OutputStream outputStream, List<?> list, String sheetName) {
        Class<?> clazz = list.get(0).getClass();

        // sheetName为sheet的名字,默认写第一个sheet
        EasyExcel.write(outputStream, clazz).sheet(sheetName).doWrite(list);
    }

➢ 向多个sheet中写入

    /**
     * 写出到指定文件文,并向多个sheet写入
     *
     * @param outFile
     * @param map     key 为sheet名,值为数据
     */
    public static void writerSheets(String outFile, HashMap<Class, List> map) {

        // 关闭自动关闭流
        ExcelWriter excelWriter = EasyExcel.write(outFile).autoCloseStream(false).build();

        try {
            int sheetCount = 0;
            for (Class clazz : map.keySet()) {
                WriteSheet sheet = EasyExcel.writerSheet(sheetCount++, clazz.getName()).head(clazz).build();
                excelWriter.write(map.get(clazz), sheet);
            }
        } catch (Exception e) {
            log.error("导出异常:{}", e);
        } finally {
            if (excelWriter != null) {
                excelWriter.close();
            }
        }
    }

➢ 内容追加写入

/**
 * 写出数据到Excel,如果文件存在则追加内容
 * 
 * @param outFilePath 
 * @param clazz
 * @param list
 * @param <T>
 */
public static <T> void writeAppend(String outFilePath, Class<T> clazz, List<T> list) {
    
    File outFile = new File(outFilePath);
    File tempFile = new File(outFile.getParentFile().getAbsolutePath(), System.currentTimeMillis() + ".xlsx");

    if (outFile.exists()) {
        EasyExcel.write().needHead(false).head(clazz).withTemplate(outFile).file(tempFile).sheet().doWrite(list);
    } else {
        EasyExcel.write(outFile).head(clazz).sheet().doWrite(list);
    }

    if (tempFile.exists()) {
        outFile.delete();
        tempFile.renameTo(outFile);
    }
}

➢ 使用模板写入



➢ 写入拦截器

在导出Excel时往往还会有一些特殊的处理,比如添加水印等,这时就可以使用拦截器进行处理,
EasyExcel的拦截器有以下5个:

WriteHandler 基础拦截器,是后四个的父接口
CellWriteHandler 单元格处理拦截器
RowWriteHandler  行处理拦截器
SheetWriteHandler Sheet处理拦截器
WorkbookWriteHandler Workbook单元格处理拦截器

例如:

import cn.hutool.core.img.ImgUtil;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import com.chengjiang.common.core.utils.reflect.ReflectUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFPictureData;
import org.apache.poi.xssf.usermodel.XSSFRelation;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * excel添加水印,
 *  easyExcel默认使用的是SXSSFWorkbook,
 *  使用时设置inMemory(true),使用 XSSFWorkbook
 *
 * @author chengjiang
 */
@Slf4j
public class CustomWaterMarkHandler implements SheetWriteHandler {

    private WaterMark watermark;

    public CustomWaterMarkHandler(WaterMark watermark) {
        this.watermark = watermark;
    }

    public CustomWaterMarkHandler(String content) {
        WaterMark waterMark = new WaterMark();
        waterMark.setContent(content);

        this.watermark = waterMark;
    }

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

    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        try {
            BufferedImage bufferedImage = createWatermarkImage();
            Workbook workbook = writeWorkbookHolder.getWorkbook();

            if (workbook instanceof SXSSFWorkbook) {
                setWaterMarkToExcel((SXSSFWorkbook) workbook, bufferedImage);
            } else if (workbook instanceof XSSFWorkbook) {
                setWaterMarkToExcel((XSSFWorkbook) workbook, bufferedImage);
            }

        } catch (Exception e) {
            log.error("添加水印出错: {}", e);
            throw new RuntimeException("添加水印出错");
        }
    }

    private BufferedImage createWatermarkImage() {
        final Font font = watermark.getFont();
        final int width = watermark.getWidth();
        final int height = watermark.getHeight();

        String[] textArray = watermark.getContent().split(",");
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // 背景透明 开始
        Graphics2D g = image.createGraphics();
        image = g.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
        g.dispose();
        // 背景透明 结束
        g = image.createGraphics();
        // 设定画笔颜色
        g.setColor(new Color(Integer.parseInt(watermark.getColor().substring(1), 16)));
        // 设置画笔字体
        g.setFont(font);
        // 设定倾斜度
        g.shear(watermark.getShearX(), watermark.getShearY());

        // 设置字体平滑
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        int y = watermark.getYAxis();
        for (String s : textArray) {
            // 从画框的y轴开始画字符串.假设电脑屏幕中心为0,y轴为正数则在下方
            g.drawString(s, 0, y);
            y = y + font.getSize();
        }

        // 释放画笔
        g.dispose();
        return image;
    }

    /**
     * 将水印添加到excel
     *
     * @param workbook
     * @param bfi
     */
    private void setWaterMarkToExcel(XSSFWorkbook workbook, BufferedImage bfi) {
        //将图片添加到工作簿
        int pictureIdx = workbook.addPicture(ImgUtil.toBytes(bfi, ImgUtil.IMAGE_TYPE_PNG), Workbook.PICTURE_TYPE_PNG);

        //建立 sheet 和 图片 的关联关系
        XSSFPictureData xssfPictureData = workbook.getAllPictures().get(pictureIdx);

        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
            XSSFSheet xssfSheet = workbook.getSheetAt(i);
            PackagePartName packagePartName = xssfPictureData.getPackagePart().getPartName();
            PackageRelationship packageRelationship = xssfSheet.getPackagePart()
                    .addRelationship(packagePartName, TargetMode.INTERNAL, XSSFRelation.IMAGES.getRelation(), null);

            //添加水印到工作表
            xssfSheet.getCTWorksheet().addNewPicture().setId(packageRelationship.getId());
        }
    }

    /**
     * 给 Excel 添加水印
     *
     * @param workbook      SXSSFWorkbook
     */
    public void setWaterMarkToExcel(SXSSFWorkbook workbook, BufferedImage image) throws IOException {

        ByteArrayOutputStream imageOs = new ByteArrayOutputStream();
        ImageIO.write(image, ImgUtil.IMAGE_TYPE_PNG, imageOs);

        int pictureIdx = workbook.addPicture(imageOs.toByteArray(), XSSFWorkbook.PICTURE_TYPE_PNG);
        XSSFPictureData pictureData = (XSSFPictureData) workbook.getAllPictures().get(pictureIdx);

        //获取每个Sheet表
        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
            SXSSFSheet sheet = workbook.getSheetAt(i);

            //这里由于 SXSSFSheet 没有 getCTWorksheet() 方法,通过反射取出 _sh 属性
            XSSFSheet shReflect = (XSSFSheet) ReflectUtil.getFieldValue(sheet, "_sh");
            PackagePartName ppn = pictureData.getPackagePart().getPartName();
            String relType = XSSFRelation.IMAGES.getRelation();
            PackageRelationship pr = shReflect.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null);
            shReflect.getCTWorksheet().addNewPicture().setId(pr.getId());
        }
    }

    /**
     * 水印配置类
     */
    @Data
    public class WaterMark {

        /**
         * 水印内容
         */
        private String content = "";

        /**
         * 画笔颜色. 格式为"#RRGGBB",eg: "#C5CBCF"
         */
        private String color = "#C5CBCF";

        /**
         * 字体样式
         */
        private Font font = new Font("Microsoft YaHei", Font.BOLD, 40);

        /**
         * 水印宽度
         */
        private int width = 400;

        /**
         * 水印高度
         */
        private int height = 300;

        /**
         * 水平倾斜度
         */
        private double shearX = 0.1;

        /**
         * 垂直倾斜度
         */
        private double shearY = -0.26;

        /**
         * 字体的y轴位置
         */
        private int yAxis = 200;

    }
}

5、转换器

➢ EasyExcel自带转换器

bigdecimal
    BigDecimalBooleanConverter
    BigDecimalNumberConverter
    BigDecimalStringConverter
biginteger
    BigIntegerBooleanConverter
    BigIntegerNumberConverter
    BigIntegerStringConverter
booleanconverter
    BooleanBooleanConverter
    BooleanNumberConverter
    BooleanStringConverter
bytearray
    BoxingByteArrayImageConverter
    ByteArrayImageConverter
byteconverter
    ByteBooleanConverter
    ByteNumberConverter
    ByteStringConverter
date
    DateDateConverter
    DateNumberConverter
    DateStringConverter
doubleconverter
    DoubleBooleanConverter
    DoubleNumberConverter
    DoubleStringConverter
file
    FileImageConverter
floatconverter
    FloatBooleanConverter
    FloatNumberConverter
    FloatStringConverter
inputstream
    InputStreamImageConverter
integer
    IntegerBooleanConverter
    IntegerNumberConverter
    IntegerStringConverter
localdate
    LocalDateDateConverter
    LocalDateNumberConverter
    LocalDateStringConverter
localdatetime
    LocalDateTimeDateConverter
    LocalDateTimeNumberConverter
    LocalDateTimeStringConverter
longconverter
    LongBooleanConverter
    LongNumberConverter
    LongStringConverter
shortconverter
    ShortBooleanConverter
    ShortNumberConverter
    ShortStringConverter
string
    StringBooleanConverter
    StringErrorConverter
    StringImageConverter
    StringNumberConverter
    StringStringConverter
url
    UrlImageConverter
    

➢ 自定义转换器

自定义转换器只需实现Converter接口即可;

import cn.hutool.core.convert.Convert;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.chengjiang.common.core.utils.excel.easyexcel.annotate.ExcelDictType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;

/**
 * Excel 数据字典转换器
 *
 * @author chengjiang
 */
@Slf4j
public class DataDictConverter implements Converter<Object> {

    /**
     * 导入时如果字段类型匹配,执行此方法
     *
     * @return
     */
    @Override
    public Class<?> supportJavaTypeKey() {
        return Object.class;
    }

    /**
     * 导出时如果字段类型匹配,执行此方法
     *
     * @return
     */
    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    /**
     * 导入时将Excel列值转换为java字段值
     * 
     * @param readCellData
     * @param contentProperty
     * @param globalConfiguration
     * @return
     */
    @Override
    public Object convertToJavaData(ReadCellData readCellData, ExcelContentProperty contentProperty,
                                    GlobalConfiguration globalConfiguration) {

        // 使用字典解析
        String dictType = getDictType(contentProperty);
        String dictLabel = readCellData.getStringValue();
        String dictValue = getDictValue(dictType, dictLabel);

        if (dictValue == null) {
            log.error("[转换器 DictConvert.convertToJavaData][dictType({}) 无法解析 dictLabel({})]", dictType, dictLabel);
            return null;
        }

        // 将 String 的 value 转换成对应的属性
        Class<?> fieldClazz = contentProperty.getField().getType();
        return Convert.convert(fieldClazz, dictValue);
    }

    /**
     * 导出时将java字段值转换为Excel列值
     *
     * @param object
     * @param contentProperty
     * @param globalConfiguration
     * @return
     */
    @Override
    public WriteCellData<String> convertToExcelData(Object object, ExcelContentProperty contentProperty,
                                                    GlobalConfiguration globalConfiguration) {
        // 空时,返回空
        if (object == null) {
            return new WriteCellData<>("");
        }

        // 使用字典格式化
        String dictType = getDictType(contentProperty);
        String dictValue = String.valueOf(object);

        String label = getDictLabel(dictType, dictValue);
        if (label == null) {
            log.error("[转换器 DictConvert.convertToExcelData ][dictType({}) 无法解析 dictValue({})]", dictType, dictValue);
            return new WriteCellData<>("");
        }

        return new WriteCellData<>(label);
    }

    /**
     * 获取字典类型
     *
     * @param contentProperty
     * @return
     */
    private static String getDictType(ExcelContentProperty contentProperty) {
        ExcelDictType annotation = contentProperty.getField().getAnnotation(ExcelDictType.class);
        return ObjectUtils.isNotEmpty(annotation) ? annotation.dictType() : null;
    }

    /**
     * 获取字典值
     *
     * @param dictType
     * @param dictLabel
     * @return
     */
    private static String getDictValue(String dictType, String dictLabel) {
        if (ObjectUtils.isEmpty(dictType) || ObjectUtils.isEmpty(dictLabel)) {
            return null;
        }

        // todo 执行字典匹配
        return "A";
    }

    /**
     * 获取字典label
     *
     * @param dictType
     * @param dictValue
     * @return
     */
    private static String getDictLabel(String dictType, String dictValue) {
        if (ObjectUtils.isEmpty(dictType) || ObjectUtils.isEmpty(dictValue)) {
            return null;
        }

        // todo 执行字典匹配
        return "a";
    }

}

➢ 转换器配置方式

1. 通过@ExcelProperty注解的converter属性进行配置,推荐使用

2. 在执行ExcelReaderBuilderExcelWriterBuilder中进行配置
EasyExcel.write(output).registerConverter();
EasyExcel.read(inputStream, clazz, listener).registerConverter()

6、实体注解

➢ 实体字段与excel列映射

@ExcelProperty

value:
用于映射Excel表头,默认值为空,必须内容全匹配才能映射
如果多个字段的value设置相同,则会进行合并
如果字段没添加@ExcelProperty注解或者value为空时,则使用字段名作为默认表头;

index:
用于映射Excel表头列序号,默认值为 -1,优先级高于value与order

order:
将字段进行排序,与excel表的列顺序映射,默认值为 Integer.MAX_VALUE

converter:
字段值转换器,默认值为自动转换

@ExcelIgnore 
用在属性上,默认所有字段都会和excel去匹配,加了这个注解会忽略该字段

@ExcelIgnoreUnannotated 
默认不管加不加ExcelProperty的注解的所有字段都会参与读写,
加了ExcelIgnoreUnannotated注解以后,不加ExcelProperty注解的字段就不会参与。

➢ 字段值格式化

@DateTimeFormat
时间格式转化,需配合转换器使用

@DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒")
@ExcelProperty(value = {"日期标题"}, converter = DateStringConverter.class)
private Date createTime;

@NumberFormat
用于数字的格式化,其值参考DecimalFormat的规则

@ExcelProperty(value = {"数字标题"})
@NumberFormat("0.0")
private double total;

DecimalFormat pattern:
n = 表达式0/#个数
m = 目标值小数点前位数
l = 目标值小数点后位数

0	每个0表示一个数字,m > n,不做处理;m < n,则用0补齐
					l > n,保留表达式0个数;l < n,则用0补齐
#	每个#表示一个数字,m > n,不做处理;m < n,不做处理
					l > n,保留表达式0个数;l < n,不做处理
.	小数点
,	分组分隔符,###,### ,按后面的#个数进行分组
E	指数表示的底数指数分隔符
%	乘以100并显示为百分比
?	乘以1000并显示为千分比

➢ 写出excel样式设置

@ColumnWidth 列宽,可用在属性和方法上

参数:
value 列高,-1代表自动

@ContentFontStyle 文本字体样式

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

@ContentLoopMerge 文本循环合并

参数:
eachRow 当前属性扩展行,每几行合并一次
columnExtend 当前属性扩展列,向后扩展几列进行合并

@ContentRowHeight 文本行高度

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

@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 设置自动单元格自动大小

@HeadFontStyle 标题字体样式

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

@HeadRowHeight 标题高度

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

@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 设置自动单元格自动大小

@OnceAbsoluteMerge 合并单元格一次

参数:
firstRowIndex 合并的第一行
lastRowIndex 合并的最后一行
firstColumnIndex 合并的第一列
lastColumnIndex 合并的最后一行

➢ 实体demo

/**
 * 角色信息表-实体
 *
 * @author: chengjiang
 */
@Data
@HeadRowHeight(value = 30)
@ContentRowHeight(value = 25)
@ColumnWidth(value = 25)
@ContentFontStyle(fontName = "宋体", fontHeightInPoints = 15)
@HeadFontStyle(fontName = "宋体", fontHeightInPoints = 18, bold = BooleanEnum.TRUE)
public class SysRoleExcelVO {

    /** 
     * 角色名称 
     */
    @ExcelProperty(value = "角色名称")
    private String roleName;
    
    /** 
     * 角色权限字符串 
     */
    @ExcelProperty(value = "角色名称")
    private String roleKey;

    /** 
     * 角色状态(0正常 1停用)
     */
    @ExcelProperty(value = "角色状态")
    @ExcelIgnore
    private String status;

    /**
     * 创建时间
     */
    @ExcelProperty(value = "创建时间", converter = LocalDateTimeStringConverter.class)
    @DateTimeFormat(value = DateUtils.DATE_FORMAT_8)
    private LocalDateTime createTime;

    /**
     * 数字标题
     */
    @ExcelProperty(value = {"数字标题"})
    @NumberFormat("#,###.###")
    private double total;
    
    /**
     * 角色说明
     */
    @ExcelProperty(value = "角色说明")
    private String remark;

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值