mybatismybatis-plus模糊查询语句特殊字符转义的实现在开发中,我们通常会遇到这样的情况。⽤户在录⼊信息是录⼊了‘%’,⽽在查询时⽆法精确匹配‘%’。究其原因,‘%’是MySQL的关键字,如果我们想要精确匹配‘%’,那么需要对其进⾏转义,本⽂就详细的介绍⼀下
⽬录
mybatis/mybatis-plus模糊查询语句特殊字符转义
在开发中,我们通常会遇到这样的情况。⽤户在录⼊信息是录⼊了‘%',⽽在查询时⽆法精确匹配‘%'。究其原因,‘%'是MySQL的关键字,如果我们想要精确匹配‘%',那么需要对其进⾏转义。
1.使⽤mybatis提供的拦截所有的查询请求。
具体实现在代码中均有注释
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 slf4j.Slf4j;
import org.apachemons.lang3.StringUtils;
import org.utor.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})})
@Slf4j
public class MybatisLikeSqlInterceptor implements Interceptor {
/**
* SQL语句like
*/
private final static String SQL_LIKE = " like ";
/**
* SQL语句占位符
*/
private final static String SQL_PLACEHOLDER = "?";
/**
* SQL语句占位符分隔
replaceall()
*/
private final static String SQL_PLACEHOLDER_REGEX = "\\?";
/
**
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    /**
* 所有的转义器
*/
private static Map<Class, AbstractLikeSqlConverter> converterMap = 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 = Args();
MappedStatement statement = (MappedStatement) args[0];
Object parameterObject = args[1];
BoundSql boundSql = BoundSql(parameterObject);
String sql = Sql();
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 = placeAll(" {2}", " ");
// 获取关键字的个数(去重)
Set<String> fields = KeyFields(sql, boundSql);
if(fields == null) {
return;
}
// 此处可以增强,不⽌是⽀持Map对象,Map对象仅⽤于传⼊的条件为Map或者使⽤@Param传⼊的对象被Mybatis转为的Map        AbstractLikeSqlConverter converter;
// 对关键字进⾏特殊字符“清洗”,如果有特殊字符的,在特殊字符前添加转义字符(\)
if(parameterObject instanceof Map) {
converter = (Map.class);
} else{
converter = (Object.class);
}
}
/**
* 是否需要转义
*
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    *
* @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;
}
LowerCase().contains(SQL_LIKE);
}
/**
* 判断SQL语句中是否包含SQL占位符
*
* @param str SQL语句
* @return true/false
*/
private boolean hasPlaceholder(String str) {
if(StringUtils.isBlank(str)) {
return false;
}
LowerCase().contains(SQL_PLACEHOLDER);
}
/**
* 获取需要替换的所有字段集合
*
* @param sql      完整SQL语句
* @param boundSql 绑定的SQL对象
* @return 字段集合列表
*/
private Set<String> getKeyFields(String sql, BoundSql boundSql) {
String[] params = sql.split(SQL_PLACEHOLDER_REGEX);
Set<String> fields = new HashSet<>();
for(int i = 0; i < params.length; i++) {
if(this.hasLike(params[i])) {
String field = ParameterMappings().get(i).getProperty();                fields.add(field);
}
}
return fields;
}
}
147
148
149
2.定义SQL语句转义模板,分别对Map和Object对象进⾏处理2.1 定义AbstractLikeSqlConverter
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 slf4j.Slf4j;
import org.apachemons.lang3.StringUtils;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import flect.InvocationTargetException;
import flect.Method;
import java.util.Set;
/**
* 包含like的SQL语句转义模板
*
* @author lieber
*/
@Slf4j
public abstract class AbstractLikeSqlConverter<T> {
/
**
* 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 = ".";
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    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<String> fields, T parameter) {
for(String field : fields) {
if(this.hasMybatisPlusLikeSql(sql)) {
if(this.hasWrapper(field)) {
/
/ 第⼀种情况:在业务层进⾏条件构造产⽣的模糊查询关键字,使⽤QueryWrapper,LambdaQueryWrapper                    ansferWrapper(field, parameter);
} else{
// 第⼆种情况:未使⽤条件构造器,但是在service层进⾏了查询关键字与模糊查询符`%`⼿动拼接
}
} else{
// 第三种情况:在Mapper类的注解SQL中进⾏了模糊查询的拼接
}
}
}
/**
* 转义条件构造的特殊字符
* 在业务层进⾏条件构造产⽣的模糊查询关键字,使⽤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 参数对象
*/

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。