字段变更操作审计

目的:记录并审计通过应用系统修改的数据。

实现方案:实现org.apache.ibatis.plugin.Interceptor接口,拦截UPDATE 操作。

获取运行中,待执行的update sql及参数。解析为select column from table 的sql语句。

落地方案:

  1. 定义@interface DataAuditLogging ,在service public方法标注,明确需要拦截哪些方法

  2. 定义Aspect DataAuditLogAspect 。

  3. 通过@Before 明确识别并拦截service public方法,组装TransmittableThreadLocal上下文参数。

  4. 通过@AfterReturning 明确在业务方法执行成功完成后,再保存数据审计日志的记录至DB,并保证最终remove TransmittableThreadLocal 。

  5. 定义Interceptor DataAuditLogAOP,明确其拦截的UPDATE SQL,并组装select sql,将change对象临时存放至TransmittableThreadLocal 。

mybatis 3.5.6,mybatis-plus 3.3.2

附加核心业务代码:

DataAuditLogging


@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataAuditLogging {
    /**
     * 标签
     */
    String tag() default "";


    /**
     * 注释
     */
    String note() default "";

    /**
     * 当前登录人ID
     * @return
     */
    String currUserId() default "";
    /**
     * 当前登录人name
     * @return
     */
    String currUsername() default "";
    /**
     * 当前业务主键
     * @return
     */
    String dataId() default "";
}

DataAuditLogAOP


import com.alibaba.druid.proxy.jdbc.JdbcParameter;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.TableNameParser;
import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler;
import com.cbi.fund.common.dto.OperationDataChange;
import com.cbi.fund.common.utils.DataOperateLogThreadLocal;
import com.mysql.cj.jdbc.ClientPreparedStatement;
import com.stars.easyms.base.trace.EasyMsTraceSynchronizationManager;
import com.stars.easyms.base.util.ApplicationContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import java.sql.Statement;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 数据更新拦截器 SQL AOP
 */
@SuppressWarnings("ALL")
@Slf4j
@Component
@Intercepts({@Signature(type = StatementHandler.class, method = "update", args = {Statement.class})})
public class DataAuditLogAOP extends AbstractSqlParserHandler implements Interceptor {
    private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
    private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
    private static final ReflectorFactory DEFAULT_REFLECTOR_FACTORY = new DefaultReflectorFactory();


    @Autowired
    @Qualifier("jdbcTemplateOne")
    @Lazy
    private JdbcTemplate jdbcTemplate;

