Mybatis-plus

内容目录

1、Mybatis-plus的介绍

2、Mybatis-plus自定义插件开发

Mybatis-plus的介绍

简介

MyBatis-Plus (简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 强大的crud:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持lambda链式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错,方便数据库字段修改
  • 内置代码生成器
  • 内置分页插件
  • 内置性能分析插件:下文中提及
  • 内置全局拦截插件:下文中提及

SpringBoot整合引入

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<modelVersion>4.0.0</modelVersion>
<artifactId>mybatis-plus-springboot</artifactId>
<name>mybatis-plus-springboot</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.30</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>

<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>

<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>

application.properties

1
2
3
4
5
6
7
#mysql数据源配置
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url= jdbc:mysql:///mybatis-study
spring.datasource.username=root
spring.datasource.password=123456
mybatis-plus.mapper-locations=classpath:mapper/system/repository/dao/**/*.xml
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
1
2
3
4
5
6
7
@SpringBootApplication
@MapperScan(basePackages = {"com.study.domain.*.dao"})
public class SpringbootClass {
public static void main(String[] args) {
SpringApplication.run(SpringbootClass.class, args);
}
}

内置代码生成器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183

public class MybatisGenerator {

/**
* <p>
* 读取控制台内容
* </p>
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotBlank(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}


public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();

// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/mybatis-plus-springboot/src/main/java");
gc.setAuthor("24khandsome");
gc.setOpen(false);
// XML 二级缓存
gc.setEnableCache(false);
// 自定义文件命名,注意 %s 会自动填充表实体属性!
gc.setEntityName("%sPO");
gc.setMapperName("%sDao");
gc.setXmlName("%sDao");
gc.setServiceName("%sService");
gc.setServiceImplName("%sServiceImpl");
gc.setControllerName("%sController");
gc.setXmlName("%sDao");
mpg.setGlobalConfig(gc);

// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql:///mybatis-study?useUnicode=true&useSSL=false&characterEncoding=utf8");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
mpg.setDataSource(dsc);

// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(scanner("模块名"));
pc.setEntity("entity.po");
pc.setMapper("dao");
pc.setController("api");
pc.setParent("com.study.domain");
mpg.setPackageInfo(pc);

// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};

// 如果模板引擎是 freemarker
String templatePath = "/templates/mapper.xml.ftl";
// 如果模板引擎是 velocity
// String templatePath = "/templates/mapper.xml.vm";

// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return projectPath + "/mybatis-plus-springboot/src/main/resources/mapper/" + pc.getModuleName()
+ "/repository/dao/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});

cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);

// 配置模板
TemplateConfig templateConfig = new TemplateConfig();

// 配置自定义输出模板
//指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
// templateConfig.setEntity("templates/entity2.java");
// templateConfig.setService();
// templateConfig.setController();

templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 选择 freemarker 引擎,默认 Veloctiy
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);

strategy.setSuperEntityClass(BasePO.class);
strategy.setSuperEntityColumns("create_time", "create_user", "update_time",
"update_user", "version", "is_delete", "last_update_time");
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
// 公共父类
//strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}

}

@Data
public class BasePO {

/**
* 创建人
*/
@TableField(value = "create_user", fill = FieldFill.INSERT)
private Long createUser;
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Date createTime;

/**
* 更新人
*/
@TableField(value = "update_user", fill = FieldFill.UPDATE)
private Long updateUser;
@TableField(value = "update_time", fill = FieldFill.UPDATE)
private Date updateTime;

/**
* 版本
*/
@Version
private Integer version;
/**
* 是否删除
*/
@TableField("is_delete")
@TableLogic
private Integer isDelete;


/**
* 删除字段枚举
*/
public enum Delete {
//删除枚举
NORMAL(0, "正常"), DELETED(1, "删除");
@Getter
private final Integer code;
@Getter
private final String name;

Delete(Integer code, String name) {
this.code = code;
this.name = name;
}

public static Delete getDelete(Integer state) {
for (Delete delete : values()) {
if (delete.getCode().equals(state)) {
return delete;
}
}
return null;
}
}
}

运行结果

image-20210529174638703

自定义SQL语句模板(Sql 注入器)

参考:https://gitee.com/baomidou/mybatis-plus-samples/tree/master/mybatis-plus-sample-deluxe

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

1.自定义方法
public class MyDeleteAllMethod extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
String sql;
String sqlMethod = "<script>\nDELETE FROM %s \n</script>";
sql = String.format(sqlMethod, tableInfo.getTableName(), sqlLogicSet(tableInfo),
sqlWhereEntityWrapper(true, tableInfo),
sqlComment());
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return this.addDeleteMappedStatement(mapperClass, "deleteAll", sqlSource);
}
}

