【问题标题】:Spring Boot - Json RequestBody, String/Enum with/without quotation marksSpring Boot - Json RequestBody,带/不带引号的字符串/枚举
【发布时间】: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 字符串类型。我会尽量记住“只需将它包装在一个对象中”。

标签: spring spring-boot jackson mapping spring-restcontroller


【解决方案1】:

在您使用@RequestBody String myString 的情况下,http 请求的有效负载按原样放入其中。因此,您发送的任何内容都将被放置在那里。内容类型无关紧要,因为它将按原样复制请求的有效负载。

在第二种情况下,需要一个实际的 JSON 字符串才能转换为枚举。基于 JSON 的字符串需要有引号,否则它不是 JSON 字符串。字符串以外的内容不能转换为枚举。

要将主体的有效负载转换为请求的对象,Spring 使用 [HttpMessageConverter]。它将根据Content-Type 标头选择正确的HttpMessageConverter。在您的情况下,假设默认值,这将导致MappingJackson2HttpMessageConverter。它将使用正文转换为枚举。然后它将失败,因为它不是有效的 JSON 字符串(没有引号)。

解释什么是 JSON 中的字符串 here

【讨论】:

    猜你喜欢
    • 2019-11-28
    • 1970-01-01
    • 1970-01-01
    • 2019-08-09
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 2017-02-08
    相关资源
    最近更新 更多