有时候业务需要,需记录一条记录的修改历史,但是不能为完成任务而硬编码,不靠谱

这种情况可以使用java反射来完成

对对象属性的描述可以通过自定义注解来完成,读取里面的属性进而记录修改历史。

在对象的属性上面加上注解,value设置为属性的中文描述

工具了代码如下

自定义注解(PropertyMsg)

@Target

表示该注解可以用于什么地方,可能的ElementType参数有:

  CONSTRUCTOR:构造器的声明

  FIELD:域声明(包括enum实例)

  LOCAL_VARIABLE:局部变量声明

  METHOD:方法声明

  PACKAGE:包声明

  PARAMETER:参数声明

  TYPE:类、接口(包括注解类型)或enum声明

@Retention

表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:

  SOURCE:注解将被编译器丢弃

  CLASS:注解在class文件中可用,但会被VM丢弃

  RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息。

@Document

将注解包含在Javadoc中

@Inherited

允许子类继承父类中的注解

  1. 1 import java.lang.annotation.*;
  2. 2
  3. 3 @Target(ElementType.FIELD)
  4. 4 @Retention(RetentionPolicy.RUNTIME)
  5. 5 @Documented
  6. 6 @Inherited
  7. 7 public @interface PropertyMsg {
  8. 8 String value();
  9. 9 }

util类(BeanChangeUtil)

  1. 1 import java.beans.PropertyDescriptor;
  2. 2 import java.lang.reflect.Field;
  3. 3 import java.lang.reflect.Method;
  4. 4 import java.util.Arrays;
  5. 5
  6. 6 public class BeanChangeUtil<T> {
  7. 7 public String contrastObj(Object oldBean, Object newBean) {
  8. 8 // 创建字符串拼接对象
  9. 9 StringBuilder str = new StringBuilder();
  10. 10 // 转换为传入的泛型T
  11. 11 T pojo1 = (T) oldBean;
  12. 12 T pojo2 = (T) newBean;
  13. 13 // 通过反射获取类的Class对象
  14. 14 Class clazz = pojo1.getClass();
  15. 15 // 获取类型及字段属性
  16. 16 Field[] fields = clazz.getDeclaredFields();
  17. 17 return jdk8Before(fields, pojo1, pojo2, str,clazz);
  18. 18 // return jdk8OrAfter(fields, pojo1, pojo2, str,clazz);
  19. 19 }
  20. 20
  21. 21 // jdk8 普通循环方式
  22. 22 public String jdk8Before(Field[] fields,T pojo1,T pojo2,StringBuilder str,Class clazz){
  23. 23 int i = 1;
  24. 24 try {
  25. 25 for (Field field : fields) {
  26. 26 if(field.isAnnotationPresent(PropertyMsg.class)){
  27. 27 PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
  28. 28 // 获取对应属性值
  29. 29 Method getMethod = pd.getReadMethod();
  30. 30 Object o1 = getMethod.invoke(pojo1);
  31. 31 Object o2 = getMethod.invoke(pojo2);
  32. 32 if (o1 == null || o2 == null) {
  33. 33 continue;
  34. 34 }
  35. 35 if (!o1.toString().equals(o2.toString())) {
  36. 36 str.append(i + "、" + field.getAnnotation(PropertyMsg.class).value() + ":" + "修改前=>" + o1 + ",修改后=>" + o2 + "\n");
  37. 37 i++;
  38. 38 }
  39. 39 }
  40. 40 }
  41. 41 } catch (Exception e) {
  42. 42 e.printStackTrace();
  43. 43 }
  44. 44 return str.toString();
  45. 45 }
  46. 46
  47. 47 // lambda表达式,表达式内部的变量都是final修饰,需要传入需要传入final类型的数组
  48. 48 public String jdk8OrAfter(Field[] fields, T pojo1, T pojo2, StringBuilder str, Class clazz){
  49. 49 final int[] i = {1};
  50. 50 Arrays.asList(fields).forEach(f -> {
  51. 51 if(f.isAnnotationPresent(PropertyMsg.class)){
  52. 52 try {
  53. 53 PropertyDescriptor pd = new PropertyDescriptor(f.getName(), clazz);
  54. 54 // 获取对应属性值
  55. 55 Method getMethod = pd.getReadMethod();
  56. 56 Object o1 = getMethod.invoke(pojo1);
  57. 57 Object o2 = getMethod.invoke(pojo2);
  58. 58 if (o1 == null || o2 == null) {
  59. 59 return;
  60. 60 }
  61. 61 if (!o1.toString().equals(o2.toString())) {
  62. 62 str.append(i[0] + "、" + f.getAnnotation(PropertyMsg.class).value() + ":" + "修改前=>" + o1 + "\t修改后=>" + o2 + "\n");
  63. 63 i[0]++;
  64. 64 }
  65. 65 }catch (Exception e){
  66. 66 e.printStackTrace();
  67. 67 }
  68. 68 }
  69. 69 });
  70. 70 return str.toString();
  71. 71 }
  72. 72 }

使用方式test

  1. public class TestChange {
  2. public static void main(String[] args) {
  3. TestChange u1 = new TestChange("我是谁", "ok", 30,"刘德华");
  4. TestChange u2 = new TestChange("我在哪", "no", 20,"郭富城");
  5. BeanChangeUtil<TestChange> t = new BeanChangeUtil<>();
  6. String str = t.contrastObj(u1, u2);
  7. if (str.equals("")) {
  8. System.out.println("未有改变");
  9. } else {
  10. System.out.println(str);
  11. }
  12. }
  13. public TestChange() {
  14. }
  15. public TestChange(String about, String lock, Integer age, String name) {
  16. this.about = about;
  17. this.lock = lock;
  18. this.age = age;
  19. this.name = name;
  20. }
  21. @PropertyMsg("关于")
  22. private String about;
  23. private String lock;
  24. @PropertyMsg("年龄")
  25. private Integer age;
  26. @PropertyMsg("姓名")
  27. private String name;
  28. public String getAbout() {
  29. return about;
  30. }
  31. public void setAbout(String about) {
  32. this.about = about;
  33. }
  34. public String getLock() {
  35. return lock;
  36. }
  37. public void setLock(String lock) {
  38. this.lock = lock;
  39. }
  40. public Integer getAge() {
  41. return age;
  42. }
  43. public void setAge(Integer age) {
  44. this.age = age;
  45. }
  46. public String getName() {
  47. return name;
  48. }
  49. public void setName(String name) {
  50. this.name = name;
  51. }
  52. }

OK,到位

 

版权声明:本文为chywx原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/chywx/p/10630457.html