Java uses more elegant code to record operation logs and change records

Time:2022-6-10

Scenario 1

Data is often recorded in the systemChange log, recording dataContent before changeandContent after change。 And sometimes they record dataMultiple fieldsContents before and after the change (e.gstateBefore and after the changeuserBefore and after the changeamount of moneyBefore and after the change of, and when some contents are not changed, they do not need to be recorded).

Now there are logging entity classes as follows:

package com.wangcp.changelog.entity;

import lombok.Data;

import java.math.BigDecimal;

/**
 *Logging entity
 *
 * @author wangcp
 * <br/>date 2021-06-24
 */
@Data
public class RecordChangeLog {
    /**
     *Operation
     */
    private String operate;

    /**
     *Operation人
     */
    private String operateUser;

    /**
     *Operation时间
     */
    private Long operateTime;

    /**
     *Before "status" change
     */
    private String statusBefore;

    /**
     *After "status" change
     */
    private String statusAfter;

    /**
     *Before "amount" change
     */
    private BigDecimal moneyBefore;

    /**
     *After the "amount" is better
     */
    private BigDecimal moneyAfter;
}

This requirement is usually realized in the following ways:

RecordChangeLog recordChangeLog = new RecordChangeLog();
recordChangeLog. Setoperate ("XXX operation");
recordChangeLog. Setoperateuser ("Zhang San");
recordChangeLog.setOperateTime(System.currentTimeMillis());
//If "status" is changed, record
recordChangeLog. Setstatusbefore ("status before change");
recordChangeLog. Setstatusbefore ("status after change");
//If "amount money" is changed, record
recordChangeLog.setMoneyBefore(new BigDecimal(100));
recordChangeLog.setMoneyAfter(new BigDecimal(200));

However, the disadvantages of this method are as follows:

  • When writing the set parameters of the set method, it is easy to omit or write the called set method incorrectly, resulting in errors in logging.
  • The amount of code redundancy is too large. If there are many attributes recorded in the log, it is complex to encapsulate them into a general method
  • The code is not clear, so it is not clear which attributes of the record need to be changed.

2 code implementation

Let’s optimize the original code and wrap the log entity class.

package com.wangcp.changelog.config;

import com.wangcp.changelog.entity.RecordChangeLog;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;

/**
 *Log wrapper
 *
 * @author wangcp
 * <br/>date 2021-06-24
 */
public class RecordChangeLogWrapper {

    private RecordChangeLog recordChangeLog;


    /**
     *Constructor
     *@param operate operation type (enumeration can be used instead)
     *@param opearteuser operator
     * @return
     * @author wangcp
     * <br/>date 2021-06-24
     */
    public RecordChangeLogWrapper(String operate , String opearteUser) {
        if(StringUtils.isEmpty(operate) || StringUtils.isEmpty(opearteUser)){
            throw new IllegalArgumentException("operate or opearteUser is null");
        }
        recordChangeLog = new RecordChangeLog();
        recordChangeLog.setOperate(operate);
        recordChangeLog.setOperateUser(opearteUser);
        recordChangeLog.setOperateTime(System.currentTimeMillis());
    }

    /**
     *Get instance
     * @return
     */
    public RecordChangeLog getInstance(){
        return this.recordChangeLog;
    }

    /**
     *Change status
     *@param statusbefore before
     *@param statusafter after status change
     * @return
     */
    public RecordChangeLogWrapper  changeStatus(String statusBefore , String statusAfter){
        this.recordChangeLog.setStatusBefore(statusBefore);
        this.recordChangeLog.setStatusAfter(statusAfter);
        return this;
    }

    /**
     *Change amount
     *@param moneybefore before amount change
     *@param moneyafter amount changed
     * @return
     */
    public RecordChangeLogWrapper changeMoney(BigDecimal moneyBefore , BigDecimal moneyAfter){
        this.recordChangeLog.setMoneyBefore(moneyBefore);
        this.recordChangeLog.setMoneyAfter(moneyAfter);
        return this;
    }
}

Use as follows:

/**
  *Call wrapper class to initialize log data
  */
public void testNewLog(){
    //Change status and amount
    Recordchangelogwrapper recordchangelogwrapper1 = new recordchangelogwrapper ("new operation", "Zhang San")
        .changeMoney(new BigDecimal(100) , new BigDecimal(200))
        . Changestatus ("to be approved", "approved");
    RecordChangeLog recordChangeLog1 = recordChangeLogWrapper1.getInstance();

    //Change status
    Recordchangelogwrapper recordchangelogwrapper2 = new recordchangelogwrapper ("modification", "Li Si")
        . Changestatus ("to be approved", "rejected");
    RecordChangeLog recordChangeLog2 = recordChangeLogWrapper2.getInstance();

    //Change amount
    Recordchangelogwrapper recordchangelogwrapper3 = new recordchangelogwrapper ("delete", "Wang Da")
        .changeMoney(new BigDecimal(200) , new BigDecimal(500));
    RecordChangeLog recordChangeLog3 = recordChangeLogWrapper3.getInstance();
}