[alibaba/easyexcel]写Excel使用注解添加单元格样式(cellStyle)的解决办法

2024-06-20 789 views
5

由于作者没有提供样式的解决办法,我使用writerHandle进行解决,我自己测试通过,但是不同场景下难免会有BUG,这里算是提供思路了 xlsx和xls字体类的问题,所以这个代码只支持xlsx的,如果要支持xls可以进行修改 版本要求 1.12-beta5 以上

准备

首先定义样式注解,我只定义了部分常用样式

注解1 CellStyleFormat

/**
 * @author luoxiao22525
 * @date 2019-1-8
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CellStyleFormat {

    /**
     * 水平居中方式 默认左居中
     * @see HorizontalAlignment
     */
    HorizontalAlignment horizontalalignment() default HorizontalAlignment.LEFT;

    /**
     *
     * 垂直居中方式 默认居中
     * @see VerticalAlignment
     */
    VerticalAlignment verticalAlignment() default VerticalAlignment.CENTER;

    /**
     * 边框方式 默认无
     * @see BorderStyle
     */
    BorderStyle borderStyle() default BorderStyle.NONE;

    /**
     * 边框颜色 默认白
     * @see IndexedColors
     */
    IndexedColors borderColor() default IndexedColors.WHITE;

    /**
     * 字体设置
     * @see org.apache.poi.xssf.usermodel.XSSFFont
     * @see org.apache.poi.hssf.usermodel.HSSFFont
     */
    CellFontFormat cellFont() default @CellFontFormat();

    /**
     * 背景颜色
     * @see IndexedColors
     */
    IndexedColors fillBackgroundColor() default IndexedColors.WHITE;

    /**
     * 单元格是否换行
     */
    boolean warpText() default false;

}

注解2 CellFontFormat 字体类型注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CellFontFormat {

    String fontName() default "宋体";

    short fontHeightInPoints() default 11;

    IndexedColors fontColor() default IndexedColors.BLACK;

}

编写自定义writerhandler


/**
 * @author luoxiao22525
 * @param <T> 必须是继承BaseRowModel类的class
 */
public class PreWriterHandler<T extends Class<? extends BaseRowModel>> implements WriteHandler {

    private T rowModel;

    private Map<Integer, CellStyleFormat> colStyleFormat = new HashMap<>();

    private Map<Integer, CellStyle> colStyle = new HashMap<>();

    private Map<String, String> infos = new HashMap<>();

    public static final String TITLE_NUM = "title_num";

    public PreWriterHandler(T rowModel) {
        this.rowModel = rowModel;
        init(rowModel);
    }

    private void init(T rowModel) {
        Field[] declaredFields = rowModel.getDeclaredFields();
        //查找有CellStyle注解和ExcelProperty注解的Field加入cellStyle
        int titleNum = 0;
        for (Field field : declaredFields) {
            CellStyleFormat cellStyle = field.getAnnotation(CellStyleFormat.class);
            ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
            if (excelProperty != null) {
                titleNum =Math.max(excelProperty.value().length, titleNum);
            }
            if (cellStyle == null || excelProperty == null) {
                continue;
            }
            colStyleFormat.put(excelProperty.index(), cellStyle);

        }
        infos.put(TITLE_NUM, String.valueOf(titleNum));
    }

    @Override
    public void sheet(int sheetNo, Sheet sheet) {
        // 只初始化一次
        if (sheetNo == 1) {
            colStyle = colStyleFormat.entrySet().stream()
                    .collect(Collectors.toMap(Map.Entry::getKey, x -> {
                                CellStyle cellStyle = sheet.getWorkbook().createCellStyle();
                                CellStyleFormat value = x.getValue();
                                //居中方式
                                cellStyle.setVerticalAlignment(value.verticalAlignment());
                                cellStyle.setAlignment(value.horizontalalignment());
                                // 设置边框
                                cellStyle.setBorderBottom(value.borderStyle());
                                cellStyle.setBorderLeft(value.borderStyle());
                                cellStyle.setBorderRight(value.borderStyle());
                                cellStyle.setBorderTop(value.borderStyle());
                                cellStyle.setBottomBorderColor(value.borderColor().getIndex());
                                cellStyle.setLeftBorderColor(value.borderColor().getIndex());
                                cellStyle.setRightBorderColor(value.borderColor().getIndex());
                                cellStyle.setTopBorderColor(value.borderColor().getIndex());
                                // 设置字体
                                XSSFFont font = (XSSFFont) sheet.getWorkbook().createFont();
                                font.setFontName(value.cellFont().fontName());
                                font.setColor(value.cellFont().fontColor().getIndex());
                                font.setFontHeightInPoints(value.cellFont().fontHeightInPoints());
                                cellStyle.setFont(font);
                                // 设置单元格是否换行
                                cellStyle.setWrapText(value.warpText());
                                // 背景颜色
                                cellStyle.setFillBackgroundColor(value.fillBackgroundColor().getIndex());
                                return cellStyle;
                            },
                            (u, v) -> v));
        }
    }

