51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

mybatisplus转义模糊查询

mybatisplus转义模糊查询

背景: MySQL 模糊查询时,如果前端传了特殊字符而后端没有对特殊字符转义的话,特殊字符就会被识别为SQL中的特殊字符,发挥其特殊字符的含义,如占位符''、'%'等,如需MySQL将这些字符识别为普通字符,则需要在其前面加上转义符,默认是反斜杠,即变为''、'%'即可。

但是每个查询的地方都加转义,又麻烦又容易遗漏,所以借鉴类似AOP的思想,加一层拦截来解决,如果你的orm框架使用的mybatis-plus,则可以通过实现一个自定义插件解决,mybatis也有类似插件规范。

要求mybatis-plus的版本(starter)>=3.4.0

直接无脑上代码 复制粘贴就行
1、写 拦截器 插件

  
   
* 
                          001
                        

   
* 
                          002
                        

   
* 
                          003
                        

   
* 
                          004
                        

   
* 
                          005
                        

   
* 
                          006
                        

   
* 
                          007
                        

   
* 
                          008
                        

   
* 
                          009
                        

   
* 
                          010
                        

   
* 
                          011
                        

   
* 
                          012
                        

   
* 
                          013
                        

   
* 
                          014
                        

   
* 
                          015
                        

   
* 
                          016
                        

   
* 
                          017
                        

   
* 
                          018
                        

   
* 
                          019
                        

   
* 
                          020
                        

   
* 
                          021
                        

   
* 
                          022
                        

   
* 
                          023
                        

   
* 
                          024
                        

   
* 
                          025
                        

   
* 
                          026
                        

   
* 
                          027
                        

   
* 
                          028
                        

   
* 
                          029
                        

   
* 
                          030
                        

   
* 
                          031
                        

   
* 
                          032
                        

   
* 
                          033
                        

   
* 
                          034
                        

   
* 
                          035
                        

   
* 
                          036
                        

   
* 
                          037
                        

   
* 
                          038
                        

   
* 
                          039
                        

   
* 
                          040
                        

   
* 
                          041
                        

   
* 
                          042
                        

   
* 
                          043
                        

   
* 
                          044
                        

   
* 
                          045
                        

   
* 
                          046
                        

   
* 
                          047
                        

   
* 
                          048
                        

   
* 
                          049
                        

   
* 
                          050
                        

   
* 
                          051
                        

   
* 
                          052
                        

   
* 
                          053
                        

   
* 
                          054
                        

   
* 
                          055
                        

   
* 
                          056
                        

   
* 
                          057
                        

   
* 
                          058
                        

   
* 
                          059
                        

   
* 
                          060
                        

   
* 
                          061
                        

   
* 
                          062
                        

   
* 
                          063
                        

   
* 
                          064
                        

   
* 
                          065
                        

   
* 
                          066
                        

   
* 
                          067
                        

   
* 
                          068
                        

   
* 
                          069
                        

   
* 
                          070
                        

   
* 
                          071
                        

   
* 
                          072
                        

   
* 
                          073
                        

   
* 
                          074
                        

   
* 
                          075
                        

   
* 
                          076
                        

   
* 
                          077
                        

   
* 
                          078
                        

   
* 
                          079
                        

   
* 
                          080
                        

   
* 
                          081
                        

   
* 
                          082
                        

   
* 
                          083
                        

   
* 
                          084
                        

   
* 
                          085
                        

   
* 
                          086
                        

   
* 
                          087
                        

   
* 
                          088
                        

   
* 
                          089
                        

   
* 
                          090
                        

   
* 
                          091
                        

   
* 
                          092
                        

   
* 
                          093
                        

   
* 
                          094
                        

   
* 
                          095
                        

   
* 
                          096
                        

   
* 
                          097
                        

   
* 
                          098
                        

   
* 
                          099
                        

   
* 
                          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
                        

   
* 
                          148
                        

   
* 
                          149
                        

   
* 
                          150
                        

   
* 
                          151
                        

   
* 
                          152
                        

   
* 
                          153
                        

   
* 
                          154
                        

   
* 
                          155
                        

   
* 
                          156
                        

   
* 
                          157
                        

   
* 
                          158
                        

   
* 
                          159
                        

   
* 
                          160
                        

   
* 
                          161
                        

   
* 
                          162
                        

   
* 
                          163
                        

   
* 
                          164
                        

   
* 
                          165
                        

   
* 
                          166
                        

   
* 
                          167
                        

   
* 
                          168
                        

   
