上一篇文章写了mybatis-plus插件的初步使用,但是使用仍不方便,例如需要过滤的表只能写死或者写配置文件,非常的不方便而且不可控,于是我想到可以使用自定义注解来统一管控受控制的表.那么就尝试实现吧.
实现方式:
1、 先写一个自定义注解,表示被打上此注解的entity受多租户插件管控.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface TenantLine {
}
2、定义一个baseEntity ,提供租户字段,并且打上此注解
@Data
@TenantLine
public class BaseTenantEntity extends BaseEntity {
private Long tenantId;
}
3、写一个方法,扫描包里的所有拥有@TenantLine注解以及@TableName注解的类,再获取@TableName注解的value来统一添加表名
public static void getTableNames(){
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
Set<String> tableNames = Sets.newHashSet();
try {
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath("com.dane") + "/**/*.class";
Resource[] resources = resourcePatternResolver.getResources(pattern);
//MetadataReader 的工厂类
MetadataReaderFactory readerfactory = new CachingMetadataReaderFactory(resourcePatternResolver);
for (Resource resource : resources) {
//用于读取类信息
MetadataReader reader = readerfactory.getMetadataReader(resource);
//扫描到的class
String classname = reader.getClassMetadata().getClassName();
Class<?> clazz = Class.forName(classname);
TableName tableName = null;
TenantLine tenantLine = null;
//判断当前class及父类是否有指定主解
while (clazz != null) {
if (tableName == null) {
tableName = clazz.getAnnotation(TableName.class);
}
if (tenantLine == null) {
tenantLine = clazz.getAnnotation(TenantLine.class);
}
clazz = clazz.getSuperclass();
}
if (tableName != null && tenantLine != null) {
tableNames.add(tableName.value());
}
}
} catch (IOException | ClassNotFoundException e) {
}
tables.addAll(tableNames);
}
4、在多租户插件的类中,提供此静态方法,并且在构造中加载这些受管控的类.
public class MyTenantLineHandler implements TenantLineHandler {
public MyTenantLineHandler() {
getTableNames();
}
private static Set<String> tables = Sets.newHashSet();
@Override
public Expression getTenantId() {
Long tenantId = UserUtil.getTenantId();
return tenantId == null ? new LongValue(1) : new LongValue(tenantId);
}
@Override
public String getTenantIdColumn() {
return "tenant_id";
}
@Override
public boolean ignoreTable(String tableName) {
return !tables.contains(tableName);
// return TenantLineHandler.super.ignoreTable(tableName);
}
public static void getTableNames(){
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
Set<String> tableNames = Sets.newHashSet();
try {
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath("com.dane") + "/**/*.class";
Resource[] resources = resourcePatternResolver.getResources(pattern);
//MetadataReader 的工厂类
MetadataReaderFactory readerfactory = new CachingMetadataReaderFactory(resourcePatternResolver);
for (Resource resource : resources) {
//用于读取类信息
MetadataReader reader = readerfactory.getMetadataReader(resource);
//扫描到的class
String classname = reader.getClassMetadata().getClassName();
Class<?> clazz = Class.forName(classname);
TableName tableName = null;
TenantLine tenantLine = null;
//判断是否有指定主解
while (clazz != null) {
if (tableName == null) {
tableName = clazz.getAnnotation(TableName.class);
}
if (tenantLine == null) {
tenantLine = clazz.getAnnotation(TenantLine.class);
}
clazz = clazz.getSuperclass();
}
if (tableName != null && tenantLine != null) {
tableNames.add(tableName.value());
}
}
} catch (IOException | ClassNotFoundException e) {
}
tables.addAll(tableNames);
}
}
5、实体类继承基础BaseTenantEntity类.
@Data
@TableName("sys_user")
public class SysUserEntity extends BaseTenantEntity {
private String username;
private String password;
}
6、测试
6.1 开启多租户
如图,此表已经受管控了
6.2 关闭多租户(取消继承baseTenantEntity父类)
如图,这时候sys_user表是不受管控的.
mybatis-plus的多租户插件还是非常强大的,依靠mybatis的jsqlparser来添加多租户,实测下来,无论是mybatis-plus的基础方法还是自定义sql,都能进行不错的多租户支持.