拦截器

作者: 常威爆打来福 | 来源:发表于2018-05-29 22:07 被阅读11次

    一 拦截器

    定义拦截器,实现HandlerInterceptor接口

    package com.Interceptor;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * @author:Yang
     * @date:2018/5/29
     */
    public class Interceptor implements HandlerInterceptor {
        /**
         *进入Handler方法之前执行
         * 用于身份认证,身份授权
         * 比如身份认证,如果认证未通过表示当前用户没有登录,需要此方法拦截不再向下执行
         */
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
            /**
             * return false 表示拦截,不再向下执行
             * return true 表示放行
             */
            return false;
        }
    
        /**
         *进入Handler方法之后,返回ModelAndView之前执行
         * 应用场景从modelAndView出发:将公用的模型数据在这里传到视图,也可以统一的指定视图
         */
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    
        }
    
        /**
         *执行Handler之后执行
         * 统一异常处理,统一日志处理
         */
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    
        }
    }
    

    二 springMVC 拦截器配置

    1 针对HandlerMapping配置(不推荐使用)

    springmvc拦截器针对HandlerMapping进行拦截设置,如果在某个HandlerMapping中配置拦截,经过该HandlerMapping映射成功的handler最终使用该拦截器。

    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
            <property name="interceptors">
                <list>
                    <ref bean="handlerInterceptor1"/>
                    <ref bean="handlerInterceptor2"/>
                </list>
            </property>
        </bean>
        <bean id="handlerInterceptor1" class="com.Interceptor.Interceptor1"/>
        <bean id="handlerInterceptor2" class="com.Interceptor.Interceptor2"/>
    

    2 类似全局的拦截器

    springmvc配置类似全局的拦截器,springmvc框架将配置的类似全局的拦截器注入到每个HandlerMapping中。

        <!--拦截器 -->
        <mvc:interceptors>
            <!--多个拦截器,顺序执行 -->
            <mvc:interceptor>
                <!-- /**表示所有url包括子url路径 -->
                <mvc:mapping path="/**"/>
                <bean class="com.Interceptor.Interceptor1"></bean>
            </mvc:interceptor>
            <mvc:interceptor>
                <mvc:mapping path="/**"/>
                <bean class="com.Interceptor.Interceptor2"></bean>
            </mvc:interceptor>
        </mvc:interceptors>
    

    三 多拦截器测试

    1 拦截器定义

    • 拦截器一(Interceptor1)
    package com.Interceptor;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * @author:Yang
     * @date:2018/5/29
     */
    public class Interceptor1 implements HandlerInterceptor {
        /**
         *进入Handler方法之前执行
         * 用于身份认证,身份授权
         * 比如身份认证,如果认证未通过表示当前用户没有登录,需要此方法拦截不再向下执行
         */
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
            /**
             * return false 表示拦截,不再向下执行
             * return true 表示放行
             */
            System.out.println("拦截器1.........preHandle");
            return false;
        }
    
        /**
         *进入Handler方法之后,返回ModelAndView之前执行
         * 应用场景从modelAndView出发:将公用的模型数据在这里传到视图,也可以统一的指定视图
         */
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
            System.out.println("拦截器1.........postHandle");
        }
    
        /**
         *执行Handler之后执行
         * 统一异常处理,统一日志处理
         */
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
            System.out.println("拦截器1.........afterCompletion");
        }
    }
    
    • 拦截器二(Interceptor2)
    package com.Interceptor;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * @author:Yang
     * @date:2018/5/29
     */
    public class Interceptor2 implements HandlerInterceptor {
        /**
         *进入Handler方法之前执行
         * 用于身份认证,身份授权
         * 比如身份认证,如果认证未通过表示当前用户没有登录,需要此方法拦截不再向下执行
         */
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
            /**
             * return false 表示拦截,不再向下执行
             * return true 表示放行
             */
            System.out.println("拦截器2.........preHandle");
            return false;
        }
    
        /**
         *进入Handler方法之后,返回ModelAndView之前执行
         * 应用场景从modelAndView出发:将公用的模型数据在这里传到视图,也可以统一的指定视图
         */
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
            System.out.println("拦截器2.........postHandle");
        }
    
        /**
         *执行Handler之后执行
         * 统一异常处理,统一日志处理
         */
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
            System.out.println("拦截器2.........afterCompletion");
        }
    }
    

    2 两个拦截器的preHandle都返回true

    .......................省略..............
    拦截器1.........preHandle
    拦截器2.........preHandle
    DEBUG [http-apr-8080-exec-3] - Fetching JDBC Connection from DataSource
    DEBUG [http-apr-8080-exec-3] - incremented pending_acquires: 1
    DEBUG [http-apr-8080-exec-3] - incremented pending_acquires: 2
    DEBUG [http-apr-8080-exec-3] - incremented pending_acquires: 3
    DEBUG [http-apr-8080-exec-3] - incremented pending_acquires: 4
    .......................省略..............
    拦截器2.........postHandle
    拦截器1.........postHandle
    .......................省略..............
    DEBUG [http-apr-8080-exec-3] - Added model object 'items' of type [java.util.ArrayList] to request in view with name 'index'
    DEBUG [http-apr-8080-exec-3] - Forwarding to resource [/index.jsp] in InternalResourceView 'index'
    拦截器2.........afterCompletion
    拦截器1.........afterCompletion
    .......................省略..............
    

    小结:preHandle按照顺序执行,postHandle、afterCompletion按照逆向顺序执行

    3 拦截器一放行,拦截器二不放行

    DEBUG [http-apr-8080-exec-3] - Returning cached instance of singleton bean 'environment'
    DEBUG [http-apr-8080-exec-3] - Returning cached instance of singleton bean 'environment'
    DEBUG [http-apr-8080-exec-3] - DispatcherServlet with name 'springmvc_result' processing GET request for [/items/queryItems]
    DEBUG [http-apr-8080-exec-3] - Looking up handler method for path /items/queryItems
    DEBUG [http-apr-8080-exec-3] - Returning handler method [public java.lang.String com.controller.ItemsController.queryItems(org.springframework.ui.Model,com.entity.ItemsQueryVo) throws java.lang.Exception]
    DEBUG [http-apr-8080-exec-3] - Returning cached instance of singleton bean 'itemsController'
    DEBUG [http-apr-8080-exec-3] - Last-Modified value for [/items/queryItems] is: -1
    拦截器1.........preHandle
    拦截器2.........preHandle
    拦截器1.........afterCompletion
    DEBUG [http-apr-8080-exec-3] - Successfully completed request
    

    小结:拦截器1放行,拦截器2 preHandle才会执行。
    拦截器2 preHandle不放行,拦截器2 postHandle和afterCompletion不会执行。
    只要有一个拦截器不放行,postHandle不会执行。

    4 拦截器一不放行,拦截器二放行

    .......................省略..............
    DEBUG [http-apr-8080-exec-8] - Returning cached instance of singleton bean 'itemsController'
    DEBUG [http-apr-8080-exec-8] - Last-Modified value for [/items/queryItems] is: -1
    拦截器1.........preHandle
    DEBUG [http-apr-8080-exec-8] - Successfully completed request
    

    小结:拦截器1 preHandle不放行,postHandle和afterCompletion不会执行。
    拦截器1 preHandle不放行,拦截器2不执行。

    5 拦截器一不放行,拦截器二不放行

    .......................省略..............
    DEBUG [http-apr-8080-exec-2] - Returning cached instance of singleton bean 'itemsController'
    DEBUG [http-apr-8080-exec-2] - Last-Modified value for [/items/queryItems] is: -1
    拦截器1.........preHandle
    DEBUG [http-apr-8080-exec-2] - Successfully completed request
    

    小结:同上

    *总结

    拦截器1 preHandle不放行,postHandle和afterCompletion不会执行。
    拦截器1 preHandle不放行,拦截器2不执行。

    四 登录拦截器

    1 思路

    (1) 用户请求url
    (2) 拦截器进行拦截效验

    • 如果请求的url是公开地址(无需登录即可访问的url)放行
    • 如果用户session不存在跳转到登录页面
    • 如果用户session存在放行,继续操作

    2 LoginInterceptor

    package com.Interceptor;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    /**
     * 登录认证拦截器
     * @author:Yang
     * @date:2018/5/29
     */
    public class LoginInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest Request, HttpServletResponse Response, Object o) throws Exception {
            //获取url
            String url = Request.getRequestURI();
            //判断url是否公开地址(实际使用时将公开地址配置在配置文件中)
            //这里公开地址是登录提交的地址
            if(url.indexOf("login")>=0){
                //如果进行登录提交,放行
                return true;
            }
            //判断session
            HttpSession session = Request.getSession();
            String username = (String) session.getAttribute("username");
            if(username != "" && username != null){
                //身份存在放行
                return true;
            }
            //执行到这里,说明用户身份需要认真,跳转登录页面
            Request.getRequestDispatcher("/login.jsp").forward(Request,Response);
            return false;
        }
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
            System.out.println("拦截器1.........postHandle");
        }
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
            System.out.println("拦截器1.........afterCompletion");
        }
    }
    

    3 拦截器配置

            <mvc:interceptor>
                <mvc:mapping path="/**"/>
                <bean class="com.Interceptor.LoginInterceptor"></bean>
            </mvc:interceptor>
    

    4 controller

    package com.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import javax.servlet.http.HttpSession;
    
    /**
     * @author:Yang
     * @date:2018/5/29
     */
    @Controller
    public class LoginController {
        @RequestMapping("/login")
        public String login(HttpSession session, String username, String password)throws Exception{
            //调用service进行用户身份验证
            //...
            session.setAttribute("username",username);
            return "redirect:/items/queryItems";
        }
        @RequestMapping("/logout")
        public String logout(HttpSession session)throws  Exception{
            session.invalidate();
            return "redirect:login";
        }
    }
    

    五 存在问题

    在登陆案例拦截器中,有两次if判断。当第一次判断是否进行登陆提交,当我们提交后会放行,执行LoginController类中的方法,多次调试发现进入LoginController类中,对应的方法会执行完,后续的postHandle和afterCompletion也会依次执行,根据多次调试发现,我们的第二次if判断是在执行完afterCompletion之后在执行,于是,想着是不是拦截器执行是在一个流程完成之后(preHandle,postHandle和afterCompletion),返回再执行,然后又去掉第二次if判断,测试就会有问题,无法登陆。preHandle按学习资料讲是在Handler执行之前执行,但案例测试实在想不明白。待解决

    相关文章

      网友评论

      • 简书水墨:bool返回值只有true和false,当执行完第一个login时,就不会往下执行。

      本文标题:拦截器

      本文链接:https://www.haomeiwen.com/subject/iilajftx.html