以处理http请求乱码为例,略解web过滤器和装饰者模式

 一.过滤器

  1.概念

         JavaWeb中的过滤器的概念: 对请求和响应进行拦截或者增强的对象,就是过滤器。

         Filter接口:功能——对请求和响应进行增强,或者进行拦截。

                             

  2.filter入门

  2.1 filter的定义及创建

 创建一个类,实现过滤器接口:

package cn.itcast.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
 * 
 * Filter 是在 Web 应用程序的部署描述符中配置的
 * 
 * 部署描述符:web.xml
 * 
 * 定义一个过滤器:
 * 第一步:创建一个类,实现过滤器接口
 * 第二步:具体需要执行的过滤任务,写在doFilter
 * 第三步:过滤器需要在web.xml中配置
 * */
public class MyFilter implements Filter{

    /**
     * 初始化方法
     * */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
    }

    /**
     * 执行过滤任务的方法
     * */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        System.out.println("MyFilter....doFilter.....");
        
    }
    /**
     * 销毁的方法
     * */
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }

}

 

 

 

 在web.xml文件中配置过滤器:

<filter>
      <filter-name>MyFilter</filter-name>
      <filter-class>cn.itcast.filter.MyFilter</filter-class>
  </filter>
  
  <filter-mapping>
      <filter-name>MyFilter</filter-name>
      <url-pattern>/1.txt</url-pattern>
  </filter-mapping>

 

 

  当我们访问项目根目录下的1.txt时就会触发过滤器:

 

2.2 filterChain过滤器放行对象

执行chain.doFilter后,就能访问到目标资源

2.3过滤器执行过程

 3.过滤器配置详解

 3.1url-pattern设置

  •   全路径配置

          地址栏:localhost:8080/项目根路径/资源路径  localhost:8080/itcast-filter2/1.txt

  •   通配符的匹配

         地址栏:localhost:8080/项目根路径/abc/*

       以上两种匹配方式,配置路径的时候必须以”/”开头

  •   后缀名匹配

         /路径/*.do:    *.do *.txt  *.action

         地址栏:localhost:8080/项目根路径/*.txt

         后缀名匹配方式,配置路径的时候不能以”/”开头

 

         web.xml配置

  •  servletName匹配  

   

   Filter的url-pattern配置与servlet一致。

   过滤器执行的顺序是按照,web.xml中filter-mapping标签的书写顺序执行(从上往下执行)

 二.装饰者模式

    1.装饰者模式设计概要

  •  定义一个类,实现被装饰对象的接口
  • 定义一个成员变量,记住被装饰对象的引用
  • 定义构造方法,传入被装饰对象的实例
  • 改写要修改的方法
  • 不需要改写的方法,调用被装饰对象的原来的方法

     2.何时使用装饰者模式

   当我们需要对一个类进行增强的时候,增强后的类不再当前类的范畴(本次以处理web请求中的代码为例)

     3.实现案例(此案例对HttpServletRequest 对象进行增强,使其具有处理web请求乱码的功能)

        3.1在filter中使用装饰者对象

    

package cn.itcast.filter;

import java.io.IOException;

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;

import cn.itcast.domain.MyRequest;

public class EncodingFilter implements Filter{

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        // 强制转换request  response
        HttpServletRequest req = (HttpServletRequest)request;
        HttpServletResponse res = (HttpServletResponse)response;
        
        //处理响应乱码
        res.setContentType("text/html;charset=utf-8");
        //自定义一个request对象:MyRequest,对服务器原来的request进行增强,使用装饰设计模式
        //要增强原来的request对象,必须先获取到原来的request对象
        MyRequest myrequest = new MyRequest(req);
        //注意:放行的时候应该,传入增强后的request对象
        chain.doFilter(myrequest, res);
        
    }

    @Override
    public void destroy() {
    }

}

 

 

 3.2自定义增强类

package cn.itcast.domain;

import java.io.UnsupportedEncodingException;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
//第一问题:HttpServletRequestWrapper他是什么?
//HttpServletRequestWrapper:它实现了HttpServletRequest接口,继承当前对象之后,也是HttpServletRequest接口的实现类
//第一问题:增强request,可以直接实现接口,为什么要继承HttpServletRequestWrapper?
//因为HttpServletRequestWrapper,已经实现了接口的方法,我们只需继承就可以使用,
//如果需要对某些方法增强,只需要修改部分方法即可,其他,调用父类的方法就完成了

/**
 * 补充(装饰(包装)设计模式心法):
1)    定义一个类,实现被装饰对象的接口
2)    定义一个成员变量,记住被装饰对象的引用
3)    定义构造方法,传入被装饰对象的实例
4)    改写要修改的方法
5)    不需要改写的方法,调用被装饰对象的原来的方法

 * */
//1)    定义一个类,实现被装饰对象的接口
public class MyRequest extends HttpServletRequestWrapper{
    //2)    定义一个成员变量,记住被装饰对象的引用
    private HttpServletRequest request = null;
    //3)    定义构造方法,传入被装饰对象的实例
    
    //设置一个标记,用来防止,编码多次运行,要保证get方式编码,只运行一次
    private boolean flag = false;
    public MyRequest(HttpServletRequest request) {
        super(request);
        this.request = request;
    }

    //4)    改写要修改的方法
    //所有获取参数的方法,都需要改写
    
    @Override
    public Map<String, String[]> getParameterMap() {
        //先判断请求的方式——每一次请求,只会有一种请求方式post get
        
        String method = this.request.getMethod();
        if("post".equalsIgnoreCase(method)){
            //post请求方式
            try {
                this.request.setCharacterEncoding("utf-8");
                return this.request.getParameterMap();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                return super.getParameterMap();
            }
        }else if("get".equalsIgnoreCase(method)){
            //先获取所有的数
            Map<String, String[]> map = this.request.getParameterMap();
            if(map == null){
                return super.getParameterMap();
            }
            //如果flag是false,说明没有执行过,执行中文乱码处理
            //如果flag是true,说明执行过乱码处理,不再重复
            if(flag){
                return map;
            }
            //遍历循环map集合,将每一个数据进行中文乱码处理
            //循环map集合的时候,先获取所有key的Set集合,然后,根据key,获取value值
            //当前循环结束,map集合中所有数据处理完成
            for (String key : map.keySet()) {
                //获取的数据是String数组
                String[] value = map.get(key);
                //当前for循环结束之后,value中的数据全部处理完成
                for(int i = 0 ;i< value.length ;i++){
                    try {
                        String temp = new String(value[i].getBytes("iso-8859-1"),"utf-8");
                        //再存入原来的位置
                        value[i] = temp;
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                        //这里还在继续循环,所以不能return结束
                    }
                }
            }
            //循环结束,标记设置为true
            flag = true;
            return map;
            
        }else{
            return super.getParameterMap();
        }
    }
    
    @Override
    public String[] getParameterValues(String name) {
        //先获取所有的数据,map
        Map<String, String[]> map = this.getParameterMap();
        if(map == null){
            return super.getParameterValues(name);
        }
        //获取map集合中指定数据,根据name指定,相当于key
        String[] values = map.get(name);
        
        return values;
    }
    
    @Override
    public String getParameter(String name) {
        //获取指定请求参数的数组
        String[] values = this.getParameterValues(name);
        if(values == null){
            return super.getParameter(name);
        }
        //如果有数据,返回,数组中的第一个数据
        return values[0];
    }
    
    
}
View Code

 

 

 

 

posted @ 2018-07-30 10:00  znlsmd123  阅读(249)  评论(0)    收藏  举报