Spring MVC Controller 方法参数 Map 的实现类是什么?

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 问题题主问题描述如下:在SpringBoot中,Controller的参数中有Map接口类型的,请问他的实现类是什么?突发奇想,在SpringBoot中,Controller的参数中有Map接口类型的

问题


题主问题描述如下:

在SpringBoot中,Controller的参数中有Map接口类型的,请问他的实现类是什么?

突发奇想,在SpringBoot中,Controller的参数中有Map接口类型的

    @GetMapping("/common")
    public HttpResult testCommonGet(Map<String,String> map){
        return  HttpResult.success("common测试get");
    }


像这里的map,声明是Map接口,那他的实现类是什么?

如果改为HashMap类型,有什么优缺点吗?


分析


题主提到 SpringBoot 中的 Controller 参数,可以推测题主在学习 Spring 框架时跳过了 Spring MVC 直接上手的 Spring Boot。自从 Spring Boot 框架推出之后,确实简化了 Spring 的使用,这也让很多人忽略了框架底层的实现。


Spring Boot 基于 Spring Framework,Spring MVC 正是 Spring Framework 框架中的其中一个模块。Controller 并非 Spring Boot 的专利,要回答题主的问题,还是需要回归到 Spring MVC,Spring MVC 环境已经支持了 Controller 方法使用不同的参数类型。


Spring MVC 中的 Controller 方法参数多用来接收请求有关的信息,还有一部分和 MVC 有关,能定义的请求相关参数可以参见《深入理解 Spring MVC Controller —— 请求参数获取》。


对于不同类型参数的解析,Spring MVC 使用的是 HandlerMethodArgumentResolver,默认情况下的实现及能处理的参数见下图。


36.png


回答


因此具体到 Controller 方法的 Map 类型的参数实现,要看 HandlerMethodArgumentResolver 如何解析的,默认情况下解析 Map 类型的 HandlerMethodArgumentResolver 主要分下面几种情况。


1. 携带指定了 name 的 @RequestParam 注解的 Map 类型


这种情况下的参数由 RequestParamMethodArgumentResolver 进行解析,不过由于默认情况下 Spring 无法将 String 转换为 Map,因此会报错。如果添加了支持 String 到 Map 类型转换服务,则 Map 实现由具体的类型转换服务决定。


{
    "timestamp": "2022-02-13T05:18:01.147+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "Failed to convert value of type 'java.lang.String' to required type 'java.util.Map'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Map': no matching editors or conversion strategy found",
    "path": "/test"
}


2. 携带未指定 name 的 @RequestParam 注解的 Map 类型参数


这种情况下的参数由 RequestParamMapMethodArgumentResolver 进行解析,支持的 Map 泛型类型包括 Map、Map、Map,不管哪种泛型类型,Map 参数的实现类型都为 LinkedHashMap,相关解析代码如下。


37.png


3. 携带指定了 name 的 @PathVariable 注解的 Map 类型参数


这种类型的 Map 参数由 PathVariableMethodArgumentResolver 进行解析,由于默认情况下 Spring 无法将路径中的字符串变量转换为 Map,因此同样会报错。如果添加了支持 String 到 Map 类型转换服务,则 Map 实现由具体的类型转换服务决定。


{
    "timestamp": "2022-02-13T05:36:31.518+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "Failed to convert value of type 'java.lang.String' to required type 'java.util.Map'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Map': no matching editors or conversion strategy found",
    "path": "/a=1"
}


4. 未携带 name 的 @PathVariable 注解的 Map 类型参数


这种情况下的 Map 参数由 PathVariableMapMethodArgumentResolver 进行解析,Spring 使用的实现同样为 LinkedHashMap,相关代码如下。


38.png


5. 携带指定了 name 的 @MatrixVariable 注解的 Map 类型参数


这种情况的 Map 参数由 PathVariableMapMethodArgumentResolver 进行解析,由于默认情况下 Spring 无法将路径中的字符串变量转换为 Map,因此同样会报错。如果添加了支持 String 到 Map 类型转换服务,则 Map 实现由具体的类型转换服务决定。


{
    "timestamp": "2022-02-14T02:02:53.772+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "Failed to convert value of type 'java.lang.String' to required type 'java.util.Map'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Map': no matching editors or conversion strategy found",
    "path": "/aaa/param=1;bbb"
}


6. 未携带 name 的 @MatrixVariable 注解的 Map 类型参数


