zoukankan      html  css  js  c++  java
  • Spring拦截器(学习笔记)

    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 对象进行操作(也就是返回的modelMap)。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 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。

    接下来是使用,

    第一步要定义Interceptor类:

    public class ShopLoginInterceptor extends HandlerInterceptorAdapter{
        /* 
         * 主要做事前拦截,即用户操作发生前,改写preHandle里面的逻辑,进行拦截
         */
        @Override
        public boolean preHandle(HttpServletRequest request,
                HttpServletResponse response, Object handler) throws Exception {
            //从session中取出用户信息来
            Object userObj = request.getSession().getAttribute("user");
            if (userObj != null) {
                //若用户信息不为空,则将session里的用户信息转换成PersonInfo实体类对象
                PersonInfo user = (PersonInfo) userObj;
                //做空值判断,确保userId不为空并且该长号的可用状态为1,并且用户类型为店家(再判断usertype是否为2店家)
                if (user != null && user.getUserId() != null
                        && user.getUserId() > 0 && user.getEnableStatus() == 1)
                    //若通过验证则返回true,拦截器返回true之后,用户接下来的操作得以正常执行
                    return true;
            }
            //若不满足登录验证,则直接跳转到账号登录页面
            PrintWriter out = response.getWriter();
            //拼接js代码
            out.println("<html>");
            out.println("<script>");
            out.println("window.open ('" + request.getContextPath()
                    + "/local/login?usertype=2','_self')");
            out.println("</script>");
            out.println("</html>");
            return false;
        }
    }

    还有一个Interceptor类:

    /**
     * 店家管理系统操作验证拦截器
     * @author L
     *
     */
    public class ShopPermissionInterceptor extends HandlerInterceptorAdapter {
        /**
         * 主要做事前拦截,即用户操作发生前,改写preHandle里的逻辑,进行用户操作权限的拦截
         * @param request 请求
         * @param response 响应
         * @param handler controller
         * @return
         * @throws Exception
         */
        @Override
        public boolean preHandle(HttpServletRequest request,
                HttpServletResponse response, Object handler) throws Exception {
            //从session中获取当前选择的店铺
            Shop currentShop = (Shop) request.getSession().getAttribute(
                    "currentShop");
            @SuppressWarnings("unchecked")
            //从session中获取当前用户可操作的店铺列表
            List<Shop> shopList = (List<Shop>) request.getSession().getAttribute(
                    "shopList");
            //非空判断
            if (currentShop != null && shopList != null) {
                for (Shop shop : shopList) {
                    //如果当前店铺在可操作的列表里则返回true,进行接下来的用户操作
                    if (shop.getShopId() == currentShop.getShopId()) {
                        return true;
                    }
                }
            }
            //若不满足拦截器的验证则返回false终止用户操作的执行
            return false;
        }
    }

    第二步是配置拦截器:

    <!-- 5.权限拦截器 -->
        <mvc:interceptors>
        <!-- 校验是否已经登录了店家管理系统的拦截器  登陆了才能做对店铺的相关操作,所有相关请求都会被拦截先进入前面定义好的ShopLoginInterceptor类中校验-->
            <mvc:interceptor>
                <mvc:mapping path="/shopadmin/**" />
                <bean id="ShopInterceptor" class="xyspgl.interceptor.ShopLoginInterceptor" />
            </mvc:interceptor>
            <!-- 校验是否对店铺有操作权限的拦截器 ,用户不能操作不属于自己的店铺-->
            <mvc:interceptor>
                <mvc:mapping path="/shopadmin/**" />
                <!-- shoplist page 排除不需要校验的方法,只有在这两个方法获取完店铺列表后,才存在相关操作权限问题-->
                <mvc:exclude-mapping path="/shopadmin/shoplist" />
                <mvc:exclude-mapping path="/shopadmin/getshoplist" />
                <!-- shopregister page 这三个方法也不需要拦截,就是注册相关的-->
                <mvc:exclude-mapping path="/shopadmin/getshopinitinfo" />
                <mvc:exclude-mapping path="/shopadmin/registershop" />        
                <mvc:exclude-mapping path="/shopadmin/shoppoperation" />                        
                <!-- shopmanage page 店铺管理页面的两个方法也不需要拦截,因为这两个方法在调用的时候,并没有
                生成currentshop的session,因此对它做拦截是没有意义的,拦截了就进入不了 -->
                <mvc:exclude-mapping path="/shopadmin/shopmanagement" />
                <mvc:exclude-mapping path="/shopadmin/getshopmanagementinfo" />
                <bean id="ShopPermissionInterceptor"
                    class="xyspgl.interceptor.ShopPermissionInterceptor" />
            </mvc:interceptor>
        </mvc:interceptors>

    当然在controller层等需要你将一些数据set入session中来当做拦截器类中的校验条件

  • 相关阅读:
    在Spring Boot中使用数据库事务
    Data Consistency Primer
    在Spring Boot中输出REST资源
    Android开发——进程间通信之Messenger
    初识在Spring Boot中使用JPA
    设计模式——享元模式详解
    回首2016,展望2017
    [转]OpenStack Keystone V3
    [原]Openstack之identity server(keystone)
    [原]secureCRT 改变显示宽度
  • 原文地址:https://www.cnblogs.com/xk920/p/10077844.html
Copyright © 2011-2022 走看看