当前位置:   article > 正文

解决ExcelProperty反射动态修改表头上线一段时间后失效

excelproperty

下面这段代码大家应该都搜到过了:

  1. /**
  2. * 动态修改Excel标题
  3. * @param clzz
  4. * @param filedName
  5. * @param valueArr
  6. */
  7. public static void setHeadValue(Class clzz, String filedName, String[] valueArr ) {
  8. try {
  9. //获取field
  10. Field filed = clzz.getDeclaredField(filedName);
  11. filed.setAccessible(true);
  12. //获取注解
  13. ExcelProperty annotation = filed.getAnnotation(ExcelProperty.class);
  14. InvocationHandler invocationHandler = Proxy.getInvocationHandler(annotation);
  15. Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
  16. memberValues.setAccessible(true);
  17. Map<String, Object> map = (Map<String, Object>) memberValues.get(invocationHandler);
  18. map.put("value", valueArr);
  19. } catch (Exception e) {
  20. e.printStackTrace();
  21. }
  22. }

但是大家可能发现最后在写excel时,实体xxxVo.class中还是之前的值。

哈哈哈我也遇到了这个问题,已经解决了,现在将原因和方法告诉大家。

实际上,反射修改的只是CLASS对象,并没有修改相应类的字节码。因此下面引入Javassist技术,修改类的字节码。

