Spring 统一功能处理(拦截器)

这篇具有很好参考价值的文章主要介绍了Spring 统一功能处理(拦截器)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


Spring拦截器

SpringBoot统一功能处理。也就是AOP的具体实现。

1.统一用户登录权限校验

最原始的用户登录验证方法,我们通过封装了一个方法来判断用户是否登录,但如果实现的功能多了,那么每一个需要登录的功能都要在对应的接口中来调用这个函数来判读是否登录。

public class LoginStatus {
    public static User getStatus(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session == null) {
            //当前用户未登录
            return null;
        }

        User user = (User) session.getAttribute("user");
        if (user == null) {
            //当前用户未登录
            return null;
        }

        return user;
    }
}

上面的代码虽然已经封装成了方法,但是如果随着程序功能的增多,那么每一个控制器都要调用这个接口进行判断,就出现了代码的冗余,也增加了代码的维护成本。

这个时候就需要提供一个公共的方法来进行统一的用户登录权限验证了。

1) SpringAOP 用户统一验证的问题

统一验证我们可以使用SpringAOP的前置通知或者是环绕通知来实现

@Aspect // 说明该类为一个切面
@Component
public class UserAspect {

    // 定义切点,使用 AspectJ表达式语法,拦截UserController所有方法
    @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
    public void pointcut(){}

    // 前置通知
    @Before("pointcut()")
    public void doBefore() {
        System.out.println("执行Before前置通知");
    }

    // 添加环绕通知
    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) {
        Object result = null;
        System.out.println("执行环绕通知的前置方法");

        try {
            // 执行(拦截的)业务方法
            result = joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("执行环绕通知的后置方法");

        return result;
    }
}

我们发现原生的SpringAOP的切面实现用户登录权限的校验功能,会有两个问题

  1. 我们是获取不到HttpSession对象的
  2. 如果我们只对一部分方法进行拦截,像登录和注册这样的方法就没有必要拦截,这样的很难定义排除对应方法的规则,甚至说没有办法定义。

那就可以使用Spring的拦截器

2) Spring拦截器

对于上面两个问题Spring中提供了解决方案,提供了具体实现的拦截器:Handlerlnterceptor,拦截器的实现分为两个步骤:

  1. 创建自定义拦截器,实现Handlerlnterceptor接口的preHandle(执行具体方法之前的预处理)方法
  2. 将自定义拦截器加入WebMvcConfigureraddInterceptors

1.自定义拦截器

用户登录权限校验,自定义拦截器代码实现:

/**
 * 定义自定义拦截器实现用户登录校验
 */
@Configuration
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession(false);
        if (session != null &&  session.getAttribute("userInfo") != null) {
            response.setStatus(200);
            return true;
        }
        response.setStatus(403);
        return false;
    }

}

2.将自定义拦截器加入到系统配置中

将上一步自定义的拦截器加入到系统配置信息中,代码实现:

@Configuration
public class AppConfig implements WebMvcConfigurer {

    //添加拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor()) // 添加自定义拦截器
                .addPathPatterns("/**") //拦截所有接口
                .excludePathPatterns("/**/login")//排除的接口
    }
}
  • addPathPatterns:表示需要拦截的 URL,*”表示拦截任意⽅法(也就是所有⽅法)
  • excludePathPatterns:表示需要排除的 URL。
  • 以上的拦截规则可以拦截程序中使用的URL、静态文件(图片、前端文件等)

排除所有静态的资源

@Configuration
public class AppConfig implements WebMvcConfigurer {

    //添加拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor()) // 添加自定义拦截器
                .addPathPatterns("/**")
                .excludePathPatterns("/**/*.html")//排除所有静态资源
                .excludePathPatterns("/**/*.css")
                .excludePathPatterns("/**/*.js")
                .excludePathPatterns("/**/img/*");
    }
}

3) 拦截器实现原理

原本正常的调用流程是这样的:

Spring 统一功能处理(拦截器)

但是添加了拦截器后,在调用Controller之前会进行相对应业务处理

Spring 统一功能处理(拦截器)

Spring 统一功能处理(拦截器)

⽽所有⽅法都会执⾏ DispatcherServlet 中的 doDispatch 调度⽅法,doDispatch 部分源码如下

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

       //此处省略上面代码
    // 调用预处理
    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
        return;
    }
    // 执行Controller中的业务
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    if (asyncManager.isConcurrentHandlingStarted()) {
        return;
    }
    // ......后面代码省略
                
}

