您当前的位置:首页 > 电脑百科 > 程序开发 > 架构

玩转Spring MVC自定义请求匹配规则

时间:2023-12-06 16:50:00  来源:  作者:Spring全家桶实战案例源码
在本文中,介绍了如何自定义RequestMAppingHandlerMapping。通过自定义getCustomMethodCondition()方法,我们可以根据特定的需求扩展HandlerMapping的行为,并使用自定义条件来匹配请求和处理器方法。通过这种方式,我们可以更好地控制请求的处理逻辑。

环境:SpringBoot2.7.12

前言

在Spring MVC框架中,HandlerMapping是用于将HTTP请求映射到处理器的方法的组件。当一个请求到达时,HandlerMapping会根据请求的URL和其他属性来确定哪个处理器方法应该处理该请求。在Spring MVC中,我们可以自定义HandlerMapping来满足特定的匹配需求。其中一个方法是使用getCustomMethodCondition()方法来自定义匹配条件。

本文将详细介绍如何使用getCustomMethodCondition()方法来自定义HandlerMapping的匹配条件。通过阅读本文,您将了解如何扩展HandlerMapping的默认行为,并使用自定义条件来匹配请求和处理器方法。

需求:我们希望根据请求header中的x-token值来匹配具体的接口。所有的接口都必须使用了自定义的注解标注。

1. 自定义请求匹配

在SpringMVC中可以通过自定义RequestMappingHandlerMapping#getCustomMethodCondition来实现此功能。

自定义请求匹配通过实现RequestCondition接口自定义规则

系统默认提供了以下RequestCondition实现

玩转Spring MVC自定义请求匹配规则

2. 自定义匹配条件

public class CustomRequestCondition implements RequestCondition<CustomRequestCondition> {


  private static final String X_TOKEN_NAME = "x-token" ;


  private Method method ;


  public CustomRequestCondition(Method method) {
    this.method = method ;
  }


  // 当接口上有多个匹配规则时,进行合并操作
  @Override
  public CustomRequestCondition combine(CustomRequestCondition other) {
    return new CustomRequestCondition(other.method) ;
  }


  // 核心方法:根据匹配的条件进行判断是否匹配,如果匹配则返回当前的对象,不匹配则返回null
  @Override
  public CustomRequestCondition getMatchingCondition(HttpServletRequest request) {
    AKF akf = method.getAnnotation(AKF.class) ;
    return akf != null ? buildToken(request, akf) : null ;
  }


  // 当有多个都满足条件的时候,进行比较具体使用哪个
  @Override
  public int compareTo(CustomRequestCondition other, HttpServletRequest request) {
    return 0 ;
  }


  // 判断请求header中的信息与注解中配置的信息是否一致
  private CustomRequestCondition buildToken(HttpServletRequest request, AKF akf) {
    String xToken = request.getHeader(X_TOKEN_NAME) ;
    if (xToken == null || xToken.length() == 0) {
      return null ;
    }
    return xToken.equals(akf.value()) ? this : null ;
  }


}

3. 配置自定义HandlerMapping

public class CustomMethodConditionRequestHandlerMapping extends RequestMappingHandlerMapping {
  @Override
  protected RequestCondition<?> getCustomMethodCondition(Method method) {
    return new CustomRequestCondition(method) ;
  }
}

配置自定义的HandlerMapping

@Component
public class CustomEndpointConfig implements WebMvcRegistrations {
  public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
    return new CustomMethodConditionRequestHandlerMapping() ;
  }
}

通过实现WebMvcRegistrations中的getRequestMappingHandlerMapping方法覆盖系统默认的RequestMappingHandlerMapping配置实现。当然这种方式你可能失去了某些功能。这里我们可以参考默认实现来完善自定义的实现。

4. 测试接口

@RestController
@RequestMapping("/conditions")
public class CustomMethodConditionController {


  @GetMapping("/index")
  public Object index() {
    return "custom method condition success" ;
  }


  @GetMapping("/index")
  @AKF
  public Object x() {
    return "x method invoke" ;
  }


  @GetMapping("/index")
  @AKF("x1")
  public Object x1() {
    return "x1 method invoke" ;
  }


  @GetMapping("/index")
  @AKF("x2")
  public Object x2() {
    return "x2 method invoke" ;
  }
}

上面的接口与通常的开发配置是一致的,只是有些有接口使用了@AKF注解。这些接口中,没有@AKF注解或者没有设置@AKF值的,都不能访问,只有设置值了,且请求中携带了x-token并匹配上值了才会访问到接口。

玩转Spring MVC自定义请求匹配规则

当访问其它没有@AKF注解的接口,返回404。

5. 原理

