中州养老项目:Mybatis自动填充拦截器

发布于:2025-08-03 ⋅ 阅读:(18) ⋅ 点赞:(0)

功能:在新增护理项目的时候,创建人,创建时间和修改时间字段会自动拦截填充,这些公共字段可以省去我们一个一个处理的麻烦

依靠:AutoFillInterceptor拦截器,MybatisConfig配置类

第一步:我们需要借助一个MybatisConfig,@configuration标志着这是一个配置类,我们需要将autoFillInterceptor放在配置类中并用@Bean注解将这个配置类交给spring容器gu

第二步:了解配置类的原理,也就是AutoFillInterceptor,这个拦截器的代码大部分是固定的我用只需要了解它的逻辑,在需要的时候复制代码并根据需求修改

package com.zzyl.intercept;

// 引入工具类和依赖
import cn.hutool.core.util.ObjectUtil;
import com.zzyl.utils.EmptyUtil;
import com.zzyl.utils.UserThreadLocal;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Properties;

// 声明这是一个MyBatis拦截器,拦截Executor的update方法
@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
@Component // 声明为Spring组件
public class AutoFillInterceptor implements Interceptor {

    // 常量定义:字段名
    private static final String CREATE_BY = "createBy";   // 创建人字段名
    private static final String UPDATE_BY = "updateBy";   // 更新人字段名
    private static final String CREATE_TIME = "createTime"; // 创建时间字段名
    private static final String UPDATE_TIME = "updateTime"; // 更新时间字段名

    // 拦截逻辑核心方法
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取方法参数:MappedStatement和SQL参数对象
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];  // 获取SQL映射信息
        SqlCommandType sqlCommandType = ms.getSqlCommandType(); // 获取SQL操作类型(INSERT/UPDATE等)
        Object parameter = args[1];  // 获取SQL参数对象

        // 仅当参数和SQL类型有效时处理
        if (parameter != null && sqlCommandType != null) {
            Long userId = loadUserId();  // 获取当前用户ID(从ThreadLocal)

            // 处理INSERT操作
            if (SqlCommandType.INSERT.equals(sqlCommandType)) {
                // 批量插入场景(参数是ParamMap且包含list字段)
                if (parameter instanceof MapperMethod.ParamMap) {
                    MapperMethod.ParamMap paramMap = (MapperMethod.ParamMap) parameter;
                    ArrayList list = (ArrayList) paramMap.get("list"); // 获取批量数据列表
                    list.forEach(v -> {
                        // 为每条数据设置创建人、创建时间、更新时间
                        setFieldValByName(CREATE_BY, userId, v);
                        setFieldValByName(CREATE_TIME, LocalDateTime.now(), v);
                        setFieldValByName(UPDATE_TIME, LocalDateTime.now(), v);
                    });
                    paramMap.put("list", list); // 更新修改后的参数
                } else {
                    // 单条插入场景
                    setFieldValByName(CREATE_BY, userId, parameter);
                    setFieldValByName(CREATE_TIME, LocalDateTime.now(), parameter);
                    setFieldValByName(UPDATE_TIME, LocalDateTime.now(), parameter);
                }
            } 
            // 处理UPDATE操作
            else if (SqlCommandType.UPDATE.equals(sqlCommandType)) {
                // 设置更新人和更新时间
                setFieldValByName(UPDATE_BY, userId, parameter);
                setFieldValByName(UPDATE_TIME, LocalDateTime.now(), parameter);
            }
        }

        // 继续执行原始SQL操作
        return invocation.proceed();
    }

    /**
     * 通过反射设置实体对象的字段值
     * @param fieldName  字段名(如createBy)
     * @param fieldVal   字段值(如用户ID)
     * @param parameter  实体对象
     */
    private void setFieldValByName(String fieldName, Object fieldVal, Object parameter) {
        // 使用MyBatis的MetaObject操作对象属性
        MetaObject metaObject = SystemMetaObject.forObject(parameter);
        
        // 如果是createBy字段且已有值,则跳过(避免覆盖)
        if (fieldName.equals(CREATE_BY)) {
            Object value = metaObject.getValue(fieldName);
            if (ObjectUtil.isNotEmpty(value)) {
                return;
            }
        }

        // 如果字段存在setter方法,则设置值
        if (metaObject.hasSetter(fieldName)) {
            metaObject.setValue(fieldName, fieldVal);
        }
    }

    // 包装目标对象(Executor),返回代理对象
    @Override
    public Object plugin(Object target) {
        if (target instanceof Executor) {
            return Plugin.wrap(target, this); // MyBatis提供的包装方法
        }
        return target; // 非Executor类型直接返回
    }

    // 可读取配置文件属性(本例未使用)
    @Override
    public void setProperties(Properties properties) {}

    /**
     * 获取当前用户ID(优先级:ThreadLocal用户ID → 管理用户ID → 默认值1)
     */
    public static Long loadUserId() {
        Long userId = UserThreadLocal.getUserId(); // 从业务线程获取
        if (ObjectUtil.isNotEmpty(userId)) {
            return userId;
        }
        userId = UserThreadLocal.getMgtUserId(); // 从管理线程获取
        if (!EmptyUtil.isNullOrEmpty(userId)) {
            return userId;
        }
        return 1L; // 默认值
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到