我怎样才能让 Spring @RestController 接受 JSON 格式的参数而不是 www-form-urlencoded?

How can I get a Spring @RestController to accept parameters in JSON format rather than www-form-urlencoded?

在 JDK 1.8 上使用 Spring 4.1.7,我有一个 @RestController class 看起来像这样:

@RestController
public class ServiceAController {

    public static final Logger LOG = Logger.getLogger(ServiceAController.class);

    @RequestMapping(value="/rest/servicea", method=RequestMethod.POST)
    public ServiceAResponse serviceA(@RequestParam(value="parmA", defaultValue="defaultParmA") String parmA,
            @RequestParam(value="parmB", defaultValue="defaultParmB") String parmB,
            @RequestParam(value="parmC", defaultValue="defaulParmC") String parmC) {
        LOG.info("Inside Service A handler: " + parmA + " B: "+ parmB + " C: "+ parmC);
}

当我像这样从 javascript 发送 POST 到 /rest/servicea 时,一切正常,我看到值 "a"、"b",并且 "c" 打印在我的日志中:

    var data = {        
        "parmA": "a",
        "parmB": "b",
        "parmC": "c"
    }

    $.ajax({
        type: "POST",
        url: "./rest/servicea",
        contentType: "application/x-www-form-urlencoded",
        data: data,
        dataType: "json",
        success: submitAuthSuccess,
        error: submitAuthFailure 
    })

但是,当我尝试将调用从 javascript 更改为此(将协议更改为 REST 而不是 www-urlencode)时,我得到了默认值(defaultParmA、defaultParmB、defaultParmC)我的日志:

    var data = {        
        "parmA": "a",
        "parmB": "b",
        "parmC": "c"
    }

    $.ajax({
        type: "POST",
        url: "./rest/servicea",
        contentType: "application/json",
        data: JSON.stringify(data),
        dataType: "json",
        success: submitAuthSuccess,
        error: submitAuthFailure 
    })

我想我在 @RestController class 中遗漏了一些东西来让它解析 JSON 而不是期待 www-urlencoded 数据。

我尝试更改 serviceA 方法上的 @RequestMapping 注释以添加 consumes="application/json" 属性,但没有效果。

在 POST 正文中使用 JSON 而不是 urlencoded 数据,我可以更改什么来使这项工作正常进行?

在我看来,您此时正在传递单个 JSON 对象,而不是一组参数,因此 Spring 无法匹配您发送给任何参数的内容你已经提供了。

尝试

@RequestBody List<ListUnit> listOfUnits

而不是@RequestParam

@RequestParam javadoc 声明

Annotation which indicates that a method parameter should be bound to a web request parameter.

这是通过请求参数的各种 ServletRequest 方法检索的。例如,ServletRequest#getParameterMap() 表示

Request parameters are extra information sent with the request. For HTTP servlets, parameters are contained in the query string or posted form data.

在你的第二个片段中,你也没有发送。您正在请求正文中发送 JSON。

Spring 有一种机制(它有很多自定义机制)可以将其反序列化为您期望的数据。如果类路径上有 Jackson 2,标准解决方案是 @RequestBody, assuming you have an appropriately registered HttpMessageConverter that can handle the JSON. Spring automatically registers MappingJackson2HttpMessageConverter,它可以正确地将 JSON 反序列化为 Java POJO 类型。

documentation 给出了一些示例并解释了如何使用它。使用 JSON,您可以定义一个 POJO 类型,其中包含与您发送的字段相对应的字段

class RequestPojo {
    private String paramA;
    private String paramB;
    private String paramC;
    // and corresponding getters and setters
}

并将此类型的 @RequestBody 注释参数添加到您的处理程序方法

public ServiceAResponse serviceA(@RequestBody RequestPojo pojo) {
    pojo.getParamB(); // do something
    return ...;
}

Jackson 允许您通过注释或配置 ObjectMapper 来定义如何处理缺失值。

@RestController这里不涉及。正如其 javadoc 所述,

Types that carry this annotation are treated as controllers where @RequestMapping methods assume @ResponseBody semantics by default.