    @Override
    public Object intercept(Invocation invocation) throws Exception {
        String originalSql = null;
        try{
            // 判断是否需要记录日志
            if (DataOperateLogThreadLocal.DATA_CHANGES.get() == null) {
                return invocation.proceed();
            }
            StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
            MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
            this.sqlParser(metaObject);
            MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
            if(!SqlCommandType.UPDATE.equals(mappedStatement.getSqlCommandType())) {
                //非更新数据
                return invocation.proceed();
            }

            if(jdbcTemplate == null){
                jdbcTemplate = ApplicationContextHolder.getBean(JdbcTemplate.class);
            }
            Object firstArg = invocation.getArgs()[0];
            Statement statement = (Statement) firstArg;
            MetaObject stmtMetaObj = SystemMetaObject.forObject(statement);
            // 分离代理对象链(由于目标类可能被多个拦截器拦截,从而形成多次代理,通过下面的两次循环可以分离出最原始的的目标类)
            while (stmtMetaObj.hasGetter("h")) {
                Object object = stmtMetaObj.getValue("h");
                stmtMetaObj = SystemMetaObject.forObject(object);
            }
            // 分离最后一个代理对象的目标类
            while (stmtMetaObj.hasGetter("target")) {
                Object object = stmtMetaObj.getValue("target");
                stmtMetaObj = SystemMetaObject.forObject(object);
            }
            try {
                statement = (Statement) stmtMetaObj.getValue("statement");
                List<Object> columnValues = (List<Object>) stmtMetaObj.getValue("columnValues");
                /*Map<Integer,Object> paramerters = (Map<Integer, Object>) stmtMetaObj.getValue("statement.stmt.parameters");
                Object sql = stmtMetaObj.getValue("statement.stmt.sql");
                //获取业务要执行的sql
                originalSql = sql.toString();
                originalSql = originalSql.replaceAll("[\\s]+", StringPool.SPACE);
                //TODO 组装参数
                originalSql = makeupExeSQL(originalSql,columnValues,paramerters);*/
                Object raw = stmtMetaObj.getValue("statement.stmt.raw");
                ClientPreparedStatement cps = (ClientPreparedStatement) raw;
                originalSql = cps.asSql();
            } catch (Exception e) {
            }

            if (stmtMetaObj.hasGetter("delegate")) {
                try {
                    statement = (Statement) stmtMetaObj.getValue("delegate");
                } catch (Exception ignored) {
                }
            }
            if(originalSql == null){
                try{
                    statement = (Statement) stmtMetaObj.getValue("stmt.statement");
                }catch (Exception e1){
                }
                originalSql = statement.toString();
            }
            originalSql = originalSql.replaceAll("[\\s]+", StringPool.SPACE);
            int index = indexOfSqlStart(originalSql);
            if (index > 0) {
                originalSql = originalSql.substring(index);
            }

            // 获取执行Sql
            String sql = originalSql.replace("where", "WHERE");
            if(sql.endsWith("]")){
                sql = sql.replaceAll("]","");
            }

            // 使用mybatis-plus 工具解析sql获取表名
            Collection<String> tables = new TableNameParser(sql).tables();
            if (CollectionUtils.isEmpty(tables) || sql.indexOf("WHERE") < 0) {
                return invocation.proceed();
            }

            String tableName = tables.iterator().next();
            OperationDataChange change = new OperationDataChange();
            change.setDataId(EasyMsTraceSynchronizationManager.getTraceId());
            change.setTableName(tableName);
            change.setJdbcTemplate(jdbcTemplate);
            log.info("====biz pre exec sql:{}",sql);
            // 设置sql用于执行完后查询新数据
            String whereSql =  sql.substring(sql.lastIndexOf("WHERE") + 5);
            // 同表对同条数据操作多次只进行一次对比
            if (DataOperateLogThreadLocal.DATA_CHANGES.get().stream().anyMatch(c -> tableName.equals(c.getTableName())
                    && whereSql.equals(c.getWhereSql()))) {
                return invocation.proceed();
            }
            change.setWhereSql(whereSql);
            String querySql = "select * from "+tableName+" where "+whereSql;

            StringBuffer sb = new StringBuffer();
            try{
                List<TableInfo> ts = TableInfoHelper.getTableInfos();
                TableInfo tableInfo = ts.stream().filter(t -> {
                    if (t.getTableName().equalsIgnoreCase(tableName)) {
                        return true;
                    }else{
                        return false;
                    }
                }).collect(Collectors.toList()).get(0);
                String selectSql = tableInfo.getAllSqlSelect();
                String[] realStrs = selectSql.split(",");
                for(int i =0;i < realStrs.length;i ++){
                    String column = realStrs[i];
                    //UPDATE sys_user SET org_code = 'A01A01A14' WHERE username = '13235654896'
                    if(sql.toLowerCase().indexOf(""+column+"=") >=0 ){
                        sb.append(column).append(",");
                    }
                }
                //List<TableFieldInfo> fieldList = tableInfo.getFieldList();
                //change.setTransferData(fieldList);
                change.setEntityType(tableInfo.getEntityType());
            }catch (Exception e){
            }
            //明确 具体的查询的字段
            if(sb.toString().endsWith(",")){
                querySql = "select "+sb.toString().substring(0,sb.length() - 1)+" from "+ tableName+" where "+whereSql;
            }
            log.info("====querySql:{}",querySql);
            change.setQuerySql(querySql);

            if(change.getEntityType() == null){
                List<Map<String, Object>> maps = jdbcTemplate.queryForList(querySql);
                change.setOldData(maps);
            }else{
                String clzzName = change.getEntityType().getName();
                Class<?> clazz = Class.forName(clzzName);
                List<?> oldList = jdbcTemplate.query(querySql,new BeanPropertyRowMapper<>(clazz));
                change.setOldData(oldList);
            }

            DataOperateLogThreadLocal.DATA_CHANGES.get().add(change);
        }catch (Exception e){
            log.info("DataOperateInterceptor-intercept-error:{}", JSON.toJSONString(e));
        }
        return invocation.proceed();
    }

