項目中的數據操作日誌設計

      在項目裏除了通常的登錄日誌外,通常還要對我們的重要的業務數據做個數據的變更記錄。但是我在網上搜索了一下,主要的解決方案是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>>(){});
    //在前端展現效果

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

下載DiffMatchPatch

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章