SpringBoot—统一功能处理(一)

简介: SpringBoot—统一功能处理

利用 AOP 的思想对一些特定的功能进行统一的处理, 包括

  • 使用拦截器实现用户登录权限的统一校验
  • 统一异常的处理
  • 统一数据格式的返回

🔎小插曲(通过一级路由调用多种方法)


通过一级路由调用多种方法, 需要保证这些方法的请求类型各不相同(GET, POST, PUT…)

🔎使用拦截器实现用户登录权限的统一校验


使用 Spring AOP 可以实现统一拦截, 但 Spring AOP 的使用较为复杂, 包括

  1. 定义拦截的规则(切点表达式)较为复杂
  2. 在切面类中拿到 HttpSession 较为复杂

于是 Pivotal 公司针对上述情况开发出 Spring 拦截器

Spring 拦截器的使用🍂

  1. 自定义拦截器
  • 实现 HandlerInterceptor 接口
  • 重写 preHandler 方法, 在方法中编写业务代码
  1. 将自定义拦截器添加至配置文件中, 并设置拦截的规则

自定义拦截器


将自定义拦截器添加至配置文件中


  • addPathPatterns, 表示需要拦截的 URL
    (/*表示一级路由, /**表示所有的请求)
  • excludePathPatterns, 表示不需要拦截的 URL

拦截器的实现原理


调用方法时, 发现 DispatcherServlet

Dispatcher → 调度器

所有方法都会执行 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);
     try {
         try {
             ModelAndView mv = null;
             Object dispatchException = null;
             try {
                 processedRequest = this.checkMultipart(request);
                 multipartRequestParsed = processedRequest != request;
                 mappedHandler = this.getHandler(processedRequest);
                 if (mappedHandler == null) {
                     this.noHandlerFound(processedRequest, response);
                     return;
                 }
                 HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                 String method = request.getMethod();
                 boolean isGet = HttpMethod.GET.matches(method);
                 if (isGet || HttpMethod.HEAD.matches(method)) {
                     long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                     if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                         return;
                     }
                 }
                 if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                     return;
                 }
                 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                 if (asyncManager.isConcurrentHandlingStarted()) {
                     return;
                 }
                 this.applyDefaultViewName(processedRequest, mv);
                 mappedHandler.applyPostHandle(processedRequest, response, mv);
             } catch (Exception var20) {
                 dispatchException = var20;
             } catch (Throwable var21) {
                 dispatchException = new NestedServletException("Handler dispatch failed", var21);
             }
             this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
         } catch (Exception var22) {
             this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
         } catch (Throwable var23) {
             this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
         }
     } finally {
         if (asyncManager.isConcurrentHandlingStarted()) {
             if (mappedHandler != null) {
                 mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
             }
         } else if (multipartRequestParsed) {
             this.cleanupMultipart(processedRequest);
         }
     }
}


当返回结果为 false 时, 拦截器将不会进行后续操作

applyPreHandle 的源码🌰

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {
        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, 并执行 HandlerInterceptor 中的 preHandle 方法

即自定义拦截器中重写的 preHandle 方法

统⼀访问前缀添加


统⼀访问前缀的添加有 2 种方式

  1. 重写 configurePathMatch( )
  2. 在配置文件中添加

重写 configurePathMatch( ) 🍂

@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
    configurer.addPathPrefix("/bibubibu", c -> true);
}
  • /bibubibu, 要添加的统一前缀
  • c -> true, 所有请求均添加统一前缀

在配置文件中添加🍂

server:
  servlet:
    context-path: /bibubibu

相关文章
|
5月前
|
XML 前端开发 Java
SpringBoot实现文件上传下载功能
本文介绍了如何使用SpringBoot实现文件上传与下载功能,涵盖配置和代码实现。包括Maven依赖配置(如`spring-boot-starter-web`和`spring-boot-starter-thymeleaf`)、前端HTML页面设计、WebConfig路径映射配置、YAML文件路径设置,以及核心的文件上传(通过`MultipartFile`处理)和下载(利用`ResponseEntity`返回文件流)功能的Java代码实现。文章由Colorful_WP撰写,内容详实,适合开发者学习参考。
475 0
|
4月前
|
安全 Java API
Spring Boot 功能模块全解析:构建现代Java应用的技术图谱
Spring Boot不是一个单一的工具,而是一个由众多功能模块组成的生态系统。这些模块可以根据应用需求灵活组合,构建从简单的REST API到复杂的微服务系统,再到现代的AI驱动应用。
|
11月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
150 4
|
11月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
591 1
|
5月前
|
SQL 前端开发 Java
深入理解 Spring Boot 项目中的分页与排序功能
本文深入讲解了在Spring Boot项目中实现分页与排序功能的完整流程。通过实际案例,从Service层接口设计到Mapper层SQL动态生成,再到Controller层参数传递及前端页面交互,逐一剖析每个环节的核心逻辑与实现细节。重点包括分页计算、排序参数校验、动态SQL处理以及前后端联动,确保数据展示高效且安全。适合希望掌握分页排序实现原理的开发者参考学习。
314 4
|
10月前
|
Java 开发者 微服务
手写模拟Spring Boot自动配置功能
【11月更文挑战第19天】随着微服务架构的兴起,Spring Boot作为一种快速开发框架,因其简化了Spring应用的初始搭建和开发过程,受到了广大开发者的青睐。自动配置作为Spring Boot的核心特性之一,大大减少了手动配置的工作量,提高了开发效率。
177 0
|
5月前
|
存储 Java 定位技术
SpringBoot整合高德地图完成天气预报功能
本文介绍了如何在SpringBoot项目中整合高德地图API实现天气预报功能。从创建SpringBoot项目、配置依赖和申请高德地图API开始,详细讲解了实体类设计、服务层实现(调用高德地图API获取实时与预报天气数据)、控制器层接口开发以及定时任务的设置。通过示例代码,展示了如何获取并处理天气数据,最终提供实时天气与未来几天天气预报的接口。文章还提供了测试方法及运行步骤,帮助开发者快速上手并扩展功能。
|
11月前
|
Java API 数据库
Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐
本文通过在线图书管理系统案例,详细介绍如何使用Spring Boot构建RESTful API。从项目基础环境搭建、实体类与数据访问层定义,到业务逻辑实现和控制器编写,逐步展示了Spring Boot的简洁配置和强大功能。最后,通过Postman测试API,并介绍了如何添加安全性和异常处理,确保API的稳定性和安全性。
141 0
|
10月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
319 62
|
10月前
|
消息中间件 缓存 Java
手写模拟Spring Boot启动过程功能
【11月更文挑战第19天】Spring Boot自推出以来,因其简化了Spring应用的初始搭建和开发过程,迅速成为Java企业级应用开发的首选框架之一。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,帮助读者深入理解其工作机制。
133 3