使用Javassist动态重新加载CLASS,需开启JDWP(-agentlib:jdwp),注意new HotSwapper()会建立长链接占用设置的端口(8000),如果是多次重新加载CLASS,HotSwapper只需实例化一次,所以设计成单例模式。

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000
  1. import com.alibaba.excel.annotation.ExcelProperty;
  2. import com.alibaba.ttl.threadpool.agent.internal.javassist.ClassClassPath;
  3. import com.alibaba.ttl.threadpool.agent.internal.javassist.ClassPool;
  4. import com.alibaba.ttl.threadpool.agent.internal.javassist.CtClass;
  5. import com.alibaba.ttl.threadpool.agent.internal.javassist.CtField;
  6. import com.alibaba.ttl.threadpool.agent.internal.javassist.bytecode.AnnotationsAttribute;
  7. import com.alibaba.ttl.threadpool.agent.internal.javassist.bytecode.ConstPool;
  8. import com.alibaba.ttl.threadpool.agent.internal.javassist.bytecode.FieldInfo;
  9. import com.alibaba.ttl.threadpool.agent.internal.javassist.bytecode.annotation.Annotation;
  10. import com.alibaba.ttl.threadpool.agent.internal.javassist.bytecode.annotation.ArrayMemberValue;
  11. import com.alibaba.ttl.threadpool.agent.internal.javassist.bytecode.annotation.MemberValue;
  12. import com.alibaba.ttl.threadpool.agent.internal.javassist.bytecode.annotation.StringMemberValue;
  13. import com.alibaba.ttl.threadpool.agent.internal.javassist.util.HotSwapper;
  14. import java.util.List;
  15. import java.util.Map;
  16. import java.util.concurrent.ConcurrentHashMap;
  17. import java.util.concurrent.ConcurrentMap;
  18. public class JavassistUtils {
  19. public static ConcurrentMap<String, HotSwapper> hotSwapperMap = new ConcurrentHashMap<>();
  20. public static HotSwapper getHotSwapper() {
  21. HotSwapper hotSwapper = hotSwapperMap.get("HotSwapper");
  22. try {
  23. if (hotSwapper == null) {
  24. hotSwapper = new HotSwapper(8000);
  25. hotSwapperMap.put("HotSwapper",hotSwapper);
  26. }
  27. } catch (Exception e) {
  28. e.printStackTrace();
  29. }
  30. return hotSwapper;
  31. }
  32. /**
  33. * 重新加载class
  34. * @param clzz
  35. */
  36. public static Class reLoadClass(Class clzz) {
  37. try {
  38. // //file:/home/ipm-starter/ipm-starter.jar!/BOOT-INF/classes!/
  39. // ///E:/idea project/ipd-ShuiXing/ipd-ipm/ipm-starter/target/classes/
  40. // Resource resourceObj = ResourceUtil.getResourceObj(".");
  41. // String classPath = URLDecoder.decode(resourceObj.getUrl().getPath(), "UTF-8").replaceAll("file:", "").replaceAll("ipm-starter.jar!/BOOT-INF/classes!/", "");
  42. ClassPool pool = ClassPool.getDefault();
  43. pool.insertClassPath(new ClassClassPath(clzz));
  44. CtClass ct = pool.get(clzz.getName());
  45. byte[] bytes = ct.toBytecode();
  46. // ct.writeFile(classPath);
  47. ct.detach();
  48. //如果在同一个ClassLoader加载两次Class抛出异常
  49. // Class<?> aClass = ct.toClass();
  50. //反射拿到的是代理类,所以拿不到对应的注解。在根据反射机制拿取类里对应的属性时,这个类要看有没被做过代理。
  51. // URLClassLoader loader = new URLClassLoader(new URL[]{new URL("file://" + classPath)});
  52. // clzz = loader.loadClass(clzz.getName());
  53. // Loader cl = new Loader(pool);
  54. // clzz = cl.loadClass(clzz.getName());
  55. // HotSwapper hotSwapper = JavassistUtils.getHotSwapper();
  56. // hotSwapper.reload(clzz.getName(), bytes);
  57. // //使用Instrumentation和Javassist修改web应用字节码 https://blog.csdn.net/helowken2/article/details/103110368
  58. // // 通过读入的class数据输入流实例化类定义对象
  59. // ClassDefinition reporterDef = new ClassDefinition(Class.forName(clzz.getName()), ct.toBytecode());
  60. // // 使用jvm监视对象重新定义类
  61. // instrumentation.redefineClasses(reporterDef);
  62. return clzz;
  63. } catch (Exception e) {
  64. e.printStackTrace();
  65. }
  66. return null;
  67. }
  68. /**
  69. * 动态修改ExcelProperty注解属性
  70. * @param clzz
  71. * @param filedName
  72. * @param value
  73. */
  74. public static void setHeadValue(Class clzz, String filedName, String value) {
  75. try {
  76. Map<String, List<String>> map = ReflectUtils.getFieldInfoWithExcelProperty(clzz);
  77. ClassPool pool = ClassPool.getDefault();
  78. pool.insertClassPath(new ClassClassPath(clzz));
  79. CtClass ct = pool.get(clzz.getName());
  80. CtField ctField = ct.getDeclaredField(filedName);
  81. if (map.keySet().contains(ctField.getName())) {
  82. FieldInfo methodInfo = ctField.getFieldInfo();
  83. ConstPool cPool = methodInfo.getConstPool();
  84. AnnotationsAttribute attribute = (AnnotationsAttribute) methodInfo.getAttribute(AnnotationsAttribute.visibleTag);
  85. Annotation anno = attribute.getAnnotation(ExcelProperty.class.getName());
  86. ArrayMemberValue arrayMemberValue = new ArrayMemberValue(cPool);
  87. MemberValue[] memberValues = new StringMemberValue[]{new StringMemberValue(value, cPool)};
  88. arrayMemberValue.setValue(memberValues);
  89. anno.addMemberValue("value", arrayMemberValue);
  90. attribute.addAnnotation(anno);
  91. methodInfo.addAttribute(attribute);
  92. }
  93. } catch (Exception e) {
  94. e.printStackTrace();
  95. }
  96. // try {
  97. // //获取field
  98. // Field filed = clzz.getDeclaredField(filedName);
  99. // filed.setAccessible(true);
  100. // //获取注解
  101. // ExcelProperty annotation = filed.getAnnotation(ExcelProperty.class);
  102. // InvocationHandler invocationHandler = Proxy.getInvocationHandler(annotation);
  103. // Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
  104. // memberValues.setAccessible(true);
  105. // Map<String, Object> map = (Map<String, Object>) memberValues.get(invocationHandler);
  106. // map.put("value", new String[]{value});
  107. // } catch (Exception e) {
  108. // e.printStackTrace();
  109. // }
  110. }
  111. }

提供另外一种写法:

写Excel | Easy Excel

EasyExcel多sheet导出,反射动态设置表头_writesheet设置表头_Milo(xiu)的博客-CSDN博客

有兴趣的可以看看下面博主的说法

 java正确动态修改注解属性,纠正网上说使用反射进行修改。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/476417
推荐阅读
相关标签
  

闽ICP备14008679号