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 注解

玩转 Spring Boot 集成篇(任务动态管理代码篇)

Spring Boot 接口加解密,新姿势来了!

Spring-boot之jQuery File Upload后台配置方法

Spring Boot - 如何在 HTTP Post api 中传递自定义值?

从 json 文件加载 spring-boot 属性