• SpringMVC controller方法获取请求数据与前端传参类型匹配


    背景

    写这篇源于最近自己写服务端遇到的。在提供给外部两个接口时,联调出现了问题。报错:

    " HTTP request parse error,Content type’application/json;charset=UTF-8’ not supported"

    然后我寻思应该是数据格式出了问题,沟通后,web端提供的不是json格式的字符串数据,而我后台接口定义的是:

    consumes = “application/json;charset=UTF-8”

    所以注定错误。于是我又增加了一个不同方法名,但接口一样的,设置为:

    consumes = “application/x-www-form-urlencoded;charset=UTF-8”

    结果本以为好了,还是报同样的错误,然后我就来精神了,仔细研究了一下,本篇做一下回顾总结吧算是。

    先说解决

    问题源于 我虽然改了接收类型,但是我仍然是用 注解@RequestBody 去接收的 !!! 所以去掉这个注解就可以了。

    在这里插入图片描述
    之前有根据资料试过去掉 @RequestBody 替换为 @RequestParam 的,但是不行,会报这个错:

    Required DeviceActiveInfoVO parameter ‘deviceActiveInfoVO’ is not present
    在这里插入图片描述

    替换成 @PathVariable 会报这个错:

    Missing URI template variable ‘deviceActiveInfoVO’ for method parameter of type DeviceActiveInfoVO
    在这里插入图片描述
    (忽略这波沙雕操作,单纯为了看看报错是嘛玩意)

    正文

    1. 了解注解@RequestBody、@RequestParam 、@PathVariable

    首先,以上前三个注解都是与Spring MVC Controller 接收参数直接相关的。

    1.1 @RequestBody

    该注解用于接收前端传递给后端的json字符串格式的数据(注意前端数据采用的是Body请求体传递)。我们也知道经常在提交数据的时候会用到请求体,即使用POST提交方式时。例子如下:
    (代码中AllocationDefineVO实体类

    @PostMapping("/add")
        public ResponseBean add(@RequestBody @Validated AllocationDefineVO allocationDefineVO) throws BusinessException {
    
            if (allocationDefineVO == null) {
                throw new BusinessException(BusinessCodeEnum.PARAMETER_ERROR, "录入新规则数据不能为空!");
            }
            allocationDefineService.add(allocationDefineVO);
            return ResponseBean.success();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    当后端参数是一个对象,且以@RequestBody修饰,(如上代码),那么在前端传递json参数时,要注意以下几点:

    • 后端@RequestBody注解对应的类在将HTTP的输入流(含请求体)装配到目标类(即:@RequestBody后面的类)时,会根据json字符串中的key来匹配对应实体类的属性,如果匹配一致且json中的该key对应的值符合实体类的对应属性的类型要求时(或可转换为对应实体类属性),会调用实体类的setter方法将值赋给该属性。
    • json字符串中,如果value为"“的话,后端对应属性如果是String类型的,那么接受到的就是”",如果是后端属性的类型是Integer、Double等类型,那么接收到的就是null。
    • json字符串中,如果value为null的话,后端对应收到的就是null
    • 如果某个参数没有value的话,在传json字符串给后端时,要么干脆就不把该字段写到json字符串中;要么写value时, 必须有值,null 或""都行。如果有key但value什么也没有,直接就不符合json格式是会报错的。

    1.2 @RequestParam

    @RequestParam:将请求参数绑定/映射到你控制器的方法参数上(是springmvc中接收普通参数的注解)

    它的语法:

    语法:@RequestParam(value=”参数名”,required=”true/false”,defaultValue=””)
    value:参数名
    required:是否包含该参数,默认为true,表示该请求路径中必须包含该参数,如果不包含就报错。
    defaultValue:默认参数值,如果设置了该值,required=true将失效,自动为false,如果没有传该参数,就使用默认值

    ① 提问, 假设我要传多个参数时具体怎么使用? 来看例子:

    @GetMapping("/getCodeInfo")
    public ResponseBean getCodeInfo(
            @RequestParam(value = "sn") String sn,
            @RequestParam(value = "type") String type,
            @RequestParam(value = "name") String name
    ) throws BusinessException {
    
        DeviceInfoVO deviceInfoVO = deviceInfoService.getCodeInfo(sn, type, name);
        return ResponseBean.success(deviceInfoVO);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    多个参数,使用逗号隔开就可以。

    ② 提问,那假设我不使用该注解@RequestParam 可以吗?
    可以,当然可以。但是有前提。 请注意以下几个区别:

    a. 不加@RequestParam前端的参数名需要和后端控制器的变量名保持一致才能生效
    b. 不加@RequestParam参数为非必传,加@RequestParam写法参数为必传。但@RequestParam可以通过@RequestParam(required = false)设置为非必传。
    c. @RequestParam可以通过@RequestParam(“id”)或者@RequestParam(value = “id”)指定传入的参数名。
    d. @RequestParam可以通过@RequestParam(defaultValue = “0”)指定参数默认值
    e. 如果接口除了前端调用还有后端RPC调用,则不能省略@RequestParam,否则RPC会找不到参数报错
    f. 访问时:
    不加@RequestParam注解:url可带参数也可不带参数,输入 localhost:8080/getCodeInfo 以及 localhost:8080/getCodeInfo?sn=xxx 方法都能执行
    加@RequestParam注解:url必须带有参数。也就是说你直接输入localhost:8080/getCodeInfo 会报错,不会执行方法。只能输入localhost:8080/getCodeInfo?sn=xxx 才能执行相应的方法

    1.3 @PathVariable

    顾名思义,该注解作用是:映射URL绑定的占位符,也就是@RequestMapping中定义的占位符中的参数(例如:/test/{id})。 带占位符的URL是 Spring3.0 新增的功能,URL中的 {xxx} 占位符可以通过 @PathVariable(“xxx”) 绑定到操作方法的入参中。

    举个例子:

        @GetMapping("/detail/{id}")
        public ResponseBean detail(@PathVariable String id) throws BusinessException {
    
            DeviceInfoVO deviceInfoVO = deviceInfoService.detail(id);
            return ResponseBean.success(deviceInfoVO);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    例子中该注解可以拿到前端传来的参数id。

    1.4 @RequestBody 和 @RequestParam 配合使用

    直接上例子:

    @GetMapping("/findLogList")
    public ResponseBean<PageVO<LogVO>> findLogList(@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
                                                   @RequestParam(value = "pageSize") Integer pageSize,
                                                   @RequestBody LogVO logVO) {
        PageVO<LogVO> logList = logService.findLogList(pageNum, pageSize, logVO);
        return ResponseBean.success(logList);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    @RequestBody 也可以不加。(@RequestBody加了接收请求体中的json数据;不加注解接收URL中的数据并组装为对象)

    1.5 @RequestBody 和 @PathVariable 结合使用

    例子:

    @PostMapping("/update/{id}")
    public ResponseBean update(@PathVariable String id,
                               @RequestBody @Validated DeviceInfoVO deviceInfoVO)
        throws BusinessException {
    
        return ResponseBean.success();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    前端传来要更改的记录id和要提交的form表单。


    注:回到原先问题背景,是因为@RequestBody注解不能接收参数类型为

    application/x-www-form-urlencoded;charset=UTF-8

    的数据,然后有看到一篇可以自定义参数解析器,以使得@RequestBody注解能够接收该类型的数据的方法,传送门:
    SpringBoot自定义参数解析器,使被@RequestBody标注的参数能额外接收Content-Type为application/x-www-form-urlencoded的请求

  • 相关阅读:
    Python数据分析案例06——现代人的婚育意愿调查分析(基于逻辑回归模型和问卷数据)
    关于Python中math 和 decimal 模块的解析与实践
    从键盘上输入数字并查找某数
    成都精灵云C++ 二面(hr面,30min)
    Cisco交换机本地SPAN和远程SPAN的配置
    【卫朋】智能硬件 | 做好一款电子硬件产品,工具必不可少
    Python——面向对象
    HTML+CSS简单的网页制作期末作业 关于我的家乡——四川文化网页介绍 DW大学生网页作业制作设计 Dreamweaver简单网页成品
    maven 新建模块 导入后 按Ctrl 点不进新建模块pom定义
    SQLite扩展插件终极集合
  • 原文地址:https://blog.csdn.net/qq_36256590/article/details/125855526