从上述源码可以看出在开始执⾏ Controller 之前,会先调⽤ 预处理⽅法 applyPreHandle,⽽
applyPreHandle ⽅法的实现源码如下

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {
            // 获取项⽬中使⽤的拦截器 HandlerIntercepto
            HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
            if (!interceptor.preHandle(request, response, this.handler)) {
                this.triggerAfterCompletion(request, response, (Exception)null);
                return false;
            }
        }

        return true;
    }

从上述源码可以看出,在 applyPreHandle 中会获取所有的拦截器 HandlerInterceptor 并执⾏拦截器中
的 preHandle ⽅法,这样就会咱们前⾯定义的拦截器对应上了,如下图所示 :

Spring 统一功能处理(拦截器)

只有当我们重写的方法放回true的时候才会继续走调用Controller的业务代码,否则就是直接放回给前端

Spring 统一功能处理(拦截器)

拦截器的实现原理:

  • 从宏观上来讲的话,它是根据AOP的思想来去执行的,把统一的方法放到前置处理器来进行处理
  • 在Spring中的拦截器实现,就是在调度器类里的调度方法,调度方法在真正调用Controller之前,它会有一个方法先去扫描当前Spring中所有拦截器的一个列表,然后去执行这些拦截器,只有当拦截器执行通过的时候,它才会继续走后面的流程,才会去走Controller然后返回结果给前端。

4)同一访问前缀添加

该方法可以给所有接口添加一个访问前缀,让前端访问接口时都要加上blog,比如原来是/add,添加前缀后就是/blog/add

@Configuration
public class AppConfig implements WebMvcConfigurer {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.addPathPrefix("blog",pre->true);
    }
}

其中第⼆个参数是⼀个表达式,设置为 true 表示启动前缀

2. 统一异常处理

同一异常处理是通过@ControllerAdvice+@ExceptionHandler两个注解结合实现的,@ControllerAdvice表示控制器通知类,@ExceptionHandler是异常处理,两个结合起来就表示出现异常的时候执行某一个通知,也就是执行某个方法,代码实现:

@ControllerAdvice
public class ErrorAdvice  {

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Object handler(Exception e) {
        Map<String,Object> map = new HashMap<>();
        map.put("success",1);
        map.put("status",-1);
        map.put("message","服务器接口异常");
        return map;
    }
}

注意:方法名和返回值可以任意,重要的是注解。

这里的代码表示的是发生任何异常都给前端返回一个HashMap,也可以指定异常进行处理代码如下

@ControllerAdvice
public class ErrorAdvice  {

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Object exceptionAdvice(Exception e) {
        Map<String,Object> map = new HashMap<>();
        map.put("success",1);
        map.put("status",-1);
        map.put("message","服务器接口异常");
        return map;
    }

    @ExceptionHandler(NullPointerException.class)
    @ResponseBody
    public Object nullPointerExceptionAdvice(NullPointerException exception) {
        Map<String,Object> map = new HashMap<>();
        map.put("success",1);
        map.put("status",-1);
        map.put("message",exception.toString());
        return map;
    }
}

当有多个异常通知时,匹配顺序为当前类及其⼦类向上依次匹配

3. 统一数据返回格式

1)统一数据返回的好处

统一数据返回格式有很多好处

  1. 方便前端程序员接收和解析后端接口返回的数据
  2. 降低前端程序员和后端程序员的沟通成本,只需要按照指定格式实现功能,所有接口放回值都是固定的
  3. 有利于项目整体的维护和修改,有利于后端统一标准规范。

2)统一数据返回实现

