JAVA使用变量动态修改注解属性值

问题场景

在使用easyexcel做数据导出时,用到了注解@ExcelProperty标记表头,代码如下:

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentStyle;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import org.apache.poi.ss.usermodel.VerticalAlignment;

/**
 * 培训收集实体
 * @Author zcc
 * @Date 2020/7/14 20:17
 * @Version 1.0
 */
@HeadRowHeight(40)
@ContentStyle(verticalAlignment = VerticalAlignment.CENTER)
public class Training{

    @ExcelProperty({"需求收集名称(2020年度需求收集)", "需求编号收集"})
    @ColumnWidth(20)
    private String xuqiushoujibianhao;

    @ExcelProperty({"需求收集名称(2020年度需求收集)", "培训内容编号"})
    @ColumnWidth(20)

    private String peixunneirongbianhao;

    @ExcelProperty({"需求收集名称(2020年度需求收集)", "企业名称"})
    @ColumnWidth(30)
    private String qiyemingcheng;

    @ExcelProperty({"需求收集名称(2020年度需求收集)", "部门名称"})
    @ColumnWidth(20)
    private String bumenmingcheng;

    @ExcelProperty({"需求收集名称(2020年度需求收集)", "岗位名称"})
    @ColumnWidth(20)
    private String gangweimingcheng;

    @ExcelProperty({"需求收集名称(2020年度需求收集)", "培训类别"})
    @ColumnWidth(20)
    private String peixunleibie;

    @ExcelProperty({"需求收集名称(2020年度需求收集)", "培训内容"})
    @ColumnWidth(60)
    private String peixunneirong;

    @ExcelProperty({"需求收集名称(2020年度需求收集)", "培训类型"})
    @ColumnWidth(20)
    private String peixunleixing;

    @ExcelProperty({"需求收集名称(2020年度需求收集)", "培训人员"})
    @ColumnWidth(60)
    private String peixunrenyuan;

    @ExcelProperty({"需求收集名称(2020年度需求收集)", "计划开展月份"})
    @ColumnWidth(10)
    private String jihuakaizhanyuefen;

	......
}

由于年份要逐年增长,故而应为变量。但是注解上的属性值只能接收常量,所以只能用反射来动态修改@ExcelProperty注解的属性值了。

反射基础

public static void main(String[] args) {
    try {
        Class clazz = Class.forName(Training.class.getName());
        // 获取类名
        String name = clazz.getName();   // 获取完整引用类名 com.zcc.test.bean.Training
        String simpleName = clazz.getSimpleName();  // 直接获取类名 Training

        // 获取属性
        Field[] fields = clazz.getFields(); // 返回属性为public的字段,包括父类中的字段
        Field[] declaredFields = clazz.getDeclaredFields(); // 返回所有的属性,但是不包括父类的申明字段
        Field idField = clazz.getDeclaredField("xuqiushoujibianhao"); // 获取属性为xuqiushoujibianhao的字段

        // 获取普通方法
        Method[] methods = clazz.getMethods(); // 返回public方法, 包括父类中的方法
        Method[] declaredMethods = clazz.getDeclaredMethods(); // 返回所有的方法,但是不包括父类的
        Method method = clazz.getDeclaredMethod("getId", null); // 返回getId这个方法,如果没有参数,就默认为null


        // 获取构造方法
        Training training = (Training) clazz.newInstance(); // 获取获得一个无参实例(如果类存在无参构造器)
        // 获取参数为(String, int)的构造函数
        Constructor constructor = clazz.getDeclaredConstructor(String.class, int.class);
        // 通过有参构造函数创建对象
        Training training1 = (Training) constructor.newInstance( "str", 1);


        // 通过反射调用普通方法
        Training training2 = (Training) clazz.newInstance();
        Method method1 = clazz.getDeclaredMethod("setId", int.class);
        method1.invoke(training2, 1002); // 调用对象training2的setId方法,参数为1002


        // 通过反射操作属性
        Training training3 = (Training) clazz.newInstance();
        Field f = clazz.getDeclaredField("xuqiushoujibianhao"); // 获取“需求收集编号”属性
        f.setAccessible(true); // 设置属性可以直接的进行访问(包括private)
        f.set(training3, "BH0001"); // 设置需求收集编号=BH0001
        
    } catch (Exception e) {
        e.printStackTrace();
    }
}

动态修改注解属性值的实现

/**
 * 变更注解的属性值
 *
 * @param clazz     注解所在的实体类
 * @param tClass    注解类
 * @param filedName 要修改的注解属性名
 * @param value     要设置的属性值
 */
public static <A extends Annotation> Class<?> changeAnnotationValue(Class<?> clazz, Class<A> tClass, String filedName, Object value) {
    try {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            A annotation = field.getAnnotation(tClass);
            setAnnotationValue(annotation, filedName, value);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return clazz;
}

/**
 * 设置注解中的字段值
 *
 * @param annotation 要修改的注解实例
 * @param fieldName  要修改的注解属性名
 * @param value      要设置的属性值
 */
public static void setAnnotationValue(Annotation annotation, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
    InvocationHandler handler = Proxy.getInvocationHandler(annotation);
    Field field = handler.getClass().getDeclaredField("memberValues");
    field.setAccessible(true);
    Map memberValues = (Map) field.get(handler);
    memberValues.put(fieldName, value);
}

public static void main(String[] args) {
	// 测试修改属性
    changeAnnotationValue(Training.class, ExcelProperty.class, "value", new String[]{"需求收集名称(2021年度需求收集)", "需求编号收集"});
    try {
        Field[] fields = trainingClass.getDeclaredFields();
        for (Field field : fields) {
            ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
            System.out.println(Arrays.toString(annotation.value()));
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

问题场景的修复

在easyexcel导出之前利用反射修改Training类

try {
    // 自定义单元格合并策略
    CustomizeMergeStrategy customizeMergeStrategy = new CustomizeMergeStrategy(2, new int[]{0, 1, 2, 3, 4, 5, 6});
    // 更改Training对象的ExcelProperty的注解属性值value
    Class<?> trainingClass = changeAnnotationValue(Training.class, ExcelProperty.class, "value", new String[]{"需求收集名称(" + DateUtils.getSdfYear().get().format(new Date()) + "年度需求收集)", "需求编号收集"});
    ExcelUtils.writeExcel(response, trainings, "需求培训收集" + DateUtils.getSdf6().get().format(new Date()), "需求培训收集", trainingClass, customizeMergeStrategy);
} catch (Exception e) {
    e.printStackTrace();
}
  • 8
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值