在mybatis中用like查询时,如果用户输入的值有"_"和“%”,则会出现这种情况:
用户本来只是想查询“abcd_”,查询结果中却有"abcd_"、"abcde"、"abcdf"等等;用户要查询"30%"(注:百分之三十)时也会出现问题。
测试后发现无论你是用#{xxxx }还是用${xxxx }取值都会存在这些问题,而且用${xxxx }取值时还存在sql注入的问题。
为了解决这些问题,我在后台对用户传入的值进行了处理,代码如下:
import org.apache.commons.lang3.StringUtils;
/**
* mybatis中like查询时,需用该方法处理字符,防止sql注入<br>
* sql server 2005测试有效
*
* @date 2013年12月9日 下午4:08:54
* @version 1.0
* @author luoy
*/
public class SqlUtil {
private static final String H = "#";
private static final String S = "$";
/**
* mapper.xml中的取值方式为#{}时
* @param str like的查询条件
* @return
*/
public static String likeEscapeH(String str) {
return likeEscapeZ(str, H, true, true);
}
/**
* mapper.xml中的取值方式为${}时
* @param str like的查询条件
* @return
*/
public static String likeEscapeS(String str) {
return likeEscapeZ(str, S, true, true);
}
/**
* @param str like的查询条件
* @param type mapper.xml中的取值方式,只能“#”或“$”
* @param start 字符串前部是否拼接“%”
* @param end 字符串尾部是否拼接“%”
* @return
*/
public static String likeEscapeZ(String str, String type, boolean start, boolean end) {
if (StringUtils.isBlank(str)) {
return null;
}
StringBuffer buffer = new StringBuffer();
// 拼接顺序不能改变
if (S.equals(type)) {
buffer.append(" '");
}
if (start) {
buffer.append("%");
}
int len = str.length();
//注意:"]"不能处理
for (int i = 0; i < len; i++) {
char c = str.charAt(i);
switch (c) {
case '\'':
if (S.equals(type)) {
buffer.append("''");// 单引号替换成两个单引号
} else {
buffer.append(c);
}
break;
case '[':
buffer.append("[[]");
break;
case '_':
buffer.append("[_]");
break;
case '%':
buffer.append("[%]");
break;
case '^':
buffer.append("[^]");
break;
case '!':
buffer.append("[!]");
break;
default:
buffer.append(c);
}
}
if (end) {
buffer.append("%");
}
if (S.equals(type)) {
buffer.append("' ");
}
return buffer.toString();
}
public static void main(String[] args) {
String str = "aaaa]p'100%_a[[][][]][[][]]df[]dfaf]";
System.out.println("result#: " + likeEscapeH(str));
System.out.println("result$: " + likeEscapeS(str));
}
}
看了代码的人应该很容易就明白了。这里的三个方法分别对应多种可能的情况,第一个是#号取值,参数前后都加百分号;第二个方法是$取值,参数前后都加百分号;第三个方法是参数可配,而且考虑到了,有时候不需要前后都加百分号的情况。
xml中的写法:
1,
<if test="xxx != null" >
select * from tabale_name a where a.xxx like ${xxx }
</if>
2,
<if test="xxx != null" >
select * from tabale_name a where a.xxx like #{xxx }
</if>
添加oracle适用类
import org.apache.commons.lang3.StringUtils;
/**
* oracle 适用<br/>
* mybatis中like查询用$取值时,需用该方法处理字符,防止sql注入<br/>
*
* @date 2016年01月20日
* @author 罗勇
*/
public final class SqlUtil {
/**
* mapper.xml中的取值方式为${}时
*
* @param str
* like的查询条件
* @return
*/
public static String likeEscape(String str) {
return likeEscape(str, true, true);
}
/**
* @param str
* like的查询条件
* @param start
* 字符串前部是否拼接“%”
* @param end
* 字符串尾部是否拼接“%”
* @return
*/
public static String likeEscape(String str, boolean start, boolean end) {
if (StringUtils.isBlank(str)) {
return null;
}
StringBuilder buf = new StringBuilder();
// 拼接顺序不能改变
buf.append(" '");
if (start) {
buf.append("%");
}
boolean flag = false;
int len = str.length();
for (int i = 0; i < len; i++) {
char c = str.charAt(i);
switch (c) {
case '\'':
buf.append("''");// 单引号替换成两个单引号
break;
case '_':
buf.append("\\_");
flag = true;
break;
case '%':
buf.append("\\%");
flag = true;
break;
default:
buf.append(c);
}
}
if (end) {
buf.append("%");
}
buf.append("' ");
if (flag) {
buf.append("escape '\\' ");
}
return buf.toString();
}
private SqlUtil() {
}
public static void main(String[] args) {
String str = "aaaa]p'100%_a[[][][]][[][]]df[]dfaf]!bbb^";
System.out.println("result$: " + likeEscape(str));
}
}