美文网首页撸一个mvc框架
SpringMVC —— 常用参数解析器介绍

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

作者: 想54256 | 来源:发表于2020-11-12 17:19 被阅读0次

    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";
    }
    

    解析:

    image

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

    image

    @RequestPart 参数解析器

    请求方式 image image

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

    @RequestBody 参数解析器

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

    下面只提一个小问题:

    image

    @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";
    }
    
    image

    解析:

    image image

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

    image image
    // 上面问题可以类比成以下代码
    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

    相关文章

      网友评论

        本文标题:SpringMVC —— 常用参数解析器介绍

        本文链接:https://www.haomeiwen.com/subject/wlmpbktx.html