package com.lantone.dblayermbg.config.mybatisLike; 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; /** * @Description: 包含like的SQL语句转义模板 * @author: gaodm * @time: 2020/11/2 16:05 */ @Slf4j public 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; } }