    private String makeupExeSQL(String originalSql, List<Object> columnValues, Map<Integer, Object> paramerters) {
        if(originalSql.indexOf(" where ") >=0 ){
            originalSql = originalSql.replace(" where "," WHERE ");
        }
        if(originalSql.indexOf("? WHERE ") >=0 ){
            originalSql = originalSql.replace("? WHERE ","?, WHERE ");
        }
        StringBuffer sb = new StringBuffer(originalSql);
        sb.append(",");
        String sql = sb.toString();
        //参数数量
        // 入参个数与执行sql的占位符?, 相等
        int paramSize = columnValues.size();
        if(paramSize == 0){
            return originalSql;
        }
        for(int i = 0;i < paramSize;i ++){
            Object obj = columnValues.get(i);
            JdbcParameter param = (JdbcParameter) paramerters.get(i);
            String pa = param.getValue().toString();
            obj.toString();
            StringBuffer str = new StringBuffer("='").append(pa).append("',");
            sql = sql.replaceFirst("=\\?,",str.toString());
        }
        if(sql.endsWith(",")){
            sql = sql.substring(0,sql.length() - 1);
            sql = sql.replace(", WHERE "," WHERE ");
        }
        log.info("makeupExeSQL sql:{}",sql);
        return sql;
    }

    /**
     * 获取sql语句开头部分
     */
    private int indexOfSqlStart(String sql) {
        String upperCaseSql = sql.toUpperCase();
        Set<Integer> set = new HashSet<>();
        set.add(upperCaseSql.indexOf("SELECT "));
        set.add(upperCaseSql.indexOf("UPDATE "));
        set.add(upperCaseSql.indexOf("INSERT "));
        set.add(upperCaseSql.indexOf("DELETE "));
        set.remove(-1);
        if (CollectionUtils.isEmpty(set)) {
            return -1;
        }
        List<Integer> list = new ArrayList<>(set);
        list.sort(Comparator.naturalOrder());
        return list.get(0);
    }
}

DataAuditLogAspect


/**
 * CG
 */
@SuppressWarnings("ALL")
@Slf4j
@Aspect
@Component
//@ConditionalOnProperty(value = "mylog.enable",havingValue = "true")
public class DataAuditLogAspect {
    @Autowired
    @Lazy
    private ProductFeign logFeign;


    /**
     *
     * 数据审核日志切面前执行
     * @param joinPoint
     * @param dataLog
     */
    @Before("@annotation(dataLog)")
    public void beforeDataAuditLogging(JoinPoint joinPoint, DataAuditLogging dataLog) {
        Object obj = DataOperateLogThreadLocal.THREADDATA_ID.get();
        if(obj == null){
            obj =  UUID.fastUUID().toString();
        }

        DataOperateLogThreadLocal.THREADDATA_ID.set(obj.toString());
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String ClassName =  methodSignature.getDeclaringTypeName();
        DataOperateLogThreadLocal.THREADDATA_METHOD.set(ClassName+"#"+joinPoint.getSignature().getName());
        DataOperateLogThreadLocal.DATA_CHANGES.set(new LinkedList<>());
        DataOperateLogThreadLocal.JOIN_POINT.set(joinPoint);
        DataOperateLogThreadLocal.DATA_LOG.set(dataLog);

        ExpressionParser parser = new SpelExpressionParser();
        LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
        Method targetMethod = ((MethodSignature) joinPoint.getSignature()).getMethod();
        String[] params = discoverer.getParameterNames(targetMethod);
        Object[] args = joinPoint.getArgs();
        EvaluationContext context = new StandardEvaluationContext();
        for (int len = 0; len < params.length; len++) {
            context.setVariable(params[len], args[len]);
        }
        String dataId = parser.parseExpression(dataLog.dataId()).getValue(context, String.class);
        String userId = parser.parseExpression(dataLog.currUserId()).getValue(context, String.class);
        String name = parser.parseExpression(dataLog.currUsername()).getValue(context, String.class);

        AuditLogDTO log = new AuditLogDTO();
        log.setDataId(dataId);
        //TODO 补充 当前的登录人ID ,Name
        log.setCurrUserId(userId);
        log.setCurrUsername(name);
        log.setTag(dataLog.tag());

        DataOperateLogThreadLocal.DATA_REQ_LOG.set(log);

    }