统一的数据返回格式可以使用@ControllerAdvice+ResponseBodyAdvice实现文章来源地址https://www.toymoban.com/news/detail-436739.html

  • supports方法返回true表示对返回内容进行重写,就会执行beforeBodyWrite方法
  • beforeBodyWrite方法中body就是Controller返回的内容
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
    /**
     * 内容是否需要重写,此方法可以选择部分控制器和方法进行重写
     * 返回 true表示重写
     */
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    /**
     *控制器方法返回之前会调用此方法
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        Map<String,Object> result = new HashMap<>();
        result.put("success",200);
        result.put("status",1);
        result.put("data",body);

        return result;
    }
}


到了这里,关于Spring 统一功能处理(拦截器)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Boot 统一功能处理(拦截器实现用户登录权限的统一校验、统一异常返回、统一数据格式返回)

    目录 1. 用户登录权限校验 1.1 最初用户登录权限效验 1.2 Spring AOP 用户统⼀登录验证 1.3 Spring 拦截器 (1)创建自定义拦截器 (2)将自定义拦截器添加到系统配置中,并设置拦截的规则 1.4 练习:登录拦截器 (1)实现 UserController 实体类 (2)返回的登录页面:login.html (3)实

    2024年02月12日
    浏览(47)
  • SpringBoot -05 SpringBoot web相关配置(静态资源访问、统一异常处理、文件上传、拦截器、统一跨域请求处理)

    小总结 SpringBoot是一个基于Spring的工具集,去帮我们完成了大量的配置。在SpringBoot中有一个约定大于配置的概念,就是他把我们很多第三方框架帮我们写好了,而且把我们整个第三方框架所需要的依赖全都通过起步依赖加进去了。开发中只需要加入起步依赖就可以实现某个场

    2024年02月01日
    浏览(43)
  • springmvc统一异常处理拦截器

    使用@RestControllerAdvice+@ExceptionHandler实现 也可以使用@ControllerAdvice+@ResponseBody+@ExceptionHandler实现 创建一个异常处理的类,放在config包下  组件类:  也可以让不同的异常返回不同的结果,捕获什么异常由@ExceptionHandler的value属性决定,传入一个类对象(可以通过反射获得)  

    2024年02月15日
    浏览(40)
  • 【SpringMVC】统一异常处理 前后台协议联调 拦截器

    1. 问题描述 在讲解这一部分知识点之前,我们先来演示个效果,修改BookController类的 getById 方法 重新启动运行项目,使用PostMan发送请求,当传入的id为1,则会出现如下效果: 前端接收到这个信息后和之前我们约定的格式不一致,这个问题该如何解决? 在解决问题之前,我们

    2024年02月11日
    浏览(48)
  • 7.5 SpringBoot 拦截器Interceptor实战 统一角色权限校验

    在【 7.1 】管理员图书录入和修改API,当时预告过:并没有写【校验是否是管理员】的逻辑,因为是通用逻辑,会单写一篇来细讲,那么今天就来安排! 角色权限校验 ,是保证接口安全必备的能力:有权限才可以操作!所以,一般对于这种通用逻辑,推荐不与主业务逻辑耦合

    2024年02月16日
    浏览(42)
  • 【SpringMVC】统一异常处理 前后台协议联调 拦截器(文末赠书)

    1. 问题描述 在讲解这一部分知识点之前,我们先来演示个效果,修改BookController类的 getById 方法 重新启动运行项目,使用PostMan发送请求,当传入的id为1,则会出现如下效果: 前端接收到这个信息后和之前我们约定的格式不一致,这个问题该如何解决? 在解决问题之前,我们

    2024年02月09日
    浏览(45)
  • Spring/SpringBoot 拦截器

    Spring/SpringBoot 拦截器 拦截器的作用: 拦截器,可以进行请求过滤、权限管理、打印日志、数据校验等。 拦截器,可以在请求前、请求后进行处理。 代码示例: 拦截器 MyInterceptor: Spring的拦截器,需要实现 HandlerInterceptor 接口。 配置拦截器: 配置拦截器,需要实现 WebMvcConf

    2024年02月19日
    浏览(42)
  • 掌握Spring MVC拦截器整合技巧,实现灵活的请求处理与权限控制!

    (1)浏览器发送一个请求会先到Tomcat的web服务器。 (2)Tomcat服务器接收到请求以后,会去判断请求的是静态资源还是动态资源。 (3)如果是静态资源,会直接到Tomcat的项目部署目录下去直接访问。 (4)如果是动态资源,就需要交给项目的后台代码进行处理。 (5)在找到具体的方法之前

    2024年01月22日
    浏览(46)
  • 【Spring】Springboot过滤器Filter和拦截器Inteceptor详解及使用场景

    Springboot过滤器Filter和拦截器Inteceptor详解及使用场景

    2024年02月13日
    浏览(42)
  • 【Spring实战项目】SpringBoot3整合WebSocket+拦截器实现登录验证!从原理到实战

    🎉🎉 欢迎光临,终于等到你啦 🎉🎉 🏅我是 苏泽 ,一位对技术充满热情的探索者和分享者。🚀🚀 🌟持续更新的专栏 《Spring 狂野之旅:从入门到入魔》 🚀 本专栏带你从Spring入门到入魔   这是苏泽的个人主页可以看到我其他的内容哦👇👇 努力的苏泽 http://suzee.blog.

    2024年04月17日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包