1. 程式人生 > 實用技巧 >mybatis plus like查詢 %_處理

mybatis plus like查詢 %_處理

如果我們資料庫中存的欄位包含有"%_"這兩個like查詢的萬用字元,那麼在查詢的時候把"%_"當作關鍵字是查詢不出來的,因為mybatis會把這兩個字元當作萬用字元。解決方法是要能加轉義字元

1.定義一個攔截器,如果要查詢的字串中包含"%_"則增加一個轉義字元

package com.booway.application;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import
java.util.regex.Pattern; import org.apache.ibatis.builder.SqlSourceBuilder; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Plugin; import org.apache.ibatis.plugin.Signature; import org.apache.ibatis.reflection.DefaultReflectorFactory; import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory; import org.apache.ibatis.reflection.factory.ObjectFactory; import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory; import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory; import org.apache.ibatis.scripting.xmltags.DynamicContext; import org.apache.ibatis.scripting.xmltags.SqlNode; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.springframework.stereotype.Component; @Component @Intercepts( { @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }), @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class }) }) public class QueryStringEscapeInterceptor implements Interceptor { private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory(); private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory(); private static final String ROOT_SQL_NODE = "sqlSource.rootSqlNode"; @Override public Object intercept(Invocation invocation) throws Throwable { Object parameter = invocation.getArgs()[1]; MappedStatement statement = (MappedStatement) invocation.getArgs()[0]; MetaObject metaMappedStatement = MetaObject.forObject(statement, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory()); BoundSql boundSql = statement.getBoundSql(parameter); if (metaMappedStatement.hasGetter(ROOT_SQL_NODE)) { SqlNode sqlNode = (SqlNode) metaMappedStatement.getValue(ROOT_SQL_NODE); getBoundSql(statement.getConfiguration(), boundSql.getParameterObject(), sqlNode); } return invocation.proceed(); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { } public static BoundSql getBoundSql(Configuration configuration, Object parameterObject, SqlNode sqlNode) { DynamicContext context = new DynamicContext(configuration, parameterObject); sqlNode.apply(context); String countextSql = context.getSql(); SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration); Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass(); String sql = modifyLikeSql(countextSql, parameterObject); SqlSource sqlSource = sqlSourceParser.parse(sql, parameterType, context.getBindings()); BoundSql boundSql = sqlSource.getBoundSql(parameterObject); for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) { boundSql.setAdditionalParameter(entry.getKey(), entry.getValue()); } return boundSql; } public static String modifyLikeSql(String sql, Object parameterObject) { if (!sql.toLowerCase().contains("like")) { return sql; } String reg = "\\bLIKE\\b.*\\#\\{\\b.*\\}"; Pattern pattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(sql); List<String> replaceFiled = new ArrayList<String>(); while (matcher.find()) { int n = matcher.groupCount(); for (int i = 0; i <= n; i++) { String output = matcher.group(i); if (output != null) { String key = getParameterKey(output); if (replaceFiled.indexOf(key) < 0) { replaceFiled.add(key); } } } } // 修改引數 MetaObject metaObject = MetaObject.forObject(parameterObject, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory()); for (String key : replaceFiled) { Object val = metaObject.getValue(key); if (val != null && val instanceof String && (val.toString().contains("%") || val.toString().contains("_"))) { val = val.toString().replaceAll("%", "/%").replaceAll("_", "/_"); metaObject.setValue(key, val); } } return sql; } private static String getParameterKey(String input) { String key = ""; String[] temp = input.split("#"); if (temp.length > 1) { key = temp[1]; key = key.replace("{", "").replace("}", "").split(",")[0]; } return key.trim(); } }

2. 對面的查詢mapper like後面要加escape '/'

<select id="selectProjectNameList" parameterType="BwProject" resultType="String">
        select PROJECT_NAME  from bw_project
        <where>
            <if test="projectName != null and projectName != ''">
                AND PROJECT_NAME like concat('%', #{projectName},'%') ESCAPE '/'
            </if>
             <if test="authConstructionUnit != null and authConstructionUnit != ''">
                and construction_unit = #{authConstructionUnit}
             </if>
        </where>
        order by CREATE_TIME desc
    </select>

引用https://www.cnblogs.com/Gyoung/p/5876632.html

這裡有點區別的是Executor介面 有兩個query方法 所以我的程式碼中 添加了 這樣兩個query方法都會被攔截到

@Signature(type = Executor.class, method = "query", args =
        { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class })

記得加入@Component 註解