项目中的数据操作日志设计

      在项目里除了通常的登录日志外,通常还要对我们的重要的业务数据做个数据的变更记录。但是我在网上搜索了一下,主要的解决方案是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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值