手写Mybatis拦截器自动填充数据

165 阅读1分钟

主要用于在执行 SQL 插入(INSERT)或更新(UPDATE)操作时,自动填充一些公共字段,如 createdBycreatedTimeupdateByupdateTime 和 isDeleted 等。它会根据操作类型(插入或更新)来设置相应的字段值,同时会从 LoginUtil 中获取登录用户的 loginId 进行填充。

也可抽取公共属性后使用MybatisPlus的MetaObjectHandler进行填充

package com.ssm.subject.infra.config;

import com.ssm.subject.common.util.LoginUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
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.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 填充 createBy, createTime 等公共字段的拦截器
 */
@Component
@Slf4j
@Intercepts({@Signature(method = "update", type = Executor.class, args = {
        MappedStatement.class, Object.class
})})
public class MybatisInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();

        // 第1个参数为当前sql执行时填充的对象,可以是一个实体类,也可以是一个map,需要分情况处理
        Object parameters = invocation.getArgs()[1];
        if (parameters == null) {
            return invocation.proceed();
        }

        // 获取当前登录用户的id
        String loginId = LoginUtil.getLoginId();
        if (StringUtils.isBlank(loginId)) {
            return invocation.proceed();
        }
        if (Objects.equals(SqlCommandType.INSERT, sqlCommandType) || Objects.equals(SqlCommandType.UPDATE, sqlCommandType)) {
            replaceProperty(parameters, loginId, sqlCommandType);
        }
        return invocation.proceed();
    }

    private void replaceProperty(Object parameters, String loginId, SqlCommandType sqlCommandType) {
        if (parameters instanceof Map) {
            replaceMap((Map) parameters, loginId, sqlCommandType);
        } else {
            replace(parameters, loginId, sqlCommandType);
        }

    }

    private void replaceMap(Map parameters, String loginId, SqlCommandType sqlCommandType) {
        for (Object value : parameters.values()) {
            // 判断是否是一个List类,如果是的话需要遍历再做分别替换
            if (value instanceof List) {
                replaceList((List<?>) value, loginId, sqlCommandType);
            } else {
                replace(value, loginId, sqlCommandType);
            }
        }
    }

    private void replaceList(List<?> parameters, String loginId, SqlCommandType sqlCommandType) {
        for (Object o : parameters) {
            replace(o, loginId, sqlCommandType);
        }
    }

    private void replace(Object parameters, String loginId, SqlCommandType sqlCommandType) {
        if (Objects.equals(SqlCommandType.INSERT, sqlCommandType)) {
            replaceInsert(parameters, loginId);
        } else {
            replaceUpdate(parameters, loginId);
        }
    }

    private void replaceUpdate(Object parameters, String loginId) {
        Class<?> clazz = parameters.getClass();
        while (clazz != null) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                try {
                    field.setAccessible(true);
                    Object o = field.get(parameters);
                    if (Objects.nonNull(o)) {
                        field.setAccessible(false);
                        continue;
                    }
                    if ("updateBy".equals(field.getName())) {
                        field.set(parameters, loginId);
                        field.setAccessible(false);
                    } else if ("updateTime".equals(field.getName())) {
                        field.set(parameters, new Date());
                        field.setAccessible(false);
                    } else {
                        field.setAccessible(false);
                    }
                } catch (Exception e) {
                    log.error("replaceUpdate.error:{}", e.getMessage(), e);
                }
            }
            clazz = clazz.getSuperclass();
        }
    }

    private void replaceInsert(Object parameters, String loginId) {
        Class<?> clazz = parameters.getClass();
        while (clazz != null) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                try {
                    field.setAccessible(true);
                    Object o = field.get(parameters);
                    if (Objects.nonNull(o)) {
                        field.setAccessible(false);
                        continue;
                    }
                    if ("isDeleted".equals(field.getName())) {
                        field.set(parameters, 0);
                        field.setAccessible(false);
                    } else if ("createdBy".equals(field.getName())) {
                        field.set(parameters, loginId);
                        field.setAccessible(false);
                    } else if ("createdTime".equals(field.getName())) {
                        field.set(parameters, new Date());
                        field.setAccessible(false);
                    } else {
                        field.setAccessible(false);
                    }
                } catch (Exception e) {
                    log.error("replaceInsert.error:{}", e.getMessage(), e);
                }
            }
            clazz = clazz.getSuperclass();
        }
    }

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

    @Override
    public void setProperties(Properties properties) {
    }
}