当前位置: 首页 > news >正文

@PathVariable注解的使用及源码解析

前言

@PathVariable 注解是我们进行JavaEE开发,最常见的几个注解之一,这篇博文我们以案例和源码相结合,帮助大家更好的了解@PathVariable 注解

使用案例

1.获取 URL 上的值

@RequestMapping("/id/{id}")
public Object getId(@PathVariable(value = "id") Integer id) {return id;
}

2.获取 URL 上的多个值

多个值以 / 分割,可以相邻也可以不相邻

2.1 多个值相邻
@GetMapping("/info/{id}/{name}")
public Object getInfo(@PathVariable(value = "id") Integer id, @PathVariable(value = "name") String name) {return "id:" + id + ",name:" + name;
}

2.1 多个值不相邻
@GetMapping("/info/{id}/delimiter/{name}")
public Object getDelimiterInfo(@PathVariable(value = "id") Integer id, @PathVariable(value = "name") String name) {return "id:" + id + ",name:" + name;
}

3. 不指定value(name)

@RequestMapping("/default/{id}")
public Object getDefaultId(@PathVariable Integer id) {return id;
}

4. 使用 Map 接受多个 URL 上的值

@GetMapping("/info_map/{id}/{name}")
public Object getInfoToMap(@PathVariable Map<String, Object> map) {StringBuilder sb = new StringBuilder();map.forEach((key, value) -> sb.append(key).append(":").append(value).append(","));return sb.substring(0, sb.length() - 1);
}

源码解析

 InvocableHandlerMethod#getMethodArgumentValues

参数的处理分为两个阶段:

  1. 判断当前环境中存在的resolvers,是否支持解析当前参数
  2. 处理参数

判断是否支持解析当前参数

我的环境中存在27个resolvers,通过命名我们大概可以猜测出 PathVariableMethodArgumentResolverPathVariableMapMethodArgumentResolver 是处理 @PathVariable 注解的 resolver 

PathVariableMethodArgumentResolver#supportsParameter
@Override
public boolean supportsParameter(MethodParameter parameter) {if (!parameter.hasParameterAnnotation(PathVariable.class)) {return false;}if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {PathVariable pathVariable = parameter.getParameterAnnotation(PathVariable.class);return (pathVariable != null && StringUtils.hasText(pathVariable.value()));}return true;
}

如果参数存在 @PathVariable 注解,并且指定了 value(name),则支持解析

PathVariableMapMethodArgumentResolver#supportsParameter
@Override
public boolean supportsParameter(MethodParameter parameter) {PathVariable ann = parameter.getParameterAnnotation(PathVariable.class);return (ann != null && Map.class.isAssignableFrom(parameter.getParameterType()) &&!StringUtils.hasText(ann.value()));
}

如果参数存在 @PathVariable 注解,并且未指定了 value(name),则支持解析

处理参数

接来下我们将重点分析 PathVariableMethodArgumentResolver 的 resolveArgument 方法,PathVariableMapMethodArgumentResolver 的 resolveArgument 方法大家可以自行阅读,相关源码如下:

大概分为以下六个步骤:

  1. 构建NamedValueInfo对象
  2. 处理Spel表达式
  3. 解析参数
  4. 处理默认值
  5. 类型转换
  6. 给 Request 域赋值
构建NamedValueInfo对象

创建NamedValueInfo对象

@PathVariable 注解的默认值是 ValueConstants.DEFAULT_NONE,并且无法手动设置

更新NamedValueInfo对象

updateNamedValueInfo 方法主要针对 @PathVariable 注解未指定 value(name)的情况,比如上文中的案例3,NamedValueInfo对象的 name 属性值为方法的参数名

处理Spel表达式

默认情况下,@PathVariable 注解是不支持解析 Spel 表达式的,我们通过源码分析一下。

如果 resolver 的 configurableBeanFactory 或 expressionContext 属性为 null ,则不进行Spel表达式的解析工作

RequestMappingHandlerAdapter#getDefaultArgumentResolvers

