Springboot中SpringMvc拦截器配置与应用(实战)

一、什么是拦截器,及其作用

拦截器(Interceptor): 用于在某个方法被访问之前进行拦截,然后在方法执行之前或之后加入某些操作,其实就是AOP的一种实现策略。它通过动态拦截Action调用的对象,允许开发者定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是提供了一种可以提取action中可重用的部分的方式。

拦截器的使用场景越来越多,尤其是面向切片编程流行之后。那通常拦截器可以做什么呢?
之前我们在Agent介绍中,提到过统计函数的调用耗时。这个思路其实和AOP的环绕增强如出一辙。

那一般来说,场景如下:

1、日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。

2、权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;

3、函数增强:比如对一个函数进行参数检查,或者结果过滤等。甚至可以对函数就行权限认证。

4、性能监控:统计函数性能,有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);

5、通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。

6、OpenSessionInView:如Hibernate,在进入处理器打开Session,在完成后关闭Session。

…………本质也是AOP(面向切面编程),也就是说符合横切关注点的所有功能都可以放入拦截器实现。

二、springmvc拦截器相关接口和实现类

package org.springframework.web.servlet;
public interface HandlerInterceptor {
    boolean preHandle(
            HttpServletRequest request, HttpServletResponse response,
            Object handler)
            throws Exception;  

    void postHandle(
            HttpServletRequest request, HttpServletResponse response,
            Object handler, ModelAndView modelAndView)
            throws Exception;  

    void afterCompletion(
            HttpServletRequest request, HttpServletResponse response,
            Object handler, Exception ex)
            throws Exception;
}  
public interface AsyncHandlerInterceptor extends HandlerInterceptor {

    void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception;

}
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {

    // 在目标方法执行前执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    // 在目标方法执行后执行,但在请求返回前,我们仍然可以对 ModelAndView进行修改
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
                          throws Exception {}

    // 在请求已经返回之后执行
    @Override
    public void afterCompletion(
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {}

    // 用来处理异步请求, 当Controller中有异步请求方法的时候会触发该方法
    @Override
    public void afterConcurrentHandlingStarted(
            HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {}
}

三、如何配置拦截器

1、springboot项目中如何配置拦截器

实现自定义拦截器只需要3步: 
1、创建我们自己的拦截器类并实现 HandlerInterceptor 接口。 
2、创建一个Java类继承WebMvcConfigurerAdapter,并重写 addInterceptors 方法。 
3、实例化我们自定义的拦截器,然后将对像手动添加到拦截器链中(在addInterceptors方法中添加)。

package com.springboot.study.interceptors;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class MyInterceptor1 implements HandlerInterceptor{

    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
        System.out.println("=====>(1)在整个请求之后调用,即在dispatcherServlet渲染了对应的视图之后(主要是进行资源清理工作)");
    }

    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
            throws Exception {
        System.out.println("=====>(1)在请求处理之后调用,即在controller方法执行之后调用");
    }

    @Override
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
        System.out.println("=====>(1)在请求处理之前调用,即在Controller方法调用之前!");
        return true;//只有返回true才会往下执行,返回FALSE的话就会取消当前请求
    }

}
package com.springboot.study.interceptors;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class MyInterceptor2 implements HandlerInterceptor{

    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
        System.out.println("=====>(2)在整个请求之后调用,即在dispatcherServlet渲染了对应的视图之后(主要是进行资源清理工作)");
    }

    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
            throws Exception {
        System.out.println("=====>(2)在请求处理之后调用,即在controller方法执行之后调用");
    }

    @Override
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
        System.out.println("=====>(2)在请求处理之前调用,即在Controller方法调用之前!");
        return true;//只有返回true才会往下执行,返回FALSE的话就会取消当前请求
    }

}
package com.springboot.study.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @RequestMapping("/index")
    public String index(){
        return "hello!";
    }

}
package com.springboot.study.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import com.springboot.study.interceptors.MyInterceptor1;
import com.springboot.study.interceptors.MyInterceptor2;