* 
                          169
                        

   
* 
                          170
                        

   
* 
                          171
                        

   
* 
                          172
                        

   
* 
                          173
                        

   
* 
                          174
                        

   
* 
                          175
                        

   
* 
                          176
                        

   
* 
                          177
                        

   
* 
                          178
                        

   
* 
                          179
                        

   
* 
                          180
                        

   
* 
                          181
                        

   
* 
                          182
                        

   
* 
                          183
                        

   
* 
                          184
                        

   
* 
                          185
                        

   
* 
                          186
                        

   
* 
                          187
                        

   
* 
                          188
                        

   
* 
                          189
                        

   
* 
                          190
                        

   
* 
                          191
                        

   
* 
                          192
                        

   
* 
                          193
                        

   
* 
                          194
                        

   
* 
                          195
                        

   
* 
                          196
                        

   
* 
                          197
                        

   
* 
                          198
                        

   
* 
                          199
                        

   
* 
                          200
                        

   
* 
                          201
                        

   
* 
                          202
                        

   
* 
                          203
                        

   
* 
                          204
                        

   
* 
                          205
                        

   
* 
                          206
                        

   
* 
                          207
                        

   
* 
                          208
                        

   
* 
                          209
                        

   
* 
                          210
                        

   
* 
                          211
                        

   
* 
                          212
                        

   
* 
                          213
                        

   
* 
                          214
                        

   
* 
                          215
                        

   
* 
                          216
                        

   
* 
                          217
                        

   
* 
                          218
                        

   
* 
                          219
                        

   
* 
                          220
                        

   
* 
                          221
                        

   
* 
                          222
                        

   
* 
                          223
                        

   
* 
                          224
                        

   
* 
                          225
                        

   
* 
                          226
                        

   
* 
                          227
                        

   
* 
                          228
                        

   
* 
                          229
                        

   
* 
                          230
                        

   
* 
                          231
                        

   
* 
                          232
                        

   
* 
                          233
                        

   
* 
                          234
                        

   
* 
                          235
                        

   
* 
                          236
                        

   
* 
                          237
                        

   
* 
                          238
                        

   
* 
                          239
                        

   
* 
                          240
                        

   
* 
                          241
                        

   
* 
                          242
                        

   
* 
                          243
                        

   
* 
                          244
                        

   
* 
                          245
                        

   
* 
                          246
                        

   
* 
                          247
                        

   
* 
                          248
                        

   
* 
                          249
                        

   
* 
                          250
                        

   
* 
                          251
                        

   
* 
                          252
                        

   
* 
                          253
                        

   
* 
                          254
                        

   
* 
                          255
                        

   
* 
                          256
                        

   
* 
                          257
                        

   
* 
                          258
                        

   
* 
                          259
                        

   
* 
                          260
                        

   
* 
                          261
                        

   
* 
                          262
                        

   
* 
                          263
                        

   
* 
                          264
                        

   
* 
                          265
                        

   
* 
                          266
                        

   
* 
                          267
                        

   
* 
                          268
                        

   
* 
                          269
                        

   
* 
                          270
                        

   
* 
                          271
                        

   
* 
                          272
                        

   
* 
                          273
                        

   
* 
                          274
                        

   
* 
                          275
                        

   
* 
                          276
                        

   
* 
                          277
                        

   
* 
                          278
                        

   
* 
                          279
                        

   
* 
                          280
                        

   
* 
                          281
                        

   
* 
                          282
                        

   
* 
                          283
                        

   
* 
                          284
                        

   
* 
                          285
                        

   
* 
                          286
                        

   
* 
                          287
                        

   
* 
                          288
                        

   
* 
                          289
                        

   
* 
                          290
                        

   
* 
                          291
                        

   
* 
                          292
                        

   
* 
                          293
                        

  

                    
                      import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Filter;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.sql.SQLException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;


/\*\*

`
`
* 
  自定义mybatis-plus拦截器, 用于转义模糊查询参数中的特殊字符





* 


* 
  @author wangjingyang