默认注册 PathVariableMethodArgumentResolver 使用的是无参构造方法,也就是  configurableBeanFactory 和 expressionContext 属性为 null,所以默认情况下,@PathVariable 注解不支持解析Spel表达式。可能有的小伙伴说我可以利用 WebMvcConfigurer ,自定义一个resolver,这里存在一个优先级问题,自定义的 resolver 优先级低于 mvc 手动注册的 resolver,所以一般情况下 @PathVariable 注解都不支持解析Spel表达式

我们可以看到手动注册的 resolver 优先级很低,一般情况下都是利用 mvc 内置的 resolver 进行解析

如何让 @PathVariable 注解支持解析 Spel 表达式 ?
替换内置的 PathVariableMapMethodArgumentResolver
@SpringBootApplication
@PropertySource("classpath:keys.properties")
public class BootApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(BootApplication.class);ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();RequestMappingHandlerAdapter adapter = context.getBean(RequestMappingHandlerAdapter.class);List<HandlerMethodArgumentResolver> resolvers = adapter.getArgumentResolvers();if (!CollectionUtils.isEmpty(resolvers)) {try {List<HandlerMethodArgumentResolver> newResolvers = new ArrayList<>();for (HandlerMethodArgumentResolver resolver : resolvers) {if (resolver instanceof PathVariableMethodArgumentResolver) {PathVariableMethodArgumentResolver pathVariableMethodArgumentResolver = new PathVariableMethodArgumentResolver();Field factoryField = AbstractNamedValueMethodArgumentResolver.class.getDeclaredField("configurableBeanFactory");factoryField.setAccessible(true);factoryField.set(pathVariableMethodArgumentResolver, beanFactory);Field expressionField = AbstractNamedValueMethodArgumentResolver.class.getDeclaredField("expressionContext");expressionField.setAccessible(true);expressionField.set(pathVariableMethodArgumentResolver, new BeanExpressionContext(beanFactory, new RequestScope()));newResolvers.add(pathVariableMethodArgumentResolver);} else {newResolvers.add(resolver);}}adapter.setArgumentResolvers(Collections.unmodifiableList(newResolvers));} catch (Exception ignore) {}}}
}

这里我们引用了一个 keys.properties 文件,为下文中演示解析Spel表达式做准备,文件明细如下

key=a
解析 ${}
@RequestMapping("/spel_1/{a}/{b}")
public Object spel1(@PathVariable(value = "${key}") String key) {return key;
}

解析 #{}

创建 RequestKey

@Component
public class RequestKey {private String key = "b";public String getKey() {return key;}public void setKey(String key) {this.key = key;}
}

接口及响应

@RequestMapping("/spel_2/{a}/{b}")
public Object spel2(@PathVariable(value = "#{requestKey['key']}") String key) {return key;
}

参数解析

主要就是获取 URL 上的值

处理默认值

@PathVariable 注解不支持设置默认值,源码这里又处理默认值,感觉有点突兀。其实这里使用了模板模式,@RequestParam 注解的处理步骤是和 @PathVariable 注解一致的,然而 @RequestParam 注解是可以设置默认值的。我的上一篇博文写了@RequestParam 注解的使用和源码解析,有兴趣的小伙伴可以阅读一下,它们的处理流程基本是一致的,就是细节有差别。博文链接 : @RequestParam注解的使用及源码解析

类型转换

SpringBoot 会提前内置很多 convert,当存在一个 convert 可以将当前类型转换为目标类型,则会进行转换。案例演示:

创建实体类 Dog

public class Dog {private String name;public Dog(String name) {this.name = name;}@Overridepublic String toString() {return "Dog{" +"name='" + name + '\'' +'}';}
}

创建配置类 WebConfig

@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addFormatters(FormatterRegistry registry) {registry.addConverter(new Converter<String, Dog>() {@Overridepublic <U> Converter<String, U> andThen(Converter<? super Dog, ? extends U> after) {return Converter.super.andThen(after);}@Overridepublic Dog convert(String source) {return new Dog(source);}});}}

接口及响应

@GetMapping("/convert/{dog}")
public String getDog(@PathVariable(value = "dog") Dog dog) {return dog.toString();
}

给 Request 域赋值

