- 近日公司需要新框架需要兼容旧代码,旧代码用的mybatis手写的动态表名 ,大概是实体类定义一个table字段 然后将table的值传到映射文件中,${table} 这种方式, 研究了一下mp发现可以直接用拦截器替换表名就有了以下代码
1. 3.4.3.4 (最新版)动态表名实现
1.配置类 (官方方式)
@Configuration
@MapperScan("com.cars.ysdd.clts.domain.clts.dao")
public class MybatisPlusConfig {
static List<String> tableList(){
List<String> tables = new ArrayList<>();
tables.add("user");
return tables;
}
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> {
// 获取参数方法
/*Map<String, Object> paramMap = RequestDataHelper.getRequestData();
paramMap.forEach((k, v) -> System.err.println(k + "----" + v));
System.err.println("表名:"+tableName);
System.err.println("sql:"+sql);
String year = "_2018";
int random = new Random().nextInt(10);
if (random % 2 == 1) {
year = "_2019";
}*/
String newTable = null;
for (String table : tableList()) {
newTable = RequestDataHelper.getRequestData(table);
if (table.equals(tableName) && newTable!=null){
tableName = newTable;
break;
}
}
return tableName;
// return tableName + year;
});
interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
// 3.4.3.2 作废该方式
// dynamicTableNameInnerInterceptor.setTableNameHandlerMap(map);
return interceptor;
}
}
2.请求参数传递辅助类
package com.baomidou.mybatisplus.samples.dytablename.config;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import java.util.Map;
/**
* 请求参数传递辅助类
*/
public class RequestDataHelper {
/**
* 请求参数存取
*/
private static final ThreadLocal<Map<String, Object>> REQUEST_DATA = new ThreadLocal<>();
/**
* 设置请求参数
*
* @param requestData 请求参数 MAP 对象
*/
public static void setRequestData(Map<String, Object> requestData) {
REQUEST_DATA.set(requestData);
}
/**
* 获取请求参数
*
* @param param 请求参数
* @return 请求参数 MAP 对象
*/
public static <T> T getRequestData(String param) {
Map<String, Object> dataMap = getRequestData();
if (CollectionUtils.isNotEmpty(dataMap)) {
return (T) dataMap.get(param);
}
return null;
}
/**
* 获取请求参数
*
* @return 请求参数 MAP 对象
*/
public static Map<String, Object> getRequestData() {
return REQUEST_DATA.get();
}
}
3.使用
@SpringBootTest
class DynamicTableNameTest {
@Resource
private UserMapper userMapper;
@Test
void test() {
RequestDataHelper.setRequestData(new HashMap<String, Object>() {{
put("user", "user_2018");
}});
// 自己去观察打印 SQL 目前随机访问 user_2018 user_2019 表
for (int i = 0; i < 6; i++) {
User user = userMapper.selectById(1);
System.err.println(user.getName());
}
}
}
2. 3.4.1版
1. 配置类
- 这里的RequestDataHelper 用的是上文的3.4.3.4中的
@Configuration
@MapperScan("com.cars.ysdd.clts.domain.clts.dao")
public class DynamicTableNameHandler {
static List<String> tableList() {
List<String> tables = new ArrayList<>();
tables.add("CR_CZJM");
return tables;
}
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor paginationInterceptor = new MybatisPlusInterceptor();
// DynamicTableNameParser 表名解析器,动态解析表名,ITableNameHandler 表名处理。
DynamicTableNameInnerInterceptor dynamicTableNameParser = new DynamicTableNameInnerInterceptor();
dynamicTableNameParser.setTableNameHandlerMap(new HashMap<String, TableNameHandler>(2) {{
//metaObject 元对象 ;sql 执行的SQL ;tableName 表名
//这里put的key就是需要替换的原始表名,也就是实体类的表名
//这里的tableName就是我们定义的动态表名变量,
for (String table : tableList()) {
put(table, (sql, tableName) -> {
// 获取传入参数 tableName,tableName的值就是替换后的表名
return RequestDataHelper.getRequestData(table) == null ? tableName : RequestDataHelper.getRequestData(table);
});
}
}});
paginationInterceptor.addInnerInterceptor(dynamicTableNameParser);
return paginationInterceptor;
}
}
2. 使用
/**
* @param crCzjmDO 实体类
* @return 执行条数
*/
@Override
public int insert(CrCzjmDO crCzjmDO) {
RequestDataHelper.setRequestData(new HashMap<String, Object>(){{
put("CR_CZJM","TJFX.CR_CZJM");
}});
return crCzjmMapper.insertSelective(crCzjmDO);
}
3. 3.4 以下版本 (3.1.2 版为例)
1.配置类
@Configuration
public class DynamicTableNameHandler {
/**
* 适用于相同表结构 不同表名
*/
//实体类对应的表名字段
public static final String DYNAMIC_TABLE_NAME = "tableName";
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// DynamicTableNameParser 表名解析器,动态解析表名,ITableNameHandler 表名处理。
DynamicTableNameParser dynamicTableNameParser = new DynamicTableNameParser();
dynamicTableNameParser.setTableNameHandlerMap(new HashMap<String, ITableNameHandler>(2) {{
//metaObject 元对象 ;sql 执行的SQL ;tableName 表名
//这里put的key就是需要替换的原始表名,也就是实体类的表名
//这里的tableName就是我们定义的动态表名变量,
put("payment", (metaObject, sql, tableName) -> {
// 获取传入参数 tableName,tableName的值就是替换后的表名
Object param = getParamValue(DYNAMIC_TABLE_NAME, metaObject);
if(param == null){
return tableName;//不带tableName参数就返回原表名
}else {
return param.toString();//带tableName参数就返回新表名
}
});
/*put("payment", (metaObject, sql, tableName) -> {
// 获取传入参数 tableName,tableName的值就是替换后的表名
Object param = getParamValue(DYNAMIC_TABLE_NAME, metaObject);
if(param == null){
return tableName;//不带tableName参数就返回原表名
}else {
return param.toString();//带tableName参数就返回新表名
}
});*/
}});
paginationInterceptor.setSqlParserList(Collections.singletonList(dynamicTableNameParser));
return paginationInterceptor;
}
/**
* 获取动态表tableName参数的值
*/
private Object getParamValue(String title, MetaObject metaObject){
//获取参数
Object originalObject = metaObject.getOriginalObject();
JSONObject originalObjectJSON = JSON.parseObject(JSON.toJSONString(originalObject));
JSONObject boundSql = originalObjectJSON.getJSONObject("boundSql");
try {
JSONObject parameterObject = boundSql.getJSONObject("parameterObject");
return parameterObject.get(title);
}catch (Exception e) {
return null;
}
}
}
2. 实体类示例
- 定义一个与上边配置类中DYNAMIC_TABLE_NAME 的值对应名称的字段(非数据库)
@Data
public class Payment implements Serializable {
private static final long serialVersionUID = 1L;
private String serial;
@TableField(exist = false)
private String tableName;
}
3. 使用
@Override
public List<Payment> selectByTable(String table) {
Payment payment = new Payment();
payment.setTableName(table);
return paymentMapper.select(payment);
}