mybatis拦截器统一处理createBy、createTime、updateBy等字段

一、问题描述

createBycreateTimeupdateBy等字段是我们创建表的时候经常要用到的几个字段,但是我们不可能每一次在增删改查的时候都手动去修改或者添加这几个字段的属性值,我们可以在系统层面统一处理,如何实现呢?

二、实现方法

要实现上述需求的一个办法就是使用mabatis拦截器进行统一处理,步骤如下:

  1. 创建基础类 BaseEntity.java

    /**
     * Entity基类
     */
    @Data
    public class BaseEntity implements Serializable
    {
        private static final long serialVersionUID = 1L;
    
        /** 搜索值 */
        @JsonIgnore
        private String searchValue;
    
        /** 创建者 */
        private String createBy;
    
        /** 创建时间 */
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private Date createTime;
    
        /** 更新者 */
        private String updateBy;
    
        /** 更新时间 */
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private Date updateTime;
    }
    
  2. 创建需要的实体,并继承基础类BaseEntity.java

    @Data
    	public class CorText extends BaseEntity {
    	    private static final long serialVersionUID = 1L;
    	
    	    /**
    	     * 主键
    	     */
    	    private String id;
    	
    	    /**
    	     * 用户ID
    	     */
    	    @Excel(name = "用户ID")
    	    private String userId;
    	  //	    xxxx
    	}
    
  3. 创建mabatis拦截器

    package com.ncjr.framework.interceptor.mybatis;
    
    import cn.hutool.core.util.IdUtil;
    import cn.hutool.core.util.ReflectUtil;
    import com.ncjr.common.core.domain.model.LoginUser;
    import com.ncjr.common.utils.DateUtils;
    import com.ncjr.common.utils.SecurityUtils;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.ibatis.binding.MapperMethod.ParamMap;
    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.*;
    
    /**
     * mybatis拦截器,自动注入创建人、创建时间、修改人、修改时间
     *
     * @Author wxz
     * @Date 2023-5-5
     */
    
    @Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
    @Component
    @Slf4j
    public class AutoInjectBaseFieldInterceptor implements Interceptor {
        /**
         * 用户字段,如果有其他命名的字段,就添加进来
         */
        private List<String> createUserFieldList() {
            List<String> createUserList = new ArrayList<>();
            createUserList.add("createUser");
            createUserList.add("createBy");
            // createUserList.add("deleteBy");
            // createUserList.add("deleteUser");
            return createUserList;
        }
    
        private List<String> updateUserFieldList() {
            List<String> createUserList = new ArrayList<>();
            createUserList.add("updateUser");
            createUserList.add("updateBy");
            return createUserList;
        }
    
        private List<String> idFieldList() {
            return Collections.singletonList("id");
        }
    
        private List<String> createTimeFieldList() {
            List<String> createTimeList = new ArrayList<>();
            createTimeList.add("createTime");
            createTimeList.add("createDate");
            return createTimeList;
        }
    
        private List<String> updateTimeFieldList() {
            List<String> createTimeList = new ArrayList<>();
            createTimeList.add("updateTime");
            createTimeList.add("updateDate");
            return createTimeList;
        }
    
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
    
            if (invocation.getArgs().length == 1) {
                return invocation.proceed();
            }
    
            MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
            SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
            Object parameter = invocation.getArgs()[1];
            if (parameter == null) {
                return invocation.proceed();
            }
            if (SqlCommandType.INSERT == sqlCommandType) {
                Field[] fields = ReflectUtil.getFields(parameter.getClass());
                for (Field field : fields) {
                    try {
                        String fieldName = field.getName();
                        //获取属性名前,先开启反射可访问,否则,无法获取到字段名,因为字段名是私有属性
                        field.setAccessible(true);
                        Object localCreateBy = field.get(parameter);
                        //  注入id
                        if (this.idFieldList().contains(fieldName)) {
                            if (localCreateBy == null || "".equals(localCreateBy)) {
                                field.set(parameter, IdUtil.fastSimpleUUID());
                            }
                        }
                        //注入创建时间
                        if (this.createTimeFieldList().contains(fieldName)) {
                            if (localCreateBy == null || "".equals(localCreateBy)) {
                                field.set(parameter, DateUtils.getNowDate());
                            }
                        }
                        //注入创建人
                        if (this.createUserFieldList().contains(fieldName)) {
                            if (localCreateBy == null || "".equals(localCreateBy)) {
                                setUserName(field, parameter);
                            }
                        }
                        field.setAccessible(false);
                    }
                    catch (Exception ignored) {
                    }
                }
            }
            if (SqlCommandType.UPDATE == sqlCommandType) {
                Field[] fields = null;
                if (parameter instanceof ParamMap) {
                    ParamMap<?> p = (ParamMap<?>) parameter;
                    if (p.containsKey("et")) {
                        parameter = p.get("et");
                    } else {
                        parameter = p.get("param1");
                    }
                    if (parameter == null) {
                        return invocation.proceed();
                    }
                }
                fields = ReflectUtil.getFields(parameter.getClass());
                for (Field field : fields) {
                    try {
                        String fieldName = field.getName();
                        field.setAccessible(true);
                        Object localUpdateBy = field.get(parameter);
                        if (this.updateUserFieldList().contains(fieldName)) {
                            if (localUpdateBy == null || "".equals(localUpdateBy)) {
                                setUserName(field, parameter);
                            }
                        }
                        if (this.updateTimeFieldList().contains(fieldName)) {
                            if (localUpdateBy == null || "".equals(localUpdateBy)) {
                                field.set(parameter, DateUtils.getNowDate());
                            }
                        }
                        field.setAccessible(false);
                    }
                    catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            return invocation.proceed();
        }
    
        @Override
        public Object plugin(Object target) {
            return Plugin.wrap(target, this);
        }
    
        @Override
        public void setProperties(Properties properties) {
        }
    
        private void setUserName(Field field, Object parameter) {
            LoginUser sysUser = null;
            //获取登录用户信息
            try {
                sysUser = SecurityUtils.getLoginUser();
                if (sysUser != null) {
                    field.setAccessible(true);
                    field.set(parameter, sysUser.getUser().getUserId() + "");
                    field.setAccessible(false);
                }
            }
            catch (Exception ignored) {
            }
        }
    
    }
    
    
  4. 依赖工具 SecurityUtils.java

    
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    
    /**
     * 安全服务工具类
     * 
     * @author ruoyi
     */
    public class SecurityUtils
    {
        /**
         * 用户ID
         **/
        public static Long getUserId()
        {
            try
            {
                return getLoginUser().getUserId();
            }
            catch (Exception e)
            {
                throw new ServiceException("获取用户ID异常", HttpStatus.UNAUTHORIZED);
            }
        }
    
        /**
         * 获取部门ID
         **/
        public static Long getDeptId()
        {
            try
            {
                return getLoginUser().getDeptId();
            }
            catch (Exception e)
            {
                throw new ServiceException("获取部门ID异常", HttpStatus.UNAUTHORIZED);
            }
        }
        
        /**
         * 获取用户账户
         **/
        public static String getUsername()
        {
            try
            {
                return getLoginUser().getUsername();
            }
            catch (Exception e)
            {
                throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED);
            }
        }
    
        /**
         * 获取用户
         **/
        public static LoginUser getLoginUser()
        {
            try
            {
                return (LoginUser) getAuthentication().getPrincipal();
            }
            catch (Exception e)
            {
                throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED);
            }
        }
    
        /**
         * 获取Authentication
         */
        public static Authentication getAuthentication()
        {
            return SecurityContextHolder.getContext().getAuthentication();
        }
    
        /**
         * 生成BCryptPasswordEncoder密码
         *
         * @param password 密码
         * @return 加密字符串
         */
        public static String encryptPassword(String password)
        {
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            return passwordEncoder.encode(password);
        }
    
        /**
         * 判断密码是否相同
         *
         * @param rawPassword 真实密码
         * @param encodedPassword 加密后字符
         * @return 结果
         */
        public static boolean matchesPassword(String rawPassword, String encodedPassword)
        {
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            return passwordEncoder.matches(rawPassword, encodedPassword);
        }
    
        /**
         * 是否为管理员
         * 
         * @param userId 用户ID
         * @return 结果
         */
        public static boolean isAdmin(Long userId)
        {
            return userId != null && 1L == userId;
        }
    }
    
    
  5. 创建mybatis-config.xml配置文件,使上面的拦截器生效

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
              <!--mybatis拦截器-->
        <plugins>
            <plugin interceptor="com.xxx.mybatis.MybatisInterceptor"/>
        </plugins>
    </configuration>
    

    其中,mybatis-config.xml结构路径如下:
    在这里插入图片描述

