【文章标题】用Java代理技术改造HttpServletRequest类
【文章作者】曾健生
【作者邮箱】zengjiansheng1@126.com
【作者QQ】190678908
【作者声明】本人水平有限,失误之处,敬请各位指出。
*******************************************************************************
开发论坛中的模块通常有要解决以下两个问题:
1. 用户的发帖内容可能有一些特殊字符需要进行处理,如HTML的标记,又例如在04闹得沸沸扬扬的“SQL注入漏洞”,就是由于没有对用户提交的数据进行严格的检查而造成的。
2. 为了建设一个良好的论坛环境,防止用户输入不雅的文字,不然会影响论坛的气氛。
针对以上两个需要,可以对用户的提交信息进行过滤。
在JavaWeb开发中,获取用户通过表单提交的信息一般的途径是使用request. getParameter函数获取提交的内容,接着就对所获取的字符串进行过滤,但这种做法做有一个问题:如果有多处需要进行过滤字符串的操作,难道每次都要重复写吗?有没有更方便的方法?
能否改造HttpServletRequest类,使得能先过滤getParameter函数获取的字符串后返回过滤后的结果呢?理论上没问题的,有一种设计模式叫“Decorator(装饰器)”模式(在本人的博文《打造山寨产品和伪造品的利器——装饰模式》对这种模式进行了讨论(http://blog.csdn.net/newjueqi)),初想一下能解决这个问题。于是就按照装饰器模式的方法进行改造。结果类的框架刚好搭建完毕就傻了眼,为啥,请看图1:
图1
图1只显示了MyHttpServletRequest_temp类需要实现包装的函数的一部分,总共有几十个函数需要重新包装一下,但本人想改写的只是函数getParameter,难道为了重写这个方法就要把另外的几十个函数写一遍!
幸好JDK中有一门技术叫“动态代理”(Proxy),利用它能方便地实现我们的需求,使用动态代理能在普通方法调用前后增加处理方法,现在的AOP(Aspect Orient Program, 面向切面编程)就是以动态代理为基础的。
动态代理类主要的方法:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
这个函数就是创建一个动态类的实例,各个参数的含义如下:
ClassLoader loader :类加载器对象
Class<?>[] interfaces:所实现的接口的Class对象
InvocationHandler h:这个是很重要的参数,定义了一个接口,实现其中的方法
,能进行的具体代理操作。
编写后的完整的代码如下:
package newjueqi.net.csdn.filter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.servlet.http.HttpServletRequest;
/**
* 本类通过动态代理实现了对httpServletRequest中用getParameter函数获取的文字信息
* 进行过滤
*
*/
public class MyHttpServletRequest implements InvocationHandler {
//被代理的类的引用
private HttpServletRequest httpServletRequest;
//传入需要被代理的类
public MyHttpServletRequest( HttpServletRequest httpServletRequest)
{
this.httpServletRequest=httpServletRequest;
}
//获取动态代理实例
public HttpServletRequest getInstance()
{
HttpServletRequest Request=null;
Request=(HttpServletRequest)Proxy.
newProxyInstance(MyHttpServletRequest.class.getClassLoader(),
httpServletRequest.getClass().getInterfaces(),
this );//自身实现了InvocationHandler接口,所以传this
return Request;
}
/*
* 过滤getParameter函数获取的文字信息
*/
@Override
public Object invoke(Object obj, Method method, Object[] arg)
throws Throwable {
String value=null;
Object result=null;
//判断当前被调用的方法是否getParameter,如果是就进行信息过滤
if( method.getName().equals("getParameter") )
{
value=httpServletRequest.getParameter( (String)arg[0]);
//把“bad”替换为"***"
value=value.replaceAll("bad", "***");
//返回替代后的结果
result=value;
}
else //如果不是调用方法“getParameter”就不正常处理
{
result=method.invoke( httpServletRequest, arg );
}
return result;
}
}
写了一个简单的页面测试,表单传递的信息含有需要过滤的字符”bad”,如图2:
图2
过滤后的信息如图3所示:
图3
效果还是不错的^-^
当然了,这个类的过滤功能还可以进一步改进,例如把需要过滤的文字信息写在一个配置文件中,就能方便地维护。