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

文章目录

  • 背景
    • 先说解决
  • 正文
    • 1. 了解注解@RequestBody、@RequestParam 、@PathVariable
      • 1.1 @RequestBody
      • 1.2 @RequestParam
      • 1.3 @PathVariable
      • 1.4 @RequestBody 和 @RequestParam 配合使用
      • 1.5 @RequestBody 和 @PathVariable 结合使用

背景

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

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

当后端参数是一个对象,且以@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);
}

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

② 提问,那假设我不使用该注解@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);
    }

例子中该注解可以拿到前端传来的参数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);
}

@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();
}

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


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

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

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

你可能感兴趣的:(#,springboot,前端,java,spring)