iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >mybatis/mybatis-plus模糊查询语句特殊字符转义拦截器的实现方法是什么
  • 720
分享到

mybatis/mybatis-plus模糊查询语句特殊字符转义拦截器的实现方法是什么

2023-06-25 14:06:52 720人浏览 独家记忆
摘要

本篇内容主要讲解“mybatis/mybatis-plus模糊查询语句特殊字符转义拦截器的实现方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“mybatis/mybatis-plus模糊

本篇内容主要讲解“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.*;@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})@Slf4jpublic class MybatisLikeSqlInterceptor implements Interceptor {        private final static String SQL_LIKE = " like ";        private final static String SQL_PLACEHOLDER = "?";        private final static String SQL_PLACEHOLDER_REGEX = "\\?";        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 = 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) {    }        private void transferLikeSql(String sql, Object parameterObject, BoundSql boundSql) {        if (!isEscape(sql)) {            return;        }        sql = sql.replaceAll(" {2}", " ");        // 获取关键字的个数(去重)        Set<String> 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);    }        private boolean isEscape(String sql) {        return this.hasLike(sql) && this.hasPlaceholder(sql);    }        private boolean hasLike(String str) {        if (StringUtils.isBlank(str)) {            return false;        }        return str.toLowerCase().contains(SQL_LIKE);    }        private boolean hasPlaceholder(String str) {        if (StringUtils.isBlank(str)) {            return false;        }        return str.toLowerCase().contains(SQL_PLACEHOLDER);    }        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 = boundSql.getParameterMappings().get(i).getProperty();                fields.add(field);            }        }        return fields;    }}

2.定义SQL语句转义模板,分别对Map和Object对象进行处理

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;@Slf4jpublic abstract class AbstractLikeSqlConverter<T> {        private final static String LIKE_SQL_KEY = "%";        private final static String[] ESCAPE_CHAR = new String[]{LIKE_SQL_KEY, "_", "\\"};        private final static String MYBATIS_PLUS_LIKE_SQL = " like ?";        private final static String MYBATIS_PLUS_WRAPPER_PREFIX = "ew.paramNameValuePairs.";        final static String MYBATIS_PLUS_WRAPPER_KEY = "ew";        final static String MYBATIS_PLUS_WRAPPER_SEPARATOR = ".";        final static String MYBATIS_PLUS_WRAPPER_SEPARATOR_REGEX = "\\.";        final static String REPLACED_LIKE_KEYWord_MARK = "replaced.keyword";        public void convert(String sql, Set<String> 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);            }        }    }        public abstract void transferWrapper(String field, T parameter);        public abstract void transferSelf(String field, T parameter);        public abstract void transferSplice(String field, T parameter);        String escapeChar(String before) {        if (StringUtils.isNotBlank(before)) {            before = before.replaceAll("\\\\", "\\\\\\\\");            before = before.replaceAll("_", "\\\\_");            before = before.replaceAll("%", "\\\\%");        }        return before;    }        boolean hasEscapeChar(Object obj) {        if (!(obj instanceof String)) {            return false;        }        return this.hasEscapeChar((String) obj);    }        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);        }    }        boolean cascade(String field) {        if (StringUtils.isBlank(field)) {            return false;        }        return field.contains(MYBATIS_PLUS_WRAPPER_SEPARATOR) && !this.hasWrapper(field);    }        private boolean hasMybatisPlusLikeSql(String sql) {        if (StringUtils.isBlank(sql)) {            return false;        }        return sql.toLowerCase().contains(MYBATIS_PLUS_LIKE_SQL);    }        private boolean hasWrapper(String field) {        if (StringUtils.isBlank(field)) {            return false;        }        return field.contains(MYBATIS_PLUS_WRAPPER_PREFIX);    }        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 定义MapLikeSqlConverter处理Map类型参数的情况

import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;import java.util.Map;import java.util.Objects;public class MapLikeSqlConverter extends AbstractLikeSqlConverter<Map> {    @Override    public void transferWrapper(String field, Map parameter) {        AbstractWrapper wrapper = (AbstractWrapper) parameter.get(MYBATIS_PLUS_WRAPPER_KEY);        parameter = wrapper.getParamNameValuePairs();        String[] keys = field.split(MYBATIS_PLUS_WRAPPER_SEPARATOR_REGEX);        // ew.paramNameValuePairs.param1,截取字符串之后,获取第三个,即为参数名        String paramName = keys[2];        String mapKey = String.fORMat("%s.%s", REPLACED_LIKE_KEYWORD_MARK, paramName);        if (parameter.containsKey(mapKey) && Objects.equals(parameter.get(mapKey), true)) {            return;        }        if (this.cascade(field)) {            this.resolveCascadeObj(field, parameter);        } else {            Object param = parameter.get(paramName);            if (this.hasEscapeChar(param)) {                String paramStr = param.toString();                parameter.put(keys[2], String.format("%%%s%%", this.escapeChar(paramStr.substring(1, paramStr.length() - 1))));            }        }        parameter.put(mapKey, true);    }    @Override    public void transferSelf(String field, Map parameter) {        if (this.cascade(field)) {            this.resolveCascadeObj(field, parameter);            return;        }        Object param = parameter.get(field);        if (this.hasEscapeChar(param)) {            String paramStr = param.toString();            parameter.put(field, String.format("%%%s%%", this.escapeChar(paramStr.substring(1, paramStr.length() - 1))));        }    }    @Override    public void transferSplice(String field, Map parameter) {        if (this.cascade(field)) {            this.resolveCascadeObj(field, parameter);            return;        }        Object param = parameter.get(field);        if (this.hasEscapeChar(param)) {            parameter.put(field, this.escapeChar(param.toString()));        }    }        private void resolveCascadeObj(String field, Map parameter) {        int index = field.indexOf(MYBATIS_PLUS_WRAPPER_SEPARATOR);        Object param = parameter.get(field.substring(0, index));        if (param == null) {            return;        }        this.resolveObj(field.substring(index + 1), param);    }}

3 定义ObjectLikeSqlConverter处理Object类型参数的情况

import lombok.extern.slf4j.Slf4j;@Slf4jpublic class ObjectLikeSqlConverter extends AbstractLikeSqlConverter<Object> {    @Override    public void transferWrapper(String field, Object parameter) {        // 尚未发现这种情况    }    @Override    public void transferSelf(String field, Object parameter) {        // 尚未发现这种情况    }    @Override    public void transferSplice(String field, Object parameter) {        this.resolveObj(field, parameter);    }}

注册到spring

import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class MybatisLikeSqlConfig {    @Bean    public MybatisLikeSqlInterceptor mybatisSqlInterceptor() {        return new MybatisLikeSqlInterceptor();    }}

到此,即可进行关键字的精确匹配。

到此,相信大家对“mybatis/mybatis-plus模糊查询语句特殊字符转义拦截器的实现方法是什么”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

--结束END--

本文标题: mybatis/mybatis-plus模糊查询语句特殊字符转义拦截器的实现方法是什么

本文链接: https://www.lsjlt.com/news/305194.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作