mybatis/mybatis-plus模糊查询语句特殊字符转义拦截器的实现方法是什么
发表于:2025-01-20 作者:千家信息网编辑
千家信息网最后更新 2025年01月20日,本篇内容主要讲解"mybatis/mybatis-plus模糊查询语句特殊字符转义拦截器的实现方法是什么",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"my
千家信息网最后更新 2025年01月20日mybatis/mybatis-plus模糊查询语句特殊字符转义拦截器的实现方法是什么1.使用mybatis提供的拦截器拦截所有的查询请求。
2.定义SQL语句转义模板,分别对Map和Object对象进行处理
本篇内容主要讲解"mybatis/mybatis-plus模糊查询语句特殊字符转义拦截器的实现方法是什么",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"mybatis/mybatis-plus模糊查询语句特殊字符转义拦截器的实现方法是什么"吧!
1.使用mybatis提供的拦截器拦截所有的查询请求。
具体实现在代码中均有注释
import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang3.StringUtils;import org.apache.ibatis.executor.Executor;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.plugin.*;import org.apache.ibatis.session.ResultHandler;import org.apache.ibatis.session.RowBounds;import java.util.*;/** * mybatis/mybatis-plus模糊查询语句特殊字符转义拦截器 * * @author lieber */@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})@Slf4jpublic class MybatisLikeSqlInterceptor implements Interceptor { /** * SQL语句like */ private final static String SQL_LIKE = " like "; /** * SQL语句占位符 */ private final static String SQL_PLACEHOLDER = "?"; /** * SQL语句占位符分隔 */ private final static String SQL_PLACEHOLDER_REGEX = "\\?"; /** * 所有的转义器 */ private static MapconverterMap = new HashMap<>(4); static { converterMap.put(Map.class, new MapLikeSqlConverter()); converterMap.put(Object.class, new ObjectLikeSqlConverter()); } @Override public Object intercept(Invocation invocation) throws Throwable { Object[] args = invocation.getArgs(); MappedStatement statement = (MappedStatement) args[0]; Object parameterObject = args[1]; BoundSql boundSql = statement.getBoundSql(parameterObject); String sql = boundSql.getSql(); this.transferLikeSql(sql, parameterObject, boundSql); return invocation.proceed(); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties arg0) { } /** * 修改包含like的SQL语句 * * @param sql SQL语句 * @param parameterObject 参数对象 * @param boundSql 绑定SQL对象 */ private void transferLikeSql(String sql, Object parameterObject, BoundSql boundSql) { if (!isEscape(sql)) { return; } sql = sql.replaceAll(" {2}", " "); // 获取关键字的个数(去重) Set fields = this.getKeyFields(sql, boundSql); if (fields == null) { return; } // 此处可以增强,不止是支持Map对象,Map对象仅用于传入的条件为Map或者使用@Param传入的对象被Mybatis转为的Map AbstractLikeSqlConverter converter; // 对关键字进行特殊字符"清洗",如果有特殊字符的,在特殊字符前添加转义字符(\) if (parameterObject instanceof Map) { converter = converterMap.get(Map.class); } else { converter = converterMap.get(Object.class); } converter.convert(sql, fields, parameterObject); } /** * 是否需要转义 * * @param sql SQL语句 * @return true/false */ private boolean isEscape(String sql) { return this.hasLike(sql) && this.hasPlaceholder(sql); } /** * 判断SQL语句中是否含有like关键字 * * @param str SQL语句 * @return true/false */ private boolean hasLike(String str) { if (StringUtils.isBlank(str)) { return false; } return str.toLowerCase().contains(SQL_LIKE); } /** * 判断SQL语句中是否包含SQL占位符 * * @param str SQL语句 * @return true/false */ private boolean hasPlaceholder(String str) { if (StringUtils.isBlank(str)) { return false; } return str.toLowerCase().contains(SQL_PLACEHOLDER); } /** * 获取需要替换的所有字段集合 * * @param sql 完整SQL语句 * @param boundSql 绑定的SQL对象 * @return 字段集合列表 */ private Set getKeyFields(String sql, BoundSql boundSql) { String[] params = sql.split(SQL_PLACEHOLDER_REGEX); Set fields = new HashSet<>(); for (int i = 0; i < params.length; i++) { if (this.hasLike(params[i])) { String field = boundSql.getParameterMappings().get(i).getProperty(); fields.add(field); } } return fields; }}
2.定义SQL语句转义模板,分别对Map和Object对象进行处理
2.1 定义AbstractLikeSqlConverter
import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang3.StringUtils;import java.beans.IntrospectionException;import java.beans.PropertyDescriptor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.Set;/** * 包含like的SQL语句转义模板 * * @author lieber */@Slf4jpublic abstract class AbstractLikeSqlConverter{ /** * SQL语句like使用关键字% */ private final static String LIKE_SQL_KEY = "%"; /** * SQL语句需要转义的关键字 */ private final static String[] ESCAPE_CHAR = new String[]{LIKE_SQL_KEY, "_", "\\"}; /** * mybatis-plus中like的SQL语句样式 */ private final static String MYBATIS_PLUS_LIKE_SQL = " like ?"; /** * mybatis-plus中参数前缀 */ private final static String MYBATIS_PLUS_WRAPPER_PREFIX = "ew.paramNameValuePairs."; /** * mybatis-plus中参数键 */ final static String MYBATIS_PLUS_WRAPPER_KEY = "ew"; /** * mybatis-plus中参数分隔符 */ final static String MYBATIS_PLUS_WRAPPER_SEPARATOR = "."; /** * mybatis-plus中参数分隔符替换器 */ final static String MYBATIS_PLUS_WRAPPER_SEPARATOR_REGEX = "\\."; /** * 已经替换过的标记 */ final static String REPLACED_LIKE_KEYWORD_MARK = "replaced.keyword"; /** * 转义特殊字符 * * @param sql SQL语句 * @param fields 字段列表 * @param parameter 参数对象 */ public void convert(String sql, Set fields, T parameter) { for (String field : fields) { if (this.hasMybatisPlusLikeSql(sql)) { if (this.hasWrapper(field)) { // 第一种情况:在业务层进行条件构造产生的模糊查询关键字,使用QueryWrapper,LambdaQueryWrapper this.transferWrapper(field, parameter); } else { // 第二种情况:未使用条件构造器,但是在service层进行了查询关键字与模糊查询符`%`手动拼接 this.transferSelf(field, parameter); } } else { // 第三种情况:在Mapper类的注解SQL中进行了模糊查询的拼接 this.transferSplice(field, parameter); } } } /** * 转义条件构造的特殊字符 * 在业务层进行条件构造产生的模糊查询关键字,使用QueryWrapper,LambdaQueryWrapper * * @param field 字段名称 * @param parameter 参数对象 */ public abstract void transferWrapper(String field, T parameter); /** * 转义自定义条件拼接的特殊字符 * 未使用条件构造器,但是在service层进行了查询关键字与模糊查询符`%`手动拼接 * * @param field 字段名称 * @param parameter 参数对象 */ public abstract void transferSelf(String field, T parameter); /** * 转义自定义条件拼接的特殊字符 * 在Mapper类的注解SQL中进行了模糊查询的拼接 * * @param field 字段名称 * @param parameter 参数对象 */ public abstract void transferSplice(String field, T parameter); /** * 转义通配符 * * @param before 待转义字符串 * @return 转义后字符串 */ String escapeChar(String before) { if (StringUtils.isNotBlank(before)) { before = before.replaceAll("\\\\", "\\\\\\\\"); before = before.replaceAll("_", "\\\\_"); before = before.replaceAll("%", "\\\\%"); } return before; } /** * 是否包含需要转义的字符 * * @param obj 待判断的对象 * @return true/false */ boolean hasEscapeChar(Object obj) { if (!(obj instanceof String)) { return false; } return this.hasEscapeChar((String) obj); } /** * 处理对象like问题 * * @param field 对象字段 * @param parameter 对象 */ void resolveObj(String field, Object parameter) { if (parameter == null || StringUtils.isBlank(field)) { return; } try { PropertyDescriptor descriptor = new PropertyDescriptor(field, parameter.getClass()); Method readMethod = descriptor.getReadMethod(); Object param = readMethod.invoke(parameter); if (this.hasEscapeChar(param)) { Method setMethod = descriptor.getWriteMethod(); setMethod.invoke(parameter, this.escapeChar(param.toString())); } else if (this.cascade(field)) { int index = field.indexOf(MYBATIS_PLUS_WRAPPER_SEPARATOR) + 1; this.resolveObj(field.substring(index), param); } } catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) { log.error("反射 {} 的 {} get/set方法出现异常", parameter, field, e); } } /** * 判断是否是级联属性 * * @param field 字段名 * @return true/false */ boolean cascade(String field) { if (StringUtils.isBlank(field)) { return false; } return field.contains(MYBATIS_PLUS_WRAPPER_SEPARATOR) && !this.hasWrapper(field); } /** * 是否包含mybatis-plus的包含like的SQL语句格式 * * @param sql 完整SQL语句 * @return true/false */ private boolean hasMybatisPlusLikeSql(String sql) { if (StringUtils.isBlank(sql)) { return false; } return sql.toLowerCase().contains(MYBATIS_PLUS_LIKE_SQL); } /** * 判断是否使用mybatis-plus条件构造器 * * @param field 字段 * @return true/false */ private boolean hasWrapper(String field) { if (StringUtils.isBlank(field)) { return false; } return field.contains(MYBATIS_PLUS_WRAPPER_PREFIX); } /** * 判断字符串是否含有需要转义的字符 * * @param str 待判断的字符串 * @return true/false */ private boolean hasEscapeChar(String str) { if (StringUtils.isBlank(str)) { return false; } for (String s : ESCAPE_CHAR) { if (str.contains(s)) { return true; } } return false; }}
2.2 定义MapLikeSqlConverter处理Map类型参数的情况
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;import java.util.Map;import java.util.Objects;/** * 参数对象为Map的转换器 * * @author lieber * @create_date 2020/1/21 12:28 */public class MapLikeSqlConverter extends AbstractLikeSqlConverter
2.3 定义ObjectLikeSqlConverter处理Object类型参数的情况
import lombok.extern.slf4j.Slf4j;/** * 通用参数的转换器 * * @author lieber */@Slf4jpublic class ObjectLikeSqlConverter extends AbstractLikeSqlConverter
3. 注册到Spring中
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/** * mybatis/mybatis-plus模糊查询语句特殊字符转义配置 * * @author lieber */@Configurationpublic class MybatisLikeSqlConfig { @Bean public MybatisLikeSqlInterceptor mybatisSqlInterceptor() { return new MybatisLikeSqlInterceptor(); }}
到此,即可进行关键字的精确匹配。
到此,相信大家对"mybatis/mybatis-plus模糊查询语句特殊字符转义拦截器的实现方法是什么"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
语句
字符
转义
对象
查询
参数
特殊
关键
关键字
字段
条件
情况
方法
拦截器
字符串
处理
名称
构造器
业务
内容
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
怎么启用数据库服务
SQL导入数据库版本
软件开发项目预算拆分粒度
软件开发老板面试
软件开发人员就业前景
福建服务器硬盘报价
dns中继服务器
南京银禾互联网科技有限公司
谷歌是属于什么服务器
oracle数据库备份与恢复
信息网络安全专业考研科目
一个服务器怎么搭建多个游戏
服务器带内和带外管理
数据库三个表进行连接
网络安全政策解决可行性分析
mt4专用服务器
使用数据库表替代配置文件
物资管理软件开发多少钱
计算机里能装两个数据库吗
吕晓阳计算机网络技术
程序员软件开发与系统维护
服务器销售怎么备案
万厨互联网科技有限公司
西安网络安全周举办地点
游戏软件开发技术说明
阿里云数据服务器
数据库恢复删除表
成都思维联动网络科技互联网
饥荒如何转让服务器
ibm服务器阵列设置