    /**
     * 数据审计日志切面后执行
     * @param dataLog
     */
    @AfterReturning("@annotation(dataLog)")
    public void afterDataAuditLogging(DataAuditLogging dataLog) {
        try{

            List<OperationDataChange> list = DataOperateLogThreadLocal.DATA_CHANGES.get();
            AuditLogDTO logDTO = DataOperateLogThreadLocal.DATA_REQ_LOG.get();
            if (CollectionUtils.isEmpty(list)) {
                return;
            }
            list.forEach(change -> {
                List<?> oldData = change.getOldData();
                if (CollectionUtils.isEmpty(oldData)) {
                    return;
                }
                if(change.getEntityType() == null){
                    //按 map处理
                    List<Map<String, Object>> maps = change.getJdbcTemplate().queryForList(change.getQuerySql());
                    change.setNewData(maps);
                }else{
                    //按对象处理
                    try {
                        String clzzName = change.getEntityType().getName();
                        Class<?> clazz = Class.forName(clzzName);
                        List<?> newList = change.getJdbcTemplate().query(change.getQuerySql(),new BeanPropertyRowMapper<>(clazz));
                        change.setNewData(newList);
                    } catch (Exception e) {
                    }
                }
                //置空 jdbc
                change.setJdbcTemplate(null);
            });
            //比对数据 并保存
            this.compareAndTransfer(list,logDTO);
        }catch (Exception e){
            log.info("数据审计日志记录失败");
            log.error(e.getMessage(),e);
        }finally {
            //删除此线程局部变量的当前线程
            DataOperateLogThreadLocal.transfer();
        }

    }

    private void compareAndTransfer(List<OperationDataChange> list, AuditLogDTO logDTO) {
        log.info("===比对后,将变更的数据写入DB= list:{}",JSON.toJSON(list));

        if(list == null || list.size() == 0){
            return ;
        }

        list.stream().forEach( change->{
            List<?> oldData = change.getOldData();
            List<?> newData = change.getNewData();
            // 更新前后数据量不对必定是删除(逻辑删除)不做处理
            if (newData == null || oldData == null) {
                return;
            }
            if (oldData.size() != newData.size()) {
                return;
            }

            for (int i = 0; i < oldData.size(); i++) {
                try{
                    SysDataLogDTO dto = CompareObjUtil.converterDataAuditRecord(change, oldData.get(i), newData.get(i),
                            logDTO.getDataId(), logDTO.getTag(), logDTO.getCurrUserId(), logDTO.getCurrUsername());
                    logFeign.saveSysDataLog(dto);
                }catch (Exception e){
                    log.error(e.getMessage(),e);
                }
            }

        });
    }


}

CompareObjUtil


/**
 *
 */
@SuppressWarnings("ALL")
@Slf4j
public class CompareObjUtil {

    /**
     * 比较两个对象的不同
     */
    public static List<ComparisonDTO> compareObj(Object beforeObj, Object afterObj) throws Exception{
        List<ComparisonDTO> diffs = new ArrayList<>();

        if(beforeObj == null) {
            throw new RuntimeException("原对象不能为空");
        }
        if(afterObj == null) {
            throw new RuntimeException("新对象不能为空");
        }
        if(!beforeObj.getClass().isAssignableFrom(afterObj.getClass())){
            throw new RuntimeException("两个对象不相同,无法比较");
        }

        //取出属性
        Field[] beforeFields = beforeObj.getClass().getDeclaredFields();
        Field[] afterFields = afterObj.getClass().getDeclaredFields();
        Field.setAccessible(beforeFields, true);
        Field.setAccessible(afterFields, true);

        //遍历取出差异值
        if(beforeFields != null && beforeFields.length > 0){
            for(int i=0; i<beforeFields.length; i++){
                Object beforeValue = beforeFields[i].get(beforeObj);
                Object afterValue = afterFields[i].get(afterObj);
                if((beforeValue != null && !"".equals(beforeValue) && !beforeValue.equals(afterValue)) || ((beforeValue == null || "".equals(beforeValue)) && afterValue != null)){
                    ComparisonDTO comparison = new ComparisonDTO();
                    comparison.setField(beforeFields[i].getName());
                    comparison.setBefore(beforeValue);
                    comparison.setAfter(afterValue);
                    // 获取指定的注解
                    ApiModelProperty api = beforeFields[i].getDeclaredAnnotation(ApiModelProperty.class);
                    if (api != null && StringUtils.isNotEmpty(api.value())) {
                        comparison.setFieldApiModelProperty(api.value());
                    }
                    diffs.add(comparison);
                }
            }
        }

        return diffs;
    }

