java的过滤器

JavaWeb三大组件

1. 都需要在web.xml中进行配置
Servlet
Listener

Filter


2. 过滤器
      它通过web.xml管理着一大片资源,它会在一组资源(jsp、servlet、.css、.html等等)的前面执行!它当你想要访问它管理的资源时,那么它就会拦截进行处理.它可以让请求得到目标资源,也可以不让请求达到!就好比如门卫.  只要是对很多的资源进行操作就应该想到filter

 


过滤器如何编写

1. 写一个类实现Filter接口
2. 在web.xml中进行配置管理哪些资源

 

1. Filter接口

1
2
3
4
5
6
    public void doFilter(ServletRequest request, ServletResponseresponse,
           FilterChain chain) throws IOException, ServletException{
       System.out.println("filterstart..."); 
       chain.doFilter(request,response);//放行 
       System.out.println("filterend..."); 
    }

 

void init(FilterConfig)
  * 创建之后,马上执行;Filter会在服务器启动时就创建!
void destory()
  * 销毁之前执行!在服务器关闭时销毁
void doFilter(ServletRequest,ServletResponse,FilterChain)
  * 每次过滤时都会执行

Filter是单例的!和servlet一样

 

2. web.xml
<filter>
  <filter-name>xxx</filter-name>
  <filter-class>web.filter.AFitler</fitler-class>
</servlet>
<fitler-mapping>
  <filter-name>xxx</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

这个配置代表了这个filter管理哪些资源.访问这些资源时,这个过滤器就会执行doFilter()..


FilterConfig-->与ServletConfig相似
  * 获取初始化参数:getInitParameter()
  * 获取过滤器名称:getFilterName()
  * 获取appliction:getServletContext()

FilterChain(这个用于放行)
  * doFilter(ServletRequest, ServletResponse):放行!
    就相当于调用了目标Servlet的service()方法!

-------------------------------

-------------------------------

多过滤器情况下FilterChain的doFilter()方法:执行目标资源,或是执行下一个过滤器!如果没有下一个过滤器那么执行的是目标资源,如果有,那么就执行下一个过滤器!


-------------------------------

过滤器的四种拦截方式

  <dispatcher>REQUEST</dispatcher>默认的!拦截直接请求
  <dispatcher>FORWARD</dispatcher>            拦截请求转发
  <dispatcher>INCLUDE</dispatcher>              拦截请求包含  
  <dispatcher>ERROR</dispatcher>                拦截错误转发

在<filter-mapping>中进行配置!


-------------------------------

多个过滤器的执行顺序

<filter-mapping>的配置顺序决定了过滤器的执行顺序!

 

过滤器的应用场景:

执行目标资源之前做预处理工作,例如设置编码,这种试通常都会放行,只是在目标资源执行之前做一些准备工作;

通过条件判断是否放行,很多java教程里都这样说的,例如校验当前用户是否已经登录,或者用户IP是否已经被禁用;

在目标资源执行后,做一些后续的特殊处理工作,例如把目标资源输出的数据进行处理

 

实例:

统计IP

循环遍历在ServletContext中的map,其中key是ip地址,value是访问次数

jsp页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<body>
<h1>分IP统计访问次数</h1>
<table align="center"width="50%" border="1">
    <tr>
       <th>IP地址</th>
       <th>次数</th>
    </tr>
<c:forEach items="${aplicationScope.ipCountMap}" var="entry">
    <tr>
       <td>${entry.key }</td>
       <td>${entry.value }</td>
    </tr>
</c:forEach>
 </table>  
</body>

filter代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public void init(FilterConfig fConfig) throws ServletException {
       context = fConfig.getServletContext();
       Map<String, Integer> ipCountMap = new LinkedHashMap<String, Integer>();
       context.setAttribute("ipCountMap", ipCountMap);
    }
  
  public void doFilter(ServletRequest request, ServletResponseresponse,
           FilterChain chain) throws IOException, ServletException{
       HttpServletRequest req = (HttpServletRequest) request;
       String ip = req.getRemoteAddr();
  
       Map<String, Integer> ipCountMap = (Map<String,Integer>) context
              .getAttribute("ipCountMap");
  
       Integer count = ipCountMap.get(ip);
       if (count == null) {
           count = 1;
       else {
           count += 1;
       }
       ipCountMap.put(ip, count);
  
       context.setAttribute("ipCountMap", ipCountMap);
       chain.doFilter(request, response);
    }
  
    public void destroy() {}
}

 

解决全站字符乱码

乱码问题:

l  获取请求参数中的乱码问题;

  POST请求:request.setCharacterEncoding(“utf-8”);

  GET请求:newString(request.getParameter(“xxx”).getBytes(“iso-8859-1”), “utf-8”);

l  响应的乱码问题:response.setContextType(“text/html;charset=utf-8”)。

处理POST请求简单,可是处理get请求需要获取参数,filter获取所有过滤资源的参数是不可能实现的.这里可以调包request再发给servlet.增强request对象(改变getParamater()方法.让每次获取参数时直接解决乱码问题).

    增强对象的方式有三种:(对a对象进行增强,fun1()方法)

  1. 继承:  AA类继承a对象的类型:A类,然后重写fun1()方法,其中重写的fun1()方法就是被增强的方法。但是,继承必须要知道a对象的真实类型,然后才能去继承。如果我们不知道a对象的确切类型,而只知道a对象是IA接口的实现类对象,那么就无法使用继承来增强a对象了;

  2. 装饰者模式: AA类去实现a对象相同的接口:IA接口,还需要给AA类传递a对象,AA类所有方法的实现都是调用a对象相同方法实现,只有fun1()方法需要改变下内容,对fun1()进行增强;

  3. 动态代理:和增强者模式比较相似

这里对request对象进行增强是通过继承request对象的装饰类,装饰类是接口的包装类,但是它不进行任何增强,我们通过继承它然后重写需要增强的方法,这样就不用重写需要增强的方法了.

 

(增强时一看继承类,二看有没有接口的包装类,三接口的装饰者模式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class EncodingFilter implements Filter {
 public void destroy() {
 }
 public void doFilter(ServletRequest request, ServletResponse response,
   FilterChain chain) throws IOException, ServletException {
  // 处理post请求编码问题
  request.setCharacterEncoding("utf-8");
   
  HttpServletRequest req = (HttpServletRequest) request;
   
  /*
   * 处理GET请求的编码问题
   */
//  String username = request.getParameter("username");
//  username = new String(username.getBytes("ISO-8859-1"), "UTF-8");
   
  /*
   * 调包request
   */
  if(req.getMethod().equals("GET")) {
   EncodingRequest er = new EncodingRequest(req);
   chain.doFilter(er, response);
  else if(req.getMethod().equals("POST")) {
   chain.doFilter(request, response);
  }
 }
 public void init(FilterConfig fConfig) throws ServletException {
 }
}

 继承包装类增强request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
 * 装饰reqeust
 */
public class EncodingRequest extends HttpServletRequestWrapper {
 private HttpServletRequest req;
  
 public EncodingRequest(HttpServletRequest request) {
  super(request);
  this.req = request;
 }
 public String getParameter(String name) {
  String value = req.getParameter(name); 
  // 处理编码问题
  try {
   value = new String(value.getBytes("iso-8859-1"), "utf-8");
  catch (UnsupportedEncodingException e) {
   throw new RuntimeException(e);
  
  return value;
 }
}
posted @ 2015-12-23 11:28  jinshiyill  阅读(292)  评论(0编辑  收藏  举报