在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));
}
}