mybatis自定义@{}符号 |
您所在的位置:网站首页 › mysql字段名可以用符号嘛 › mybatis自定义@{}符号 |
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、研究一下DynamicTableNameParser的原理1.mybatis的plugin功能 二、实现自己的插件和sql解析器总结 前言 工作中,mybatis的${}如果能切实避免sql注入,还是很好用的,比如动态字段、动态表名,但代码安全扫描可不管能不能避免,见到${}直接判定高风险,甚是恼人啊。我这几天就遇到了,动态表名功能可以用mybatis-plus里的DynamicTableNameParser类实现,但我用的是mybatis,框架不宜轻易更换,没办法只能研究DynamicTableNameParser,模仿着自己写一个动态表名的功能,然后赌气式的自定义了一个@{}替换符,我就不信你安全扫描还能扫出@{}提示:以下是本篇文章正文内容,下面案例可供参考 一、研究一下DynamicTableNameParser的原理 1.mybatis的plugin功能mybatis的plugin是针对于mybatis四大组件(Statementhandler、resultsethandler、parameterHandler、executor)做增强操作的,相当于spring中的AOP,平时用的最多的分页插件PageHelper就是通过plugin实现的,如以下mybatis-plus自带的分页插件代码 @Setter @Deprecated @Accessors(chain = true) @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) public class PaginationInterceptor extends AbstractSqlParserHandler implements Interceptor {实现Interceptor 接口,加上@Intercepts注解即可实现plugin功能,@Signature配置拦截规则,可配置多个,type只能配四大上述四大对象中的一个,配其他无效,method配对应的对象里的方法,args配方法的所有参数(不要多配或者遗漏,否则报错,找不到拦截的方法)。当程序执行到StatementHandler的prepare方法时,就会被拦截,执行PaginationInterceptor的intercept方法 @Override public Object intercept(Invocation invocation) throws Throwable { StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget()); MetaObject metaObject = SystemMetaObject.forObject(statementHandler); // SQL 解析 this.sqlParser(metaObject);intercept方法的其他部分未粘贴进来,感兴趣的可以看下源码,继续跟sqlParser方法,调用AbstractSqlParserHandler里的sqlParser方法 public abstract class AbstractSqlParserHandler { //在应用程序里,传入DynamicTableNameParser private List sqlParserList; private ISqlParserFilter sqlParserFilter; /** * 拦截 SQL 解析执行 */ protected void sqlParser(MetaObject metaObject) { if (null != metaObject) { Object originalObject = metaObject.getOriginalObject(); StatementHandler statementHandler = PluginUtils.realTarget(originalObject); metaObject = SystemMetaObject.forObject(statementHandler); if (null != this.sqlParserFilter && this.sqlParserFilter.doFilter(metaObject)) { return; } // @SqlParser(filter = true) 跳过该方法解析 if (SqlParserHelper.getSqlParserInfo(metaObject)) { return; } // SQL 解析 if (CollectionUtils.isNotEmpty(this.sqlParserList)) { // 好像不用判断也行,为了保险起见,还是加上吧. statementHandler = metaObject.hasGetter("delegate") ? (StatementHandler) metaObject.getValue("delegate") : statementHandler; if (!(statementHandler instanceof CallableStatementHandler)) { // 标记是否修改过 SQL boolean sqlChangedFlag = false; String originalSql = (String) metaObject.getValue(PluginUtils.DELEGATE_BOUNDSQL_SQL); for (ISqlParser sqlParser : this.sqlParserList) { //使用DynamicTableNameParser if (sqlParser.doFilter(metaObject, originalSql)) { SqlInfo sqlInfo = sqlParser.parser(metaObject, originalSql); if (null != sqlInfo) { originalSql = sqlInfo.getSql(); sqlChangedFlag = true; } } } if (sqlChangedFlag) { metaObject.setValue(PluginUtils.DELEGATE_BOUNDSQL_SQL, originalSql); } } } } } }重点看这里 for (ISqlParser sqlParser : this.sqlParserList) {,sqlParserList里装的是一系列的实现了ISqlParser接口的解析器,SqlInfo sqlInfo = sqlParser.parser(metaObject, originalSql);这一行实现了sql里表名的替换 public class DynamicTableNameParser implements ISqlParser { //String为需要替换的表名,ITableNameHandler为动态表名处理器,即替换规则 private Map tableNameHandlerMap; @Override public SqlInfo parser(MetaObject metaObject, String sql) { Assert.isFalse(CollectionUtils.isEmpty(tableNameHandlerMap), "tableNameHandlerMap is empty."); if (allowProcess(metaObject)) { //将sql语句按空格切开成一个一个单词,然后通过from join等关键字确定表名 Collection tables = new TableNameParser(sql).tables(); if (CollectionUtils.isNotEmpty(tables)) { boolean sqlParsed = false; String parsedSql = sql; for (final String table : tables) { ITableNameHandler tableNameHandler = tableNameHandlerMap.get(table); if (null != tableNameHandler) { //找到了该表名的替换器,process方法里替换 parsedSql = tableNameHandler.process(metaObject, parsedSql, table); sqlParsed = true; } } if (sqlParsed) { return SqlInfo.newInstance().setSql(parsedSql); } } } return null; } public boolean allowProcess(MetaObject metaObject) { return true; } }感兴趣的朋友可以网上搜一下mybaits-plus实现动态表名的方法 二、实现自己的插件和sql解析器按照mybatis-plus的步骤指引,一步步实现即可,先定义plugin,然后定义sql解析器,把mybatis-plus能用的类copy过来,不报错就差不多了。接下来引入springboot,将plugin连带着sql解析器注入进spring容器,建mapper即可验证,上代码,gitee地址:https://gitee.com/wangchaoam/mybatisCustomLabel.git |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |