当我们在做web应用的时候都会处理客户端提交到服务器的数据,如去除前后空格,一些非常字符,SQL注入类似的东西,在这里我主要说前后空格我是怎么来解决的,其它也都可以照此方法快速、方便、有效的解决,但是我一般对于非法字符,都是采用了标签来解决它的,并没有使用Filter转义掉(纯属个人解决办法)。
去除前后空格看似非常简单的事,但是有许多人可能就是因为这一个小问题,折磨自己半天,客户端提交到所有的东西,都是以字符串形式提交的,我们不知道客户是怎么操作的,他可能把一个age属性对应的值,在输入时多加了一个空格,而服务器age对应的却是Integer类型,如果你使用servlet这事也好解决,但是如果你使用的是MVC框架,自动封装时就会得到一个类型转换异常,然而这个时候你是否有好的解决办法呢?
这里我使用Filter来解决这一问题,这是最简单方便有效的解决方式,因为你不需要对每一个属性在封装前都去trim(),因为这是一件非常乏味的事情。大家都知道filter可以过滤我们想要它过滤的每一个请求,在这请求中有
HttpServletRequest、HttpServletResponse。我们知道服务器取得客户端发送的参数都是通过HttpServletRequest来获取的,那我们可不可以在使用HttpServletRequest取值的时候就为每一个客户端提交的属性去除前后空格,或者其它的一些过滤操作。这肯定是可以的,那我们先来了解一下服务器是怎么取得客户端的值的。
1.getParameter(name),返回单个值。
2.getParameterValues(name),返回一个数组。
3.getParameterMap(),把客户端提交参数封装为一个Map返回。K:name,V:value。
当我们使用servlet的时候一般都是使用前两种,struts1使用的第2种,struts2(xwork)则使用的第3种,那么我们只要在这三个方法调用的时候处理前后空格,那么返回到服务器的参数就又减少了一分出bug的机会,看下面的实现。
public class RequestParameterFilter implements Filter {
private static Log log = LogFactory.getLog(RequestParameterFilter.class);
private List<String> excludeNames;
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//
request = new HttpServletRequestWrapper2((HttpServletRequest) request);
chain.doFilter(request, response);
}
public void init(FilterConfig config) throws ServletException {
String exclude = config.getInitParameter("exclude");
// not is null.
if (exclude != null && exclude.length() > 0) {
excludeNames = Arrays.asList(exclude.split(","));
if (log.isDebugEnabled()) {
log.debug("initialize arguments.");
}
}
}
/**
* 该类继承之HttpServletRequestWrapper,并重写了对应取得客户端相当参数值的所有的方法。
* <ul>
* <li>getParameter</li>
* <li>getParameterValues</li>
* <li>getParameterMap</li>
* </ul>
*
* @version 1.0/2010-6-10 上午11:25:47
* @author Aidan
* @see HttpServletRequestWrapper
*/
private class HttpServletRequestWrapper2 extends HttpServletRequestWrapper {
private ParameterMap2 pm2;
public HttpServletRequestWrapper2(HttpServletRequest request) {
super(request);
}
public String getParameter(String name) {
if (excludeNames != null && excludeNames.contains(name)) {
return super.getParameter(name);
}
return trim(super.getParameter(name));
}
@SuppressWarnings("unchecked")
public Map getParameterMap() {
// xwork便使用此方法取值
// 该方法返回一个Map,Map映射了客户端请求对应的键值(K,V)。
if (pm2 == null) {
pm2 = new ParameterMap2(super.getParameterMap());
}
return pm2;
}
public String[] getParameterValues(String name) {
// Struts1使用此方法取得所有的参数值
if (excludeNames != null && excludeNames.contains(name)) {
return super.getParameterValues(name);
}
return (String[]) trim(super.getParameterValues(name));
}
}
/**
* 该此继承自HashMap。
*
* @version 1.0/2010-6-10 上午11:30:13
* @author Aidan
* @see HashMap
*/
@SuppressWarnings( { "unchecked", "serial" })
private class ParameterMap2 extends HashMap {
private Set entrySet;
/**
* 若要构造此类对象,则需要传入一个map参数,该map对应的客户端请求的参数(K,V)。
*
* @param map
* 映射客户端参数。
*/
public ParameterMap2(Map map) {
super(map);
}
public Set entrySet() {
// xwork使用了此方法取值
if (entrySet == null) {
entrySet = new HashSet();
Set temSet = super.entrySet();
for (Iterator iterator = temSet.iterator(); iterator.hasNext();) {
Map.Entry me = (Map.Entry) iterator.next();
Entry2 entry = new Entry2(me);
entrySet.add(entry);
}
}
return entrySet;
}
// 若直接从map使用key取得
public Object get(Object key) {
Object value = super.get(key);
// 不过滤此对象
if (excludeNames != null && excludeNames.contains(key)) {
return value;
}
if (value != null) {
return trim(value);
}
return null;
}
}
@SuppressWarnings("unchecked")
private class Entry2<K, V> implements Map.Entry<K, V> {
private Map.Entry me;
private boolean isTrim = true;
public Entry2(Map.Entry me) {
if (me == null) {
throw new IllegalArgumentException(
"Map.Entiry argument not null.");
}
this.me = me;
// 不过滤此对象
if (excludeNames != null && excludeNames.contains(me.getKey())) {
isTrim = false;
}
}
public K getKey() {
return (K) me.getKey();
}
public V getValue() {
if (isTrim) {
return (V) trim(me.getValue());
}
return (V) me.getValue();
}
public V setValue(V value) {
return (V) me.setValue(value);
}
}
/**
* 去除一个Object类型对应的前后空格,因为客户端提交参数有两种,一种:String,另一种:String[],此方法会自动判断调用哪个方法。
*
* @param value
* 需要处理的参数。
* @return 处理后的值。
*/
protected Object trim(Object value) {
if (value instanceof String[]) {
return trim((String[]) value);
}
return trim(value.toString());
}
/**
* 去除某个字符串的前后空格。
*
* @param value
* 需要处理的参数。
* @return 处理后的值。
*/
protected String trim(String value) {
if (value != null && value.length() > 0) {
return value.trim();
}
return value;
}
/**
* 去除某个数组中所有的值的前后空格。
*
* @param values
* 需要处理的数组。
* @return 处理后的值,当数组的length为1时,则返回一个String,反之返回一个数组。
*/
protected Object trim(String[] values) {
if (values != null && values.length > 0) {
int len = values.length;
for (int i = 0; i < len; i++) {
values[i] = trim(values[i]);
}
}
if (values.length == 1) {
return values[0];
}
return values;
}
/**
*
* @return 不处理的对象。
*/
public List<String> getExcludeNames() {
return excludeNames;
}
}
这个Filter实现原理非常简单,我会过滤所有的请求,HttpServletRequestWrapper2继承自HttpServletRequestWrapper,在构造函数中需要一个HttpServletRequest对象(这个request是web窗口创建的),然后我重载了上面所说的3个方法,在方法内部每次会去过滤当前值,这是利用了Java多态特性。在使用getParameterMap时较为麻烦,原理一样。
当然我们有时候可能有些特殊情况不需要过滤前后空格或者其它一些规则,这里我们可以使用exclude属性来判断是否过滤此属性。
DEMO:
<form action="test!create.action" method="post">
name:
<input name="name" value=" My name is haha.. " />
<br />
<!-- This is a String,isn't number. -->
age:
<input name="age" value=" 15 " />
<br />
email:
<input name="email" value=" grasszring@gmail.com " />
<br />
email2:
<input name="email" value=" grasszring@foxmail.com " />
<br />
<input type="submit" value=" submit " />
</form>
web.xml
<filter>
<filter-name>requestParameter</filter-name>
<filter-class>com.onlyeffort.commons.web.filter.RequestParameterFilter</filter-class>
<init-param>
<!-- 不需要过滤此参数 -->
<param-name>exclude</param-name>
<param-value>email</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>requestParameter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
action
@Action(params = { "actionName", "test" })
@Result(location = "http://www.google.com", type = "redirect")
@SuppressWarnings("serial")
public class TestController extends ActionSupport {
private String name;
private Integer age;
private String[] email;
//.. get set method.
@Override
public String create() throws CreateFailureException {
System.out.println(name);
System.out.println(age);
for (String mail : email) {
System.out.println(mail);
}
return SUCCESS;
}
}
OK,如果大家有什么问题或有什么意见都尽管留言,感激不尽。
转载时请注明转载地址,onlyeffort.QQ:501276913
posted on 2010-06-10 14:45
Aidan 阅读(2210)
评论(7) 编辑 收藏