最近做项目时,页面传递给后台的特殊字符很烦人,想写一个公共方法来给需要使用的地方调用,但是后来发现,要调用的地方实在太多,万一有什么变动的话,改起来烦死人。后来发现使用过滤器可以完成这个功能。
过滤器中的主要代码如下:
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
chain.doFilter(new HTMLCharacterRequest(req), resp);
}
其中 HTMLCharacterRequest 是继承与 HttpServletRequest包装类的:
public class HTMLCharacterRequest extends HttpServletRequestWrapper {
public HTMLCharacterRequest(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name){
return filter(super.getParameter(name));
}
/**
* 过滤请求参数值
* @param parameter
* @return
*/
private String filter(String parameter) {
if(StringHelper.isNullOrEmpty(parameter)){
return null;
}
return StringEscapeUtils.escapeSql(StringHelper.unescape(parameter));
}
}
StringHelper.unescape()方法内容如下:
public static String unescape(String src) {
StringBuffer tmp = new StringBuffer();
tmp.ensureCapacity(src.length());
int lastPos = 0, pos = 0;
char ch;
while (lastPos < src.length()) {
pos = src.indexOf("%", lastPos);
if (pos == lastPos) {
if (src.charAt(pos + 1) == 'u') {
ch = (char) Integer.parseInt(
src.substring(pos + 2, pos + 6), 16);
tmp.append(ch);
lastPos = pos + 6;
} else {
ch = (char) Integer.parseInt(
src.substring(pos + 1, pos + 3), 16);
tmp.append(ch);
lastPos = pos + 3;
}
} else {
if (pos == -1) {
tmp.append(src.substring(lastPos));
lastPos = src.length();
} else {
tmp.append(src.substring(lastPos, pos));
lastPos = pos;
}
}
}
return tmp.toString();
}
这样做完之后,前端传递过来的escape("xxx") 就可以在Controller中可以使用request.getParameter("xxx")的形式获取到解码之后并且对数据库操作无影响的字符串了。
截图如下:
可以看到request的真正类型是 HTMLCharacterRequest ,并且 通过 request.getParameter("provinceName") 获取到的值 也是 解码并且对数据库无影响的值。
但是,这个时候就有个问题了,如下:
方法参数列表中 使用 @RequestParam 获取到的参数 却是未解码的。
为什么呢???
后来跟踪Annotation源码发现了如下的一段代码:
(详见:org.springframework.web.bind.annotation.support.HandlerMethodInvoker 的 resolveRequestParam方法)
if (paramValue == null) {
String[] paramValues = webRequest.getParameterValues(paramName);
if (paramValues != null) {
paramValue = (paramValues.length == 1 ? paramValues[0] : paramValues);
}
}
if (paramValue == null) {
if (defaultValue != null) {
paramValue = resolveDefaultValue(defaultValue);
}
else if (required) {
raiseMissingParameterException(paramName, paramType);
}
paramValue = checkValue(paramName, paramValue, paramType);
}
由此发现,在源码中是使用 getParameterValues 方法来获取参数值的,而不是 getParameter方法
所以需要在 HTMLCharacterRequest 中再 @override 一下 getParameterValues 的方法:
@Override
public String[] getParameterValues(String name) {
return filter(super.getParameterValues(name));
}
/**
* 过滤请求参数值
* @param parameters
* @return
*/
private String[] filter(String[] parameters) {
if(parameters.length == 0){
return null;
}
for (int i=0; i<parameters.length; i++) {
parameters[i] = StringEscapeUtils.escapeSql(StringHelper.unescape(parameters[i]));
}
return parameters;
}
这个时候再来看 @RequestParam 注解的参数值 就是 解码之后的了: