首页 > 其他分享 >`基于Mybatis-Plus`+AOP实现动态表名切换

`基于Mybatis-Plus`+AOP实现动态表名切换

时间:2022-12-13 10:01:19浏览次数:44  
标签:AOP dynamic 表名 spel Plus org import com

说明

由于项目中某些场景用到动态表名,度娘之后发现很多案例并不是很友好。所有打算通过自定义注解方式实现,更加的灵活。

废话不多说,直接上代码。

定义注解

package com.zpl.dynamic.framework.annotations;

import com.zpl.dynamic.framework.context.DynamicTableNameHelper;

import java.lang.annotation.*;

/**
 * 动态表名注解
 * 通过spel表达式。自动注入到{@link DynamicTableNameHelper}中。而无需手动注入。减少代码侵入性
 *
 * @author: pinlin
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DynamicName {

    /**
     * spel 表达式
     */
    String spel();
}

定义切面类,具体代码如何下

package com.zpl.dynamic.framework.aop;

import com.zpl.dynamic.framework.annotations.DynamicName;
import com.zpl.dynamic.framework.context.DynamicTableNameHelper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;

/**
 * 切面。用户解析spel表达式,并且赋值到 {@link DynamicTableNameHelper}中
 *
 * @author: pinlin
 */
@Aspect
@Slf4j
public class DynamicNameAspect {

    /**
     * spel解析器
     */
    private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();


    /**
     * 方法形参名解析器
     */
    private static final DefaultParameterNameDiscoverer NAME_DISCOVERER = new DefaultParameterNameDiscoverer();

    @Around("@annotation(dynamicName)")
    public Object around(ProceedingJoinPoint joinPoint, DynamicName dynamicName) throws Throwable {
        try {
            // 获取到spel表达式为空,就不需要解析了
            if (!StringUtils.hasText(dynamicName.spel())) {
                return joinPoint.proceed();
            }

            Object[] args = joinPoint.getArgs();
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            Method method = methodSignature.getMethod();
            String[] paramNames = NAME_DISCOVERER.getParameterNames(method);

            Expression expression = EXPRESSION_PARSER.parseExpression(dynamicName.spel());

            EvaluationContext context = new StandardEvaluationContext();
            for (int i = 0; i < args.length; i++) {
                assert paramNames != null;
                context.setVariable(paramNames[i], args[i]);
            }
            String tableName = expression.getValue(context, String.class);
            if (StringUtils.hasText(tableName)) {
                DynamicTableNameHelper.set(tableName);
            }
            return joinPoint.proceed();
        } finally {
            // 释放缓存内容
            DynamicTableNameHelper.remove();
        }
    }


}

定义动态表名处理器

package com.zpl.dynamic.framework.handler;

import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler;
import com.zpl.dynamic.framework.context.DynamicTableNameHelper;
import org.springframework.util.StringUtils;

/**
 * 动态表名处理器
 *
 * @author: pinlin
 */
public class DynamicTableNameHandler implements TableNameHandler {

    @Override
    public String dynamicTableName(String sql, String tableName) {
        String tableNameSuffix = DynamicTableNameHelper.get();
        if (StringUtils.hasText(tableNameSuffix)) {
            return tableName + "_" + tableNameSuffix;
        }
        return tableName;
    }
}

创建自动配置类

package com.zpl.dynamic.framework.config;


import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.zpl.dynamic.framework.aop.DynamicNameAspect;
import com.zpl.dynamic.framework.handler.DynamicTableNameHandler;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * mybatis 自动配置类
 *
 * @author: pinlin
 */
@MapperScan(value = {"com.zpl"}, annotationClass = Mapper.class)
@Component
public class MybatisAutoConfiguration {

    @Resource
    private TableNameHandler tableNameHandler;

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
        // 需要放到第一位,切记不要放错,不然会导致动态表名切换失效
        dynamicTableNameInnerInterceptor.setTableNameHandler(tableNameHandler);
        interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

    @Bean
    public DynamicNameAspect dynamicNameAspect() {
        return new DynamicNameAspect();
    }

    @Bean
    public DynamicTableNameHandler dynamicTableNameHandler() {
        return new DynamicTableNameHandler();
    }
}

说明

这里的动态表名处理器,一定要放到拦截器的第一位,不然会导致动态表名处理切换失败。

这里的动态表名处理器,一定要放到拦截器的第一位,不然会导致动态表名处理切换失败。

这里的动态表名处理器,一定要放到拦截器的第一位,不然会导致动态表名处理切换失败。

使用

  1. 在方式添加动态表名注解,具体如何下

注意

这里需要注意的地方就是,注解的spel获取的值的名称要和方法的形参名要一致,不然会报错。

比如上面案列 reqVO那么spel表达式的取值也是reqVO.tableNameSffix中的reqVO需要保持一致。

如果suffixNamereqVO.tableNameSffix为空贼默认查询主表

  1. 具体用法可参考单元测试类UserServiceTest
  2. 具体代码仓库地址为https://github.com/zengpinlin/dynamic-demo

说明

如果有哪里不对的地方。还请各位伙伴指出。谢谢。

标签:AOP,dynamic,表名,spel,Plus,org,import,com
From: https://www.cnblogs.com/zengpinlin/p/16977778.html

相关文章