2.自定义SqlInjector,注册自定义方法
public class MyLogicSqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
List<AbstractMethod> list = super.getMethodList(mapperClass);
list.add(new MyTruncateMethod());
return list;
}
}

3.把方法定义到BaseMapper
public interface MyBaseMapper<T> extends BaseMapper<T> {
int deleteAll();
}

4、mapper继承自己的basemapper
public interface UserDao extends MyBaseMapper<UserPO> {

UserPO selectOneUserByName(String userName);

List<UserPO> findPageUser(Page<UserPO> page);
}

5、覆盖全局SQL注入器配置
@Configuration
public class MybatisPlusConfig {
@Bean
public ISqlInjector myLogicSqlInjector(){
return new MyLogicSqlInjector();
}
}
6、使用
@Service
public class UserServiceImpl extends ServiceImpl<UserDao, UserPO> implements UserService {
@Resource
private UserDao userDao;

@Override
public void deleteAll() {
userDao.deleteAll();
}
}

内置性能分析插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
@Intercepts({@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
@Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),
@Signature(type = StatementHandler.class, method = "batch", args = {Statement.class})})
public class PerformanceInterceptor implements Interceptor {
private static final String HIKARIPROXY_PREPARED_STATEMENT = "com.zaxxer.hikari.pool.HikariProxyPreparedStatement";

private final static SqlFormatter SQL_FORMATTER = new SqlFormatter();
/**
* 格式sql
*
* @param boundSql
* @param format
* @return
*/
public static String sqlFormat(String boundSql, boolean format) {
if (format) {
return SQL_FORMATTER.format(boundSql);
} else {
return boundSql.replaceAll("[\\s]+", " ");
}
}
/**
* SQL 执行最大时长,超过自动停止运行,有助于发现问题。
*/
@Getter
@Setter
private long maxTime = 0;
/**
* SQL 是否格式化
*/
@Getter
@Setter
private boolean format = false;


@Override
public Object intercept(Invocation invocation) throws Throwable {
Statement statement;
Object firstArg = invocation.getArgs()[0];
if (Proxy.isProxyClass(firstArg.getClass())) {
statement = (Statement) SystemMetaObject.forObject(firstArg).getValue("h.statement");
} else {
statement = (Statement) firstArg;
}
try {
statement = (Statement) SystemMetaObject.forObject(statement).getValue("stmt.statement");
} catch (Exception e) {
// do nothing
}

String originalSql = null;
String stmtClassName = statement.getClass().getName();
if (HIKARIPROXY_PREPARED_STATEMENT.equals(stmtClassName)) {
try {
Class<?> clazz = Class.forName(HIKARIPROXY_PREPARED_STATEMENT);
Method druidGetSqlMethod = clazz.getMethod("getSql");
Object stmtSql = druidGetSqlMethod.invoke(statement);
if (stmtSql != null && stmtSql instanceof String) {
originalSql = (String) stmtSql;
}
} catch (Exception ignored) {
}
}

if (originalSql == null) {
originalSql = statement.toString();
}
originalSql = originalSql.replaceAll("[\\s]+", " ");
int index = originalSql.indexOf(':');
if (index > 0) {
originalSql = originalSql.substring(index + 1, originalSql.length());
}
String sqlFormat = sqlFormat(originalSql, format);
Object target = realTarget(invocation.getTarget());
MetaObject metaObject = SystemMetaObject.forObject(target);
MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
Logger mybatisLogger = LoggerFactory.getLogger(this.getClass());
// 计算执行 SQL 耗时
long start = System.currentTimeMillis();
Object result = null;
try {
result = invocation.proceed();
} catch (InvocationTargetException | IllegalAccessException e) {
long timing = System.currentTimeMillis() - start;
StringBuilder formatSql = new StringBuilder()
.append("execute sql error, use time:").append(timing).append("\n")
.append(sqlFormat);
mybatisLogger.error(formatSql.toString());
throw e;
}
long timing = System.currentTimeMillis() - start;

// 格式化 SQL 打印执行结果
StringBuilder formatSql = new StringBuilder().append("Execute sql use time:").append(timing)
.append("\n")
.append(" Execute SQL:").append(sqlFormat)
.append("\n")
.append(" result: ").append(result);

if (this.getMaxTime() >= 1 && timing > this.getMaxTime()) {
mybatisLogger.error(formatSql.toString());
} else {
mybatisLogger.debug(formatSql.toString());
}

return result;
}

@Override
public Object plugin(Object target) {
if (target instanceof StatementHandler) {
return Plugin.wrap(target, this);
}
return target;
}

@Override
public void setProperties(Properties prop) {
String maxTime = prop.getProperty("maxTime");
String format = prop.getProperty("format");
if (!StringUtils.isEmptyOrWhitespaceOnly(maxTime)) {
this.maxTime = Long.parseLong(maxTime);
}
if (!StringUtils.isEmptyOrWhitespaceOnly(format)) {
this.format = Boolean.valueOf(format);
}
}

public static <T> T realTarget(Object target) {
if (Proxy.isProxyClass(target.getClass())) {
MetaObject metaObject = SystemMetaObject.forObject(target);
return realTarget(metaObject.getValue("h.target"));
}
return (T) target;
}

}

