MyBatis日常:MyBatis日志拦截,实现用户操作记录入库

该需求目标:以最小的变更实现用户操作日志,并记录操作之前数据值。

经分析得知,该需求的主要目的就是拦截用户操作日志,由于需要记录用户、操作记录,故拦截Mybatis的操作日志。
具体代码如下:

核心类(实现mybatis Interceptor接口)

@Component
@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
public class SqlLogInterceptor implements Interceptor {
   private static final Logger logger = LoggerFactory.getLogger(SqlLogInterceptor.class);

   @Autowired
   private SysOperationLogServiceImpl sysOperationLogService;

   @Override
   public Object intercept(Invocation invocation) throws Throwable {

      SysOperationLog sol = new SysOperationLog();
      // 获取当前用户ID
      SysUser token = (SysUser) SecurityUtils.getSubject().getPrincipal();
      String userId = token == null ? "--" : token.getId() + "";
      logger.info("-->userID  " + userId);
      if (token != null) {
         sol.setUserId(token.getId());
         sol.setUserRealName(token.getRealName());
      }

      MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
      BoundSql boundSql = mappedStatement.getBoundSql(invocation.getArgs()[1]);
      Configuration configuration = mappedStatement.getConfiguration();
      // 获取sql语句
      String sql = showSql(configuration, boundSql);
      sql = sql.replaceAll("\'", "").replace("\"", "");
      String splod = sql.toLowerCase().replace("call", "");

      if(splod.indexOf("sys_operation_log") == -1){
         String tableName = null;
         sol.setLogTime(new Date());
         sol.setSqlLog(splod);
         logger.info(splod.indexOf("update") + "----");

         if (splod.indexOf("update") > -1) {
            sol.setLogType("UPADTE");
            // 修改日志记录
            tableName = splod.substring(splod.indexOf("update") + 7, splod.indexOf(" set")).trim();
            sol.setTableName(tableName);
            logger.info(splod + "   tableName--->  " + tableName);
            // 拼接修改操作之前的SQL语句
            String condition = splod.split("where")[1];
            this.saveLog(sol,tableName,condition);

         } else if (splod.indexOf("insert") > -1) {
            sol.setLogType("INSERT");
            // 新增日志记录
            tableName = splod.substring(splod.indexOf("into") + 5, splod.indexOf("(")).trim();
            sol.setTableName(tableName);
            this.saveLog(sol,null,null);
         } else if (splod.indexOf("delete") > -1) {
            sol.setLogType("DELETE");
            // 删除日志记录
            tableName = splod.substring(splod.indexOf("from") + 5, splod.indexOf(" where")).trim();
            sol.setTableName(tableName);
            String condition = splod.split("where")[1];
            this.saveLog(sol,tableName,condition);
         }
      }

      // 执行结果
      Object returnValue = null;
      returnValue = invocation.proceed();
      return returnValue;
   }

   public void saveLog(SysOperationLog sol,String tableName,String condition){
      try{
         if (sysOperationLogService == null) {// 解决service为null无法注入问题
            System.out.println("sysOperationLogService is null!!!");
            sysOperationLogService = (SysOperationLogServiceImpl) SpringContextUtil
                  .getBean("sysOperationLogServiceImpl");
         }
         if (sysOperationLogService != null) {
            if(null != tableName){
               Map<String,Object > map = sysOperationLogService.query(tableName,condition);
               sol.setSqlValue(JSONUtils.valueToString(map));
            }
            int a = sysOperationLogService.save(sol);
            logger.info("插入操作日志:TABLE:"+sol.getTableName()+"  响应条数:"+a);
         }
      }catch(RuntimeException re){
         logger.error("等待日志对象注入(由于tomcat加载机制,启动时出现该错误正常): "+re);
      }
      catch(Exception e){
         logger.error("日志插入失败:",e);
      }

   }

   @Override
   public Object plugin(Object target) {
      return Plugin.wrap(target, this);
   }

   @Override
   public void setProperties(Properties properties) {

   }

   private String getParameterValue(Object obj) {
      String value = null;
      if (obj instanceof String) {
         value = "'" + obj.toString() + "'";
      } else if (obj instanceof Date) {
         DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA);
         value = "'" + formatter.format(obj) + "'";
      } else {
         if (obj != null) {
            value = obj.toString();
         } else {
            value = "";
         }

      }
      return value;
   }

   public String showSql(Configuration configuration, BoundSql boundSql) {
      Object parameterObject = boundSql.getParameterObject();
      List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
      String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
      if (parameterMappings.size() > 0 && parameterObject != null) {
         TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
         if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
            sql = sql.replaceFirst("\\?", getParameterValue(parameterObject));

         } else {
            MetaObject metaObject = configuration.newMetaObject(parameterObject);
            for (ParameterMapping parameterMapping : parameterMappings) {
               String propertyName = parameterMapping.getProperty();
               if (metaObject.hasGetter(propertyName)) {
                  Object obj = metaObject.getValue(propertyName);
                  sql = sql.replaceFirst("\\?", getParameterValue(obj));
               } else if (boundSql.hasAdditionalParameter(propertyName)) {
                  Object obj = boundSql.getAdditionalParameter(propertyName);
                  sql = sql.replaceFirst("\\?", getParameterValue(obj));
               }
            }
         }
      }
      return sql;
   }
}

拦截器配置:

日志记录实体类
image.png

service层实现。
image.png

Dao层实现
image.png
在这里插入图片描述
注:仅个人观点,不足之处还请留言或微信相互学习交流!
在这里插入图片描述

  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值