通过Header控制MyBatis-Plus动态数据源
动态参数解释器说明
在MyBatis dynamic-datasource中,默认有三个职责链来处理动态参数解析器 header->session->spel
@DS("#session.tenantName")//从session获取
public List selectSpelBySession() {
return userMapper.selectUsers();
}
@DS("#header.tenantName")//从header获取
public List selectSpelByHeader() {
return userMapper.selectUsers();
}
@DS("#tenantName")//使用spel从参数获取
public List selectSpelByKey(String tenantName) {
return userMapper.selectUsers();
}
@DS("#user.tenantName")//使用spel从复杂参数获取
public List selecSpelByTenant(User user) {
return userMapper.selectUsers();
}
如果想让前端控制不同的数据库只需要用到第一个DsHeaderProcessor
就能实现。
实际开发场景需求
在开发可视化大屏中,由于不同地市连接不同地市的数据库,并且不同地市的表结构都是相同的情况下就可以使用@DS("#header.data-source")
注解,可以通过源码发现他只获取了#header
8个字符串后面的字符。
package com.baomidou.dynamic.datasource.processor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* @author TaoYu
* @since 2.5.0
*/
public class DsHeaderProcessor extends DsProcessor {
/**
* header prefix
*/
private static final String HEADER_PREFIX = "#header";
@Override
public boolean matches(String key) {
return key.startsWith(HEADER_PREFIX);
}
@Override
public String doDetermineDatasource(MethodInvocation invocation, String key) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
return request.getHeader(key.substring(8));
}
}
request.getHeader(key.substring(8));
当作动态数据源标识,matches
方法为是否匹配成功。这时候只需要和前端约定名为data-source
的header让前端去控制在*application.yml
中的* spring.datasource.dynamic.datasource.xxxxx
xxxx就是与前端约定的data-source
来选择数据库。
从业务逻辑层去控制不同数据源
参考header解析器,继承DsProcessor,如果matches返回true则匹配成功,调用doDetermineDatasource返回匹配到的数据源,否则跳到写一个解析器.
自定义一个处理器类似
DsHeaderProcessor
解析器。重写完后重新注入一个根据自己解析顺序的解析处理器.
@Configuration
public class MyDynamicDataSourceConfig{
@Bean
public DsProcessor dsProcessor() {
DsHeaderProcessor headerProcessor = new DsHeaderProcessor();
DsSessionProcessor sessionProcessor = new DsSessionProcessor();
DsSpelExpressionProcessor spelExpressionProcessor = new DsSpelExpressionProcessor();
headerProcessor.setNextProcessor(sessionProcessor);
sessionProcessor.setNextProcessor(spelExpressionProcessor);
return headerProcessor;
}
}
在Mapper接口下面的方法使用
public interface UserMapper{
// 前缀可以是p0,a0
@DS("#p0.tenantName")
public List selecSpelByTenant(User user);
}
对于在接口下面的使用, 由于编译器的默认配置没有将接口参数的元数据写入字节码文件中.
所以spring el会无法识别参数名称, 只能用默认的参数命名方式
第一个参数: p0,a0,(加入-parameter后,可以使用参数具体的名字,例如这里的#user)
第二个参数: p1,a1
第三个参数: P2,a2
可以通过修改maven配置和java编译配置将接口参数信息写入字节码文件
maven配置:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<!-- 想启用 <parameters>true</parameters> 的maven编译最低版本为:3.6.2 -->
<version>3.6.2</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<parameters>true</parameters>
</configuration>
</plugin>