两种特殊符号查询问题总结

1 篇文章 0 订阅

问题

1.接口无法查询含有 \ 的内容(基于JeecgBoot框架自动生成的接口和开发人员自己写的接口都有这个问题)。

2.部分开发人员写的接口存在 输入% 或者 _ 时,返回所有数据 的bug。

解决办法

在请求接口前对内容进行一次转义处理。前端已封装对\ % _ 三种符号转义方法:

import { escapeMysql } from '@/utils/util.js'
...
this.queryParam.name = '*' + escapeMysql(s.name.trim()) + '*'
...

特殊符号转义的问题

在框架中,需要模糊查询的时候,最终在SQL语句中是 LIKE ‘%xxx%’ 的形式。 而下划线(_)和百分号(%)是mysql中的通配符, 反斜线()是转义字符, 如果不对这三个字符进行转义, 得到的结果可能不正确。

在JeecgBoot框架生成的代码中,有三种模糊查询方式

  1. 简单查询: 前端通过queryParam进行传参,后端初始化queryWrapper时处理参数。 高级查询:
  2. 前端通过superQueryParams进行传参,后端初始化queryWrapper时处理参数。 自定义查询:
  3. 前端自定义参数,后端在queryWrapper中添加该参数模糊查询条件。

后端转义

在使用简单查询时,会在QueryGenerator类中调用到specialStrConvert方法,对特殊字符进行转义; 但高级查询暂不支持,需要改造jeecg框架后才行;自定义查询需要手工调用specialStrConvert对值进行处理。

public static final String LIKE_MYSQL_SPECIAL_STRS="\\,_,%";

private static String specialStrConvert(String value){
    if(DataBaseConstant.DB_TYPE_MYSQL.equals(getDbType())||DataBaseConstant.DB_TYPE_MARIADB.equals(getDbType())){
        String[]special_str=QueryGenerator.LIKE_MYSQL_SPECIAL_STRS.split(",");
            for(String str:special_str){
                if(value.indexOf(str)!=-1){
                    value=value.replace(str,"\\"+str);
                }
        }
    }
    return value;
}

前端转义

由于历史原因,并且便于高级查询和自定义查询的特殊字符转义 ,模糊查询采用前端转义的方式。 不使用后端转义。

//不使用后端转义,在QueryGenerator类中注释代码取消转义
//value=value.replace(str,"\\"+str);
//转义方法
export function escapeMysql(str) {
    if (!str) {
        return str
    }
    // 360浏览器不支持replaceAll方法
    // str = str
    //   .replaceAll('\\', '\\\\')
    //   .replaceAll('%', '\\%')
    //   .replaceAll('_', '\\_') //  将\替换为\\(mysql转义)
    const arr = [
        {
            search: /\\/g,
            replacement: '\\\\'
        },
        {
            search: /%/g,
            replacement: '\\%'
        },
        {
            search: /_/g,
            replacement: '\\_'
        }
    ]
    arr.forEach(r => {
        str = str.replace(r.search, r.replacement)
    })
    return str
}

//引入转义工具
import {escapeMysql} from '@/utils/util.js'

//简单查询
this.queryParam.name = `*${escapeMysql(s.name.trim())}*`

//高级查询
params.push({
    field: 'name',
    val: escapeMysql(s.name.trim()),
    rule: 'like'
})

//自定义查询
params = Object.assign(params, {
    description: '*' + escapeMysql(this.taskDescription.trim()) + '*'
})
getList('/space.based.patrol/sbpTask/list', params)

注意

SQL语句模糊查询(LIKE)会转义两次, 精确查询(=)只转义一次

在mybatis+mysql中,在xml里面传参进行模糊查询一般有两种方式:sql拼接、传参

  1. 拼接sql: AND a.username like ‘%${username}%’ (转义两次)
  2. 传参: AND a.username like #{username} (转义一次)
    在使用拼接sql方式时,模糊查询时匹配\这个特殊符号,参数值要提前转义2次才行,与其他方式不一致(大多数代码都是传参方式),建议改成传参方式

原因:在mysql的like语法中,like后边的字符串除了会在语法解析时转义一次外,还会在正则匹配时进行第二次的转义。因此如果期望最终匹配到"“,就要反转义两次,也就是由”“到”“再到”"。 如果是普通的精确查询(=),则无需第二次的正则转义,和INSERT语句一样。

参考文档:https://blog.csdn.net/lizhengyu891231/article/details/120107579

例如在用户组件调用的接口,接口中模糊查询是

SELECT... FROM... WHERE...
AND a.username like '%${username}%'
建议修改为
SELECT... FROM... WHERE...
AND a.username like CONCAT('%',#{username},'%')

针对后端无法对源码进行修改的情况(例如pop弹框),此时在前端对反斜杠进行两次转义

param.username = param.username.replace(/\\/g,'\\\\')
param.username = escapeMysql(param.username)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ciito

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值