    @Override
    public void row(int rowNum, Row row) {

    }

    @Override
    public void cell(int cellNum, Cell cell) {
        CellStyle cellStyle = colStyle.get(cellNum);
        // 表头不操作 行序号是从0开始的
        if (cell.getRowIndex() <= Integer.valueOf(infos.get(TITLE_NUM))-1)  {
            return;
        }
        // 没有不操作
        if (cellStyle == null) {
            return;
        }
        //设置居中方式
        cell.setCellStyle(cellStyle);
    }
}
使用

以上准备完毕,现在给实体类添加注解,以右居中为例 注意必须有@ExcelProperty并且是从0开始,支持多行表头 这个例子里 eeee和 ffff进行的样式修改,进行右居中

public class demoExport extends BaseRowModel {

    private static final long serialVersionUID = 1L;

    @ExcelProperty(value = "aaaaa",index = 0)
    private String aaaaa;
    @ExcelProperty(value = "bbbb",index = 1)
    private String bbbbb;
    @ExcelProperty(value = "cccc",index = 2)
    private String ccccc;
    @ExcelProperty(value = "dddd",index = 3)
    private String dddd;
    @ExcelProperty(value = "eeee",index = 4)
    @CellStyleFormat(horizontalalignment = HorizontalAlignment.RIGHT)
    private String eeee;
    @CellStyleFormat(horizontalalignment = HorizontalAlignment.RIGHT)
    @ExcelProperty(value = "ffff",index = 5)
    private String ffffff;

最后进行调用,只需要writer获取方式修改一下

ExcelWriter writer = EasyExcelFactory.getWriterWithTempAndHandler(null, out, ExcelTypeEnum.XLSX, true, new PreWriterHandler<>(demoExport .class));

我自己还弄了一个数字类型格式化的注解,这个如果有需要我再分享吧

回答

5

image image image 为什么注解设置样式只能配置对齐方式呢,别的样式都设置不了

0

image image image 为什么注解设置样式只能配置对齐方式呢,别的样式都设置不了

使用@CellStyleFormat注解 里面嵌套了一个@CellFontFormat 不要单独使用@CellFontFormat

4

谢谢,实现了。还有一个问题。我如何自己添加一个cell样式呢。比如 添加cell的单元格批注

0

谢谢,实现了。还有一个问题。我如何自己添加一个cell样式呢。比如 添加cell的单元格批注

你查查看POI的接口CellStyle 样式都在里面 你在PreWriterHandler里面设置样式的时候加上好了, 我记得批注好像不是样式,也可以仿照poI调用方法在PreWriterHandler里面添加

2

多个sheet 的时候, 不同sheet 不同的数据模型,那么 ExcelWriter writer = EasyExcelFactory.getWriterWithTempAndHandler(null, out, ExcelTypeEnum.XLSX, true, new PreWriterHandler<>(demoExport .class)); 这里writer 是不是要改变, 那就不能写到一个excel 里面了吧

5

多个sheet 的时候, 不同sheet 不同的数据模型,那么 ExcelWriter writer = EasyExcelFactory.getWriterWithTempAndHandler(null, out, ExcelTypeEnum.XLSX, true, new PreWriterHandler<>(demoExport .class)); 这里writer 是不是要改变, 那就不能写到一个excel 里面了吧

没错,这个类如果有多个数据模型是没有办法配置的。

不过,可以改写PreWriterHandler这个类,里面维护一个 List< Class<? extends BaseRowModel>> 而不是像现在的 T RowModel 这样就可以支持多个模型了

7

支持多个模型搞的太复杂. 业务数据到Model数据转一次再处理要简单多了

2

我使用上面的代码提示我 WriteHandler interface 不存在为啥呀? 版本: implementation 'com.alibaba:easyexcel:1.1.1'

4

版本要求 1.12-beta5 以上

5

谢谢,现在可以了^^