{#codeBlock0-1735747125581}
* `
  `@date 2021/6/24 10:33
  /
  public class EscapeLikeSqlInterceptor implements InnerInterceptor {
  /*
  `
  `

  * 点
    */
    public static final String DOT = ".";


  `
  `

  /**
  `
  `

  * 按?分割字符串表达式
    */
    public static final String PLACEHOLDER_REGEX = "\?";


  `
  `

  /**
  `
  `

  * 按.分割字符串表达式
    */
    public static final String DOT_REGEX = "\.";


  `
  `

  /**
  `
  `

  * like操作通配符
    */
    public static final char LIKE_WILDCARD_CHARACTER = '%';


  `
  `

  /**
  `
  `

  * like操作通常会存在的占位符形式
    */
    public static final String PLACEHOLDER = " ?";


  `
  `

  /**
  `
  `

  * 条件构造器生成sql特有的参数名前缀
    */
    public static final String WRAPPER_PARAMETER_PROPERTY = "ew.paramNameValuePairs.";


  `
  `

  /**
  `
  `

  * like语句在sql中的字符串
    */
    private final String LIKE_SQL = " like ";


  `
  `

  private static final String SQL_SPECIAL_CHARACTER = "_%*@|&()[]"'\";
  `
  `

  /**
  `
  `

  * 不应用此拦截器的参数名,方法参数中有此名称的参数则不应用此拦截器
    */
    private final String IGNORE = "EscapeLikeSqlIgnore";


  `
  `

  @Override
  public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
  if (parameter instanceof Map) {
  Map<?, ?> parameterMap = (Map<?, ?>) parameter;
  if (parameterMap.containsKey(IGNORE)){
  return;
  }
  }
  `
  `

       if (!needEscape(boundSql.getSql())) {
           return;
       }
       escapeSql(boundSql);


  `
  `

  }
  `
  `

  @Override
  public void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException {
  if (parameter instanceof Map) {
  Map<?, ?> parameterMap = (Map<?, ?>) parameter;
  if (parameterMap.containsKey(IGNORE)){
  return;
  }
  }
  `
  `

       BoundSql boundSql = ms.getBoundSql(parameter);
       if (!needEscape(boundSql.getSql())) {
           return;
       }
       escapeSql(boundSql);


  `
  `

  }
  `
  `

  /**
  `
  `

  * sql是否需要转义


  * 


  * @param sql


  * @return
    */
    private boolean needEscape(String sql) {
    return containLike(sql) && containPlaceholder(sql);
    }


  `
  `

  /**
  `
  `

  * sql是否包含like语句


  * 


  * @param sql


  * @return
    */
    private boolean containLike(String sql) {
    return StrUtil.containsIgnoreCase(sql, LIKE_SQL);
    }


  `
  `

  /**
  `
  `

  * sql是否包含占位符


  * 


  * @param sql


  * @return
    */
    private boolean containPlaceholder(String sql) {
    return StrUtil.contains(sql, PLACEHOLDER);
    }


  `
  `

  /**
  `
  `

  * 参数名是否是条件构造器生成


  * 


  * @param property


  * @return
    */
    private boolean containWrapper(String property) {
    return StrUtil.contains(property, WRAPPER_PARAMETER_PROPERTY);
    }


  `
  `

  /**
  `
  `

  * 参数名是否是对象的嵌套表达式


  * 


  * @param property


  * @return
    */
    private boolean cascadeParameter(String property) {
    return StrUtil.contains(property, DOT);
    }


  `
  `

  /**
  `
  `

  * 转义sql语句中的特殊字符


  * 


  * @param boundSql
    */
    @SuppressWarnings("unchecked")
    private void escapeSql(BoundSql boundSql) {
    String[] split = boundSql.getSql().split(PLACEHOLDER_REGEX);
    Object parameter = boundSql.getParameterObject();
    Set<String> processedProperty = new HashSet<>();
    for (int i = 0; i < split.length; i++) {
    // like 通常在末尾
    if (StrUtil.lastIndexOfIgnoreCase(split[i], LIKE_SQL) > -1) {
    if (parameter instanceof Map) {
    // 拿到此位置的"?"对应的参数名
    String property = boundSql.getParameterMappings().get(i).getProperty();
    // 防止重复转义
    if (processedProperty.contains(property)){
    continue;
    }
    Map<Object, Object> parameterMap = (Map<Object, Object>) parameter;
    if (containWrapper(property)) {
    // 条件构造器构造sql方式
    handlerWrapperEscape(property, parameterMap);
    } else {
    // 自主写sql方式
    handlerOriginalSqlEscape(property, parameterMap);
    }
    processedProperty.add(property);
    } else if (parameter instanceof String) {
    // 单条件&&不通过条件构造器&&直接写sql&&mapper不写@Param注解,会导致parameter直接为参数值而不是map
    //                    BeanUtil.setFieldValue(boundSql, "parameterObject", SqlUtil.addSalashes((String) parameter));
    // 强行反射设置属性,暂不清楚为什么更改parameterObject无效
    BeanUtil.setFieldValue(boundSql.getParameterObject(), "value", addSalashes(((String) parameter)).toCharArray());
    }
    }
    }
    }


  `
  `

  /**
  `
  `

  * 处理通过条件构造器构造sql的转义


  * 


  * @param property        参数名


  * @param parameterObject 此条sql的参数map
    */
    private void handlerWrapperEscape(String property, Map<?, ?> parameterObject) {
    String[] keys = property.split(DOT_REGEX);
    Object ew = parameterObject.get(keys[0]);
    if (ew instanceof AbstractWrapper) {
    Map<String, Object> paramNameValuePairs = ((AbstractWrapper<?, ?, ?>) ew).getParamNameValuePairs();
    // 拿到参数值
    Object paramValue = paramNameValuePairs.get(keys[2]);
    if (paramValue instanceof String) {
    // 去除首尾%并转义后再拼上%
    paramNameValuePairs.put(keys[2], String.format("%%%s%%", addSalashes((String) paramValue, LIKE_WILDCARD_CHARACTER)));
    }
    }
    }


  `
  `

  /**
  `
  `

  * 处理自己写sql的转义


  * 


  * @param property        参数名


  * @param parameterObject 此条sql的参数map
    */
    private void handlerOriginalSqlEscape(String property, Map<Object, Object> parameterObject) {
    if (cascadeParameter(property)) {
    // 级联形式的参数,比如参数是对象中的某个字段的值:filter.name
    String[] keys = property.split(DOT_REGEX, 2);
    Object parameterBean = parameterObject.get(keys[0]);
    Object parameterValue = BeanUtil.getProperty(parameterBean, keys[1]);
    if (parameterValue instanceof String) {
    BeanUtil.setProperty(parameterBean, keys[1], addSalashes((CharSequence) parameterValue));
    }
    } else {
    // 普通参数名
    parameterObject.computeIfPresent(property, (key, value) -> {
    if (value instanceof String) {
    return addSalashes((CharSequence) value);
    }
    return value;
    });
    }
    }


  `
  `

  private static String addSalashes(CharSequence content, Filter<Character> filter){
  if (StrUtil.isEmpty(content)) {
  return StrUtil.str(content);
  }
  `
  `

       StringBuilder sb = new StringBuilder();
       for (int i = 0; i &lt; content.length(); i++) {
           char c = content.charAt(i);
           if (filter.accept(c)) {
               sb.append('\\');
           }
           sb.append(c);
       }

       return sb.toString();


  `
  `

  }
  `
  `

  private static String addSalashes(CharSequence content, CharSequence applyCharacters){
  if (StrUtil.isEmpty(content)) {
  return StrUtil.str(content);
  }
  `
  `

       StringBuilder sb = new StringBuilder();
       for (int i = 0; i &lt; content.length(); i++) {
           char c = content.charAt(i);
           if (StrUtil.contains(applyCharacters, c)) {
               sb.append('\\');
           }
           sb.append(c);
       }

       return sb.toString();


  `
  `

  }
  `
  `

  private static String addSalashes(CharSequence content){
  if (StrUtil.isEmpty(content)) {
  return StrUtil.str(content);
  }
  `
  `

       StringBuilder sb = new StringBuilder();
       for (int i = 0; i &lt; content.length(); i++) {
           char c = content.charAt(i);
           if (StrUtil.contains(SQL_SPECIAL_CHARACTER, c)) {
               sb.append('\\');
           }
           sb.append(c);
       }

       return sb.toString();


  `
  `

  }
  `
  `

  private static String addSalashes(CharSequence content, char trimFix){
  if (content.charAt(0) == trimFix){
  content = content.subSequence(1,content.length());
  }
  if (content.charAt(content.length() - 1) == trimFix){
  content = content.subSequence(0,content.length() - 1);
  }
  `
  `

       return addSalashes(content);


  `
  `{#codeBlock0-1735747125581}

  `}
  }
  123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  `{#codeBlock0-1735747125581}



2、把拦截器插件加到mybatisplus插件集合

如果之前配置了分页插件,注意顺序,自定义插件要放在分页插件前面,否则会导致分页查询的总数对不上查询结果集 ,看日志就能看出就是 count(*) 查询总数的时候特殊字符没来得及加 "\",导致全表查。

                    
                      @Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new EscapeLikeSqlInterceptor());
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }



`}
`


赞(1)
未经允许不得转载:工具盒子 » mybatisplus转义模糊查询