springmvc

二十二. SpringMVC-拦截器

2019-09-30  本文已影响0人  任未然

一、概要

Spring Web MVC的拦截器,类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。

二、核心接口

拦截器

preHandle方法

进入Handler方法之前执行。可以用于身份认证、身份授权。比如如果认证没有通过表示用户没有登陆,需要此方法拦截不再往下执行(return false),否则就放行(return true)。

postHandle方法

进入Handler方法之后,返回ModelAndView之前执行。可以看到该方法中有个modelAndView的形参。应用场景:从modelAndView出发:将公用的模型数据(比如菜单导航之类的)在这里传到视图,也可以在这里同一指定视图。

afterCompletion方法

执行Handler完成之后执行。应用场景:统一异常处理,统一日志处理等。

拦截器适配器

spring提供了一个HandlerInterceptorAdapter适配器(一种适配器设计模式的实现),允许我们只实现需要的回调方法

三、使用步骤

第一步 创建一个类实现 HandlerInterceptor

/**
 * 现在需要实现用户登录检查——如果发现用户没有登录,跳转到登录页面,登
 * 录成功后跳转回之前访问的页面。
 *
 * @author zhangwei
 */
@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    public static final String USER_SESSION_NAME = "username";
    /**
     * 作用
     * 预处理回调方法
     * 1> 如果方法返回true 表示继续执行下一个拦截器
     * 2> 如果方法返回false 请求处理流程中断
     * 不会继续调用其他的拦截器或处理器方法,此时需要通过response产生响应
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object attribute = request.getSession().getAttribute(USER_SESSION_NAME);
        log.debug("VerifyInterceptor====> preHandle方法执行" );
        if (attribute != null) {
            return true;
        }
        response.sendRedirect("/account/login?next=" + request.getRequestURI());
        return false;
    }
    /**
     * 后处理回调方法,
     * 实现处理器的后处理(但在渲染视图之前),
     * 此时可以通过modelAndView对模型数据进行处理或对视图进行处理
     *
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.debug("VerifyInterceptor====> preHandle2方法执行" );
    }
    /**
     * 整个请求处理完毕回调方法,即在视图渲染完毕时调用
     *
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.debug("VerifyInterceptor====> afterCompletion 方法执行" );
    }
}

第二步 控制器

@Controller
@RequestMapping("/account")
public class AccountController {
    @RequestMapping("/login")
    public String login(HttpServletRequest request) {
        request.getSession().setAttribute("username", "admin");
        return   "redirect:/";
    }
}

四、注册方式

一种通过java类注册,另外一种通过xml注册

java类注册(spring-boot)

@Configuration
public class WebMvcConfigInterceptor implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 添加拦截器
        registry.addInterceptor(new VerifyInterceptor())
                    // 添加拦截的url地址
                .addPathPatterns("/**")
                    // 排除不拦截的url地址
                .excludePathPatterns("/login");
    }
}

xml注册

拦截所有的url

<mvc:interceptors>
    <bean class="com.vip.mvc.interceptor.LoginInterceptor"/>
</mvc:interceptors>

拦截匹配的URL

<mvc:interceptors >
  <mvc:interceptor>
            <interceptor下面定义的mapping和exclude-mapping都是可以有多个的>
             <!-- /user/*  -->
        <mvc:mapping path="/admin/**" />
     <mvc:exclude-mapping path="/account/login" /><!-- 不拦截 -->
        <bean class="com.vip.mvc.interceptor.LoginInterceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>

注 拦截器语法

Wildcard Description
? 匹配任何单字符
* 匹配0或者任意数量的字符
** 匹配0或者更多的目录

栗子

匹配 说明
/app/*.x 匹配(Matches)所有在app路径下的.x文件
/app/p?ttern 匹配(Matches) /app/pattern 和 /app/pXttern,但是不包括/app/pttern
/**/example 匹配(Matches) /app/example, /app/foo/example, 和 /example
/app/**/dir/file. 匹配(Matches) /app/dir/file.jsp, /app/foo/dir/file.html,/app/foo/bar/dir/file.pdf, 和 /app/dir/file.java
/*/.jsp 匹配(Matches)任何的.jsp 文件

五、栗子

需求

创建登录拦截器

/**
 * 现在需要实现用户登录检查——如果发现用户没有登录,跳转到登录页面,登
 * 录成功后跳转回之前访问的页面。
 *
 * @author zhangwei
 */
@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    public static final String USER_SESSION_NAME = "username";
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object attribute = request.getSession().getAttribute(USER_SESSION_NAME);
        log.debug("VerifyInterceptor====> preHandle方法执行" );
        if (attribute != null) {
            return true;
        }
        response.sendRedirect("/account/login?next=" + request.getRequestURI());
        return false;
    }
}

创建登录控制器

@Controller
@RequestMapping("/account")
public class AccountController {
    @RequestMapping("/login")
    public String login(HttpServletRequest request) {
        request.getSession().setAttribute("name", "admin");
        // 重定向
        return "redirect:/";
    }
}

注册拦截器

<mvc:interceptors>
  <mvc:interceptor>
    <mvc:mapping path="/"/>
    <mvc:exclude-mapping path="/account/login"/>
    <bean class="com.vip.mvc.interceptor.LoginInterceptor"/>
  </mvc:interceptor>
</mvc:interceptors>

性能检测案例

@Component
@Slf4j
public class PerformanceInterceptor extends HandlerInterceptorAdapter {
    ThreadLocal<Long> threadLocal = new ThreadLocal<>();
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1、开始时间
        long beginTime = System.currentTimeMillis();
        threadLocal.set(beginTime);
        return true;
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //2、结束时间
        long endTime = System.currentTimeMillis();
        //3、消耗的时间
        long consumeTime = endTime - threadLocal.get();
        // 此处认为处理时间超过300毫秒的请求为慢请求
        if (consumeTime > 300) {
            log.error("请求url:{} 执行时间:{}" , request.getRequestURI(),consumeTime);
        }
    }
}
<mvc:interceptors>
  <mvc:interceptor>
    <mvc:mapping path="/**"/>
    <bean class="com.vip.mvc.interceptor.PerformanceInterceptor"/>
  </mvc:interceptor>
</mvc:interceptors>

六、区别

1、过滤器:

依赖于servlet容器;

2、拦截器:

上一篇下一篇

猜你喜欢

热点阅读