@Bean
public PerformanceInterceptor performanceInterceptor(){
return new PerformanceInterceptor();
}

事务检查插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
@Bean
public MybatisUpdateCheckInterceptor mybatisUpdateCheckInterceptor(DataSource dataSource) {
return new MybatisUpdateCheckInterceptor(dataSource);
}
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class MybatisUpdateCheckInterceptor implements Interceptor {

private DataSource dataSource;

public MybatisUpdateCheckInterceptor(DataSource dataSource) {
this.dataSource = dataSource;
}

@Override
public Object intercept(Invocation invocation) throws Throwable {

// 检查事务是否开启
assertTransactional();

Object[] args = invocation.getArgs();
MappedStatement ms = (MappedStatement) args[0];
SqlCommandType sqlCommandType = ms.getSqlCommandType();

Object param = args[1];

// 插入只判断是否插入成功即可
if (SqlCommandType.INSERT == sqlCommandType) {
checkParam(param);
Object proceed = invocation.proceed();
validateReturnGtZero(proceed);
return proceed;
}
Object proceed = invocation.proceed();
return proceed;
}

/**
* 校验是否已经开启事务
*/
private void assertTransactional() {
Connection connection = DataSourceUtils.getConnection(dataSource);
if (!DataSourceUtils.isConnectionTransactional(connection, dataSource)) {
throw new RuntimeException("mybatis can not update without transactional");
}
}

/**
* 检查参数是否非空
*
* @param param
*/
private void checkParam(Object param) {
if (null == param) {
throw new RuntimeException("mybatis update can not insert null object");
}
}

/**
* 校验更新数量是否大于0
*
* @param proceed
*/
private void validateReturnGtZero(Object proceed) {
if (!(proceed instanceof Number)) {
throw new RuntimeException("mybatis update return is not a number");
}

Number result = (Number) proceed;
if (0L == result.longValue()) {
throw new RuntimeException("数据已被他人修改,请刷新重试");
}
}

}

动态表名插件(since 3.4.0)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
DynamicTableNameInnerInterceptor interceptor = new DynamicTableNameInnerInterceptor();
int b=(int)(Math.random()*3);
String[] table = {"system_user","system_user_copy1","system_user_copy2"};
Map<String, TableNameHandler> tableNameHandlerMap = new HashMap<String,TableNameHandler>(1);
//自定义逻辑,用新的表明替换旧的表名
tableNameHandlerMap.put("system_user",((sql,tablename) -> table[b]));
interceptor.setTableNameHandlerMap(tableNameHandlerMap);
//tableNameHandlerMap.put("system_user",((sql,tablename) -> tablename +table[b]));
mybatisPlusInterceptor.addInnerInterceptor(interceptor);
return mybatisPlusInterceptor;
}

多租户(约等于数据隔离、也可作为权限过滤)

多租户 != 权限过滤,不要乱用,租户之间是完全隔离的!!!
启用多租户后所有执行的method的sql都会进行处理.
自写的sql请按规范书写(sql涉及到多个表的每个表都要给别名,特别是 inner join 的要写标准的 inner join)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* 租户处理器( TenantId 行级 )
*
* @author hubin
* @since 2017-08-31
*/
public interface TenantHandler {

/**
* 获取租户 ID 值表达式,支持多个 ID 条件查询
* <p>
* 支持自定义表达式,比如:tenant_id in (1,2) @since 2019-8-2
* 多参请使用 {@link ValueListExpression}
*
* @param select 参数 true 表示为 select 下的 where 条件,false 表示 insert/update/delete 下的条件
* 只有 select 下才允许多参,否则只支持单参
* @return 租户 ID 值表达式
*/
Expression getTenantId(boolean select);

/**
* 获取租户字段名
*
* @return 租户字段名
*/
String getTenantIdColumn();

/**
* 根据表名判断是否进行过滤
*
* @param tableName 表名
* @return 是否进行过滤, true:表示忽略,false:需要解析多租户字段
*/
boolean doTableFilter(String tableName);
}

假设有如下场景:

查询某些表的数据需要根据这些表的某个字段进行数据隔离

于是

  1. 自定义TenantHandler
  2. 自定义MyTenantSqlParser
  3. 注册多租户组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