案例演示
@GetMapping("/attribute/{id}")
public String getAttribute(@PathVariable(value = "id") Integer id, HttpServletRequest request) {return request.getAttribute(View.PATH_VARIABLES).toString();
}

相关文章:

@PathVariable注解的使用及源码解析

前言 PathVariable 注解是我们进行JavaEE开发&#xff0c;最常见的几个注解之一&#xff0c;这篇博文我们以案例和源码相结合&#xff0c;帮助大家更好的了解PathVariable 注解 使用案例 1.获取 URL 上的值 RequestMapping("/id/{id}") public Object getId(Path…...

服务器配置重点看哪些参数

对服务器有需求时&#xff0c;应重点考虑以下几个关键参数&#xff0c;以下仅供参考&#xff1a; 处理器&#xff08;CPU&#xff09;&#xff1a;包括CPU的品牌&#xff08;如Intel或AMD&#xff09;、型号、核心数、线程数、主频和缓存大小。核心数越多&#xff0c;处理并发请…...

WSL Ubuntu 如何设置中文语言?

本章教程,主要介绍如何在WSL Ubuntu 如何设置中文语言。 操作系统:Windows 10 Pro 64 WSL子系统:Ubuntu 20.04 LTS 一、安装中文语言包 sudo apt install language-pack-zh-hans二、设置中文语言 sudo dpkg-reconfigure locales选择en_US.UTF-8 和 zh_CN.UTF-8 选择zh_CN.…...

「51媒体」政企活动媒体宣发如何做?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体宣传加速季&#xff0c;100万补贴享不停&#xff0c;一手媒体资源&#xff0c;全国100城线下落地执行。详情请联系胡老师。 政企活动媒体宣发是一个系统性的过程&#xff0c;需要明确…...

K近邻回归原理详解及Python代码示例

K近邻回归原理详解 K近邻回归&#xff08;K-Nearest Neighbors Regression, KNN&#xff09;是一种基于实例的学习算法&#xff0c;用于解决回归问题。它通过找到输入数据点在特征空间中最相似的K个邻居&#xff08;即最近的K个数据点&#xff09;&#xff0c;并使用这些邻居的…...

idea 开发工具properties文件中的中文不显示

用idea打开一个项目&#xff0c;配置文件propertise中的中文都不展示&#xff0c;如图&#xff1a; 可修改idea配置让中文显示&#xff1a; 勾选箭头指向的框即可&#xff0c;点击应用保存&#xff0c;重新打开配置文件&#xff0c;显示正常...

让DroidVNC-NG支持中文输入

DroidVNC-NG支持控制端输入内容&#xff0c;但是仅支持英文字符&#xff0c;如果需要控制输入法软键盘输入中文的话就没办法了&#xff0c;经过摸索找到了解决办法。 这个解决办法有个条件就是让DroidVNC-NG成为系统级应用&#xff08;这个条件比较苛刻&#xff09;&#xff…...

android dialog 显示时 activity 是否会执行 onPause onStop

当一个 Android Dialog 显示时&#xff0c;当前 Activity 通常不会执行 onPause 或 onStop 方法。Dialog 是附加到 Activity 上的一个窗口&#xff0c;它不会中断或替换当前的 Activity&#xff0c;因此 Activity 的生命周期方法 onPause 和 onStop 不会被调用。 然而&#xf…...

如何在MySQL中按字符串中的数字排序

在管理数据库时&#xff0c;我们经常遇到需要按嵌入在字符串中的数字进行排序的情况。这在实际应用中尤为常见&#xff0c;比如文件名、代码版本号等字段中通常包含数字&#xff0c;而这些数字往往是排序的关键。本文将详细介绍如何在MySQL中利用正则表达式提取字符串中的数字并…...

memcacheredis构建缓存服务器

Memcached&Redis构建缓存服务器 前言 许多Web应用都将数据保存到 RDBMS中&#xff0c;应用服务器从中读取数据并在浏览器中显示。但随着数据量的增大、访问的集中&#xff0c;就会出现RDBMS的负担加重、数据库响应恶化、 网站显示延迟等重大影响。Memcached/redis是高性能…...

Linux基础- 使用 Apache 服务部署静态网站

