关于 Java spring web 接收 Content-Type=application/json 请求参数的问题

26 天前
 coollight56

请问 spring web 只能用 @RequestBody 来接受 json 格式参数吗? 而且好像必须是用对象来接收

比如下面的情况就会报错 json 参数为

{
    "taskId":123
    ....
}

controller 为

    @PostMapping("/info")
    public void info(@RequestBody Long taskId) {
		System.out.println("taskId:" + taskId);
		// TODO
        
        
    }

错误提示

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.lang.Long` from Object value (token `JsonToken.START_OBJECT`)]

但是只要把 taskId 包装到一个对象中就可以正常接收,然而这样会不会太麻烦了,例如我又要接收一个 userId 那又得创建一个对象,spring web 不考虑自己封装的情况下(因为感觉这种场景应该很多才对,可能是我没掌握)有什么办法可以像 @RequestParam (只要定义需要接受的参数类型和名称就可以)来接收 json 参数

2935 次点击
所在节点    程序员
46 条回复
xiaohupro
26 天前
最好定义一个对应的参数类,例如:xxxParam.java ,一般项目中我就会这样定义,方便后期维护,而且这样定义了之后 post 和 get 都能用
ZeroDu
26 天前
spring 的做法是正确的。op 缺少一些理解。
Kaiv2
26 天前
不推荐使用 Map ,定义一个对象,有 lombok 和 AI 定义一个对象花不了多少时间。代码更安全也更好维护。
bitmin
26 天前
a = {
"taskId":123
....
}

request body 是 a 而不是 taskId

你想直接取 taskId 看看 @RequestBody 有没有参数设置,类似 python fastapi 里 task_id: int = Body(..., embed=True) 指定 embed=True

@RequestBody 没有这样的功能可以自己自定义一个注解例如 @EmbedRequestBody ,如果用了文档生成的库或者插件,可能会不识别自定义的注解,还得去做兼容
NickX
26 天前
@RequestBody 就是用来接收 application/json 的类型,你非得让他接收表单,明显是用法问题。用 @RequestParam
hailiang88
26 天前
把 post 改成 get ,参数使用 @PathValue 的格式或许更符合 rest 规范吧
coollight56
26 天前
@bitmin #24 是的 看了下别的人的处理方法都是自定义一个注解 ,文档生成确实就没法兼容了
https://blog.csdn.net/llwutong/article/details/116273360
ikas
26 天前
创建一个专门用于接收 Id 的参数类型算了.
record IdParam<T>(T id){}
ikas
26 天前
我们是统一了前端传递的参数名
coollight56
26 天前
@ikas #29 嗯嗯 这也是一种方法 👍
xuanbg
26 天前
你要是觉得定义一个对象很麻烦,那也可以用万能的 Map 来接收的。只是 key 改了名字就比较麻烦。
oneisall8955
26 天前
OP 刚刚入行? content type 的含义就是客户端和服务端数据交互的格式定义协议。json 代表客户端按照 json 格式传参,相对的,服务端就得按照 json 格式解析
Hstar
26 天前
楼主脑洞有点大, 经验有点少. 建议你听大家的, 就把 taskId 封在一个 Class 里.
然后你记得收藏一下这个帖子, 等五年十年后你再回来看自己的发言和思路, 有惊喜!
iv8d
26 天前
你直接写数字到 data 就行了
cenbiq
25 天前
看了半天也没看懂 OP 的问题在哪,我想几乎所有语言/框架对 POST 请求的处理都是类似 fun info(queryParam1: Int, queryParam2: String?, body: InfoRequestBodyJsonMappingObject): InfoResponseContentJsonMappingObject 这种形式吧,应该不存在任何疑问?
cenbiq
25 天前
@cenbiq 依据 OP 的需求 InfoRequestBodyJsonMappingObject(taskId: Long, taskName: String, userId: Long) 这样存在任何疑问吗
cenbiq
25 天前
@cenbiq 如果你的框架支持,应该还能这么做 fun info(task: TaskPartOfInfoBodyObject, user: UserPartOfInfoBodyObject); 数据类型定义是 TaskPartOfInfoBodyObject(taskId: Long, taskName: String); UserPartOfInfoBodyObject(userId: Long, ...)。如果 OP 是想要从 body 的一个 json 内分出两组请求数据方便处理的话
shangfabao
25 天前
你要是按照参数方式获取,注解都不对啊,肯定取不到
coollight56
25 天前
@cenbiq #37 @cenbiq #36 是的 就是想要把单个 json 对象里的属性拆分开来在 controller 方法参数列表上接收,我这几天已经看到别的大佬的实现,就是自己写一个注解然后处理,spring web 也提供了这方面的扩展,同时也实现了组合参数的接收,如下
```java

public ApiResult<PageResult<?>> schemeUserList(@SingleParam @NotNull Long schemeId,
@ComboParam @Valid UserSearchParam userSearchParam,
@ComboParam @Valid PageParam pageParam) {
// TODO
}

```
这样真的很方便,不过大家讨论的更多是全部用 json 来传参符不符合规范。确实不知道怎么样才规范,好像都是学习前人的代码风格,然后想在此基础上优化而已。
coollight56
25 天前
@coollight56 #39 显示不友好 写到补充里了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://yangjunhui.monster/t/1131110

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX