EasyExcel 动态表头+表头合并

EasyExcel 动态表头+表头合并

​ 最终呈现效果:

请添加图片描述

​ 以前对EasyExcel的使用都是一个实体类字段对应一列,通过以下来一一对应即可。

@ExcelProperty(index = 0,value = "姓名" )
private String xm;

​ 所以此中出现的两个问题:

  1. 表头合并,第一行是合并的汇总

  2. 动态表头,下载的几月的汇总表头就要出现202x年x月销售部门员工·····

  • 表头合并:针对1. EasyExcel对相邻数据相同的单元格将自动合并。为实现上下表头以及上侧表头合并,此处用value={}的形式,即value为表头,集合内多少元素则表头有多少行,此中集合用两个元素即可。value={“currentDate”,“部门”},value={“currentDate”,“出差总人数”}······,此时效果将呈现为上侧currentDate已合并,下侧完成。接下来要做的就是对currentDate在运行时替换为前端传来的month+“销售部门员工出差效果考核情况汇总”
  • 动态表头:原理大概为通过反射进行动态代理。工具类如下:
package com.googosoft.common.utils;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.CellType;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

/**
 * 注解工具类
 */
public class AnnotationUtils {

    /**
     * 变更注解的属性值再处理业务,处理完业务之后恢复类的属性
     *
     * @param clazz     注解所在的实体类
     * @param tClass    注解类
     * @param attrName 要修改的注解属性名
     * @param attrTypeEnum 要修改的注解属性的类型
     * @param valueMap  要设置的属性值
     */
    public static <A extends Annotation> void changeAnnotationValueToDealProcess(
            Class<?> clazz,
            Class<A> tClass,
            String attrName,
            AttrTypeEnum attrTypeEnum,
            Map<String, String> valueMap,
            DealProcess dealProcess) {
        try {

            Map<String, Object> fieldAnnotationValueMap = new HashMap<>();

            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                A annotation = field.getAnnotation(tClass);
                if (annotation == null) continue;
                Object value = setAnnotationValue(annotation, attrName, attrTypeEnum, valueMap);
                String fieldName = field.getName();
                fieldAnnotationValueMap.put(fieldName, value);
            }

            // 处理业务逻辑
            dealProcess.deal();

            // 恢复
            for (Field field : fields) {
                A annotation = field.getAnnotation(tClass);
                String fieldName = field.getName();
                if (annotation == null) continue;
                Object value = fieldAnnotationValueMap.get(fieldName);

                InvocationHandler handler = Proxy.getInvocationHandler(annotation);
                Field memberValuesField = handler.getClass().getDeclaredField("memberValues");
                memberValuesField.setAccessible(true);
                @SuppressWarnings("all")
                Map<String, Object> memberValues = (Map) memberValuesField.get(handler);
                memberValues.put(attrName, value);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置注解中的字段值
     *
     * @param annotation 要修改的注解实例
     * @param attrName  要修改的注解属性名
     * @param attrTypeEnum 要修改的注解属性的类型
     * @param valueMap   替换属性集的map
     */
    @SuppressWarnings("all")
    private static Object setAnnotationValue(Annotation annotation, String attrName,
                                             AttrTypeEnum attrTypeEnum, Map<String, String> valueMap) throws NoSuchFieldException, IllegalAccessException {
        InvocationHandler handler = Proxy.getInvocationHandler(annotation);
        Field field = handler.getClass().getDeclaredField("memberValues");
        field.setAccessible(true);
        Map memberValues = (Map) field.get(handler);
        Object value = memberValues.get(attrName);
        switch (attrTypeEnum) {
            case STRING: {
                String oldValue = (String) value;
                String newValue = valueMap.get(oldValue);
                if (StringUtils.isNotBlank(newValue)) {
                    memberValues.put(attrName, newValue);
                }
            }
            break;
            case STRING_ARR: {
                String[] oldValue = (String[]) value;
                String[] newValue = new String[oldValue.length];
                for (int i = 0; i < oldValue.length; i++) {
                    String replace = valueMap.get(oldValue[i]);
                    newValue[i] = replace != null ? replace : oldValue[i];
                }
                memberValues.put(attrName, newValue);
            }
            break;
        }
        return value;
    }

    public enum AttrTypeEnum {
        STRING,
        STRING_ARR
    }

    public interface DealProcess {

        void deal() throws Exception;

    }

}

​ 在本例中,需要在controller中如下设置

HashMap<String, String> replaceMap = new HashMap<>();
replaceMap.put("currentDate", month+"销售部门员工出差效果考核情况汇总");
sheetNameMap.put("出差效果统计",sheetNameList);
AnnotationUtils.changeAnnotationValueToDealProcess(CcxgtjInfo.class, ExcelProperty.class, "value", AnnotationUtils.AttrTypeEnum.STRING_ARR, replaceMap, new AnnotationUtils.DealProcess() {
            @Override
            public void deal() {   FileDownloadUtils.downLoadMoreSheetFile(response,fileName,sheetNameMap,classMap,dataMap);
            }
        });

方法共五个参数,参数解释已于配置类中注释。例中,

1.注解所在实体类为CcxgtjInfo.class。2.注解类为easysxcel注解类。

3.要修改的注解属性名为value。4.要修改的注解属性AnnotationUtils.AttrTypeEnum.STRING_ARR,即{}字符串集合形式。

5.要替代的字符串replaceMap.put(“currentDate”, month+“销售部门员工出差效果考核情况汇总”);

在deal()方法中,将自己的业务逻辑放入即可,例子中为一个多sheet页的导出方法,此处不再展示详情。

本文参考如下:

easyExcel - 动态复杂表头的编写_easyexcel 动态表头-CSDN博客

对于使用 EasyExcel 动态合并表头,您可以按照以下步骤操作: 1. 导入 EasyExcel 的相关依赖包,确保您的项目中已经正确引入了 EasyExcel。 2. 创建一个表头合并的实体类,例如 `MergeHeader`,用于描述每个合并表头单元格的位置和内容。该实体类可以包含以下属性: - `firstRow`:合并表头起始行索引(从0开始计数) - `lastRow`:合并表头结束行索引(从0开始计数) - `firstCol`:合并表头起始列索引(从0开始计数) - `lastCol`:合并表头结束列索引(从0开始计数) - `content`:表头内容 3. 创建一个 List,用于存储所有的 MergeHeader 对象,表示所有需要合并表头。 4. 使用 EasyExcel 提供的 API 进行表格的写入,并设置合并表头的样式。示例代码如下: ```java // 创建 ExcelWriter 对象 ExcelWriter excelWriter = EasyExcel.write("output.xlsx").build(); // 设置表头样式 CellStyle headerStyle = excelWriter.getWorkbook().createCellStyle(); headerStyle.setAlignment(HorizontalAlignment.CENTER); // 设置居中对齐 // 设置表头字体 Font headerFont = excelWriter.getWorkbook().createFont(); headerFont.setBold(true); // 设置加粗 headerStyle.setFont(headerFont); // 写入数据 Sheet sheet = excelWriter.write(...).sheet(); // 写入表头数据 List<List<String>> headers = new ArrayList<>(); // 添加表头数据 // ... // 合并表头单元格 for (MergeHeader mergeHeader : mergeHeaders) { CellRangeAddress cellRangeAddress = new CellRangeAddress(mergeHeader.getFirstRow(), mergeHeader.getLastRow(), mergeHeader.getFirstCol(), mergeHeader.getLastCol()); sheet.addMergedRegion(cellRangeAd
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值