在使用easyexcel导出excel文件的时候,在实体类字段上使用@Excel定义表头、顺序、宽度,很方便;但是同一个字段在不同的场景中导出的表头不一样的时候,导出的表头需要根据具体参数变化;找了一下这个框架好像没有封装这种场景的方法
然后我自己定义了一个注解,在导出的时候动态将字段上面的@Excel参数修改掉,来实现在根据不同的参数导出不同表头的效果
/**
* 解决同一个实体类 导出的excel表头不一样的问题
* 添加该注解必须要同时添加 cn.afterturn.easypoi.excel.annotation.Excel 注解
* 配合 ExcelUtils 工具类中 modifyExcelAnnotation 方法来使用
* 该注解中 所有数据都配置多个,默认以英文逗号(,)隔开,没有的要加空格;单个没必要用到这个注解
* 属性配置多个的时候,各属性的下标要一致
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelData {
/**
* 表头
* @return
*/
public String names();
/**
* 列序号,从0开始
* 默认以英文逗号(,)隔开
*
* @return
*/
public String orderNums() default "0";
}
/**
* 处理 ExcelData 注解中对应index的表头信息 塞到 Excel 注解中
* @author YHSJ
*
*/
@Target({METHOD})
@Retention(RUNTIME)
public @interface ExcelHeaderAnnotation {
/**
* 要处理的实体类全限名
* @return
*/
public String clazzName();
/**
* 分隔符
* @return
*/
public String separate() default ",";
}
@Aspect
@Component
public class ExcelHeaderAspect {
@Before("@annotation(com.aop.ExcelHeaderAnnotation)")
public void before(JoinPoint point) throws Exception {
// String methodName = point.getSignature().getName();
MethodSignature methodSignature = (MethodSignature)point.getSignature();
Method method = methodSignature.getMethod();
// 获取注解 ExcelHeaderAnnotation
ExcelHeaderAnnotation annotation = method.getAnnotation(ExcelHeaderAnnotation.class);
// 获取注解 ExcelHeaderAnnotation 的参数的值
String clazzName = annotation.clazzName();
String separate = annotation.separate();
// 获取切点方法入参列表
Object[] objArray = point.getArgs();
// 下面代码根据具体入参类型进行修改
Integer index = 0;
for (Object obj: objArray) {
if(obj instanceof Integer){
index = (Integer) obj;
}
}
// 获取实体类的字段
Class<?> clazz = Class.forName(clazzName);
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
// 判断注解是否存在
boolean isData = field.isAnnotationPresent(ExcelData.class);
boolean is = field.isAnnotationPresent(Excel.class);
if(!is || !isData) continue;
// 获取 ExcelData 对应 index 的属性值
ExcelData excelDataInterface = field.getAnnotation(ExcelData.class);
String[] names = excelDataInterface.names().split(StringUtils.isNotBlank(separate) ? separate : ",");
String[] orderNums = excelDataInterface.orderNums().split(StringUtils.isNotBlank(separate) ? separate : ",");
String name = (names != null && names.length > index) ? names[index] : names[0];
String orderNum = (orderNums != null && orderNums.length > index) ? orderNums[index] : orderNums[0];
// 将 ExcelData 中对应的属性值 塞到 Excel注解中
Excel excelInterface = field.getAnnotation(Excel.class);
InvocationHandler h = Proxy.getInvocationHandler(excelInterface);
// 获取 AnnotationInvocationHandler 的 memberValues 字段
Field hField = h.getClass().getDeclaredField("memberValues");
// 因为字段是 private 修饰,所以要打开权限
hField.setAccessible(true);
// 获取 memberValues
Map<String, Object> memberValues = (Map<String, Object>) hField.get(h);
memberValues.put("name", StringUtils.isNotBlank(name) ? name : "");
memberValues.put("orderNum", StringUtils.isNotBlank(orderNum) ? orderNum : "");
}
}
}
public class DemoTest {
@Excel(name = "")
@ExcelData(names = "参数0,参数01,参数02", orderNums = "0")
private String parame1;
@Excel(name = "")
@ExcelData(names = "参数1,参数11,参数12", orderNums = "1")
private String parame2;
@Excel(name = "")
@ExcelData(names = "参数2,参数21,参数22", orderNums = "2")
private String parame3;
@Excel(name = "")
@ExcelData(names = "参数3,参数31,参数32", orderNums = "3")
private String parame4;
@Excel(name = "")
@ExcelData(names = "参数4,参数41,参数42", orderNums = "4")
private String parame5;
}
@ExcelHeaderAnnotation(clazzName = "com.model.DemoTest")
public void export(Integer index, HttpServletResponse response) {
// 导出代码
}
不用aop注解也可以在调用导出代码前执行一下下面的工具方法
/**
*
* @param clazz 实体类class对象
* @param index @ExcelData 注解中第 index 个表头信息
* @param separate @ExcelData 注解中表头信息中间的 分隔符
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
public static void modifyExcelAnnotation(Class<?> clazz, int index, String separate) throws NoSuchFieldException, IllegalAccessException {
// 获取实体类的字段
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
// 判断注解是否存在
boolean isData = field.isAnnotationPresent(ExcelData.class);
boolean is = field.isAnnotationPresent(Excel.class);
if(!is || !isData) continue;
// 获取 ExcelData 对应 index 的属性值
ExcelData excelDataInterface = field.getAnnotation(ExcelData.class);
String[] names = excelDataInterface.names().split(StringUtils.isNotBlank(separate) ? separate : ",");
String[] orderNums = excelDataInterface.orderNums().split(StringUtils.isNotBlank(separate) ? separate : ",");
String name = (names != null && names.length > index) ? names[index] : names[0];
String orderNum = (orderNums != null && orderNums.length > index) ? orderNums[index] : orderNums[0];
// 将 ExcelData 中对应的属性值 塞到 Excel注解中
Excel excelInterface = field.getAnnotation(Excel.class);
InvocationHandler h = Proxy.getInvocationHandler(excelInterface);
// 获取 AnnotationInvocationHandler 的 memberValues 字段
Field hField = h.getClass().getDeclaredField("memberValues");
// 因为字段是 private 修饰,所以要打开权限
hField.setAccessible(true);
// 获取 memberValues
Map<String, Object> memberValues = (Map<String, Object>) hField.get(h);
memberValues.put("name", StringUtils.isNotBlank(name) ? name : "");
memberValues.put("orderNum", StringUtils.isNotBlank(orderNum) ? orderNum : "");
}
}
public void export(Integer index, HttpServletResponse response) {
modifyExcelAnnotation(DemoTest.class, index, "");
// 导出代码
}
参考博客
https://www.jb51.net/article/217449.htm
https://blog.csdn.net/qq_39309348/article/details/118551620