- 2023-05-01 17:14:41
- 1999 热度
- 0 评论
在一个 Web 请求中,参数我们无非就是放在地址栏或者请求体中,个别请求可能放在请求头中。
放在地址栏中,我们可以通过如下方式获取参数:
1 |
String javaboy = request.getParameter("name "); |
放在请求体中,如果是 key/value 形式,我们可以通过如下方式获取参数:
1 |
String javaboy = request.getParameter("name "); |
如果是 JSON 形式,我们则通过如果如下方式获取到输入流,然后解析成 JSON 字符串,再通过 JSON 工具转为对象:
1 |
BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream())); |
如果参数放在请求头中,我们可以通过如下方式获取:
1 |
String javaboy = request.getHeader("name"); |
如果你用的是 Jsp/Servlet 那一套技术栈,那么参数获取无外乎这几种方式。
如果用了 SpringMVC 框架,有的小伙伴们可能会觉得参数获取方式太丰富了,各种注解如 @RequestParam
、@RequestBody
、@RequestHeader
、@PathVariable
,参数可以是 key/value 形式,也可以是 JSON 形式,非常丰富!但是,无论多么丰富,最底层获取参数的方式无外乎上面几种。
那有小伙伴要问了,SpringMVC 到底是怎么样从 request 中把参数提取出来直接给我们用的呢?例如下面这个接口:
1 |
@RestController |
我们都知道 name 参数是从 HttpServletRequest 中提取出来的,到底是怎么提取出来的?这就是無名今天要和大家分享的话题。
1.自定义参数解析器
为了搞清楚这个问题,我们先来自定义一个参数解析器看看。
自定义参数解析器需要实现 HandlerMethodArgumentResolver 接口,我们先来看看该接口:
1 |
public interface HandlerMethodArgumentResolver { |
这个接口中就两个方法:
- supportsParameter:该方法表示是否启用这个参数解析器,返回 true 表示启用,返回 false 表示不启用。
- resolveArgument:这是具体的解析过程,就是从 request 中取出参数的过程,方法的返回值就对应了接口中参数的值。
自定义参数解析器只需要实现该接口即可。
假设我现在有这样一个需求(实际上在 Spring Security 中获取当前登录用户名非常方便,这里只是为了该案例而做,勿抬杠):
假设我现在系统安全框架使用了 Spring Security(对 Spring Security 不熟悉的小伙伴,可以在公众号江南一点雨后台回复 ss,有教程),如果我在接口的参数上添加了 @CurrentUserName 注解,那么该参数的值就是当前登录的用户名,像下面这样:
1 |
@RestController |
要实现这个功能,非常 easy,首先我们自定义一个 @CurrentUserName
注解,如下:
1 |
@Retention(RetentionPolicy.RUNTIME) |
这个注解没啥好解释的。
接下来我们自定义参数解析器 CurrentUserNameHandlerMethodArgumentResolver,如下:
1 |
public class CurrentUserNameHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { |
- supportsParameter:如果参数类型是 String,并且参数上有
@CurrentUserName
注解,则使用该参数解析器。 - resolveArgument:该方法的返回值就是参数的具体值,当前登录用户名从 SecurityContextHolder 中获取即可(具体参数無名的 Spring Security 教程,公号后台回复 ss)。
最后,我们再将自定义的参数解析器配置到 HandlerAdapter 中,配置方式如下:
1 |
@Configuration |
至此,就算配置完成了。
接下来启动项目,用户登录成功后,访问 /hello
接口,就可以看到返回当前登录用户数据了。
这就是我们自定义的一个参数类型解析器。可以看到,非常 Easy。
在 SpringMVC 中,默认也有很多 HandlerMethodArgumentResolver 的实现类,他们处理的问题也都类似,無名再给大家举个例子。
2.PrincipalMethodArgumentResolver
如果我们在项目中使用了 Spring Security,我们可以通过如下方式获取当前登录用户信息:
1 |
@GetMapping("/hello2") |
即直接在当前接口的参数中添加 Principal 类型的参数即可,该参数描述了当前登录用户信息,这个用过 Spring Security 的小伙伴应该都知道(不熟悉 Spring Security 的小伙伴可以在公众号【江南一点雨】后台回复 ss)。
那么这个功能是怎么实现的呢?当然就是 PrincipalMethodArgumentResolver 在起作用了!
我们一起来看下这个参数解析器:
1 |
public class PrincipalMethodArgumentResolver implements HandlerMethodArgumentResolver { |
- supportsParameter:这个方法主要是判断参数类型是不是 Principal,如果参数类型是 Principal,就支持。
- resolveArgument:这个方法的逻辑很简单,首先获取原生的请求,再从请求中获取 Principal 对象返回即可。
是不是很简单,有了这个,我们就可以随时加载到当前登录用户信息了。
3.RequestParamMapMethodArgumentResolver
無名再给大家举个例子:
1 |
@RestController |
这个接口很多小伙伴可能都写过,使用 Map 去接收前端传来的参数,那么这里用到的参数解析器就是 RequestParamMapMethodArgumentResolver。
1 |
public class RequestParamMapMethodArgumentResolver implements HandlerMethodArgumentResolver { |
- supportsParameter:参数类型是 Map,并且使用了
@RequestParam
注解,并且@RequestParam
注解中没有配置 name 属性,就可以使用该参数解析器。 - resolveArgument:具体解析分为两种情况:MultiValueMap 和其他 Map,前者中又分三种情况:MultipartFile、Part 或者其他普通请求,前两者可以处理文件上传,第三个就是普通参数。如果是普通 Map,则直接获取到原始请求参数放到一个 Map 集合中返回即可。
4.小结
前面和大家聊的都是几种简单的情况,还有复杂的如 PathVariableMethodArgumentResolver 和 RequestParamMethodArgumentResolver 無名以后再和大家详细聊。同时还有一个问题就是这些参数解析器具体是在哪里调用的,这个也会在無名近期的 SpringMVC 源码解析系列文章中和大家分享,好啦,今天周末,就这点简单的小知识祝大家周末愉快~
- Spring(403)
- Boot(208)
- Spring Boot(187)
- Spring Cloud(82)
- Java(82)
- Cloud(82)
- Security(60)
- Spring Security(54)
- Boot2(51)
- Spring Boot2(51)
- Redis(31)
- SQL(29)
- Mysql(25)
- Dalston(24)
- IDE(24)
- mongoDB(22)
- MVC(22)
- JDBC(22)
- IDEA(22)
- Web(21)
- CLI(20)
- Alibaba(19)
- SpringMVC(19)
- Docker(17)
- SpringBoot(17)
- Git(16)
- Eclipse(16)
- Vue(16)
- JPA(15)
- Apache(15)
- ORA(15)
- Tomcat(14)
- Linux(14)
- HTTP(14)
- Mybatis(14)
- Oracle(14)
- jdk(14)
- OAuth(13)
- Nacos(13)
- Pro(13)
- XML(13)
- JdbcTemplate(13)
- JSON(12)
- OAuth2(12)
- Data(12)
- int(11)
- Myeclipse(11)
- stream(11)
- not(10)
- Bug(10)
- Hystrix(9)
- ast(9)
- maven(9)
- Map(9)
- Swagger(8)
- APP(8)
- Bit(8)
- API(8)
- session(8)
- Window(8)
- windows(7)
- too(7)
- HTML(7)
- Github(7)
- JavaMail(7)
- Cache(7)
- File(7)
- IntelliJ(7)
- mail(7)
- Server(6)
- nginx(6)
- jar(6)
- ueditor(6)
- ehcache(6)
- UDP(6)
- RabbitMQ(6)
- and(6)
- star(6)
- Excel(6)
- Log4J(6)
- pushlet(6)
- apt(6)
- Freemarker(6)
- read(6)
- WebFlux(6)
- JSP(6)
- Bean(6)
- error(6)
- are(5)
- SVN(5)
- for(5)
- DOM(5)
- Sentinel(5)
- the(5)
- JWT(5)
- rdquo(5)
- PHP(5)
- Struts(5)
- string(5)
- script(5)