【修真院小课堂】拦截器、过滤器、监听器各有什么作用?

大家好,我是IT修真院西安分院第2期学员,一枚正直善良的java程序员。
今天给大家分享一下,修真院官网java任务三中可能会使用到的知识点:

拦截器、过滤器、监听器的作用


背景介绍


拦截器

java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。在AOP中,拦截器用于在某个方法或者字段被访问之前,进行拦截然后再之前或者之后加入某些操作。

拦截器原理

SpringMVC 中的Interceptor 拦截请求是通过HandlerInterceptor 来实现的。在SpringMVC 中定义一个Interceptor 非常简单,主要有两种方式,第一种方式是要定义的Interceptor类要实现了Spring 的HandlerInterceptor 接口,或者是这个类继承实现了HandlerInterceptor 接口的类,比如Spring 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter;
第二种方式是实现Spring的WebRequestInterceptor接口,或者是继承实现了WebRequestInterceptor的类。

本次代码演示是继承HandlerInterceptor.


拦截器实现

HandlerInterceptor 接口中定义了三个方法,我们就是通过这三个方法来对用户的请求进行拦截处理的。

(1 )preHandle (HttpServletRequest request, HttpServletResponse response, Object handle) 方法,顾名思义,该方法将在请求处理之前进行调用。SpringMVC 中的Interceptor 是链式的调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor 。每个Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor 中的preHandle 方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值Boolean 类型的,当它返回为false 时,表示请求结束,后续的Interceptor 和Controller 都不会再执行;当返回值为true 时就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法

(2 )postHandle (HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView) 方法,由preHandle 方法的解释我们知道这个方法包括后面要说到的afterCompletion 方法都只能是在当前所属的Interceptor 的preHandle 方法的返回值为true 时才能被调用。postHandle 方法,顾名思义就是在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。postHandle 方法被调用的方向跟preHandle 是相反的,也就是说先声明的Interceptor 的postHandle 方法反而会后执行,这和Struts2 里面的Interceptor 的执行过程有点类型。Struts2 里面的Interceptor 的执行过程也是链式的,只是在Struts2 里面需要手动调用ActionInvocation 的invoke 方法来触发对下一个Interceptor 或者是Action 的调用,然后每一个Interceptor 中在invoke 方法调用之前的内容都是按照声明顺序执行的,而invoke 方法之后的内容就是反向的。
(3 )afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法,该方法也是需要当前对应的Interceptor 的preHandle 方法的返回值为true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。

过滤器

Filter也称之为过滤器,它是Servlet技术中最激动人心的技术之一,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp,Servlet, 静态图片文件或静态html文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。  Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截,Filter接口源代码:

过滤器原理

Filter接口中有一个doFilter方法,当我们编写好Filter,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前,调用目标资源之前,让一段代码执行。
是否调用目标资源(即是否让用户访问web资源)。
调用目标资源之后,让一段代码执行。  

web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,否则web资源不会被访问。

过滤器中的方法

init(FilterConfig var1): web应用程序启动时,web服务器将创建Filter的实例对象,并调用其init方法,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作,filter对象只会创建一次,init方法也只会执行一次。
doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3):当有人访问web服务器时对请求进行操作。

destroy()web容器调用destroy方法销毁Filter。destroy方法在Filter的生命周期中仅执行一次。在destroy方法中,可以释放过滤器使用的资源。


代码展示

过滤脏话

public class myFilter3 implements Filter{


    public myFilter3(){
        System.out.println("FilterDemo3构造方法");
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("-----------------------FilterDemo3  初始化----------");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {


        //用装饰模式把 原装的request的功能增强
        //拦截后台调用的getParamter()方法
        MyRequest req = new MyRequest((HttpServletRequest)request);
        System.out.println("-----------------------FilterDemo3  执行----------");
        chain.doFilter(req, response);//放行
    }

    @Override
    public void destroy() {
        System.out.println("-----------------------FilterDemo3  销毁----------");
    }
}

class MyRequest extends HttpServletRequestWrapper {
    public MyRequest(HttpServletRequest request) {
        super(request);
    }

