动态代理技术在JavaWeb中的应用

来源:互联网 发布:中国知网数据库查重 编辑:程序博客网 时间:2024/06/05 15:32

(这是我的第五次反馈)
本次所上的内容是:
1.用动态代理技术解决全站乱码问题
2.用动态代理技术解决压缩输出问题

1.1用动态代理技术解决全站乱码问题思路
在这里我们用到了JavaWeb中的Filter技术
在以前我们在Filter中放行的时候所传的对象是HttpServletRequest和HttpServletResponse,通过这两个对象直接设置编码会解决全站的post请求的乱码
而单单靠这两个原始对象不能解决get请求的乱码
通过动态代理技术我们可以产生一个request的代理对象,通过这个代理对象中的方法可以对getParameter方法进行拦截
然后再将得到的数据进行手动转换
最后放行,解决全站乱码问题

核心代码如下:

package filter;import java.io.IOException;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;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 javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class CharacterEncodingFilter implements Filter{    @Override    public void doFilter(ServletRequest req, ServletResponse res,            FilterChain chain) throws IOException, ServletException {        //解决了post请求下的乱码问题        final HttpServletRequest request = (HttpServletRequest) req;        HttpServletResponse response = (HttpServletResponse) res;        request.setCharacterEncoding("UTF-8");        response.setCharacterEncoding("UTF-8");        response.setContentType("text/html;character=UTF-8");        //在Filter放行之前我们要对request包装一把来对get请求拦截处理        chain.doFilter((ServletRequest) Proxy.newProxyInstance(CharacterEncodingFilter.class.getClassLoader(),request.getClass().getInterfaces(),new InvocationHandler() {            @Override            public Object invoke(Object proxy, Method method, Object[] args)                    throws Throwable {                if(!method.getName().equals("getParameter")){                    return method.invoke(request, args);                }                if(!request.getMethod().equalsIgnoreCase("get")){                    return method.invoke(request, args);                }                //到了这里肯定就是get方法所带过来的数据                String value = (String) method.invoke(request, args);//手动转换                if(value == null){                    return null;                }                return new String(value.getBytes("iso8859-1"),"UTF-8");            }        }), response);    }    @Override    public void init(FilterConfig arg0) throws ServletException {    }    @Override    public void destroy() {    }}

2.1解决压缩输出问题的思路
首先我们要压缩的数据是来自于服务器端的
servlet会通过response给客户机输出数据
而重点就是response会直接给客户机输出数据不会压缩之后输出数据
在此我们又用到了Filter(拦截器)对输出的数据进行拦截然后压缩打给客户机以减少流量

具体来说response输出数据的方式有两种 getWriter和getOutPutStream

其中getOutPutStream得到的对象自己没有带缓冲流所以我们先要new一个缓冲流对象
然后重写它的write方法,让数据写到我们所new的缓冲流对象中然后压缩输出给客户机

然后getWriter得到的对象自己带有缓冲流
所以我们用OutputStreamWriter作为桥梁来将数据写到我们自己的缓冲流中
最后一并压缩输出

具体的思路见代码

package filter;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.zip.GZIPOutputStream;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletOutputStream;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpServletResponseWrapper;public class GzipFilter implements Filter {    @Override    public void doFilter(ServletRequest req, ServletResponse res,            FilterChain chain) throws IOException, ServletException {        final HttpServletRequest request = (HttpServletRequest) req;        final HttpServletResponse response = (HttpServletResponse) res;        final ByteArrayOutputStream bout = new ByteArrayOutputStream();        final PrintWriter pw = new PrintWriter(new OutputStreamWriter(bout,"UTF-8"));        chain.doFilter(request, (ServletResponse) Proxy.newProxyInstance(GzipFilter.class.getClassLoader(),response.getClass().getInterfaces(),new InvocationHandler() {            @Override            public Object invoke(Object proxy, Method method, Object[] args)                    throws Throwable {                if(method.getName().equalsIgnoreCase("getWriter")){                    return pw;                }else if(method.getName().equalsIgnoreCase("getOutPutStream")){                    //返回我们的自定义流                    return new MyOutputStream(bout);                }else{                    return null;                }            }        }));        pw.close();//让pw的数据释放确保都到了bout里面        byte[] result = bout.toByteArray();//让流中的数据还原到一个比特数组中准备压缩输出        System.out.println("原始大小:"+result.length);        ByteArrayOutputStream bout2 = new ByteArrayOutputStream();//它是存储压缩后的数据的        GZIPOutputStream gzip = new GZIPOutputStream(bout2);//写到Bout的缓存里面        gzip.write(result);//这就是那个压缩过程        gzip.close();//保证写到了bout2里面        result = bout2.toByteArray();//bout2还原数据        System.out.println("压缩后的数据大小:"+result.length);        response.setHeader("content-encoding","gzip");        response.setContentLength(result.length);        response.getOutputStream().write(result);    }    @Override    public void init(FilterConfig arg0) throws ServletException {        // TODO Auto-generated method stub    }    @Override    public void destroy() {        // TODO Auto-generated method stub    }}class MyOutputStream extends ServletOutputStream{    private ByteArrayOutputStream bout = new ByteArrayOutputStream();    public MyOutputStream(ByteArrayOutputStream bout) {        this.bout = bout;    }    @Override    public void write(int b) throws IOException {        bout.write(b);//把数据写到这个字节数组中    }}

在此特别感谢方立勋老师!

这里写图片描述