这种情况下的 Map 参数由 MatrixVariableMapMethodArgumentResolver 解析,这种情况下的 Map 参数实现为 LinkedHashMap,相关源码如下。


39.png


7. 未携带任何注解的 Map 类型


不带注解的 Controller 方法中的 Map 参数被 Spring 认为是 MVC 中的 Model,由 MapMethodProcessor 进行解析,相关代码如下。


40.png


可以看到,Spring 使用的 Map 实现是 ModelAndViewContainer#getModel 方法的返回值,看下这个方法。


public class ModelAndViewContainer {
  private final ModelMap defaultModel = new BindingAwareModelMap();
  public ModelMap getModel() {
    if (useDefaultModel()) {
      // 没有重定向,使用默认 Model
      return this.defaultModel;
    } else {
        // 发生重定向,使用 ModelMap
      if (this.redirectModel == null) {
        this.redirectModel = new ModelMap();
      }
      return this.redirectModel;
    }
  }
  private boolean useDefaultModel() {
    return (!this.redirectModelScenario || (this.redirectModel == null && !this.ignoreDefaultModelOnRedirect));
  }
}


如果没有发生重定向,Spring 使用的 Map 实现是 ModelAndViewContainer 内部的 BindingAwareModelMap 实例;

如果发生了重定向,Spring 使用的 Map 实现是 ModelMap;

BindingAwareModelMap 和 ModelMap 都实现了 LinkedHashMap,这也意味着如果你使用 TreeMap 作为参数,由于类型不匹配将会导致程序报错。


8. 携带 @RequestBody 注解的 Map 参数


带 @RequstBody 注解的 Map 参数由 RequestResponseBodyMethodProcessor 解析,默认情况下交由 MappingJackson2HttpMessageConverter 实例化参数,实例化出来的是 HashMap 类型,这块源码内容较多,可自己尝试分析。


总结

Spring MVC 对于 Map 类型的 Controller 方法参数,多数情况下使用 LinkedHashMap 作为实现,这样可以保证参数有序,兼容了程序获取指定索引位置参数的情况。


目录
相关文章
|
3天前
|
Java 数据库连接 API
Spring事务管理嵌套事务详解 : 同一个类中,一个方法调用另外一个有事务的方法
Spring事务管理嵌套事务详解 : 同一个类中,一个方法调用另外一个有事务的方法
|
16天前
|
Java 应用服务中间件 Maven
ContextLoaderListener在Spring应用中的作用与配置方法
ContextLoaderListener在Spring应用中的作用与配置方法
|
12天前
|
Java API 微服务
Spring Boot中的跨服务调用方法
Spring Boot中的跨服务调用方法
|
12天前
|
负载均衡 监控 Java
Spring Boot与微服务治理框架的集成方法
Spring Boot与微服务治理框架的集成方法
|
12天前
|
Java API 数据中心
Spring Cloud中的服务注册与发现实现方法
Spring Cloud中的服务注册与发现实现方法
|
15天前
|
消息中间件 Java 开发工具
消息队列 MQ产品使用合集之topic相同,但是tag不同,这个类不能放入map中,该如何处理
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
2月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
114 0
|
2月前
|
开发框架 前端开发 JavaScript
JavaScript云LIS系统源码ASP.NET CORE 3.1 MVC + SQLserver + Redis医院实验室信息系统源码 医院云LIS系统源码
实验室信息系统(Laboratory Information System,缩写LIS)是一类用来处理实验室过程信息的软件,云LIS系统围绕临床,云LIS系统将与云HIS系统建立起高度的业务整合,以体现“以病人为中心”的设计理念,优化就诊流程,方便患者就医。
44 0
|
11月前
|
存储 开发框架 前端开发
[回馈]ASP.NET Core MVC开发实战之商城系统(五)
经过一段时间的准备,新的一期【ASP.NET Core MVC开发实战之商城系统】已经开始,在之前的文章中,讲解了商城系统的整体功能设计,页面布局设计,环境搭建,系统配置,及首页【商品类型,banner条,友情链接,降价促销,新品爆款】,商品列表页面,商品详情等功能的开发,今天继续讲解购物车功能开发,仅供学习分享使用,如有不足之处,还请指正。
139 0
|
12月前
|
开发框架 前端开发 .NET
[回馈]ASP.NET Core MVC开发实战之商城系统(三)
[回馈]ASP.NET Core MVC开发实战之商城系统(三)
78 0