Java过滤器高级案例之装饰器模式

基础

装饰器模式(包装模式)简单来说就是扩展原有类的原有方法,其他详细内容这里不做过多说明

这里用两个案例讲解:

1.目标:扩展数据库连接的close方法,不要关闭连接,要还回池中(模拟连接池)

//java.sql.Connection:被包装类

//自己写的:包装类 MyConnection1

//a、编写包装类,实现与被包装类相同的接口(使他们有相同的行为)

//b、定义一个变量,引用被包装的对象(记住原有对象的信息)

//c、定义包装类的构造方法,传入被包装对象的引用(给b赋值)

//d、对于要改写的方法(比如close),编写你自己的代码即可(功能的扩展)

//e、对于不需要改写的方法,调用原有对象的。

public class MyConnection1 implements Connection {
    private Connection conn;//原来的conn,针对所有的驱动
    private LinkedList<Connection> pool;//原来的池
    public MyConnection1(Connection conn,LinkedList<Connection> pool) {
        this.conn = conn;
        this.pool = pool;
    }
    //还回池中
    public void close() throws SQLException{
        pool.addLast(conn);
    }

确认包装的法宝:System.out.println(*.class.getName());打印看看

2.IO流中的装饰器模式

建立BufferedReaderDemo

public class BufferedReaderDemo {
    public static void main(String[] args) throws IOException {
        //记住,不能加/
        Reader r = new FileReader("src/com/itheima/filter/FilterDemo.java");
        BufferedReader br = new BufferedReader(r);
        MyBufferedReader mbr = new MyBufferedReader(br);
        String str = null;//记录读到的数据
        while((str=mbr.readLine())!=null){
            System.out.println(str);
        }
        mbr.close();
    }
}

建立MyBufferedReader包装类

//包装五步之一,实现被包装相同的接口
public class MyBufferedReader extends BufferedReader {
    private int linenum=1;//行号
    //包装五步之二,引用被包装的对象
    private BufferedReader br;
    //包装五步之三,构造函数传入被包装类的对象
    public MyBufferedReader(BufferedReader br){
        super(br);
        this.br=br;
    }
    //包装五步之四,改写需要修改的方法
    //先拿到原有对象的放回值,然后再做判断后进行包装
    public String readLine() throws IOException {
        String str = br.readLine();
        if(str==null)
            return null;
        if(linenum<10)
            return linenum++ +"  "+":"+str;
        if(linenum>9&&linenum<100)
            return linenum++ +" "+":"+str;
        return linenum++ +":"+str;
    }
    //包装五步之五,不需要改写的方法调用原有对象
}

如果上面的内容理解了,相信下面的例子也能很好理解,接下来讲解Java中的过滤器高级案例,这里应用到了上面的装饰器模式!

过滤器中的装饰器模式

案例一:全站乱码解决(get+post)

建立AllCharacterEncodingFilter

//实现解决全站乱码问题的过滤器
public class AllCharacterEncodingFilter implements Filter {
    private String encoding = "UTF-8";//设置默认编码
    public void init(FilterConfig filterConfig) throws ServletException {
        //获取配置文件中的信息,初始化信息encoding的值
        String value = filterConfig.getInitParameter("encoding");
        if(value!=null){
            encoding = value;
        }
    }
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
        //必须转成HTTP协议的request类,因为放行后的servlet有可能会使用http协议的方法
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        //解决POST请求参数中文编码问题
        request.setCharacterEncoding(encoding);
        //输出编码及通知客户端编码
        response.setCharacterEncoding(encoding);
        response.setContentType("text/html;charset="+encoding);
        //写一个包装类,对request进行包装,包装类必须把被包装的对象传进来;
        MyHttpServletRequest mrequest = new MyHttpServletRequest(request);
        chain.doFilter(mrequest, response);
    }
    public void destroy() {
    }
}
class MyHttpServletRequest extends HttpServletRequestWrapper{
    private HttpServletRequest request;//引用原有对象
    public MyHttpServletRequest(HttpServletRequest request) {
        super(request);
        this.request=request;
    }
    //覆盖方法
    public String getParameter(String name) {
        //获取name的值,后续使用
        String value = request.getParameter(name);
        if(value==null){
            return null;
        }
        //只解决GET请求参数编码问题        //获取提交方式
        String method = request.getMethod();
        //因为浏览器提交的方法名大小写不同,所以比较的时候需要忽略大小写
        if("get".equalsIgnoreCase(method)){
            try {
                //Tomcat的默认编码是ISO-8859-1,所以设置编码的时候需要注意
                value = new String(value.getBytes("ISO-8859-1"), request.getCharacterEncoding());
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return value;
    }
}

设置配置文件

 <filter>
        <filter-name>AllCharacterEncodingFilter</filter-name>
        <filter-class>com.itheima.filter.AllCharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>AllCharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping> 

 

案例二:脏话过滤器

DirtyWordsFilter(注意要有解决全站乱码的过滤器)

public class DirtyWordsFilter implements Filter {
    public void destroy() {
    }
    public void doFilter(ServletRequest arg1, ServletResponse arg2,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) arg1;
        HttpServletResponse response = (HttpServletResponse) arg2;
        //对request进行包装,过滤
        DwHttpServletRequest dwrequest = new DwHttpServletRequest(request);
        chain.doFilter(dwrequest, response);
    }
    public void init(FilterConfig filterConfig) throws ServletException {
    }
}
class DwHttpServletRequest extends HttpServletRequestWrapper{
    private HttpServletRequest request;
    public DwHttpServletRequest(HttpServletRequest request){
        super(request);
        this.request = request;
    }
    public String getParameter(String name) {
        String value = request.getParameter(name);
        if(value==null){
            return null;
        }//定义脏话字典
        String[] dws = new String[]{"畜生","禽兽"};
        for(String s:dws){
            //判断value里面是否包含脏话字典里的词
            if(value.contains(s)){
                //
                value = value.replace(s, "**");
            }
        }
        return value;
    }
}

案例三:全站压缩

注意在进行配置文件设置的时候,只需要设置和文本相关的*.jsp;.html,.js;*.css

public class GzipFilter implements Filter {
    public void destroy() {
    }
    public void doFilter(ServletRequest arg1, ServletResponse arg2,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) arg1;
        HttpServletResponse response = (HttpServletResponse) arg2;
        GzipHttpServletResponse gresponse = new GzipHttpServletResponse(response);
        chain.doFilter(request, gresponse);
        //获取原始字节,进行压缩
        byte[] b = gresponse.getBufferData();
        System.out.println("压缩前的大小:"+b.length);//测试用
        //建立一个byte[]输出流,关联到Gzip压缩流
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        //Gzip流需要一个字节输出流来关联,压缩流内的数据
        GZIPOutputStream gos = new GZIPOutputStream(baos);
        gos.write(b);
        gos.close();
        b = baos.toByteArray();//取出缓存中被压缩后的数据
        System.out.println("压缩有的大小:"+b.length);
        //告知浏览器压缩方式,就是设置头
        response.setHeader("Content-Encoding", "gzip");
        response.getOutputStream().write(b);
    }
    public void init(FilterConfig filterConfig) throws ServletException {
    }
}
class GzipHttpServletResponse extends HttpServletResponseWrapper{
    private ByteArrayOutputStream baos = new ByteArrayOutputStream();
    private PrintWriter pw;
    public GzipHttpServletResponse(HttpServletResponse response) {
        super(response);
    }
    //servlet是使用getOutputStream获取流输出的
    //覆盖这个方法,把数据写到一个缓存中,就可以进行获得数据
    public ServletOutputStream getOutputStream() throws IOException {
        ServletOutputStream sos = super.getOutputStream();
        MyServletOutputStream msos = new MyServletOutputStream(sos,baos);
        return msos;
    }
    //1如果是字符流则转成字符流,2把数据弄到baos中去
    //查看API文档,PrintWriter的构造函数可以直接调用字符流进行输出
    public PrintWriter getWriter() throws IOException {
        pw = new PrintWriter(new OutputStreamWriter(baos, super.getCharacterEncoding()));
        return pw;
    }
    public byte[] getBufferData() {
        try {
            //关闭Printwriter流
            if(pw!=null)
                pw.close();
            baos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return baos.toByteArray();
    }
}
class MyServletOutputStream extends ServletOutputStream{
    private ServletOutputStream sos;
    private ByteArrayOutputStream baos;
    public MyServletOutputStream(ServletOutputStream sos,ByteArrayOutputStream baos){
        this.sos = sos;
        this.baos = baos;
    }
    public void write(int b) throws IOException {
        baos.write(b);
    }
}

案例四:对于常用的动态资源生成的结果进行缓存

web.xml配置 CacheResultFilter

只为category.jsp服务

建立CacheResultFilter 过滤器

建立cache HashMap。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Apple_Web

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

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

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

打赏作者

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

抵扣说明:

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

余额充值