在sql语句中使用单引号模糊查询可能报错,例如:查询的单引号与%%两端的单引号匹配了形成断句,从而导致查询失败。所以要将单引号转义,变成两个单引号 '' 就行了。
SELECT * from ft_providers WHERE last_name like '%'%'; //报错
SELECT * from ft_providers WHERE last_name like '%''%'; //正确
那么在前端或者java里面就要将查询字符串进行替换,java里面比较简单,有replaceAll( )方法。但是js中没有,则可以用正则表达式来全局替换。
var account = $("#query_account").val().replace(new RegExp("'","gm"),"''"); //将单引号变成两个单引号,防止数据库模糊查询出错 g:表示全局匹配 m表示执行多行匹配
我们也可以编写String对象的原型方法,来添加一个replaceAll()方法:
String.prototype.replaceAll = function(s1,s2){
return this.replace(new RegExp(s1,"gm"),s2);
}
str.replaceAll("'","''"); //使用自定义替换全局
在js语句中,当很多页面很多模糊查询的条件时,都要运用上面的方法进行一遍替换操作,很麻烦。
function queryDataInfo(){
$('#datagrid').datagrid('load',{
'vo.account': $("#query_account").val().replaceAll("'","''"),
'vo.storeId': $("#query_storeId").val().replaceAll("'","''"),
'vo.isAble': $("#query_isAble").combobox('getValue')
});
$("#query_dialog").dialog('close');
}
既然都是通过val()方法取值然后替换,则干脆扩展val()方法直接全部替换:
可能出现问题:
当取值中确实有单引号,而我们并不需要去进行模糊查询操作,则可能获取的值与传递的值不一致。所有这样扩展只能用于本例中用于模糊查询,一般form表单也不用一个一个取值去传递,所以这权当是一次学习扩展方法,以后有想满足自己什么功能自己再修改就是了。
//一定要写在这里面,不然会报错
$(function(){
/**
* 修改Jquery的val() 方法,进行全局替换' 为''
* 用于在sql模糊查询中,一个单引号会对sql语句造成影响,两个单引号则形成转义作用
* @param options
* @returns
*/
(function ($) { //形成一个闭包
var originalVal = $.fn.val; //获取原val方法
$.fn.val = function(value) {
if (arguments.length >= 1) { //判断是否传入参数,来判断是赋值还是取值
return originalVal.call(this, value); //赋值的话则执行原方法
}
var r = originalVal.call(this); //执行原方法
return r.replace(new RegExp("'","gm"),"''"); //扩展:一个单引号变成两个单引号
};
})(jQuery);
});
上面是将Jquery原型val方法处理了,但是难免会在某些地方出现不可预知的问题。怎么办?其实这种,逻辑更愿意放在后台代码处理,而不是前台。所以查阅了相关资料,可以利用拦截器或者过滤器来处理字段。
我们来简单区分一下这两者的区别:
过滤器:能过滤所有的请求, 依赖与servlet容器,基于回调函数,不能获取值。
拦截器 : 只拦截Action请求,基于java的反射机制,能够获取值栈的值。能够多次调用。
所以,要满足我们的需求,需要处理参数值,所以使用拦截器再好不过了。而过滤器则不能实现功能。如下为参数值方法拦截器实现,并在方法中处理单引号为双单引号。
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
/**
* 查询值拦截器
* 用于sql语句模糊查询时,关于单引号查询进而在此转义
* @author aggerChen
*
*/
public class QueryValueInterceptor extends MethodFilterInterceptor {
@SuppressWarnings("rawtypes")
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
HttpServletRequest request = ServletActionContext.getRequest(); //获取请求
String type = request.getHeader("X-Requested-With"); //获取请求头
if(type == null) return invocation.invoke(); //type为null则表示非ajax请求。本项目查询方式都是ajax请求的,所以在此来排除一些其他的请求,比如表单
Map<String,String[]> map = request.getParameterMap(); //获取请求中所有的参数map
Iterator it = map.entrySet().iterator();
//迭代
while (it.hasNext()) {
Entry entry = (Entry) it.next();
String key = (String) entry.getKey();
String[] values = (String[]) entry.getValue();
if(key.indexOf("vo.")!=-1){ //判断是否是对象传参,vo.xxx 则为查询请求
if(!"".equals(values[0])){
values[0] = values[0].replaceAll("'", "''"); //将一个单引号处理为两个单引号
}
}
}
return invocation.invoke();
}
}
在struts.xml中配置拦截器。此示例只展示过滤器相关配置。
将默认拦截器设置为loginAndroleInterceptor拦截器栈,此栈中先进入roleInterceptor拦截器,再引入loginStack拦截器栈。loginStack栈中先经过登录拦截器,在经过本例自定义的查询条件拦截器,最后经过struts默认拦截器。
struts默认拦截器一定是在自定义拦截器最后再经过的。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!-- 引入默认拦截器 -->
<include file="struts-default.xml" />
<package name="base-packege" extends="struts-default">
<interceptors>
<!-- 登陆拦截器 -->
<interceptor name="loginInterceptor" class="com.fortis.cms.interceptor.LoginInterceptor"></interceptor>
<!-- 角色拦截器 -->
<interceptor name="roleInterceptor" class="com.fortis.cms.interceptor.RoleInterceptor"></interceptor>
<!-- 查询条件值拦截器 本例自定义拦截器-->
<interceptor name="queryValueInterceptor" class="com.fortis.cms.interceptor.QueryValueInterceptor"></interceptor>
<!--登录拦截器栈 -->
<interceptor-stack name="loginStack">
<interceptor-ref name="loginInterceptor">
<param name="excludeMethods">login,notNeedRoleForwardLogin</param>
</interceptor-ref>
<interceptor-ref name="queryValueInterceptor"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
<!--登录和角色拦截器栈 -->
<interceptor-stack name="loginAndroleInterceptor">
<interceptor-ref name="roleInterceptor">
<param name="excludeMethods">login,notNeedRole*,queryMenuTree</param>
</interceptor-ref>
<interceptor-ref name="loginStack" />
</interceptor-stack>
</interceptors>
<!--设置默认拦截器栈 -->
<default-interceptor-ref name="loginAndroleInterceptor"></default-interceptor-ref>
</package>
</struts>
总结:这是在项目中遇到的问题,这也是我解决的思路历程,暂时没报错了,不过其他地方调用val()有没有问题还没有一一去验证,权当是一次联系重写方法了。拦截器处理的话,应该是不会出错了。
转载请注明原文地址: https://ju.6miu.com/read-1126284.html