根据请求查找HandlerMethod

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping {
  protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    String lookupPath = initLookupPath(request);
    try {
      // 根据请求查找匹配d饿HandlerMethod
      HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
      return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
  }
  protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<>();
    // 根据请求的uri,获取相应的RequestMappingInfo(该对象对应的Controller中的每一个接口)
    List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
    if (directPathMatches != null) {
      // 根据请求找到了相应的RequestMappingInfo,则进行匹配执行相应的条件
      addMatchingMappings(directPathMatches, matches, request);
    }
    // ...
  }
  private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
    for (T mapping : mappings) {
      // 执行相应的条件进行匹配,比如:你在@RequestMapping中配置了header,params等相应的值
      T match = getMatchingMapping(mapping, request);
      if (match != null) {
        matches.add(new Match(match, this.mappingRegistry.getRegistrations().get(mapping)));
      }
    }
  }
}
public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> {
  protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
    return info.getMatchingCondition(request);
  }
}
// RequestMappingInfo
public final class RequestMappingInfo {
  // 该方法中就会根据请求request对象,判断是否当前对象符合条件
  public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
    RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
    if (methods == null) {
      return null;
    }
    ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
    if (params == null) {
      return null;
    }
    HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
    if (headers == null) {
      return null;
    }


    // ...
    // 我们配置了自定义的,这里就会执行我们自定义的条件(必须有@AKF注解)
    RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
    if (custom == null) {
      // 返回null 则表示当前的RequestMappingInfo没有匹配。
      // 最终如果都是返回的null,则最终返回客户端将是404
      return null;
    }
    return new RequestMappingInfo(this.name, pathPatterns, patterns,
        methods, params, headers, consumes, produces, custom, this.options);
  }
}

在本文中,介绍了如何自定义RequestMappingHandlerMapping。通过自定义getCustomMethodCondition()方法,我们可以根据特定的需求扩展HandlerMapping的行为,并使用自定义条件来匹配请求和处理器方法。通过这种方式,我们可以更好地控制请求的处理逻辑。