    /**
     * 比较两个json串的不同
     */
    public static String campareJsonObject(String oldJsonStr, String newJsonStr1) {
        //将字符串转换为json对象
        JSON oldJson = JSON.parseObject(oldJsonStr);
        JSON newJson = JSON.parseObject(newJsonStr1);
        //递归遍历json对象所有的key-value,将其封装成path:value格式进行比较
        Map<String, Object> oldMap = new LinkedHashMap<>();
        Map<String, Object> newMap = new LinkedHashMap<>();
        convertJsonToMap(oldJson, "", oldMap);
        convertJsonToMap(newJson, "", newMap);
        Map<String, Object> differenceMap = campareMap(oldMap, newMap);
        //将最终的比较结果把不相同的转换为json对象返回
        String jsonObject = convertMapToJson(differenceMap);
        return jsonObject;
    }

    /**
     * 将json数据转换为map存储用于比较
     */
    private static void convertJsonToMap(Object json, String root, Map<String, Object> resultMap) {
        if (json instanceof JSONObject) {
            JSONObject jsonObject = ((JSONObject) json);
            Iterator iterator = jsonObject.keySet().iterator();
            while (iterator.hasNext()) {
                Object key = iterator.next();
                Object value = jsonObject.get(key);
                String newRoot = "".equals(root) ? key + "" : root + "." + key;
                if (value instanceof JSONObject || value instanceof JSONArray) {
                    convertJsonToMap(value, newRoot, resultMap);
                } else {
                    resultMap.put(newRoot, value);
                }
            }
        } else if (json instanceof JSONArray) {
            JSONArray jsonArray = (JSONArray) json;
            for (int i = 0; i < jsonArray.size(); i++) {
                Object vaule = jsonArray.get(i);
                String newRoot = "".equals(root) ? "[" + i + "]" : root + ".[" + i + "]";
                if (vaule instanceof JSONObject || vaule instanceof JSONArray) {
                    convertJsonToMap(vaule, newRoot, resultMap);
                } else {
                    resultMap.put(newRoot, vaule);
                }
            }
        }
    }

    /**
     * 比较两个map,返回不同数据
     */
    private static Map<String, Object> campareMap(Map<String, Object> oldMap, Map<String, Object> newMap) {
        //遍历newMap,将newMap的不同数据装进oldMap,同时删除oldMap中与newMap相同的数据
        campareNewToOld(oldMap, newMap);
        //將舊的有新的沒有的數據封裝數據結構存在舊的裡面
        campareOldToNew(oldMap);
        return oldMap;
    }

    /**
     * 將舊的有新的沒有的數據封裝數據結構存在舊的裡面
     */
    private static void campareOldToNew(Map<String, Object> oldMap) {
        //统一oldMap中newMap不存在的数据的数据结构,便于解析
        for (Iterator<Map.Entry<String, Object>> it = oldMap.entrySet().iterator(); it.hasNext(); ) {
            Map.Entry<String, Object> item = it.next();
            String key = item.getKey();
            Object value = item.getValue();
            int lastIndex = key.lastIndexOf(".");
            if (!(value instanceof Map)) {
                Map<String, Object> differenceMap = new HashMap<>();
                differenceMap.put("oldValue", value);
                differenceMap.put("newValue", "");
                oldMap.put(key, differenceMap);
            }
        }
    }

    /**
     * 將新的map與舊的比較,並將數據統一存在舊的裡面
     */
    private static void campareNewToOld(Map<String, Object> oldMap, Map<String, Object> newMap) {
        for (Iterator<Map.Entry<String, Object>> it = newMap.entrySet().iterator(); it.hasNext(); ) {
            Map.Entry<String, Object> item = it.next();
            String key = item.getKey();
            Object newValue = item.getValue();
            Map<String, Object> differenceMap = new HashMap<>();
            int lastIndex = key.lastIndexOf(".");
            String lastPath = key.substring(lastIndex + 1).toLowerCase();
            if (oldMap.containsKey(key)) {
                Object oldValue = oldMap.get(key);
                if (newValue.equals(oldValue)) {
                    oldMap.remove(key);
                    continue;
                } else {
                    differenceMap.put("oldValue", oldValue);
                    differenceMap.put("newValue", newValue);
                    oldMap.put(key, differenceMap);
                }
            } else {
                differenceMap.put("oldValue", "");
                differenceMap.put("newValue", newValue);
                oldMap.put(key, differenceMap);
            }
        }
    }

