© 2006 版权声明
1. 本文作者为 javafuns
2. 本文可经/不经作者许可,任意转载
3. 转载时请表明原作者及修改者,并附带本版权声明
4. 本文未经实践检验,故对由采用本文所述操作而引起的任何后果,本文作者均不作任何担保,亦不承担任何责任
做过web开发的人可能都有这种感觉,不时的需要从request中提取参数及数据,如果有一种方式可以省却这一步骤,是否会令你的开发工作更愉悦呢?本文在此做了如下的探讨。
很显然,从request中提取参数需要一个尽职尽责的,但是又很优雅的让我们感觉不到它的辛苦工作的模块来实现,它的任务就是,1)截取所有的request,2)从request取出数据并填充到bean留给其他人使用。大概你也会想到Filter,它的特性符合要求。
Filter截取了请求如何处理呢? 我想到了2种方式(当然,还有其它的),
1)request参数需要指明本次提交的数据要填充至哪个bean,且参数与bean的field严格匹配,这样利用 Reflection ,取出bean的field,然后从request.getParameter(field)取得数据进行填充。
2)采取配置文件进行request 的form数据到bean的映射,方式也是采用Reflection来完成填充工作。
2种方式各有优缺点,方式1不够灵活,方式2则对于某些人看来则是烦琐,毕竟还需要配置,也失去了本文简化request form处理的目的。因此本人推荐第一种方式,即使存在某些情况,也可以在bean中增加新方法来处理。
数据的有效性检查也放在bean里做,将数据无效的信息放在bean的error hashmap里,在filter填充完bean后,检查bean是否有效,有无效的数据,则直接返回客户端;否则,调用chain.doFilter(request, response)继续处理,并将这个bean放入ThreadLocal中,留待后续class访问,当这个线程结束后,bean会被垃圾收集器清除。
Filter样例:
/*
* SimpleFilter.java
*
* Created on 2006年9月20日, 下午2:54
*/
package org.openthoughts.testings;
import Java.io.*;
import Java.lang.reflect.Field;
import Java.lang.reflect.InvocationTargetException;
import Java.lang.reflect.Method;
import Java.util.HashMap;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.openthoughts.util.Form2BeanUtil;
/**
* Stuff a bean specified by request with form data.
*
* @author <a href="guangquanzhang@gmail.com">javafuns</a>
* @version
*/
public class SimpleFilter implements Filter {
// The filter configuration object we are associated with. If
// this value is null, this filter instance is not currently
// configured.
private FilterConfig filterConfig = null;
public SimpleFilter() {
}
/**
* Init method for this filter
*
*/
public void init(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
}
/**
* Do actual work for filling.
*
* @param request The servlet request we are processing
* @param result The servlet response we are creating
* @param chain The filter chain we are processing
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet error occurs
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
String beanName = ((HttpServletRequest)request).getParameter("formbean");
System.err.println(" form bean is " + beanName);
Class beanClazz = null;
Object beanObject = null;
boolean isValid = false;
if(beanName != null) {
try {
beanClazz = Class.forName(beanName);
if(beanClazz != null) {
beanObject = beanClazz.newInstance();
}
} catch (ClassNotFoundException ex) {
request.setAttribute("MainErrMsg", beanName + " not found");
this.filterConfig.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
return;
} catch (InstantiationException ex) {
request.setAttribute("MainErrMsg", beanName + " can not be instantiated");
this.filterConfig.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
return;
} catch (IllegalAccessException ex) {
request.setAttribute("MainErrMsg", beanName + " not access");
this.filterConfig.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
return;
}
}
if(beanObject != null) {
Field[] fields = beanClazz.getDeclaredFields();
for(Field field : fields) {
Method beanMethod = null;
String fieldName = field.getName();
String fieldValue = ((HttpServletRequest)request).getParameter(fieldName);
StringBuilder sb = new StringBuilder();
sb.append("set");
sb.append(fieldName.substring(0, 1).toUpperCase());
sb.append(fieldName.substring(1));
try {
beanMethod = beanClazz.getDeclaredMethod(sb.toString(), String.class);
} catch (SecurityException ex) {
request.setAttribute("MainErrMsg", " Security reason ");
this.filterConfig.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
return;
} catch (NoSuchMethodException ex) {
request.setAttribute("MainErrMsg", beanName + " does not have method named " + sb.toString());
this.filterConfig.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
return;
}
if(beanMethod != null) {
try {
beanMethod.invoke(beanObject, fieldValue);
} catch (IllegalArgumentException ex) {
request.setAttribute("MainErrMsg", "illegal argument for the method " + sb.toString() + " of " + beanName);
this.filterConfig.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
return;
} catch (InvocationTargetException ex) {
request.setAttribute("MainErrMsg", beanName + " invoke target exception ");
this.filterConfig.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
return;
} catch (IllegalAccessException ex) {
request.setAttribute("MainErrMsg", beanName + " illegal access to " + sb.toString());
this.filterConfig.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
return;
}
}
}
Form2BeanUtil.put(beanObject);
Method getAllErrors = null;
try {
getAllErrors = beanClazz.getDeclaredMethod("getAllErrors");
} catch (SecurityException ex) {
System.err.println("Security exception when call getAllErrors()");
} catch (NoSuchMethodException ex) {
System.err.println("No such method named getAllErrors()");
}
if(getAllErrors != null) {
try {
isValid = ((HashMap)getAllErrors.invoke(beanObject)).isEmpty();
} catch (IllegalArgumentException ex) {
System.err.println("Illegal argument for getAllErrors()");
} catch (IllegalAccessException ex) {
System.err.println("Illegal Access to getAllErrors()");
} catch (InvocationTargetException ex) {
System.err.println("Invocation target exception");
}
}
}
if(beanName == null || isValid) {
chain.doFilter(request, response);
} else {
if(beanObject != null) {
request.setAttribute("formbean", beanObject);
}
this.filterConfig.getServletContext().getRequestDispatcher(getRequestURI(request)).forward(request, response);
}
}
/**
* Destroy method for this filter
*
*/
public void destroy() {
}
public String getRequestURI(ServletRequest request) {
String requestURI = ((HttpServletRequest)request).getRequestURI();
String queryString = ((HttpServletRequest)request).getQueryString();
return requestURI + queryString;
}
/**
* Return a String representation of this object.
*/
public String toString() {
if (filterConfig == null) return ("SimpleFilter()");
StringBuffer sb = new StringBuffer("SimpleFilter(");
sb.append(filterConfig);
sb.append(")");
return (sb.toString());
}
}
Bean样例:
/*
* SimpleBean.java
*
* Created on 2006年9月20日, 下午5:51
*/
package org.openthoughts.beans;
import Java.io.Serializable;
import Java.util.HashMap;
/**
* @author Administrator
*/
public class SimpleBean implements Serializable {
private String userName;
private String password;
public SimpleBean() {
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
//错误信息
public HashMap getAllErrors() {
return new HashMap();
}
}
ThreadLocal实现:
/*
* Form2BeanUtil.java
*
* Created on 2006年9月20日, 下午4:51
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package org.openthoughts.util;
/**
* Hold formbean for appropriate thread via ThreadLocal.
*
* @author <a href="guangquanzhang@gmail.com">javafuns</a>
*/
public class Form2BeanUtil {
private static final ThreadLocal container = new ThreadLocal();
/**
* Put the form bean to ThreadLocal.
*/
public static void put(Object object) {
container.set(object);
}
/**
* Get the current thread's form bean.
*/
public static Object get() {
return container.get();
}
}
PS: 类似的方式在很多框架都有实现,比如struts的formbean