EasyExcel 动态表头+表头合并
最终呈现效果:
以前对EasyExcel的使用都是一个实体类字段对应一列,通过以下来一一对应即可。
@ExcelProperty(index = 0,value = "姓名" )
private String xm;
所以此中出现的两个问题:
-
表头合并,第一行是合并的汇总
-
动态表头,下载的几月的汇总表头就要出现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博客