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

26 篇文章 0 订阅

(这是我的第五次反馈)
本次所上的内容是:
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);//把数据写到这个字节数组中
    }

}

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

这里写图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Elong_Hu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值