• springmvc过滤器,拦截器,监听器作用与区别


    小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

    1.过滤器

    配置在web.xml中。依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等,最常用的过滤字符串的拦截器。

           <filter>
    		<filter-name>CharacterEncodingFilter</filter-name>
    		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    		<init-param>
    			<param-name>encoding</param-name>
    			<param-value>utf-8</param-value>
    		</init-param>
    	</filter>
    	<filter-mapping>
    		<filter-name>CharacterEncodingFilter</filter-name>
    		<url-pattern>/*</url-pattern>
    	</filter-mapping>
    复制代码

    1.自定义过滤器

    我们还可以自定义过滤器,以下一个登陆过滤器。

      @RequestMapping(value="/login",method=RequestMethod.GET)
        public String login(HttpServletRequest request,HttpServletResponse response){
            //获取Cookie
            Cookie[] cookies = request.getCookies();
            for(Cookie cookie : cookies){
                System.out.println("cookie>>"+cookie.getValue());
                //从数据库获取保存的cookie
                Session session = iSessionDAO.getSession(cookie.getValue());
                if(session!=null){
                    //如果存在,就跳转到首页
                    return "index";
                }
            }
            return "login";
        }
        
        @RequestMapping(value="/login",method=RequestMethod.POST)
        public String loginPOST(HttpServletRequest request, HttpServletResponse response,Model model){
            //用户名
            String username=request.getParameter("username");  
            System.out.println("username>>>"+username);
            //密码
            String password=request.getParameter("password"); 
            System.out.println("password>>>"+password);
            //先从数据库查找该账号信息
            User user = null;
            try {
                user = iUserDAO.queryForUser(username);
            } catch (NullPointerException e) {
                e.printStackTrace();
                model.addAttribute("message", "No account");
            }
            if(user==null){
                model.addAttribute("message", "No account");
            }else{
                // 匹配密码
                if (user.getPassword().equals(password)) {
                    //登录成功,保存session
                    request.getSession().setAttribute("user", user);
                    // 保存cookie
                    Cookie[] cookies = request.getCookies();
                    Cookie cookie = cookies[0];//获得最新的那个cookie
                    Session isSession = iSessionDAO.getSessionByUserId(user.getId());
                    //没有session,就添加
                    if(isSession==null){
                        Session session = new Session();
                        session.setId(UUID.randomUUID().toString());
                        session.setSession(cookie.getValue());
                        session.setUser_id(user.getId());
                        System.out.println("cookie>>" + cookie.getValue());
                        iSessionDAO.save(session);
                        System.out.println("==添加session==");
                    }else{
                        //如果已经有session,就更新
                        isSession.setSession(cookie.getValue());
                        iSessionDAO.update(isSession);
                        System.out.println("==更新session==");
                    }
                    model.addAttribute("message", user.getUsername());
                    return "index";
                }else{
                    model.addAttribute("message", "Wrong password");
                }
            }
            return "login";
        }
    
        @RequestMapping(value="/sessionTest",method=RequestMethod.GET)
        public String sessionTest(HttpServletRequest request,HttpServletResponse response,Model model){
            System.out.println(">>>sessionTest");
            model.addAttribute("message", "sessionTest");
            return "index";
    
        }
    
    复制代码

    2.如何配置

    在使用中,需要在web.xml中配置才生效。

        <filter>
            <description>session过滤器</description>
            <filter-name>sessionFilter</filter-name>
            <filter-class>com.mocha.filter.SessionFilter</filter-class>
        </filter>
    
        <filter-mapping>
            <filter-name>sessionFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    复制代码

    2.拦截器

    依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。

    1.实现方式

    1. 通过实现HandlerInterceptor接口,或继承HandlerInterceptor接口的实现类(如HandlerInterceptorAdapter)来定义。
    2. 通过实现WebRequestInterceptor接口,或继承WebRequestInterceptor接口的实现类来定义。 以下是一个拦截器。

    2.代码实现

    @Component
    public class HandlerInterceptor extends HandlerInterceptorAdapter {
    
    	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
    			ModelAndView modelAndView) throws Exception {
    
    		System.out.println("11111111");
    	}
    	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
    			throws Exception {
    
    		System.out.println("222222222");
    	}
    
    	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    		System.out.println("44444");
    		return true;
    	}
    }
    复制代码

    同时也需要在mvc的配置文件中加入配置。

        <mvc:interceptors>
    		<mvc:interceptor>
    			<!--配置拦截器的作用路径 -->
    			<mvc:mapping path="/**" />
    			<!--定义在<mvc:interceptor>下面的表示匹配指定路径的请求才进行拦截 -->
    			<bean class="com.HandlerInterceptor" />
    		</mvc:interceptor>
    	</mvc:interceptors>
    复制代码

    3.监听器

    监听器是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或者属性改变,当被监听对象发生上述事件后,监听器某个方法将立即执行。 监听器用于监听web应用中某些对象、信息的创建、销毁、增加,修改,删除等动作的发生,然后作出相应的响应处理。当范围对象的状态发生变化的时候,服务器自动调用监听器对象中的方法。常用于统计在线人数和在线用户,系统加载时进行信息初始化,统计网站的访问量等等。或者在开发工作中,会遇到一种场景,做完某一件事情以后,需要广播一些消息或者通知,告诉其他的模块进行一些事件处理,一般来说,可以一个一个发送请求去通知,但是有一种更好的方式,那就是事件监听,事件监听也是设计模式中 发布-订阅模式、观察者模式的一种实现。

    1.代码实现

    监听事件

    import org.springframework.context.ApplicationEvent;
    public class MyTestEvent extends ApplicationEvent{
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        private String msg ;
        public MyTestEvent(Object source,String msg) {
            super(source);
            this.msg = msg;
        }
        public String getMsg() {
            return msg;
        }
        public void setMsg(String msg) {
            this.msg = msg;
        }
    }
    
    复制代码

    定义监听器

    import org.springframework.context.ApplicationListener;
    import org.springframework.stereotype.Component;
    
    import com.mu.event.MyTestEvent;
    
    @Component
    public class MyNoAnnotationListener implements ApplicationListener<MyTestEvent>{
    
        @Override
        public void onApplicationEvent(MyTestEvent event) {
            System.out.println("非注解监听器:" + event.getMsg());
        }
    }
    
    复制代码

    事件发布

    package com.mu.event;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.stereotype.Component;
    
    @Component
    public class MyTestEventPubLisher {
        @Autowired
        private ApplicationContext applicationContext;
        // 事件发布方法
        public void pushListener(String msg) {
            applicationContext.publishEvent(new MyTestEvent(this, msg));
        }
    }
    
    复制代码

    调用

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import com.mu.event.MyTestEventPubLisher;
    @Controller
    public class TestEventListenerController {
        @Autowired
        private MyTestEventPubLisher publisher;
        @RequestMapping(value = "/test/testPublishEvent1" )
        public void testPublishEvent(){
            publisher.pushListener("我来了!");
        }
    }
    
    复制代码

    也可以使用注解实现

    import org.springframework.context.event.EventListener;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Component;
    
    import com.mu.event.MyTestEvent;
    
    @Component
    public class MyAnnotationListener {
    
        @EventListener
        public void listener1(MyTestEvent event) {
            System.out.println("注解监听器1:" + event.getMsg());
        }
    }
    复制代码

    4.过滤器与拦截器的区别

    过滤器可以简单的理解为“取你所想取”,过滤器关注的是web请求;拦截器可以简单的理解为“拒你所想拒”,拦截器关注的是方法调用,比如拦截敏感词汇。

    1. 拦截器是基于java反射机制来实现的,而过滤器是基于函数回调来实现的。(有人说,拦截器是基于动态代理来实现的)
    2. 拦截器不依赖servlet容器,过滤器依赖于servlet容器。
    3. 拦截器只对Action起作用,过滤器可以对所有请求起作用。
    4. 拦截器可以访问Action上下文和值栈中的对象,过滤器不能。
    5. 在Action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时调用一次。

    5.AOP与拦截器的区别

    Filter过滤器:拦截web访问url地址。 Interceptor拦截器:拦截以 .action结尾的url,拦截Action的访问。 Spring AOP拦截器:只能拦截Spring管理Bean的访问(业务层Service)

    拦截顺序:监听器>filter—>Interceptor—->@Aspect

    aop与拦截器的实现方式都是动态代理实现的。

    来源:https://juejin.cn/post/7021684725018263583#heading-6
  • 相关阅读:
    跨域访问方法列举 jsonp 和 客户端
    session 垃圾回收机制
    php 根据数据权重,得分或者持有数量等进行均衡分配给定数量分配方法
    进程和线程比较
    redis 过期策略分析
    redis 基础知识详解
    tcp/ip 协议
    ip 协议详解
    php redis 分布式类
    nginx打开目录游览功能
  • 原文地址:https://www.cnblogs.com/konglxblog/p/16523101.html
Copyright © 2020-2023  润新知