Commit e9385219c21eee812f5fa3541a141e8cce316447
1 parent
eda2b11d
数据权限的逻辑处理,暂未测试
Showing
2 changed files
with
132 additions
and
75 deletions
yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/interceptor/DataPermissionInterceptor.java
| @@ -4,18 +4,20 @@ import cn.hutool.core.collection.CollUtil; | @@ -4,18 +4,20 @@ import cn.hutool.core.collection.CollUtil; | ||
| 4 | import cn.iocoder.yudao.framework.common.util.collection.SetUtils; | 4 | import cn.iocoder.yudao.framework.common.util.collection.SetUtils; |
| 5 | import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; | 5 | import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; |
| 6 | import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRuleFactory; | 6 | import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRuleFactory; |
| 7 | +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; | ||
| 7 | import com.alibaba.ttl.TransmittableThreadLocal; | 8 | import com.alibaba.ttl.TransmittableThreadLocal; |
| 8 | import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; | 9 | import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; |
| 9 | import com.baomidou.mybatisplus.core.toolkit.PluginUtils; | 10 | import com.baomidou.mybatisplus.core.toolkit.PluginUtils; |
| 10 | -import com.baomidou.mybatisplus.core.toolkit.StringPool; | ||
| 11 | import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport; | 11 | import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport; |
| 12 | import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; | 12 | import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; |
| 13 | import lombok.RequiredArgsConstructor; | 13 | import lombok.RequiredArgsConstructor; |
| 14 | import net.sf.jsqlparser.expression.*; | 14 | import net.sf.jsqlparser.expression.*; |
| 15 | import net.sf.jsqlparser.expression.operators.conditional.AndExpression; | 15 | import net.sf.jsqlparser.expression.operators.conditional.AndExpression; |
| 16 | import net.sf.jsqlparser.expression.operators.conditional.OrExpression; | 16 | import net.sf.jsqlparser.expression.operators.conditional.OrExpression; |
| 17 | -import net.sf.jsqlparser.expression.operators.relational.*; | ||
| 18 | -import net.sf.jsqlparser.schema.Column; | 17 | +import net.sf.jsqlparser.expression.operators.relational.ExistsExpression; |
| 18 | +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; | ||
| 19 | +import net.sf.jsqlparser.expression.operators.relational.InExpression; | ||
| 20 | +import net.sf.jsqlparser.expression.operators.relational.ItemsList; | ||
| 19 | import net.sf.jsqlparser.schema.Table; | 21 | import net.sf.jsqlparser.schema.Table; |
| 20 | import net.sf.jsqlparser.statement.delete.Delete; | 22 | import net.sf.jsqlparser.statement.delete.Delete; |
| 21 | import net.sf.jsqlparser.statement.select.*; | 23 | import net.sf.jsqlparser.statement.select.*; |
| @@ -32,6 +34,15 @@ import java.sql.Connection; | @@ -32,6 +34,15 @@ import java.sql.Connection; | ||
| 32 | import java.util.*; | 34 | import java.util.*; |
| 33 | import java.util.concurrent.ConcurrentHashMap; | 35 | import java.util.concurrent.ConcurrentHashMap; |
| 34 | 36 | ||
| 37 | +/** | ||
| 38 | + * 数据权限拦截器,通过 {@link DataPermissionRule} 数据权限规则,重写 SQL 的方式来实现 | ||
| 39 | + * 主要的 SQL 重写方法,可见 {@link #builderExpression(Expression, Table)} 方法 | ||
| 40 | + * | ||
| 41 | + * 整体的代码实现上,参考 {@link com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor} 实现。 | ||
| 42 | + * 所以每次 MyBatis Plus 升级时,需要 Review 下其具体的实现是否有变更! | ||
| 43 | + * | ||
| 44 | + * @author 芋道源码 | ||
| 45 | + */ | ||
| 35 | @RequiredArgsConstructor | 46 | @RequiredArgsConstructor |
| 36 | public class DataPermissionInterceptor extends JsqlParserSupport implements InnerInterceptor { | 47 | public class DataPermissionInterceptor extends JsqlParserSupport implements InnerInterceptor { |
| 37 | 48 | ||
| @@ -40,7 +51,8 @@ public class DataPermissionInterceptor extends JsqlParserSupport implements Inne | @@ -40,7 +51,8 @@ public class DataPermissionInterceptor extends JsqlParserSupport implements Inne | ||
| 40 | private final MappedStatementCache mappedStatementCache = new MappedStatementCache(); | 51 | private final MappedStatementCache mappedStatementCache = new MappedStatementCache(); |
| 41 | 52 | ||
| 42 | @Override // SELECT 场景 | 53 | @Override // SELECT 场景 |
| 43 | - public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { | 54 | + public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, |
| 55 | + RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { | ||
| 44 | // 获得 Mapper 对应的数据权限的规则 | 56 | // 获得 Mapper 对应的数据权限的规则 |
| 45 | List<DataPermissionRule> rules = ruleFactory.getDataPermissionRule(ms.getId()); | 57 | List<DataPermissionRule> rules = ruleFactory.getDataPermissionRule(ms.getId()); |
| 46 | if (mappedStatementCache.noRewritable(ms, rules)) { // 如果无需重写,则跳过 | 58 | if (mappedStatementCache.noRewritable(ms, rules)) { // 如果无需重写,则跳过 |
| @@ -59,12 +71,12 @@ public class DataPermissionInterceptor extends JsqlParserSupport implements Inne | @@ -59,12 +71,12 @@ public class DataPermissionInterceptor extends JsqlParserSupport implements Inne | ||
| 59 | } | 71 | } |
| 60 | } | 72 | } |
| 61 | 73 | ||
| 62 | - @Override // 只处理 UPDATE / DELETE 场景 | 74 | + @Override // 只处理 UPDATE / DELETE 场景,不处理 INSERT 场景 |
| 63 | public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) { | 75 | public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) { |
| 64 | PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh); | 76 | PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh); |
| 65 | MappedStatement ms = mpSh.mappedStatement(); | 77 | MappedStatement ms = mpSh.mappedStatement(); |
| 66 | SqlCommandType sct = ms.getSqlCommandType(); | 78 | SqlCommandType sct = ms.getSqlCommandType(); |
| 67 | - if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) { // 无需处理 Insert 语句 | 79 | + if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) { |
| 68 | // 获得 Mapper 对应的数据权限的规则 | 80 | // 获得 Mapper 对应的数据权限的规则 |
| 69 | List<DataPermissionRule> rules = ruleFactory.getDataPermissionRule(ms.getId()); | 81 | List<DataPermissionRule> rules = ruleFactory.getDataPermissionRule(ms.getId()); |
| 70 | if (mappedStatementCache.noRewritable(ms, rules)) { // 如果无需重写,则跳过 | 82 | if (mappedStatementCache.noRewritable(ms, rules)) { // 如果无需重写,则跳过 |
| @@ -117,7 +129,8 @@ public class DataPermissionInterceptor extends JsqlParserSupport implements Inne | @@ -117,7 +129,8 @@ public class DataPermissionInterceptor extends JsqlParserSupport implements Inne | ||
| 117 | @Override | 129 | @Override |
| 118 | protected void processUpdate(Update update, int index, String sql, Object obj) { | 130 | protected void processUpdate(Update update, int index, String sql, Object obj) { |
| 119 | final Table table = update.getTable(); | 131 | final Table table = update.getTable(); |
| 120 | - update.setWhere(this.andExpression(table, update.getWhere())); | 132 | +// update.setWhere(this.andExpression(table, update.getWhere())); |
| 133 | + update.setWhere(this.builderExpression(update.getWhere(), table)); | ||
| 121 | } | 134 | } |
| 122 | 135 | ||
| 123 | /** | 136 | /** |
| @@ -125,26 +138,27 @@ public class DataPermissionInterceptor extends JsqlParserSupport implements Inne | @@ -125,26 +138,27 @@ public class DataPermissionInterceptor extends JsqlParserSupport implements Inne | ||
| 125 | */ | 138 | */ |
| 126 | @Override | 139 | @Override |
| 127 | protected void processDelete(Delete delete, int index, String sql, Object obj) { | 140 | protected void processDelete(Delete delete, int index, String sql, Object obj) { |
| 128 | - delete.setWhere(this.andExpression(delete.getTable(), delete.getWhere())); | 141 | +// delete.setWhere(this.andExpression(delete.getTable(), delete.getWhere())); |
| 142 | + delete.setWhere(this.builderExpression(delete.getWhere(), delete.getTable())); | ||
| 129 | } | 143 | } |
| 130 | 144 | ||
| 131 | - /** | ||
| 132 | - * delete update 语句 where 处理 | ||
| 133 | - */ | ||
| 134 | - protected BinaryExpression andExpression(Table table, Expression where) { | ||
| 135 | - //获得where条件表达式 | ||
| 136 | - EqualsTo equalsTo = new EqualsTo(); | ||
| 137 | - equalsTo.setLeftExpression(this.getAliasColumn(table)); | ||
| 138 | - equalsTo.setRightExpression(getTenantId()); | ||
| 139 | - if (null != where) { | ||
| 140 | - if (where instanceof OrExpression) { | ||
| 141 | - return new AndExpression(equalsTo, new Parenthesis(where)); | ||
| 142 | - } else { | ||
| 143 | - return new AndExpression(equalsTo, where); | ||
| 144 | - } | ||
| 145 | - } | ||
| 146 | - return equalsTo; | ||
| 147 | - } | 145 | +// /** |
| 146 | +// * delete update 语句 where 处理 | ||
| 147 | +// */ | ||
| 148 | +// protected BinaryExpression andExpression(Table table, Expression where) { | ||
| 149 | +// //获得where条件表达式 | ||
| 150 | +// EqualsTo equalsTo = new EqualsTo(); | ||
| 151 | +// equalsTo.setLeftExpression(this.getAliasColumn(table)); | ||
| 152 | +// equalsTo.setRightExpression(getTenantId()); | ||
| 153 | +// if (null != where) { | ||
| 154 | +// if (where instanceof OrExpression) { | ||
| 155 | +// return new AndExpression(equalsTo, new Parenthesis(where)); | ||
| 156 | +// } else { | ||
| 157 | +// return new AndExpression(equalsTo, where); | ||
| 158 | +// } | ||
| 159 | +// } | ||
| 160 | +// return equalsTo; | ||
| 161 | +// } | ||
| 148 | 162 | ||
| 149 | /** | 163 | /** |
| 150 | * 处理 PlainSelect | 164 | * 处理 PlainSelect |
| @@ -155,10 +169,11 @@ public class DataPermissionInterceptor extends JsqlParserSupport implements Inne | @@ -155,10 +169,11 @@ public class DataPermissionInterceptor extends JsqlParserSupport implements Inne | ||
| 155 | processWhereSubSelect(where); | 169 | processWhereSubSelect(where); |
| 156 | if (fromItem instanceof Table) { | 170 | if (fromItem instanceof Table) { |
| 157 | Table fromTable = (Table) fromItem; | 171 | Table fromTable = (Table) fromItem; |
| 158 | - if (!ignoreTable(fromTable.getName())) { | ||
| 159 | - //#1186 github | ||
| 160 | - plainSelect.setWhere(builderExpression(where, fromTable)); | ||
| 161 | - } | 172 | +// if (!ignoreTable(fromTable.getName())) { |
| 173 | +// //#1186 github | ||
| 174 | +// plainSelect.setWhere(builderExpression(where, fromTable)); | ||
| 175 | +// } | ||
| 176 | + plainSelect.setWhere(builderExpression(where, fromTable)); | ||
| 162 | } else { | 177 | } else { |
| 163 | processFromItem(fromItem); | 178 | processFromItem(fromItem); |
| 164 | } | 179 | } |
| @@ -311,20 +326,21 @@ public class DataPermissionInterceptor extends JsqlParserSupport implements Inne | @@ -311,20 +326,21 @@ public class DataPermissionInterceptor extends JsqlParserSupport implements Inne | ||
| 311 | processJoin(join); | 326 | processJoin(join); |
| 312 | continue; | 327 | continue; |
| 313 | } | 328 | } |
| 314 | - // 当前表是否忽略 | ||
| 315 | - boolean needIgnore = ignoreTable(fromTable.getName()); | ||
| 316 | - // 表名压栈,忽略的表压入 null,以便后续不处理 | ||
| 317 | - tables.push(needIgnore ? null : fromTable); | 329 | +// // 当前表是否忽略 |
| 330 | +// boolean needIgnore = ignoreTable(fromTable.getName()); | ||
| 331 | +// // 表名压栈,忽略的表压入 null,以便后续不处理 | ||
| 332 | +// tables.push(needIgnore ? null : fromTable); | ||
| 318 | // 尾缀多个 on 表达式的时候统一处理 | 333 | // 尾缀多个 on 表达式的时候统一处理 |
| 319 | if (originOnExpressions.size() > 1) { | 334 | if (originOnExpressions.size() > 1) { |
| 320 | Collection<Expression> onExpressions = new LinkedList<>(); | 335 | Collection<Expression> onExpressions = new LinkedList<>(); |
| 321 | for (Expression originOnExpression : originOnExpressions) { | 336 | for (Expression originOnExpression : originOnExpressions) { |
| 322 | Table currentTable = tables.poll(); | 337 | Table currentTable = tables.poll(); |
| 323 | - if (currentTable == null) { | ||
| 324 | - onExpressions.add(originOnExpression); | ||
| 325 | - } else { | ||
| 326 | - onExpressions.add(builderExpression(originOnExpression, currentTable)); | ||
| 327 | - } | 338 | +// if (currentTable == null) { |
| 339 | +// onExpressions.add(originOnExpression); | ||
| 340 | +// } else { | ||
| 341 | +// onExpressions.add(builderExpression(originOnExpression, currentTable)); | ||
| 342 | +// } | ||
| 343 | + onExpressions.add(builderExpression(originOnExpression, currentTable)); | ||
| 328 | } | 344 | } |
| 329 | join.setOnExpressions(onExpressions); | 345 | join.setOnExpressions(onExpressions); |
| 330 | } | 346 | } |
| @@ -341,15 +357,18 @@ public class DataPermissionInterceptor extends JsqlParserSupport implements Inne | @@ -341,15 +357,18 @@ public class DataPermissionInterceptor extends JsqlParserSupport implements Inne | ||
| 341 | protected void processJoin(Join join) { | 357 | protected void processJoin(Join join) { |
| 342 | if (join.getRightItem() instanceof Table) { | 358 | if (join.getRightItem() instanceof Table) { |
| 343 | Table fromTable = (Table) join.getRightItem(); | 359 | Table fromTable = (Table) join.getRightItem(); |
| 344 | - if (ignoreTable(fromTable.getName())) { | ||
| 345 | - // 过滤退出执行 | ||
| 346 | - return; | ||
| 347 | - } | 360 | +// if (ignoreTable(fromTable.getName())) { |
| 361 | +// // 过滤退出执行 | ||
| 362 | +// return; | ||
| 363 | +// } | ||
| 348 | // 走到这里说明 on 表达式肯定只有一个 | 364 | // 走到这里说明 on 表达式肯定只有一个 |
| 349 | - Collection<Expression> originOnExpressions = join.getOnExpressions(); | ||
| 350 | - List<Expression> onExpressions = new LinkedList<>(); | ||
| 351 | - onExpressions.add(builderExpression(originOnExpressions.iterator().next(), fromTable)); | ||
| 352 | - join.setOnExpressions(onExpressions); | 365 | +// Collection<Expression> originOnExpressions = join.getOnExpressions(); |
| 366 | +// List<Expression> onExpressions = new LinkedList<>(); | ||
| 367 | +// onExpressions.add(builderExpression(originOnExpressions.iterator().next(), fromTable)); | ||
| 368 | +// join.setOnExpressions(onExpressions); | ||
| 369 | + Expression originOnExpression = CollUtil.getFirst(join.getOnExpressions()); | ||
| 370 | + originOnExpression = builderExpression(originOnExpression, fromTable); | ||
| 371 | + join.setOnExpressions(CollUtil.newArrayList(originOnExpression)); | ||
| 353 | } | 372 | } |
| 354 | } | 373 | } |
| 355 | 374 | ||
| @@ -357,50 +376,69 @@ public class DataPermissionInterceptor extends JsqlParserSupport implements Inne | @@ -357,50 +376,69 @@ public class DataPermissionInterceptor extends JsqlParserSupport implements Inne | ||
| 357 | * 处理条件 | 376 | * 处理条件 |
| 358 | */ | 377 | */ |
| 359 | protected Expression builderExpression(Expression currentExpression, Table table) { | 378 | protected Expression builderExpression(Expression currentExpression, Table table) { |
| 360 | - EqualsTo equalsTo = new EqualsTo(); | ||
| 361 | - equalsTo.setLeftExpression(this.getAliasColumn(table)); | ||
| 362 | - equalsTo.setRightExpression(getTenantId()); | 379 | + // 获得 Table 对应的数据权限条件 |
| 380 | + Expression equalsTo = buildDataPermissionExpression(table); | ||
| 381 | + if (equalsTo == null) { // 如果没条件,则返回 currentExpression 默认 | ||
| 382 | + return currentExpression; | ||
| 383 | + } | ||
| 384 | + | ||
| 385 | + // 表达式为空,则直接返回 equalsTo | ||
| 363 | if (currentExpression == null) { | 386 | if (currentExpression == null) { |
| 364 | return equalsTo; | 387 | return equalsTo; |
| 365 | } | 388 | } |
| 389 | + // 如果表达式为 Or,则需要 (currentExpression) AND equalsTo | ||
| 366 | if (currentExpression instanceof OrExpression) { | 390 | if (currentExpression instanceof OrExpression) { |
| 367 | return new AndExpression(new Parenthesis(currentExpression), equalsTo); | 391 | return new AndExpression(new Parenthesis(currentExpression), equalsTo); |
| 368 | - } else { | ||
| 369 | - return new AndExpression(currentExpression, equalsTo); | ||
| 370 | } | 392 | } |
| 393 | + // 如果表达式为 And,则直接返回 currentExpression AND equalsTo | ||
| 394 | + return new AndExpression(currentExpression, equalsTo); | ||
| 371 | } | 395 | } |
| 372 | 396 | ||
| 397 | +// /** | ||
| 398 | +// * 租户字段别名设置 | ||
| 399 | +// * <p>tenantId 或 tableAlias.tenantId</p> | ||
| 400 | +// * | ||
| 401 | +// * @param table 表对象 | ||
| 402 | +// * @return 字段 | ||
| 403 | +// */ | ||
| 404 | +// protected Column getAliasColumn(Table table) { | ||
| 405 | +// StringBuilder column = new StringBuilder(); | ||
| 406 | +// if (table.getAlias() != null) { | ||
| 407 | +// column.append(table.getAlias().getName()).append(StringPool.DOT); | ||
| 408 | +// } | ||
| 409 | +// column.append(getTenantIdColumn()); | ||
| 410 | +// return new Column(column.toString()); | ||
| 411 | +// } | ||
| 412 | + | ||
| 373 | /** | 413 | /** |
| 374 | - * 租户字段别名设置 | ||
| 375 | - * <p>tenantId 或 tableAlias.tenantId</p> | 414 | + * 构建指定表的数据权限的 Expression 过滤条件 |
| 376 | * | 415 | * |
| 377 | - * @param table 表对象 | ||
| 378 | - * @return 字段 | 416 | + * @param table 表 |
| 417 | + * @return Expression 过滤条件 | ||
| 379 | */ | 418 | */ |
| 380 | - protected Column getAliasColumn(Table table) { | ||
| 381 | - StringBuilder column = new StringBuilder(); | ||
| 382 | - if (table.getAlias() != null) { | ||
| 383 | - column.append(table.getAlias().getName()).append(StringPool.DOT); | 419 | + private Expression buildDataPermissionExpression(Table table) { |
| 420 | + // 生成条件 | ||
| 421 | + Expression allExpression = null; | ||
| 422 | + for (DataPermissionRule rule : ContextHolder.getRules()) { | ||
| 423 | + // 判断表名是否匹配 | ||
| 424 | + if (!rule.getTableNames().contains(table.getName())) { | ||
| 425 | + continue; | ||
| 426 | + } | ||
| 427 | + // 单条规则的条件 | ||
| 428 | + String tableName = MyBatisUtils.getTableName(table); | ||
| 429 | + Expression oneExpress = rule.getExpression(tableName, table.getAlias()); | ||
| 430 | + // 拼接到 allExpression 中 | ||
| 431 | + allExpression = allExpression == null ? oneExpress | ||
| 432 | + : new AndExpression(allExpression, oneExpress); | ||
| 384 | } | 433 | } |
| 385 | - column.append(getTenantIdColumn()); | ||
| 386 | - return new Column(column.toString()); | ||
| 387 | - } | ||
| 388 | - | ||
| 389 | - // TODO 芋艿:未实现 | ||
| 390 | 434 | ||
| 391 | - private boolean ignoreTable(String tableName) { | ||
| 392 | - return false; | ||
| 393 | - } | ||
| 394 | - | ||
| 395 | - private String getTenantIdColumn() { | ||
| 396 | - return "dept_id"; | ||
| 397 | - } | ||
| 398 | - | ||
| 399 | - private Expression getTenantId() { | ||
| 400 | - return new LongValue(1L); | 435 | + // 如果条件非空,说明已经重写了 |
| 436 | + if (allExpression != null) { | ||
| 437 | + ContextHolder.setRewrite(true); | ||
| 438 | + } | ||
| 439 | + return allExpression; | ||
| 401 | } | 440 | } |
| 402 | 441 | ||
| 403 | - | ||
| 404 | /** | 442 | /** |
| 405 | * 判断 SQL 是否重写。如果没有重写,则添加到 {@link MappedStatementCache} 中 | 443 | * 判断 SQL 是否重写。如果没有重写,则添加到 {@link MappedStatementCache} 中 |
| 406 | * | 444 | * |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java
| @@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.metadata.OrderItem; | @@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.metadata.OrderItem; | ||
| 7 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; | 7 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; |
| 8 | import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; | 8 | import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; |
| 9 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | 9 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| 10 | +import net.sf.jsqlparser.schema.Table; | ||
| 10 | 11 | ||
| 11 | import java.util.ArrayList; | 12 | import java.util.ArrayList; |
| 12 | import java.util.Collection; | 13 | import java.util.Collection; |
| @@ -18,6 +19,8 @@ import java.util.stream.Collectors; | @@ -18,6 +19,8 @@ import java.util.stream.Collectors; | ||
| 18 | */ | 19 | */ |
| 19 | public class MyBatisUtils { | 20 | public class MyBatisUtils { |
| 20 | 21 | ||
| 22 | + private static final String MYSQL_ESCAPE_CHARACTER = "`"; | ||
| 23 | + | ||
| 21 | public static <T> Page<T> buildPage(PageParam pageParam) { | 24 | public static <T> Page<T> buildPage(PageParam pageParam) { |
| 22 | return buildPage(pageParam, null); | 25 | return buildPage(pageParam, null); |
| 23 | } | 26 | } |
| @@ -48,4 +51,20 @@ public class MyBatisUtils { | @@ -48,4 +51,20 @@ public class MyBatisUtils { | ||
| 48 | interceptor.setInterceptors(inners); | 51 | interceptor.setInterceptors(inners); |
| 49 | } | 52 | } |
| 50 | 53 | ||
| 54 | + /** | ||
| 55 | + * 获得 Table 对应的表名 | ||
| 56 | + * | ||
| 57 | + * 兼容 MySQL 转义表名 `t_xxx` | ||
| 58 | + * | ||
| 59 | + * @param table 表 | ||
| 60 | + * @return 去除转移字符后的表名 | ||
| 61 | + */ | ||
| 62 | + public static String getTableName(Table table) { | ||
| 63 | + String tableName = table.getName(); | ||
| 64 | + if (tableName.startsWith(MYSQL_ESCAPE_CHARACTER) && tableName.endsWith(MYSQL_ESCAPE_CHARACTER)) { | ||
| 65 | + tableName = tableName.substring(1, tableName.length() - 1); | ||
| 66 | + } | ||
| 67 | + return tableName; | ||
| 68 | + } | ||
| 69 | + | ||
| 51 | } | 70 | } |