过滤器、监听器、拦截器

无人久伴 提交于 2020-03-17 17:45:16

过滤器、监听器、拦截器三者联系

 

过滤器(Filter)

主要用于对用户的请求进行预处理

通过过滤器Filter技术,可以管理Web服务器的所有资源(例如jsp,html,静态资源文件等),并进行拦截,从而实现一些特殊的功能(例如实现URL级别的权限访问控制,过滤铭感词汇,设置字符集编码格式等)。

功能实现:

  • 在HttpServletRequest到达Servlet之前,拦截客户的HttpServletRequest请求(检查或修改其数据)。
  • 在HttpServletResponse到达客户端之前,拦截HttpServletResponse请求(检查或修改其数据)。

如何实现:

  1. 编写Java类实现Filiter接口,并实现doFilter()方法
  2. 在web.xml中注册编写的Filter类

示例:(对请求统一设置字符编码格式utf-8,解决乱码问题)

1.创建项目--filter,增加web框架支持(add Frameworks Support)

2.创建包--cn.zero.servlet,编写类MyServlet

package cn.zero.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

//Servlet需要继承HttpServlet接口
public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("你好,世界!");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }

}

3.在web.xml中配置servlet

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!--配置servlet-->
    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>cn.zero.servlet.MyServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

</web-app>

4.配置tomcat,启动项目,运行:http://localhost:8080/hello

我们发现页面存在乱码的情况,为了解决这个问题,我们需要在请求中设置字符编码格式来解决这类问题。

req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("你好,世界!");

这样便解决了乱码问题!

可是我们存在多个方法,倘若都可能存在乱码问题的话,我们就需要重复增加上述代码,久而久之代码便会更加繁重冗余,那么有没有一种方法可以解决这类问题呢?

有,使用拦截器!!!

5.创建包--cn.zero.filter,编写类MyFilter

package cn.zero.filter;

import javax.servlet.*;
import java.io.IOException;

//实现Filter接口
public class MyFilter implements Filter {

    //1.过滤器的初始化工作
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Filiter初始化完成!");
    }

    //过滤器执行过滤操作
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");

        System.out.println("过滤器执行前--before");
        chain.doFilter(req, resp); // doFilter过滤操作将请求获取,然后再将请求抛出去
        System.out.println("过滤器执行后--after");
    }

    //3.过滤器销毁
    public void destroy() {
        System.out.println("Filter销毁!");
    }

}

6.修改web.xml文件,增加filter配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!--配置servlet-->
    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>cn.zero.servlet.MyServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

    <!--配置filter-->
    <filter>
        <filter-name>MyFilter</filter-name>
        <filter-class>cn.zero.filter.MyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>MyFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

配置filter时,设置url-pattern为:/*,因此所有的请求执行都会进过cn.zero.filter.MyFilter类中的方法!

7.配置tomcat,再次启动项目,运行:http://localhost:8080/hello

这样,我们增加的拦截器便发挥了作用!

 

监听器(Listener)

用于监听web应用中某些对象、信息的创建、销毁、增加、修改、删除等动作的发生,然后做出相应的响应处理。当范围对象的状态发生变化的时候,服务器自动调用监听器对象中的方法。

常用于统计在线人数和在线用户,系统加载时进行信息的初始化,统计网站的访问量等。

示例:(使用监听器统计网站的在线人数)

实现原理:每当有访问连接到服务器时,服务器就会创建一个session来管理会话,由此我们可通过session的数量多少来统计在线人数。

1.创建项目--listener,增加web框架支持(add Frameworks Support)

2.创建包cn.zero.listener,编写MyListener类

package cn.zero.listener;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

//实现HttpSessionListener接口,通过session会话了解监听器
public class MyListener implements HttpSessionListener {

    /**
     * 我们使用 访问网页的在线人数 做Demo
     * 创建session时,在线人数onLine+1
     * 销毁session时,在线人数onLine-1
     */

    //session创建时,将执行该方法
    //也证明程序创建session时被监听器监听到
    public void sessionCreated(HttpSessionEvent se) {
        ServletContext sc = se.getSession().getServletContext();
        //在线人数onLine
        Integer onLine = (Integer) sc.getAttribute("onLine");
        if (onLine == null) {
            onLine = 1;
        } else {
            onLine = onLine + 1;
        }
        sc.setAttribute("onLine", onLine);
    }

    //session销毁时,将执行该方法
    //也证明程序销毁session时被监听器监听到
    public void sessionDestroyed(HttpSessionEvent se) {
        ServletContext sc = se.getSession().getServletContext();
        //在线人数onLine
        Integer onLine = (Integer) sc.getAttribute("onLine");
        if (onLine == null) {
            onLine = 0;
        } else {
            onLine = onLine - 1;
        }
        sc.setAttribute("onLine", onLine);
    }

}

3.编写index.jsp页面内容

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
  <title>测试在线人数Demo--listener</title>
</head>
<body>

    <p>
      当前共有<%=request.getSession().getServletContext().getAttribute("onLine") %>人在线<br>
    </p>

</body>
</html>

4.在web.xml中配置监听器

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <listener>
        <listener-class>cn.zero.listener.MyListener</listener-class>
    </listener>

</web-app>

5.配置tomcat,发布项目,访问路径:http://localhost:8080/ 使用不同浏览器访问,可以发现session数量的增加。

 

拦截器(Interceptor)

实现对每一个请求处理前后进行相关的业务处理。

基于Java反射机制实现,拦截的对象只能是实现了接口的类,而不能拦截url类似的链接。

Java中的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。

在Aop中,拦截器用于在某个方法或者字段被访问之前,进行拦截,然后在其前后加入某些操作。

示例:

1.创建项目--interceptor,创建包 cn.zero.interceptor

2.编写接口 InterDao, 编写InterDaoImpl实现接口

package cn.zero.interceptor;

public interface InterDao {

    //执行处理业务
    void doSomething();

}
package cn.zero.interceptor;

public class InterDaoImpl implements InterDao {

    //执行处理业务
    public void doSomething() {
        System.out.println("处理业务!");
    }

}

3.自定义拦截器Interceptor

package cn.zero.interceptor;

//自定义拦截器
public class Interceptor {

    //拦截器执行前方法
    public void before() {
        System.out.println("拦截器执行前--before");
    }

    ////拦截器执行后方法
    public void after() {
        System.out.println("拦截器执行后--after");
    }

}

4.创建拦截器代理对象

package cn.zero.interceptor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//拦截器代理对象
public class InterceptorProxy {

    //被代理对象
    private Object target;

    //实例化一个拦截器对象
    Interceptor interceptor = new Interceptor();

    //动态生成一个代理对象,并绑定被代理类和代理处理器
    public Object getProxyInstance(final Object target) {

        this.target = target;

        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        interceptor.before();
                        Object object = method.invoke(target, args);
                        interceptor.after();

                        return object;
                    }
                });
    }

}

5.编写启动类,测试运行

package cn.zero.interceptor;

public class InterceptorMain {

    public static void main(String[] args) {

        //创建动态代理工具
        InterceptorProxy interceptorProxy = new InterceptorProxy();

        //创建业务组件
        InterDao interDao = new InterDaoImpl();

        //获取代理对象
        InterDao proxy = (InterDao) interceptorProxy.getProxyInstance(interDao);

        //通过代理对象调用目标对象方法
        proxy.doSomething();

    }

}

6.控制台查看运行结果

我们看到,我们执行目标方法doSomething()时,通过拦截器,可以在其前后增加我们需要的业务!

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!