目录 零. 简介 一. linux安装Apache 二. 创建网页 三. window访问 修改了一下默认端口 到 8080 零. 简介 Apache 是世界使用排名第一的 Web 服务器软件。 它具有以下一些显著特点和优势&#xff1a; 开源免费&#xff1a;可以免费使用和修改&#xff0c;拥有庞大的社区支…...

接口自动化测试框架实战(Pytest+Allure+Excel)

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 1. Allure 简介 Allure 框架是一个灵活的、轻量级的、支持多语言的测试报告工具&#xff0c;它不…...

如何预防和处理他人盗用IP地址?

IP地址的定义及作用 解释 IP 地址在互联网中的作用。它是唯一标识网络设备的数字地址&#xff0c;类似于物理世界中的邮政地址。 1、IP地址盗窃的定义 解释一下什么是IP地址盗用&#xff0c;即非法使用他人的IP地址或者伪造IP地址的行为&#xff0c;这种行为可能引发法律和安…...

【ai】李沐 动手深度学学v2 环境安装:anaconda3、pycharm、d2

cuda-toolkit cuda_12.5.0_windows_network.exe 官方课程网站 第二版资源下载release版本 pycharm版本 李沐 【动手学深度学习v2 PyTorch版】 课程笔记 CUDA 选择11, 实际下载 12.5.0...

前后端分离对软件行业及架构设计的影响

在软件开发领域&#xff0c;前后端分离是一种越来越流行的架构设计模式。这种方法将用户界面&#xff08;前端&#xff09;与服务器逻辑&#xff08;后端&#xff09;分离开来&#xff0c;允许它们独立开发、测试和部署。本文将探讨前后端分离对软件行业和架构设计的影响&#…...

深入解析Dubbo架构层次

什么是Dubbo&#xff1f; Dubbo是阿里巴巴开源的一款高性能优秀的服务框架&#xff0c;致力于提供高性能和透明化的 RPC 远程服务调用方案&#xff0c;以及 SOA 服务治理方案。它的主要功能包括&#xff1a; 远程通信&#xff1a;提供高效的远程通信能力。负载均衡&#xff1…...

关于GPIO的上拉、下拉,无上下拉

1.GPIO_PULLUP&#xff08;上拉&#xff09; 作用和原理 作用&#xff1a;上拉模式会在GPIO引脚和电源电压&#xff08;Vcc&#xff09;之间连接一个内部上拉电阻。原理&#xff1a;当引脚配置为输入模式时&#xff0c;如果引脚没有连接到其他外部电路&#xff0c;内部上拉电…...

Python 语法基础二

7.常用内置函数 执行这个命令可以查看所有内置函数和内置对象&#xff08;两个下划线&#xff09; >>>dir(__builtins__) [__class__, __contains__, __delattr__, __delitem__, __dir__, __doc__, __eq__, __format__, __ge__, __getattribute__, __getitem__, __gt…...

HTML5与HTML:不仅仅是标签的革新

当我们提到HTML5&#xff0c;很多人会想到这是HTML的一个升级版本&#xff0c;增加了许多新的标签和特性。然而&#xff0c;HTML5带来的变化远不止于此。它是一个全面的网页开发框架&#xff0c;重新定义了网络应用程序的构建方式&#xff0c;为开发者提供了前所未有的灵活性和…...

Mybatis面试学习

1.介绍一下mybatis mybatis是一个半自动的ORM的框架&#xff0c;ORM就是对象关系映射。&#xff08;对象指的是Java对象&#xff0c;关系指的是数据库中的关系模型&#xff0c;对象关系映射&#xff0c;指的就是在Java对象和数据库的关系模型之间建立一种对应关系&#xff09;…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...

Git常用命令完全指南:从入门到精通

Git常用命令完全指南&#xff1a;从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...

深入浅出Diffusion模型:从原理到实践的全方位教程

I. 引言&#xff1a;生成式AI的黎明 – Diffusion模型是什么&#xff1f; 近年来&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;领域取得了爆炸性的进展&#xff0c;模型能够根据简单的文本提示创作出逼真的图像、连贯的文本&#xff0c;乃至更多令人惊叹的…...