【问题标题】:How to call a @RestController with @RequestBody?如何用@RequestBody 调用@RestController?
【发布时间】:2017-04-16 01:48:40
【问题描述】:

我有一个简单的 servlet,如下所示:

@RestController
public class TestServlet {
    @RequestMapping(value = "/test1")
    public String test1() {
        return "test1";
    }

    @RequestMapping(value = "/test2")
    public String test2(@RequestBody TestClass req) {
        return "test2";
    }

    public static class TestClass {
        private String value;

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }
}

但只有不接收参数的servlet在工作:

作品:http://localhost:8080/test1

不起作用:http://localhost:8080/test2?value=1234

org.springframework.http.converter.HttpMessageNotReadableException: 缺少所需的请求正文:public java.lang.String

为什么@RequestBody 注释不起作用?我错过了重要的部分吗?

【问题讨论】:

标签: java spring servlets spring-web


【解决方案1】:

@Controller@RestController 之间的区别之一是您不必编写@RequestBody@ResponseBody,这意味着您的控制器方法中的任何参数都没有注释(如@ 987654326@, @ModelAttribute, ...) 将隐含 @RequestBody,因此必须作为 HTTP 实体主体发布。因此,您需要将 JSON/XML 作为 POST 的一部分发送。您所做的是将数据作为 URL 的一部分发送,这使其成为请求参数而不是正文数据,并且您需要 @RequestParam 从 URL 中提取数据。

另外,我建议您使用@GetMapping/@PostMapping 或在@RequestMapping 注释中包含方法参数,您不太可能希望将服务用于POST 和GET,所以您应该在控制器方法描述中尽可能具体,以限制错误情况。

【讨论】:

  • 关于 @RequestBody 注释的更正:@RestController 是一个组合注释,它本身就是元-annotated@Controller@ResponseBody 表示一个控制器,它的每个方法都继承了类型级别的@ResponseBody 注释,你仍然需要@RequestBody 作为POST 参数。更多详情请见this answer
  • 在我的测试用例中,如果参数是可选的,您似乎仍然需要@RequestBody,即使您使用@PathVariable 等注释其他人,并且控制器为@RestController
【解决方案2】:

第二个 URL 不起作用的原因是,当使用 @RequestBody 时,您发送到端点的数据需要通过请求标头中的 data 属性来传递。当您将?attr=value 附加到发送params 标头中的属性的URL 时。

有两种方法可以解决这个问题:

  1. 更改您的端点以读取如下内容:

    public String test2(@RequestParam("value") TestClass req) { //Endpoint code }

  2. 更改您的端点以读取如下内容:

    @RequestMapping(value="test2",method=RequestMethod.POST) public String test2(@RequestBody TestClass req){ //Endpoint code }

    让你的电话与此类似(例如 angularjs):

    http.post({url:/*url*/,data:/*object to send*/});

第二个选项很可能是您想要使用的,因为看起来您正在尝试将 json 对象发送到您的端点,我相信您只能通过发出 POST 请求而不是 GET 请求来做到这一点

【讨论】:

  • 如果这解决了您的问题,请选择它作为解决方案。
【解决方案3】:

只需省略 @RequestBody 注释,因为这仅适用于 POST 请求。

  public String test2(@Valid TestClass req) {
        return "test2";
    }

【讨论】:

  • 这可能适用于您的测试环境,但如果您想在端点内使用对象 TestClass,我不相信 Jackson 会为您自动反序列化 json。原因是你不能通过 GET 请求发送 json
【解决方案4】:

当您将控制器方法参数声明为@RequestBody 时,您希望它从请求正文中恢复,而不是作为“常规”http 参数。

您可以尝试使用任何类型的 Firefox (RESTClient) 或 Chrome (PostMan) 插件并尝试使用其中一个。您也可以使用 SoapUI 来完成。

请求应该是一个POST到请求的url:

POST http://localhost:8080/test2

您必须提供 http 标头来证明预期的 Content-TypeAccept。如果使用 Json,请将它们设置为:

Content-Type: application/json
Accept: text/html (As your method returns only a String)

然后将参数写入请求正文。如果在 Json 中,像这样:

{
"value":"the provided value"
}

【讨论】:

    猜你喜欢
    • 2018-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-12
    • 2020-01-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多