原有动态表插件功能基于拦截器采取的是提取字符串解析表名替换操作,可能会出现表名提取错误操作,不需要替换的表名方法需要加上注解才能忽略。我想设计基于OGNL表达式实现提供一个虚拟表名在运行时动态处理并替换表名。大致实现思路如下:
1. 定义虚拟表名
在 SQL 语句中使用特定格式的虚拟表名占位符。例如,使用 #tableName#
表示虚拟表名。
2. 解析 SQL 语句
在 MyBatis 拦截器中解析 SQL 语句,并检测虚拟表名占位符。
3. 使用 OGNL 表达式计算真实表名
定义一个接口和实现类,用于根据运行时上下文信息动态计算真实表名。
4. 替换虚拟表名
将解析得到的真实表名替换 SQL 语句中的虚拟表名。
5. 集成到拦截器
将上述逻辑集成到 MyBatis 的拦截器中,在 SQL 语句执行前进行处理。
具体实现步骤
1. 定义接口 DynamicTableNameHandler
public interface DynamicTableNameHandler { String dynamicTableName(Object parameter, String tableName); }
2. 实现接口 OgnlDynamicTableNameHandler
import ognl.Ognl; import ognl.OgnlException; public class OgnlDynamicTableNameHandler implements DynamicTableNameHandler { private String expression; public OgnlDynamicTableNameHandler(String expression) { this.expression = expression; } @Override public String dynamicTableName(Object parameter, String tableName) { try { Object realTableName = Ognl.getValue(expression, parameter); return realTableName != null ? realTableName.toString() : tableName; } catch (OgnlException e) { throw new RuntimeException("Failed to evaluate OGNL expression", e); } } }
3. 修改拦截器 DynamicTableNameInnerInterceptor
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils; import com.baomidou.mybatisplus.core.toolkit.PluginUtils; import com.baomidou.mybatisplus.core.toolkit.TableNameParser; import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlCommandType; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; @Getter @Setter @NoArgsConstructor @SuppressWarnings({"rawtypes"}) public class DynamicTableNameInnerInterceptor implements InnerInterceptor { private DynamicTableNameHandler tableNameHandler; public DynamicTableNameInnerInterceptor(DynamicTableNameHandler tableNameHandler) { this.tableNameHandler = tableNameHandler; } @Override public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { if (InterceptorIgnoreHelper.willIgnoreDynamicTableName(ms.getId())) return; PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql); mpBs.sql(this.changeTable(mpBs.sql(), parameter)); } @Override public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) { PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh); MappedStatement ms = mpSh.mappedStatement(); SqlCommandType sct = ms.getSqlCommandType(); if (sct == SqlCommandType.INSERT || sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) { if (InterceptorIgnoreHelper.willIgnoreDynamicTableName(ms.getId())) { return; } PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql(); mpBs.sql(this.changeTable(mpBs.sql(), mpSh.boundSql().getParameterObject())); } } public String changeTable(String sql, Object parameter) { ExceptionUtils.throwMpe(null == tableNameHandler, "Please implement DynamicTableNameHandler processing logic"); TableNameParser parser = new TableNameParser(sql); List<TableNameParser.SqlToken> names = new ArrayList<>(); parser.accept(names::add); StringBuilder builder = new StringBuilder(); int last = 0; for (TableNameParser.SqlToken name : names) { int start = name.getStart(); if (start != last) { builder.append(sql, last, start); builder.append(tableNameHandler.dynamicTableName(parameter, name.getValue())); } last = name.getEnd(); } if (last != sql.length()) { builder.append(sql.substring(last)); } return builder.toString(); } }
4. 配置拦截器
DynamicTableNameInnerInterceptor interceptor = new DynamicTableNameInnerInterceptor( new OgnlDynamicTableNameHandler("user.role + '_table'") ); // 将拦截器添加到 MyBatis 配置中 mybatisConfiguration.addInterceptor(interceptor);
更多精彩请关注我的Github:Utopia007 (Qiao Guanhao) · GitHub