import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Slf4j
@Configuration
public class MybatisPlusCommonConfig {
@Bean
public TableNameInterceptor tableNameInterceptor() {
return new TableNameInterceptor();
}
}
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 自定义拦截器,用于替换SQL语句中没有前缀的表名
*/
@Slf4j
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class TableNameInterceptor implements Interceptor {
// 匹配表名的正则表达式
private static final Pattern TABLE_NAME_PATTERN = Pattern.compile(
"\\b(from|join|update|into|table)\\s+([a-zA-Z0-9_\"'`]+)(?!\\s*\\()(?!\\s*,)",
Pattern.CASE_INSENSITIVE
);
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
MetaObject metaObject = MetaObject.forObject(
statementHandler,
SystemMetaObject.DEFAULT_OBJECT_FACTORY,
SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,
new DefaultReflectorFactory()
);
BoundSql boundSql = statementHandler.getBoundSql();
String sql = boundSql.getSql();
log.info("原始SQL: {}", sql);
// 替换SQL中的表名
String newSql = replaceTableNames(sql);
// String newSql ="ALTER SESSION SET CURRENT_SCHEMA = xxx;" + sql;
log.info("修改后SQL: {}", newSql);
// 通过反射修改sql语句
Field field = boundSql.getClass().getDeclaredField("sql");
field.setAccessible(true);
field.set(boundSql, newSql);
return invocation.proceed();
}
/**
* 替换SQL中的表名,给没有前缀的表名加上"xxx."前缀
* @param sql 原始SQL
* @return 修改后的SQL
*/
private String replaceTableNames(String sql) {
Matcher matcher = TABLE_NAME_PATTERN.matcher(sql);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
String keyword = matcher.group(1); // 关键字 (from, join, update等)
String tableName = matcher.group(2); // 表名
// 清理表名中的引号
String cleanTableName = tableName.replaceAll("[\"'`]", "");
// 如果表名不包含点号(即没有前缀),则添加前缀
if (!cleanTableName.contains(".") && !"xxx".equals(cleanTableName)) {
// 转义特殊字符
String replacement = keyword + " xxx." + tableName;
matcher.appendReplacement(sb, replacement.replaceAll("\\$", "\\\\\\$"));
} else {
// 表名已经有前缀,保持原样
matcher.appendReplacement(sb, matcher.group(0).replaceAll("\\$", "\\\\\\$"));
}
}
matcher.appendTail(sb);
return sb.toString();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// 可以设置一些自定义属性
}
}
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
@Configuration
public class DataSourceConfig {
@Bean
@Primary
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
// 设置默认schema为xxx
dataSource.setSchema("xxx");
return dataSource;
}
}
mybatis-plus:
global-config:
enable-sql-runner: true
db-config:
table-prefix: xxx.
configuration-properties:
prefix: xxx.
configuration:
map-underscore-to-camel-case: true
auto-mapping-behavior: full
call-setters-on-nulls: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
use-generated-keys: false