カスタム注釈反射ログの使用

89898 ワード

シーン:プロジェクトには仕入先モジュールがあり、仕入先の基礎情報、仕入先資質などが含まれている.ログを記録する必要もなく、監査する必要もない情報を変更したものもあります.
最初のプロジェクトでログを記録するのは3、4つのキーフィールドのみで、比較的簡単で、更新するbaseで指定されたフィールド値をデータベースのこのフィールドの元の値と比較します.たとえば、StringBuffer sb=new StringBuffer(");if(updateBean.getPropertiesA().equals(oldBean.getPropertiesA()){//パッチ変更情報sb.append("XXXはoldBean.getPropertiesA()---->updateBean.getPropertiesA()).append(");");";"""";";";"";";";
if(updateBean.getPropertiesB().equals(oldBean.getPropertiesB()){//パッチ変更情報sb.append("XXXはoldBean.getPropertiesB()---->updateBean.getPropertiesB()).append(";");")}......
最後に、接続された変更情報をログのcontentとしてデータベース・ログ・テーブルに保存します.
他のフィールドでもログを取る必要がある場合は、もちろん後からifを付けて判断を続けることもできますが、ログを記録する必要があるフィールドが多くなり、例えば20個、30個、ifを付け続けるのが煩わしいと感じたら、反射でget値を取ることができるかどうか考えて、その後、フィールド値を逆射で取得する文章を探して見ました
私はまたどのフィールドがログを覚える必要があるのか、どのフィールドがログを覚える必要がないのかを区別する必要があります.反射して値を取得するときにログを覚える必要があるのは、前の経験と結びつけて、注釈を使って、自分の関心のあるフィールドにカスタム注釈を加えることができます.
コードの一部は次のとおりです.
package com.lyc.util;

import java.lang.annotation.*;

/**
 * Created by liyanchun on 2019/11/15.
 *       
 */
@Documented
@Target(ElementType.FIELD)
@Inherited
@Retention(RetentionPolicy.RUNTIME )
public @interface MyLogAnnotation {

    /**       */
    String paramName();

    /**          */
    boolean isNeedExamine() default true;

    /**       */
    boolean isNeedLog() default true;
	
	/**             */

}
package com.lyc.bean;

import com.lyc.util.MyLogAnnotation;

import java.io.Serializable;
import java.util.Date;

/**
 * Created by liyanchun on 2019/11/15.
 *
 *       
 */
public class UserBase implements Serializable {
    private static final long serialVersionUID = -4831337074413975246L;

    @MyLogAnnotation(paramName = "  ")
    private String userName;

    @MyLogAnnotation(paramName = "  ")
    private Integer age;

    @MyLogAnnotation(paramName = "  ")
    private Date birthDay;

    @MyLogAnnotation(paramName = "  ",isNeedExamine = false)
    private Double height;

    /**                      ^_^ */
    private Double weight;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthDay() {
        return birthDay;
    }

    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }

    public Double getHeight() {
        return height;
    }

    public void setHeight(Double height) {
        this.height = height;
    }

    public Double getWeight() {
        return weight;
    }

    public void setWeight(Double weight) {
        this.weight = weight;
    }
}




package com.lyc.bean;

import com.lyc.util.MyLogAnnotation;

import java.io.Serializable;

/**
 * Created by liyanchun on 2019/11/15.
 *
 *       
 */
public class ClassBase implements Serializable {
    private static final long serialVersionUID = 874547538509067967L;


    @MyLogAnnotation(paramName = "    ")
    private String classNo;

    @MyLogAnnotation(paramName = "      ",isNeedExamine = false)
    private Integer studentNum;

    @MyLogAnnotation(paramName = "   ")
    private String classTeacher;


    public String getClassNo() {
        return classNo;
    }

    public void setClassNo(String classNo) {
        this.classNo = classNo;
    }

    public Integer getStudentNum() {
        return studentNum;
    }

    public void setStudentNum(Integer studentNum) {
        this.studentNum = studentNum;
    }

    public String getClassTeacher() {
        return classTeacher;
    }

    public void setClassTeacher(String classTeacher) {
        this.classTeacher = classTeacher;
    }
}
package com.lyc.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * Created by liyanchun on 2019/11/15.
 *      
 */
public class ReflectUtil {

    /**
     *       ,         
     *
     * @param  o   
     * @return String[]      
     */
    private String[] getFiledName(Object o){
        try{
            Field[] fields = o.getClass().getDeclaredFields();
            String[] fieldNames = new String[fields.length];
            for (int i=0; i < fields.length; i++)
            {
                fieldNames[i] = fields[i].getName();
            }
            return fieldNames;
        } catch (SecurityException e){
            e.printStackTrace();
            System.out.println(e.toString());
        }
        return null;
    }


    /**
     *                
     *
     * @param  fieldName     
     * @param  o     
     * @return Object    
     */
    public static Object getFieldValueByName(String fieldName, Object o){
        try{
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            String getter = "get" + firstLetter + fieldName.substring(1);
            Method method = o.getClass().getMethod(getter, new Class[] {});
            Object value = method.invoke(o, new Object[] {});
            return value;
        } catch (Exception e){
            System.out.println("     ");
            return null;
        }
    }
}
package com.lyc.bean;

import java.io.Serializable;

/**
 * Created by liyanchun on 2019/11/15.
 *       
 */
public class TestLogVo implements Serializable{
    private static final long serialVersionUID = -4378093647208529734L;
	
	/**      */
    private String paramName;
    /**     */
    private String fmParam;
	/**     */
    private String toParam;

    public String getParamName() {
        return paramName;
    }

    public void setParamName(String paramName) {
        this.paramName = paramName;
    }

    public String getFmParam() {
        return fmParam;
    }

    public void setFmParam(String fmParam) {
        this.fmParam = fmParam;
    }

    public String getToParam() {
        return toParam;
    }

    public void setToParam(String toParam) {
        this.toParam = toParam;
    }
}

実装ロジックを書く準備ができています
package com.lyc.util;

import com.lyc.bean.TestLogVo;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * Created by liyanchun on 2019/11/15.
 *           
 */
public class LogUtil {

    public static Boolean buildLogByReflect(Object oldBase,Object newBase,List<TestLogVo> updateParamLogList){
        Boolean isNeedReSubmitExamine = Boolean.FALSE;
        List<Field> list = Arrays.asList(oldBase.getClass().getDeclaredFields());
        if(ListUtil.isNullOrEmpty(list)){
            return isNeedReSubmitExamine;
        }
        for(Field field : list){
            if(!field.isAnnotationPresent(MyLogAnnotation.class)){//         MyLogAnnotation  
                continue;
            }
            for (Annotation anno : field.getDeclaredAnnotations()) {//       
                if(!anno.annotationType().equals(MyLogAnnotation.class) ){//       
                    continue;
                }
                if (((MyLogAnnotation)anno).isNeedLog()){//             

                    Object oldValue = ReflectUtil.getFieldValueByName(field.getName(), oldBase);
                    Object newValue = ReflectUtil.getFieldValueByName(field.getName(), newBase);
                    String paramName = ((MyLogAnnotation)anno).paramName();

                    //                    
                    TestLogVo logVo = compareValue(oldValue,newValue,field,paramName);
                    if (null == logVo){//     
                        continue;
                    }
                    updateParamLogList.add(logVo);
                    if(((MyLogAnnotation)anno).isNeedExamine()){//               
                        isNeedReSubmitExamine = Boolean.TRUE;
                    }
                }
            }
        }
        return isNeedReSubmitExamine;
    }


    public static TestLogVo compareValue(Object oldValue,Object newValue,Field field,String paramName){
        //      String
        if (field.getGenericType().toString().equals("class java.lang.String")) { //   type    ,     "class ",     
            String val1 = (String) oldValue;
            String val2 = (String) newValue;
            if (StringUtil.isNullOrBlank(val1) && !StringUtil.isNullOrBlank(val2)){//     
                return buildLogVo(paramName," ",val2);
            } else if (!StringUtil.isNullOrBlank(val1) && StringUtil.isNullOrBlank(val2)){//     
                return buildLogVo(paramName,val1," ");
            } else if (!StringUtil.isNullOrBlank(val1) && !StringUtil.isNullOrBlank(val2) && !val1.equals(val2)){//       
                return buildLogVo(paramName,val1,val2);
            }
        }

        //      Integer
        if (field.getGenericType().toString().equals("class java.lang.Integer")) {
            Integer val1 = (Integer) oldValue;
            Integer val2 = (Integer) newValue;
            if (null == val1 && null != val2){
                return buildLogVo(paramName," ",val2.toString());
            } else if (null != val1 && null == val2){
                return buildLogVo(paramName,val1.toString()," ");
            } else if (null != val1 && null != val2 && !val1.equals(val2)){
                return buildLogVo(paramName,val1.toString(),val2.toString());
            }
        }

        //      Double
        if (field.getGenericType().toString().equals("class java.lang.Double")) {
            Double val1 = (Double) oldValue;
            Double val2 = (Double) newValue;
            if (null == val1 && null != val2){
                return buildLogVo(paramName," ",val2.toString());
            } else if (null != val1 && null == val2){
                return buildLogVo(paramName,val1.toString()," ");
            } else if (null != val1 && null != val2 && !val1.equals(val2)){
                return buildLogVo(paramName,val1.toString(),val2.toString());
            }
        }

        //      Boolean     
        if (field.getGenericType().toString().equals("class java.lang.Boolean")) {
            Boolean val1 = (Boolean) oldValue;
            Boolean val2 = (Boolean) newValue;
            if (null == val1 && null != val2){
                return buildLogVo(paramName," ",val2.toString());
            } else if (null != val1 && null == val2){
                return buildLogVo(paramName,val1.toString()," ");
            } else if (null != val1 && null != val2 && !val1.equals(val2)){
                return buildLogVo(paramName,val1.toString(),val2.toString());
            }
        }

        //      boolean                        isXXX       isXXX 
        //      getter    
//        if (field.getGenericType().toString().equals("boolean")) {
//            Method m = (Method) object.getClass().getMethod(
//                    field.getName());
//            Boolean val = (Boolean) m.invoke(object);
//            if (val != null) {
//                System.out.println("boolean type:" + val);
//            }
//        }

        //      Date
        if (field.getGenericType().toString().equals("class java.util.Date")) {
            Date val1 = (Date) oldValue;
            Date val2 = (Date) newValue;
            if (null == val1 && null != val2){
                return buildLogVo(paramName," ", DateUtil.dateFormatToString(val2, DateUtil.ISO_EXPANDED_DATE_FORMAT));
            } else if (null != val1 && null == val2){
                return buildLogVo(paramName,DateUtil.dateFormatToString(val1,DateUtil.ISO_EXPANDED_DATE_FORMAT)," ");
            } else if (null != val1 && null != val2 && !val1.equals(val2)){
                return buildLogVo(paramName,DateUtil.dateFormatToString(val1,DateUtil.ISO_EXPANDED_DATE_FORMAT),DateUtil.dateFormatToString(val2,DateUtil.ISO_EXPANDED_DATE_FORMAT));
            }
        }
        //                 
        return null;
    }

    private static TestLogVo buildLogVo(String paramName,String fmParam,String toParam){
        TestLogVo logVo = new TestLogVo();
        logVo.setParamName(paramName);
        logVo.setFmParam(fmParam);
        logVo.setToParam(toParam);
        return logVo;
    }
}


最後に、同じエンティティークラスの異なる変更を複数のUserBaseシミュレーションで作成した後、異なるエンティティークラスに適用できる複数のClassBaseシミュレーションログツールクラスを作成しました.
package com.lyc.test;

import com.lyc.bean.ClassBase;
import com.lyc.bean.TestLogVo;
import com.lyc.bean.UserBase;
import com.lyc.util.DateUtil;
import com.lyc.util.ListUtil;
import com.lyc.util.LogUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by liyanchun on 2019/11/15.
 */
public class TestReflectLog {

    public static void main(String[] args){

        testUserLog();

        System.out.println();
        System.out.println();
        System.out.println();

//        testClassLog();
    }


    public static void testUserLog(){

        UserBase userBase = new UserBase();
        userBase.setUserName("  ");
        userBase.setAge(23);
        userBase.setBirthDay(DateUtil.strFormatToDate("1992-02-23",DateUtil.SIMPLE_FORMAT));
        userBase.setHeight(1.23);
        userBase.setWeight(123d);

        //                 
        UserBase userBase2 = new UserBase();
        userBase2.setUserName("  ");
        userBase2.setAge(23);
        userBase2.setBirthDay(DateUtil.strFormatToDate("1992-02-23",DateUtil.SIMPLE_FORMAT));
        userBase2.setHeight(1.23);
        userBase2.setWeight(222d);


        //       、            
        UserBase userBase3 = new UserBase();
        userBase3.setUserName("  ");
        userBase3.setAge(23);
        userBase3.setBirthDay(DateUtil.strFormatToDate("1992-02-23",DateUtil.SIMPLE_FORMAT));
        userBase3.setHeight(1.32);
        userBase3.setWeight(333d);

        //                 
        UserBase userBase4 = new UserBase();
        userBase4.setUserName("  ");
        userBase4.setAge(64);
        userBase4.setBirthDay(DateUtil.strFormatToDate("1992-06-04",DateUtil.SIMPLE_FORMAT));
        userBase4.setHeight(1.64);
        userBase4.setWeight(164d);

        //     
        UserBase userBase5 = new UserBase();


        List<TestLogVo> testLogVoList = new ArrayList<TestLogVo>();
        //     
        Boolean result = LogUtil.buildLogByReflect(userBase,userBase2,testLogVoList);
        //     
//        Boolean result = LogUtil.buildLogByReflect(userBase,userBase3,testLogVoList);
		//     
//        Boolean result = LogUtil.buildLogByReflect(userBase,userBase4,testLogVoList);
		//     
//        Boolean result = LogUtil.buildLogByReflect(userBase,userBase5,testLogVoList);
		//     
//        Boolean result = LogUtil.buildLogByReflect(userBase5,userBase,testLogVoList);


        System.out.println("            result:" + result);
        System.out.println("             :" + testLogVoList.size());
        if (ListUtil.isNotEmpty(testLogVoList)){
            for (TestLogVo logVo : testLogVoList){
                System.out.println("【" + logVo.getParamName() + "】 " + logVo.getFmParam() + "--->" + logVo.getToParam());
            }
        }
    }


    public static void testClassLog(){

        ClassBase classBase = new ClassBase();
        classBase.setClassNo("00001");
        classBase.setStudentNum(10);
        classBase.setClassTeacher("    ");

        //                       
        ClassBase classBase2 = new ClassBase();
        classBase2.setClassNo("00001");
        classBase2.setStudentNum(11);
        classBase2.setClassTeacher("    ");

        //                    
        ClassBase classBase3 = new ClassBase();
        classBase3.setClassNo("00002");
        classBase3.setStudentNum(20);
        classBase3.setClassTeacher("    ");


        List<TestLogVo> testLogVoList = new ArrayList<TestLogVo>();
        //     
//        Boolean result = LogUtil.buildLogByReflect(classBase,classBase2,testLogVoList);
		//     
//        Boolean result = LogUtil.buildLogByReflect(classBase,classBase3,testLogVoList);
        System.out.println("            result:" + result);
        System.out.println("             :" + testLogVoList.size());
        if (ListUtil.isNotEmpty(testLogVoList)){
            for (TestLogVo logVo : testLogVoList){
                System.out.println("【" + logVo.getParamName() + "】 " + logVo.getFmParam() + "--->" + logVo.getToParam());
            }
        }
    }
}

testUserLog()を実行する最初のケースで、テスト結果:result:false変更ユーザー情報生成ログ数:0をレビューする必要があるかどうかをユーザー情報を変更します.
################################################################################################################
【身長】1.23—>1.32
################################################################################################################
【名前】従張三—>李四【年齢】従23—>64【誕生日】从1992-02-23 00:00->1992-06-04 00:00:00【身長】从1.23—>1.64
################################################################################################################
【名前】従張三—>空【年齢】从23—>空【誕生日】从1992-02-23 00:00—>空【身長】从1.23—>空
################################################################################################################
【名前】従空—>張三【年齢】従空—>23【誕生日】従空—>1992-02-23 00:00【身長】従空—>1.23
###########################################################################################################################################
###############################################################################################################################################
この個人的には、関心のあるフィールドは、空>空ではなく、空>空ではなく、値1>値2から対応する変化情報が記録されています.また、これらのフィールドに重要な再監査が必要な場合は、監査が必要なタグも与えられます.そうしないと、監査タグは必要ありません.私が最初に言ったシーンを満たすことができます.
構築されたtestLogVoListは、データベースを直接保存したり、jsonに変換して既存のログテーブルの1つのフィールドに保存したりすることができます.複数のエンティティはログを変更する必要があります.対応するエンティティの属性にカスタムのこの注釈を加えるだけで、属性の名前は自分で定義できます.
中にはまだ不完全なところがあるかもしれませんが、プロジェクトで最適化してみます.