public enum DataAccessTable {
//数据权限过滤表名
SYSTEM_USER("system_user", "用户表", "user_id"),
;

private static Map<String, DataAccessTable> TABLE_MAP = new HashMap<>();
static {
for (DataAccessTable value : DataAccessTable.values()) {
TABLE_MAP.put(value.getTableName(), value);
}
}

@Getter
private final String tableName;
@Getter
private final String desc;
@Getter
private final String publisherColumn;

DataAccessTable(String tableName, String desc, String publisherColumn) {
this.tableName = tableName;
this.desc = desc;
this.publisherColumn = publisherColumn;
}

public static Set<String> getDataAccessTables(){
return TABLE_MAP.keySet();
}


public static String getDataPublisherColumn(String tableName){
DataAccessTable dataAccessTable = TABLE_MAP.get(tableName);
return dataAccessTable == null ? "" : dataAccessTable.getPublisherColumn();

}
}
public interface MyTenantHandler extends TenantHandler {


/**
* 自定义方法
* 获取发布人用户ID
*
* @param tableName 表名
* @return 发布人字段名
*/
String getPublishUserIdColumn(String tableName);
}
@Data
public class MyTenantSqlParser extends TenantSqlParser{

private MyTenantHandler greatTenantHandler;
@Override
public TenantSqlParser setTenantHandler(TenantHandler tenantHandler) {
greatTenantHandler = (MyTenantHandler) tenantHandler;
return super.setTenantHandler(tenantHandler);
}


/**
* 目前: 针对自定义的tenantId的条件表达式[tenant_id in (1,2,3)],无法处理多租户的字段加上表别名
* select a.id, b.name
* from a
* join b on b.aid = a.id and [b.]tenant_id in (1,2) --别名[b.]无法加上 TODO
*
* @param expression
* @param table
* @return 加上别名的多租户字段表达式
*/
@Override
protected Expression processTableAlias4CustomizedTenantIdExpression(Expression expression, Table table) {
Expression target;
//判断多租户字段
if (expression instanceof ValueListExpression) {
InExpression inExpression = new InExpression();
inExpression.setLeftExpression(this.getTableAliasColumn(table, greatTenantHandler.getTenantIdColumn()));
inExpression.setRightItemsList(((ValueListExpression) expression).getExpressionList());
target = inExpression;
} else {
EqualsTo equalsTo = new EqualsTo();
equalsTo.setLeftExpression(this.getTableAliasColumn(table, greatTenantHandler.getTenantIdColumn()));
equalsTo.setRightExpression(expression);
target = equalsTo;
}
String publishUserIdColumn = greatTenantHandler.getPublishUserIdColumn(table.getName());
if(StringUtils.isBlank(publishUserIdColumn)){
return target;
}
//自定义多租户逻辑
EqualsTo equalsTo = new EqualsTo();
equalsTo.setLeftExpression(this.getTableAliasColumn(table, publishUserIdColumn));
//自定义多租户字段写死 -1
equalsTo.setRightExpression(new LongValue("8"));
// equalsTo.setRightExpression(new LongValue(SessionContext.getCurrentUserId()));
return new Parenthesis(new OrExpression(target, equalsTo));
}


/**
* 租户字段别名设置
* <p>tenantId 或 tableAlias.tenantId</p>
*
* @param table 表对象
* @return 字段
*/
protected Column getTableAliasColumn(Table table, String columnName) {
StringBuilder column = new StringBuilder();
if (table.getAlias() != null) {
column.append(table.getAlias().getName()).append(StringPool.DOT);
}
column.append(columnName);
return new Column(column.toString());
}
}


@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor page = new PaginationInterceptor();
List<ISqlParser> sqlParserList = new ArrayList<>();
MyTenantSqlParser tenantSqlParser = new MyTenantSqlParser();
tenantSqlParser.setTenantHandler(new MyTenantHandler() {
@Override
public String getPublishUserIdColumn(String tableName) {
return DataAccessTable.getDataPublisherColumn(tableName);
}

@Override
public Expression getTenantId(boolean select) {
//没有设置数据权限,设置为本中心数据权限
ValueListExpression expression = new ValueListExpression();
List<Expression> expressions = new ArrayList<>();
expressions.add(new StringValue("木子李"));


expression.setExpressionList(new ExpressionList(expressions));
return expression;
}

@Override
public String getTenantIdColumn() {
return "username";
}

/**
* 返回true忽略,false需要解析多租户字段
* @param tableName
* @return
*/
@Override
public boolean doTableFilter(String tableName) {
//查询所有进行数据权限过滤的表名
Set<String> tableNameSet = DataAccessTable.getDataAccessTables();
// 强制检查表单内,返回false
if (tableNameSet.contains(tableName)) {
return false;
}
return true;
}
});
sqlParserList.add(tenantSqlParser);
page.setSqlParserList(sqlParserList);
page.setSqlParserFilter(metaObject ->{
// 不处理非select之外的语句
MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
if(!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())){
return true;
}



return false;
});
return page;
}

效果

image-20210531170508023