    /**
     * 将已经找出不同数据的map根据key的层级结构封装成json返回
     */
    private static String convertMapToJson(Map<String, Object> map) {
        JSONObject resultJSONObject = new JSONObject();
        for (Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator(); it.hasNext(); ) {
            Map.Entry<String, Object> item = it.next();
            String key = item.getKey();
            Object value = item.getValue();
            String[] paths = key.split("\\.");
            int i = 0;
            Object remarkObject = null;//用於深度標識對象
            int indexAll = paths.length - 1;
            while (i <= paths.length - 1) {
                String path = paths[i];
                if (i == 0) {
                    //初始化对象标识
                    if (resultJSONObject.containsKey(path)) {
                        remarkObject = resultJSONObject.get(path);
                    } else {
                        if (indexAll > i) {
                            if (paths[i + 1].matches("\\[[0-9]+\\]")) {
                                remarkObject = new JSONArray();
                            } else {
                                remarkObject = new JSONObject();
                            }
                            resultJSONObject.put(path, remarkObject);
                        } else {
                            resultJSONObject.put(path, value);
                        }
                    }
                    i++;
                    continue;
                }
                if (path.matches("\\[[0-9]+\\]")) {//匹配集合对象
                    int startIndex = path.lastIndexOf("[");
                    int endIndext = path.lastIndexOf("]");
                    int index = Integer.parseInt(path.substring(startIndex + 1, endIndext));
                    if (indexAll > i) {
                        if (paths[i + 1].matches("\\[[0-9]+\\]")) {
                            while (((JSONArray) remarkObject).size() <= index) {
                                if(((JSONArray) remarkObject).size() == index){
                                    ((JSONArray) remarkObject).add(index,new JSONArray());
                                }else{
                                    ((JSONArray) remarkObject).add(null);
                                }
                            }
                        } else {
                            while(((JSONArray) remarkObject).size() <= index){
                                if(((JSONArray) remarkObject).size() == index){
                                    ((JSONArray) remarkObject).add(index,new JSONObject());
                                }else{
                                    ((JSONArray) remarkObject).add(null);
                                }
                            }
                        }
                        remarkObject = ((JSONArray) remarkObject).get(index);
                    } else {
                        while(((JSONArray) remarkObject).size() <= index){
                            if(((JSONArray) remarkObject).size() == index){
                                ((JSONArray) remarkObject).add(index, value);
                            }else{
                                ((JSONArray) remarkObject).add(null);
                            }
                        }
                    }
                } else {
                    if (indexAll > i) {
                        if (paths[i + 1].matches("\\[[0-9]+\\]")) {
                            if(!((JSONObject) remarkObject).containsKey(path)){
                                ((JSONObject) remarkObject).put(path, new JSONArray());
                            }
                        } else {
                            if(!((JSONObject) remarkObject).containsKey(path)){
                                ((JSONObject) remarkObject).put(path, new JSONObject());
                            }
                        }
                        remarkObject = ((JSONObject) remarkObject).get(path);
                    } else {
                        ((JSONObject) remarkObject).put(path, value);
                    }
                }
                i++;
            }
        }
        return JSON.toJSONString(resultJSONObject);
    }

    public static SysDataLogDTO converterDataAuditRecord(OperationDataChange change, Object oldData, Object newData,String dataId,String tag,String userId,String username) throws Exception {
        String oldDataStr = JSON.toJSONString(oldData);
        String newDataStr = JSON.toJSONString(newData);
        String json = campareJsonObject(oldDataStr,newDataStr);
        log.info("json:{}",json);
        List<ComparisonDTO> diff = compareObj(oldData, newData);
        String diffStr = JSON.toJSONString(diff);
        log.info("diffStr:{}",diffStr);
        SysDataLogDTO dto = new SysDataLogDTO();
        dto.setDataContent(diffStr);
        dto.setDataTable(change.getTableName());
        dto.setDataId(dataId);
        dto.setTags(tag);
        dto.setMethodName(DataOperateLogThreadLocal.THREADDATA_METHOD.get().toString());
        dto.setCreateTime(new Date());
        dto.setCreateBy(userId);
        dto.setCreatedName(username);
        dto.setRemark(change.getWhereSql());
        //dto.setId(String.valueOf(IdWorker.getId()));

        return dto;
    }

}

注解案例

@DataAuditLogging(tag = "产品信息",dataId = "1",currUserId="#input.adminId",currUsername="#input.adminName")

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值