    @Override
    public String getParameter(String name) {
        String str = super.getParameter(name);
        List<String> list = wordUtil.getWords();
        for(String word : list){
            str = str.replaceAll(word, "**");
        }
        return str;
    }
}

以上是过滤器类,下面是获得脏话字眼的类:

public class wordUtil {
    private static List<String> list = new ArrayList<String>();
    static{

        list.add("骂人");
        list.add("sb");
        list.add("操你老母");
    }
    public static List<String> getWords(){
        return list;
    }

}

Controller处理:
@RequestMapping(value = "/result", method = RequestMethod.POST)
public String result(Model model, HttpServletRequest request)throws Exception{

    System.out.println("执行controller:  result");


    String name = request.getParameter("name");
    String words = request.getParameter("note");
    System.out.println(name+":  "+ words);

    model.addAttribute("word",words);
    model.addAttribute("name",name);

    return "finalword";
}

jsp的输入与输出view

输入:

<!-- 支持EL表达式 -->
<%@ page isELIgnored="false" %>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
   <title>过滤器应用示例---敏感词过滤</title>
</head>

<body>
<h2>过滤器应用示例---敏感词过滤</h2>
<form action="${pageContext.request.contextPath}/result" method="post">
   用户名:<input type="text" name="name" /><br/><br/>
   <fieldset>
      <legend>留言板</legend>
      <textarea name="note" rows="10" cols="20"></textarea>
   </fieldset>
   <input type="submit" value="留言" />
</form>
</body>
</html>

输出:

<!-- 支持EL表达式 -->
<%@ page isELIgnored="false" %>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
   <title>过滤器应用示例---敏感词过滤</title>
</head>

<body>
<h2>过滤器应用示例---敏感词过滤</h2>
<form action="${pageContext.request.contextPath}/result" method="post">
   用户名:<input type="text" name="name" value="${name}"/><br/><br/>

      留言板:
   <br/>
   ${word}
</form>
</body>
</html>

最后记得在web.xml里配置下

<filter>
  <filter-name>filterDemo1</filter-name>
  <filter-class>com.demo.filter.myFilter</filter-class>
</filter>

<filter-mapping>
  <filter-name>filterDemo3</filter-name>
  <url-pattern>/*</url-pattern>
  <!-- 默认拦截的类型:(直接访问或者重定向)
  <dispatcher>REQUEST</dispatcher>
  拦截转发:
  <dispatcher>FORWARD</dispatcher>
  拦截包含的页面(RequestDispatcher.include(/page.jsp);    page.jsp也执行拦截)
  <dispatcher>INCLUDE</dispatcher>
  拦截声明式异常信息:
  <dispatcher>ERROR</dispatcher>-->
</filter-mapping>


显示效果,过滤前:


过滤后:     将骂人字眼用**代替




监听器

主要是用来监听特定对象的创建或销毁、属性的变化的, 是一个实现特定接口的普通java类。

对象:

         自己创建自己用 (不用监听)

         别人创建自己用 (需要监听)

Servlet中哪些对象需要监听?


         request / session / servletContext

         分别对应的是request监听器、session相关监听器、servletContext监听器


监听器接口:

一、监听对象创建/销毁的监听器接口

         InterfaceServletRequestListener     监听request对象的创建或销毁

         InterfaceHttpSessionListener        监听session对象的创建或销毁

         InterfaceServletContextListener     监听servletContext对象的创建或销毁

二、监听对象属性的变化

         InterfaceServletRequestAttributeListener 监听request对象属性变化: 添加、移除、修改

         InterfaceHttpSessionAttributeListener    监听session对象属性变化: 添加、移除、修改

InterfaceServletContextAttributeListener  监听servletContext对象属性变化

三、session相关监听器

         InterfaceHttpSessionBindingListener   监听对象绑定到session上的事件

    InterfaceHttpSessionActivationListener(了解) 监听session序列化及反序列化的事件

 

生命周期监听器

生命周期监听器:监听对象的创建、销毁的过程


监听器开发步骤:

1.     写一个普通java类,实现相关接口;

2.     配置(web.xml)


代码展示

在线人数监听器


监听器代码

public class Listener implements HttpSessionListener {

        private static int count = 0;

        public void sessionCreated(HttpSessionEvent se) {
            count++;
            String id = se.getSession().getId();
            System.out.println("session创建:" + new java.util.Date()+"  ID: "+id);
        }

        public void sessionDestroyed(HttpSessionEvent se) {
            count--;
            String id = se.getSession().getId();
            System.out.println("session销毁:" + new java.util.Date()+"  ID: "+id);
        }

        public static int getCount() {
            return count;
        }
}
web.xml

 <listener>
  <listener-class>com.demo.listener.Listener</listener-class>
</listener>

jsp代码

<%@ page import="com.demo.listener.Listener" %>
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%--引入JSTL核心标签库 --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page isELIgnored="false" %>

<html>
<body>
<h2>Hello World!</h2>

<%
    int count= com.demo.listener.Listener.getCount();
    out.println("在线人数:"+count);
%>

</body>
</html>


显示效果:



 

鸣谢 : 魏振恒

本人的小课堂是在师兄基础上的完善,特此致谢!


感谢大家观看

BY : LittleSong


阅读更多
上一篇【修真院小课堂】如何写shell脚本?尝试自己编写一个简单脚本
下一篇git命令使用
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