程序员社区

SpringMVC —— 常用参数解析器介绍


title: SpringMVC —— 常用参数解析器介绍
subTitle: @RequestPart 与 @RequestParam 与 @RequestBody 注解使用的完全攻略
date: 2020/11/10 16:58


注解 参数解析器 请求 content-type 是否使用到 MediaType 使用场景 原理简述
@RequestParm RequestParamMethodArgumentResolver 无(get请求)和multipart/form-data get 请求,但也支持 form-data 的获取文件和参数 1. 代码中对 MultipartFile 做了特殊处理。2. request.getParameterValues()
@RequestPart RequestPartMethodArgumentResolver multipart/form-data 获取文件、获取 form-data 中的内容 如果参数列表接收的是文件,直接封装成 MultipartFile 类型,如果不是那么根据他的 content-type 解析成对象
@RequestBody RequestResponseBodyMethodProcessor application/json 接收 json 数据
@RequestBody + MultiValueMap RequestResponseBodyMethodProcessor application/x-www-form-urlencoded 接收 form 表单提交的数据

@RequestParm 与 @RequestPart 作用场景

@RequestParam:请求参数到处理器功能处理方法的方法参数上的绑定;
@RequestPart:提供对“multipart/form-data”请求的全面支持,支持Servlet 3.0文件上传(javax.servlet.http.Part)、支持内容的HttpMessageConverter(即根据请求头的Content-Type,来判断内容区数据是什么类型,如JSON、XML,能自动转换为命令对象),比@RequestParam更强大(只能对请求参数数据绑定,key-alue格式),而@RequestPart支持如JSON、XML内容区数据的绑定;

HandlerMethodArgumentResolver

他是所有参数解析器继承的接口

public interface HandlerMethodArgumentResolver {

    /**
     * 判断当前参数解析器能否解析参数列表上的指定参数
     */
    boolean supportsParameter(MethodParameter parameter);

    /**
     * 从请求中将参数解析成对象
     */
    @Nullable
    Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;

}

RequestParm 参数解析器

代码:

// 使用 @RequestPart 接收文件和参数
@PostMapping("/v1/design/add")
public String addDesign(
  @RequestPart(value = "file") MultipartFile file,      // 这里也可以用 @RequestParam,但是还是推荐用 @RequestPart 以防有别的坑
  @RequestParam(value = "pid") Long pid,
  @RequestPart User user    // 这里只能用 @RequestPart 注解
) {
  return "123";
}

解析:

SpringMVC —— 常用参数解析器介绍插图

注:后面参数绑定器相关代码解析参见之前的文章。

SpringMVC —— 常用参数解析器介绍插图1

@RequestPart 参数解析器

SpringMVC —— 常用参数解析器介绍插图2
请求方式
SpringMVC —— 常用参数解析器介绍插图3
SpringMVC —— 常用参数解析器介绍插图4

后面的流程在这篇文章中已经详细的讲了(他和@RequestBody 参数解析器调用了同一个抽象父类的方法)。

@RequestBody 参数解析器

在这篇文章中已经详细的讲了。

下面只提一个小问题:

SpringMVC —— 常用参数解析器介绍插图5

@RequestBody 参数解析器和@RequestPart 参数解析器调用了同一个抽象父类,那么他可不可以解析本例中的 user 对象呢,反正我第一时间是觉得可以,但是经过测试发现并不可以,所以就开始看两个解析器调用抽象父类方法的入参有什么不同,玄机就在上面图中的紫字中。

Form 表单提交 —— AllEncompassingFormHttpMessageConverter 消息转换器

本来这个是消息转换器的,但是在这里顺道讲一下吧,这个是以前传统 form 表单提交时的参数转换器,对应的 content-type 为 application/x-www-form-urlencoded,示例如下:

@PostMapping("/v1/testForm")
public String testForm(@RequestBody MultiValueMap<String, String> req) {    // form 表单提交的参数必须要使用 MultiValueMap 来接收
    List<String> name = req.get("name");    // 这个 map 中一个 key 可以对应多个 value
    List<String> age = req.get("age");

    return "456";
}
SpringMVC —— 常用参数解析器介绍插图6

解析:

SpringMVC —— 常用参数解析器介绍插图7
SpringMVC —— 常用参数解析器介绍插图8

注意点,实际使用的时候(虽然这种方法一百年都可能不会使用了)接收的参数类型最好不要改他的泛型:

SpringMVC —— 常用参数解析器介绍插图9
SpringMVC —— 常用参数解析器介绍插图10
// 上面问题可以类比成以下代码
public static void main(String[] args) {
  
  // 因为 java 采用的泛型擦除方式实现的泛型,所以实际上代码中是没有进行类型的限制的
  Map map = new HashMap();
  // 所以 spring 可以向这个 map 中注入任何类型的数据
  map.put("name", Arrays.asList("123", "456"));

  // 在 Spring 给我们绑定参数的时候其实也是没有泛型的
  Map req = map;

  // 当我们代码调用 get("name") 的时候,java 帮我们做了一次强转成 List 操作,但实际上 List 也是没有泛型的,所以此时也不会报错
  List name = (List) map.get("name");
  // 当调用 get(0) 方法的时候,java 帮我们做了一次强转成 Long 类型的操作,但实际上他是 String 类型,
  // 所以会报出:java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Long
  Long aLong = (Long) name.get(0);
}

本文参考

Springboot使用feign上传文件

@RequestPart 解决同时上传文件和json的解决方案

@RequestBody与Content-type

赞(0) 打赏
未经允许不得转载:IDEA激活码 » SpringMVC —— 常用参数解析器介绍

一个分享Java & Python知识的社区