最近做项目时,页面传递给后台的特殊字符很烦人,想写一个公共方法来给需要使用的地方调用,但是后来发现,要调用的地方实在太多,万一有什么变动的话,改起来烦死人。后来发现使用过滤器可以完成这个功能。
过滤器中的主要代码如下:
@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
这个时候再来看 @RequestParam 注解的参数值 就是 解码之后的了: