Spring Boot - Json RequestBody,带/不带引号的字符串/枚举
Posted
技术标签:
【中文标题】Spring Boot - Json RequestBody,带/不带引号的字符串/枚举【英文标题】:Spring Boot - Json RequestBody, String/Enum with/without quotation marks 【发布时间】:2022-01-19 09:11:32 【问题描述】:我遇到了一个奇怪的问题。为什么第一个代码接受不带引号的输入,而第二个代码不接受?
说实话,第二个是有道理的。但是为什么第一个接受不带引号的输入呢?
我真的很想知道为什么会做出这个决定。
package com.example.corntest;
import lombok.extern.log4j.Log4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE;
@SpringBootApplication
@RestController
public class CornTestApplication
public static void main(String[] args)
SpringApplication.run(CornTestApplication.class, args);
//works - does NOT remove quotation marks
//curl 'http://localhost:8080/test' -X POST -H 'Content-Type: application/json' --data-raw '"SunGoesUp"' -vv
//works - but doesnt make sense - in comp. to code made in the bottom
//curl 'http://localhost:8080/test' -X POST -H 'Content-Type: application/json' --data-raw 'SunGoesUp' -vv
@PostMapping(value = "/test", consumes = APPLICATION_JSON_VALUE)
void mytestPost(@RequestBody String myString)
System.out.println(myString);
enum Test
TESTA,
TESTB,
TESTC
//works
//curl 'http://localhost:8080/testEnum' -X POST -H 'Content-Type: application/json' --data-raw '"TESTA"' -vv
//does not work
//curl 'http://localhost:8080/testEnum' -X POST -H 'Content-Type: application/json' --data-raw 'TESTA' -vv
//Why
@PostMapping(value = "/testEnum", consumes = APPLICATION_JSON_VALUE)
void myTestEnum(@RequestBody Test myEnumValue)
System.out.println(myEnumValue);
【问题讨论】:
第一个接受正文内容作为字符串,无论内容类型如何。在第二种情况下,第二个失败,因为没有引号它不是 JSON 意义上的字符串,因此解释不同,您只能将字符串转换为枚举。 但是第一个声明它接受 APPLICATION_JSON_VALUE 并且原始字符串(不带引号)不是有效的 json 值。它不应该被接受。另一方面,带引号的字符串 是 一个有效的 json 值,在创建 java 字符串之前删除引号是有意义的。@RequestBody
不关心 JSON 或任何内容类型。如果您将它放在String
上,它将把请求的主体放在那里,而不管内容类型如何。当您将它放在对象/枚举上时,它将使用HttpMessageConverter
将有效负载(主体)转换为请求的对象。只要有HttpMessageConverter
,有效负载就可以是任何东西,在您的情况下,它将是用于将有效负载转换为对象的JacksonHttpMessageConverter
。
感谢您的澄清,我想我可以理解这种行为是如何产生的。但我必须承认,我仍然觉得它有点奇怪并且不太喜欢它。如果您想使用 json,最好不要只使用带有 @RequestBody 的 java 字符串类型。我会尽量记住“只需将它包装在一个对象中”。
【参考方案1】:
在您使用@RequestBody String myString
的情况下,http 请求的有效负载按原样放入其中。因此,您发送的任何内容都将被放置在那里。内容类型无关紧要,因为它将按原样复制请求的有效负载。
在第二种情况下,需要一个实际的 JSON 字符串才能转换为枚举。基于 JSON 的字符串需要有引号,否则它不是 JSON 字符串。字符串以外的内容不能转换为枚举。
要将主体的有效负载转换为请求的对象,Spring 使用 [HttpMessageConverter
]。它将根据Content-Type
标头选择正确的HttpMessageConverter
。在您的情况下,假设默认值,这将导致MappingJackson2HttpMessageConverter
。它将使用正文转换为枚举。然后它将失败,因为它不是有效的 JSON 字符串(没有引号)。
解释什么是 JSON 中的字符串 here。
【讨论】:
以上是关于Spring Boot - Json RequestBody,带/不带引号的字符串/枚举的主要内容,如果未能解决你的问题,请参考以下文章
Spring-boot之jQuery File Upload后台配置方法