@Configuration
public class MyWebAppConfigurer extends WebMvcConfigurerAdapter{

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/**");
        registry.addInterceptor(new MyInterceptor2()).addPathPatterns("/**");
        super.addInterceptors(registry);
    }
}
运行结果:=====>(1)在请求处理之前调用,即在Controller方法调用之前!
=====>(2)在请求处理之前调用,即在Controller方法调用之前!
=====>(2)在请求处理之后调用,即在controller方法执行之后调用
=====>(1)在请求处理之后调用,即在controller方法执行之后调用
=====>(2)在整个请求之后调用,即在dispatcherServlet渲染了对应的视图之后(主要是进行资源清理工作)
=====>(1)在整个请求之后调用,即在dispatcherServlet渲染了对应的视图之后(主要是进行资源清理工作)

四、实例

自定义权限注解

定义一个@interface

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Access {

    String[] value() default {};

    String[] authorities() default {};

    String[] roles() default {};

}

@Target注解是标注这个类它可以标注的位置:
常用的元素类型(ElementType):

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    // TYPE类型可以声明在类上或枚举上或者是注解上
    TYPE,
    /** Field declaration (includes enum constants) */
    // FIELD声明在字段上
    FIELD,
    /** Method declaration */
    // 声明在方法上
    METHOD,
    /** Formal parameter declaration */
    // 声明在形参列表中
    PARAMETER,
    /** Constructor declaration */
    // 声明在构造方法上
    CONSTRUCTOR,
    /** Local variable declaration */
    // 声明在局部变量上
    LOCAL_VARIABLE,
    /** Annotation type declaration */
    ANNOTATION_TYPE,
    /** Package declaration */
    PACKAGE,
    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,
    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

@Retention注解表示的是本注解(标注这个注解的注解保留时期)

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    // 源代码时期
    SOURCE,
    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    // 字节码时期, 编译之后
    CLASS,
    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
     // 运行时期, 也就是一直保留, 通常也都用这个
    RUNTIME
}

@Documented是否生成文档的标注, 也就是生成接口文档是, 是否生成注解文档

注解说完了, 下面需要到对应的controller的方法中取添加注解, 配置该方法允许的权限

在方法上配置权限

@RestController
public class HelloController {

    @RequestMapping(value = "/admin", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.GET)
    // 配置注解权限, 允许身份为admin, 或者说允许权限为admin的人访问
    @Access(authorities = {"admin"})
    public String hello() {
        return "Hello, admin";
    }
}

编写权限拦截逻辑

// 自定义一个权限拦截器, 继承HandlerInterceptorAdapter类
public class AuthenticationInterceptor extends HandlerInterceptorAdapter {

    // 在调用方法之前执行拦截
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 将handler强转为HandlerMethod, 前面已经证实这个handler就是HandlerMethod
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        // 从方法处理器中获取出要调用的方法
        Method method = handlerMethod.getMethod();
        // 获取出方法上的Access注解
        Access access = method.getAnnotation(Access.class);
        if (access == null) {
        // 如果注解为null, 说明不需要拦截, 直接放过
            return true;
        }
        if (access.authorities().length > 0) {
            // 如果权限配置不为空, 则取出配置值
            String[] authorities = access.authorities();
            Set<String> authSet = new HashSet<>();
            for (String authority : authorities) {
            // 将权限加入一个set集合中
                authSet.add(authority);
            }
            // 这里我为了方便是直接参数传入权限, 在实际操作中应该是从参数中获取用户Id
            // 到数据库权限表中查询用户拥有的权限集合, 与set集合中的权限进行对比完成权限校验
            String role = request.getParameter("role");
            if (StringUtils.isNotBlank(role)) {
                if (authSet.contains(role)) {
                // 校验通过返回true, 否则拦截请求
                    return true;
                }
            }
        }
        // 拦截之后应该返回公共结果, 这里没做处理
        return false;
    }

}

拦截器详解源码地址:https://www.cnblogs.com/fangjian0423/p/springMVC-interceptor.html

原文地址:https://www.cnblogs.com/ysq2018China/p/10250897.html

时间: 2024-10-06 12:37:24

Springboot中SpringMvc拦截器配置与应用(实战)的相关文章

在springboot中使用拦截器

在springMVC中可以实现拦截器,是通过实现HandlerInterceptor接口,然后在springmvc-web.xml中配置就可以使用拦截器了.在springboot中拦截器也是一样的思想,使用方法还是没有变,只不过是配置稍微变了一下. 在springboot中使用拦截器步骤如下: 1.按照springmvc模式写一个拦截器类 和springmvc一样,也要写一个类实现HandlerInterceptor接口,然后重新其中的prehandle方法. 2.然后写一个配置类,继承WebM

SpringMVC拦截器配置

拦截器顾名思义就是用于拦截访问请求的,我们可以在拦截器里对访问请求进行事先的处理,例如权限检查.记录日志.验证请求数据等等.说白了就是我们可以在请求到控制器之前对其进行一个处理. 拦截器基本上和过滤器是类似的,只不过拦截器提供的方法比较实用,参数也比较多,而且拦截器是受到spring容器的管理的. 实现拦截器很简单,只需要实现spring里的HandlerInterceptor接口并实现接口中的三个方法即可,如下示例: package org.zero01.test; import org.sp

SpringMVC拦截器的使用

SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理.比如通过它来进行权限验证,或者是来判断用户是否登陆,或者是像12306 那样子判断当前时间是否是购票时间. 一.springMVC拦截器的实现方式 springMVC拦截器的实现一般有两种方式:第一种方式是要定义的Interceptor类要实现了Spring的HandlerInterceptor 接口.第二种方式是继承实现了HandlerInterceptor接口的类,比

springboot三种拦截器的使用与比较

springboot中有三种拦截器可供选择:filter.interceptort和aop.本文主要讨论三种拦截器的使用场景与使用方式. 下文中的举例功能是计算每个请求的从开始到结束的时间,例子来源是慕课网. 一.filter 特点:可以获取原始的ServletRequest,但无法获取具体方法 实现: 1.继承javax.servlet.Filter类, [email protected]注解将其注入到框架中 3.实现其中的dofilter方法,所有的请求都会经过该方法,可以在此计算出每个请求

关于springmvc拦截器,不拦截jsp的问题

这是xml中的拦截器配置 <mvc:interceptors> <mvc:interceptor> <!-- 不放行的 --> <mvc:mapping path="/**"/> <!-- 放行的 --> <mvc:exclude-mapping path="/login/*"/> <mvc:exclude-mapping path="/static/**"/>

springboot+springmvc拦截器做登录拦截

springboot+springmvc拦截器做登录拦截 LoginInterceptor 实现 HandlerInterceptor 接口,自定义拦截器处理方法 LoginConfiguration 实现 WebMvcConfigurer 接口,注册拦截器 ResourceBundle 加载 properties文件数据,配置不进行拦截的路径 LoginInterceptor package com.ytkj.smart_sand.system.interceptor; import com.

【SpringMVC学习11】SpringMVC中的拦截器

Springmvc的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理.本文主要总结一下springmvc中拦截器是如何定义的,以及测试拦截器的执行情况和使用方法. 1. springmvc拦截器的定义和配置 1.1 springmvc拦截器的定义 在springmvc中,定义拦截器要实现HandlerInterceptor接口,并实现该接口中提供的三个方法,如下: //测试拦截器1 public class HandlerInterceptor1 im

在SpringMVC中使用拦截器(interceptor)拦截CSRF攻击

关于什么是CSRF我这里就不多说了,以前转载的一篇文章(PS:https://www.zifangsky.cn/358.html)已经说得很清楚了.这里只是简单介绍如何在SpringMVC中使用拦截器拦截CSRF攻击.具体代码如下: (1)登录页面: <%@page import="java.security.SecureRandom"%> <%@ page language="java" contentType="text/html; 

SpringMVC学习(十二)——SpringMVC中的拦截器

SpringMVC学习(十二)--SpringMVC中的拦截器 SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理.本文主要总结一下SpringMVC中拦截器是如何定义的,以及测试拦截器的执行情况和使用方法. SpringMVC中拦截器的定义和配置 SpringMVC中拦截器的定义 在SpringMVC中,定义拦截器要实现HandlerInterceptor接口,并实现该接口中提供的三个方法,如下: public class Inter