Tags:Spring   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Spring Security:保障应用安全的利器
SpringSecurity作为一个功能强大的安全框架,为Java应用程序提供了全面的安全保障,包括认证、授权、防护和集成等方面。本文将介绍SpringSecurity在这些方面的特性和优势,以及它...【详细内容】
2024-02-27  Search: Spring  点击:(52)  评论:(0)  加入收藏
Spring Security权限控制框架使用指南
在常用的后台管理系统中,通常都会有访问权限控制的需求,用于限制不同人员对于接口的访问能力,如果用户不具备指定的权限,则不能访问某些接口。本文将用 waynboot-mall 项目举例...【详细内容】
2024-02-19  Search: Spring  点击:(39)  评论:(0)  加入收藏
详解基于SpringBoot的WebSocket应用开发
在现代Web应用中,实时交互和数据推送的需求日益增长。WebSocket协议作为一种全双工通信协议,允许服务端与客户端之间建立持久性的连接,实现实时、双向的数据传输,极大地提升了用...【详细内容】
2024-01-30  Search: Spring  点击:(8)  评论:(0)  加入收藏
Spring实现Kafka重试Topic,真的太香了
概述Kafka的强大功能之一是每个分区都有一个Consumer的偏移值。该偏移值是消费者将读取的下一条消息的值。可以自动或手动增加该值。如果我们由于错误而无法处理消息并想重...【详细内容】
2024-01-26  Search: Spring  点击:(84)  评论:(0)  加入收藏
SpringBoot如何实现缓存预热?
缓存预热是指在 Spring Boot 项目启动时,预先将数据加载到缓存系统(如 Redis)中的一种机制。那么问题来了,在 Spring Boot 项目启动之后,在什么时候?在哪里可以将数据加载到缓存系...【详细内容】
2024-01-19  Search: Spring  点击:(86)  评论:(0)  加入收藏
Spring Boot2.0深度实践 核心原理拆解+源码分析
Spring Boot2.0深度实践:核心原理拆解与源码分析一、引言Spring Boot是一个基于Java的轻量级框架,它简化了Spring应用程序的创建过程,使得开发者能够快速搭建一个可运行的应用...【详细内容】
2024-01-15  Search: Spring  点击:(93)  评论:(0)  加入收藏
SpringBoot3+Vue3 开发高并发秒杀抢购系统
开发高并发秒杀抢购系统:使用SpringBoot3+Vue3的实践之旅随着互联网技术的发展,电商行业对秒杀抢购系统的需求越来越高。为了满足这种高并发、高流量的场景,我们决定使用Spring...【详细内容】
2024-01-14  Search: Spring  点击:(90)  评论:(0)  加入收藏
Spring Boot 3.0是什么?
Spring Boot 3.0是一款基于Java的开源框架,用于简化Spring应用程序的构建和开发过程。与之前的版本相比,Spring Boot 3.0在多个方面进行了改进和增强,使其更加易用、高效和灵活...【详细内容】
2024-01-11  Search: Spring  点击:(130)  评论:(0)  加入收藏
GraalVM与Spring Boot 3.0:加速应用性能的完美融合
在2023年,SpringBoot3.0的发布标志着Spring框架对GraalVM的全面支持,这一支持是对Spring技术栈的重要补充。GraalVM是一个高性能的多语言虚拟机,它提供了Ahead-of-Time(AOT)编...【详细内容】
2024-01-11  Search: Spring  点击:(124)  评论:(0)  加入收藏
Spring Boot虚拟线程的性能还不如Webflux?
早上看到一篇关于Spring Boot虚拟线程和Webflux性能对比的文章,觉得还不错。内容较长,抓重点给大家介绍一下这篇文章的核心内容,方便大家快速阅读。测试场景作者采用了一个尽可...【详细内容】
2024-01-10  Search: Spring  点击:(115)  评论:(0)  加入收藏
▌简易百科推荐
对于微服务架构监控应该遵守的原则
随着软件交付方式的变革,微服务架构的兴起使得软件开发变得更加快速和灵活。在这种情况下,监控系统成为了微服务控制系统的核心组成部分。随着软件的复杂性不断增加,了解系统的...【详细内容】
2024-04-03  步步运维步步坑    Tags:架构   点击:(4)  评论:(0)  加入收藏
大模型应用的 10 种架构模式
作者 | 曹洪伟在塑造新领域的过程中,我们往往依赖于一些经过实践验证的策略、方法和模式。这种观念对于软件工程领域的专业人士来说,已经司空见惯,设计模式已成为程序员们的重...【详细内容】
2024-03-27    InfoQ  Tags:架构模式   点击:(13)  评论:(0)  加入收藏
哈啰云原生架构落地实践
一、弹性伸缩技术实践1.全网容器化后一线研发的使用问题全网容器化后一线研发会面临一系列使用问题,包括时机、容量、效率和成本问题,弹性伸缩是云原生容器化后的必然技术选择...【详细内容】
2024-03-27  哈啰技术  微信公众号  Tags:架构   点击:(10)  评论:(0)  加入收藏
DDD 与 CQRS 才是黄金组合
在日常工作中,你是否也遇到过下面几种情况: 使用一个已有接口进行业务开发,上线后出现严重的性能问题,被老板当众质疑:“你为什么不使用缓存接口,这个接口全部走数据库,这怎么能扛...【详细内容】
2024-03-27  dbaplus社群    Tags:DDD   点击:(11)  评论:(0)  加入收藏
高并发架构设计(三大利器:缓存、限流和降级)
软件系统有三个追求:高性能、高并发、高可用,俗称三高。本篇讨论高并发,从高并发是什么到高并发应对的策略、缓存、限流、降级等。引言1.高并发背景互联网行业迅速发展,用户量剧...【详细内容】
2024-03-13    阿里云开发者  Tags:高并发   点击:(5)  评论:(0)  加入收藏
如何判断架构设计的优劣?
架构设计的基本准则是非常重要的,它们指导着我们如何构建可靠、可维护、可测试的系统。下面是这些准则的转换表达方式:简单即美(KISS):KISS原则的核心思想是保持简单。在设计系统...【详细内容】
2024-02-20  二进制跳动  微信公众号  Tags:架构设计   点击:(36)  评论:(0)  加入收藏
详解基于SpringBoot的WebSocket应用开发
在现代Web应用中,实时交互和数据推送的需求日益增长。WebSocket协议作为一种全双工通信协议,允许服务端与客户端之间建立持久性的连接,实现实时、双向的数据传输,极大地提升了用...【详细内容】
2024-01-30  ijunfu  今日头条  Tags:SpringBoot   点击:(8)  评论:(0)  加入收藏
PHP+Go 开发仿简书,实战高并发高可用微服务架构
来百度APP畅享高清图片//下栽のke:chaoxingit.com/2105/PHP和Go语言结合,可以开发出高效且稳定的仿简书应用。在实现高并发和高可用微服务架构时,我们可以采用一些关键技术。首...【详细内容】
2024-01-14  547蓝色星球    Tags:架构   点击:(114)  评论:(0)  加入收藏
GraalVM与Spring Boot 3.0:加速应用性能的完美融合
在2023年,SpringBoot3.0的发布标志着Spring框架对GraalVM的全面支持,这一支持是对Spring技术栈的重要补充。GraalVM是一个高性能的多语言虚拟机,它提供了Ahead-of-Time(AOT)编...【详细内容】
2024-01-11    王建立  Tags:Spring Boot   点击:(124)  评论:(0)  加入收藏
Spring Boot虚拟线程的性能还不如Webflux?
早上看到一篇关于Spring Boot虚拟线程和Webflux性能对比的文章,觉得还不错。内容较长,抓重点给大家介绍一下这篇文章的核心内容,方便大家快速阅读。测试场景作者采用了一个尽可...【详细内容】
2024-01-10  互联网架构小马哥    Tags:Spring Boot   点击:(115)  评论:(0)  加入收藏
站内最新
站内热门
站内头条