1. 程式人生 > >專案中的資料操作日誌設計

專案中的資料操作日誌設計

      在專案裡除了通常的登入日誌外,通常還要對我們的重要的業務資料做個數據的變更記錄。但是我在網上搜索了一下,主要的解決方案是spring AOP + 註解 的方式進行記錄。這種操作起來簡便,但是粗糙了許多。下面我將介紹下另一種做法,程式碼多了,但是也精確了。
      首先,建立一個listener

public interface DataChangeListener{
    saveUser(String operUserId,User data,Date now);
    updateUser(String operUserId,User old,User Data
); }

      然後再建立一個proxy

public class DataChangeListenerProxy implements DataChangeListener {

    private List<DataChangeListener> listenters ;

    public List<DataChangeListener> getListenteres() {
        return listenters;
    }

    public void setListenteres(List<DataChangeListener> listenteres) {
        this
.listenters = listenteres; } @Override public void saveUser(String operUserId, User data,Date now) throws Exception { for(ContractChangeListener listenter: listenters){ listenter.saveUser(operUserId, data,now); } } @Override public void updateUser(String operUserId,User old, User data,Date now) throws
Exception { for(ContractChangeListener listenter: listenters){ listenter.updateSaleContract(operUserId,old, data,now); } } }

這裡做下解釋:建立這個proxy的目的是為了方便日後的功能擴充套件,比如日後在儲存人員後還要進行某些關聯的操作時,可以通過繼承DataChangeListener然後注入到這個proxy的listeners裡面,那麼在呼叫的時候就會通過方法裡面的for迴圈自然的呼叫後面擴充套件的實現類方法。
       最後建立一個預設的實現類,主要用於對人員的資料進行記錄。

public class DefualtDataChangeListener implements ContractChangeListener {

    /**
     * 儲存日誌
     * @param operUserId 操作人
     * @param operType 選單操作型別
     * @param operAct 操作方法
     * @param dataId 操作資料編號
     * @param operData 操作資料內容
     * @param date 資料修改時間
     */
    private void saveLog(String operUserId,String operType,String operAct,String dataId,String operData,Date date){
        ConOperLog log = new ConOperLog();
        log.setOperId(PubHelper.getNewId(ConOperLog.class));
        log.setUserId(operUserId);
        log.setOperType(operType);
        log.setOperAct(operAct);
        log.setOperDate(date);
        log.setOperData(operData);
        log.setDataId(dataId);
        FrameworkHelper.getDAO().save(log);
    }



    @Override
    public void saveUser(String operUserId, User data,Date now) throws Exception {
    //getProcessDataBySave下面解釋
        saveLog(operUserId,"人員基本資訊", SAVE, data.getUserId(), JSON.toJSONString(getProcessDataBySave(data)),now);
    }

    @Override
    public void updateUser(String operUserId, User old,User data,Date now)throws Exception {
        saveLog(operUserId,"更新人員基本資訊", UPDATE, data.getUserId(), JSON.toJSONString(getProcessDataByUpdate(old, data)),now);
    }

/**
     * 對新舊資料進行對比,返回結果value會帶有html標籤
     * @param oldData
     * @param newData
     * @return
     * @throws Exception
     */
    private Map<String, String> getProcessDataByUpdate(Object oldData,Object newData) throws Exception{
        Map<String,String> oldMap = getPropertyValue(oldData);
        Map<String,String> newMap = getPropertyValue(newData);
        for(Entry<String, String> entry:oldMap.entrySet()){
            String oldValue = entry.getValue();
            String newValue = newMap.get(entry.getKey());
            if(Utils.isEmpty(oldValue)&&Utils.isEmpty(newValue)){
                continue;
            }
            //[下載DiffMatchPatch](https://download.csdn.net/download/b45bobo/10584374)
            DiffMatchPatch match = new DiffMatchPatch();
            entry.setValue(match.diff_prettyHtml(match.diff_main(oldValue, newValue)));
        }
        return oldMap;
    }
    /**
     * 新增資料時
     * @param data
     * @return key:UserName value:<ins style='background:#E6FFE6;'>陳陳</ins>
     * @throws Exception
     */
    private Map<String,String> getProcessDataBySave(Object data) throws Exception{
        Map<String,String> map = getPropertyValue(data);
        for(Entry<String, String> entry: map.entrySet()){
            StringBuilder html = new StringBuilder();
             //INS_SUFIX="<ins style='background:#E6FFE6;'>"
             //INS_SUFIX="</ins>"
             html.append(ContractConstants.INS_PERFIX).append(entry.getValue())
                .append(ContractConstants.INS_SUFIX);
            entry.setValue(html.toString());
        }
        return map;
    }

    /**
     * 刪除資料時
     * @param data
     * @return key:UserName  value: <del style='background:red;'>陳陳</del>
     * @throws Exception
     */
    private Map<String,String> getProcessDataByDelete(Object data) throws Exception{
        Map<String,String> map = getPropertyValue(data);
        for(Entry<String, String> entry: map.entrySet()){
            StringBuilder html = new StringBuilder();
            //DEL_PERFIX = "<del style='background:red;'>"
            //DEL_SUFIX = "</del>"
            html.append(ContractConstants.DEL_PERFIX).append(entry.getValue())
            .append(ContractConstants.DEL_SUFIX);
            entry.setValue(html.toString());
        }
        return map;
    }
    /**
    * 該方法是提取實體物件裡面的屬性值,並以屬性名為key,屬性值為value存入map
    * @param data 實體物件
    * @return 例如 key:UserName value: 陳
    *                  Address         中國
    */
    private Map<String,String> getPropertyValue(Object data) throws Exception{
        Map<String,String> map = new HashMap<>(); 
        for(Method m: data.getClass().getMethods()){
            String methodName =  m.getName();
            if(methodName.startsWith("get")){
                Object o = m.invoke(data, new Object[]{});
                if(o instanceof Double){
                    o = Double.toString((Double)o);
                }else if(o instanceof Date){
                    o = DateUtil.format((Date)o,DateUtil.PATTERN_FULL);
                }else if(o instanceof Class){
                    continue;
                }
                map.put(m.getName().replace("get", ""), (String)o);
            }
        }
        return map;
    }

}

在專案裡面呼叫

    //這裡注入proxy的bean物件
    @Resource(name = "contractListener")
    protected ContractChangeListener listenter;

    public void saveUser(String loginUserId,User user){
        Date now = new Date();
        //儲存人員到資料庫
        //。。。。
        //----
        //呼叫listener
        listenter.saveUser(loginUserId,user,now);
    }

這樣資料就存入資料庫裡面了,在要展現修改差異時查詢資料獲取文字對比後的json

    //從資料裡面根據分類查詢人員的基本資訊更新操作記錄
    ConOperLog conOperLog = 從資料庫查詢到的物件;
    //json字串的人員資料
    String  data = conOperlog.getOperData();
    //key UserName value: <del style='background:red;'>陳</del><ins style='background:#E6FFE6;'>徐</ins>笑
    Map<String,String> map = JSON.parseObject(data, new TypeReference<Map<String,String>>(){});
    //在前端展現效果

如下:這樣就明顯了。
這裡寫圖片描述