经过以上步骤,就可以实现使用mabatis拦截器统一处理创建人/创建时间/更新人/更新时间等字段了;

问题

如果项目里面使用了 com.github.pagehelper.PageInterceptor ,有可能会导致上面的自定义拦截器失效,如果遇见这种情况,请补充下面代码:

	package com.ncjr.framework.config;
	
	import com.ncjr.framework.interceptor.mybatis.AutoInjectBaseFieldInterceptor;
	import lombok.RequiredArgsConstructor;
	import org.apache.ibatis.session.SqlSessionFactory;
	import org.springframework.context.ApplicationListener;
	import org.springframework.context.event.ContextRefreshedEvent;
	import org.springframework.stereotype.Component;
	
	import java.util.List;
	
	/**
	 * 注册 MyBatis 自定义拦截器,mybatis使用责任链模式,可能会导致自定义插件失效
	 * @author wxz
	 */
	@Component
	@RequiredArgsConstructor
	public class RegisterCustomerInterceptor implements ApplicationListener<ContextRefreshedEvent> {
	    /**
	     * 需要注册的自定义插件
	     */
	    private final AutoInjectBaseFieldInterceptor switchDataSourceInterceptor;
	    
	    private final List<SqlSessionFactory> sqlSessionFactories;
	
	    @Override
	    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
	        for (SqlSessionFactory factory : sqlSessionFactories) {
	            //由于mybatis拦截器使用责任链模式,有可能会导致自定义拦截器失效,因此下面方法可以将自定义拦截器重新注入到sql中
	            factory.getConfiguration().addInterceptor(switchDataSourceInterceptor);
	        }
	    }
	}
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值