Spring Boot:我可以将多个对象作为多个@RequestParams发布到REST服务吗?

时间:2018-03-13 11:40:06

标签: java spring rest spring-boot

使用Spring Boot我使用单一资源构建玩具REST服务,如下所示:

@RestController
@RequestMapping("/checkout")
public class CheckoutRestController {

    @PostMapping("/book")
    public boolean buyBook(@RequestParam CreditCard creditCard, @RequestParam ShippingAddress shippingAddress) {
        return true;
    }
}

CreditCardShippingAddress都是我编写过的POJO(普通的旧Java对象)。

我尝试使用此有效负载发布到此端点:

{
    "creditCard" : {
        "nameOnCard":"foo",
        "number":12345678,
        "expiryMonth":12,
        "expiryYear":2018,
        "ccv":100
    },
    "shippingAddress" : {
        "steert":"foor",
        "houseNumber":"1a",
        "city":"bar",
        "state":"bazz",
        "country":"buzz",
        "zipCode":"booz"
    },
}

但是我收到了一个错误:

{
    "timestamp": "2018-03-13T11:36:52.745+0000",
    "status": 400,
    "error": "Bad Request",
    "message": "Required CreditCard parameter 'creditCard' is not present",
    "path": "/checkout/book"
}

我知道一种解决方法是将两个POJO包装在一个请求包装器中,但除非我真的需要,否则我不愿意。

是否可以发布两个@RequestParam注释对象?如果是这样,JSON会是什么样的?

2 个答案:

答案 0 :(得分:5)

@RequestParam参数是查询参数,而不是正文参数。

这意味着你的方法:

@PostMapping("/book")
    public boolean buyBook(@RequestParam CreditCard creditCard, @RequestParam 
ShippingAddress shippingAddress) {
        return true;
    }

期待以下请求:

POST /checkout/book?creditCard=<...>&shippingAddress=<...>

但是,Spring不知道如何将String查询参数转换为CreditCardShippingAddress

您可以通过实施Converter来解决此问题,如下所示:

public class StringToCreditCardConverter implements Converter<String, CreditCard> {

    @Override
    public CreditCard convert(String source) {
         <...>
    }
}

但是,我不建议这样做。

相反,我建议您执行以下操作:

@PostMapping("/book")
    public boolean buyBook(@RequestBody BookCreationRequest bookCreationRequest) {
        CreditCard creditCard = bookCreationRequest.getCreditCard();
        ShippingAddress shippingAddress = bookCreationRequest.getShippingAddress();
        ...
    }

bookCreationRequest包含CreditCardShippingAddress字段:

public class BookCreationRequest {
    private ShippingAddress shippingAddress;
    private CreditCredit creditCard;

    public ShippingAddress  getShippingAddress() {...}
    public CreditCard       getCreditCard() {...}

    public BookCreationRequest(ShippingAddress shippingAddress, CreditCard creditCard) {
        this.creditCard = creditCard;
        this.shippingAddress = shippingAddress;
}

然后期望JSON请求如下:

POST /checkout/book
Payload:
{
    "creditCard": {
        ... 
    },
    "shippingAddress": {
        ...
    }
}

请注意,请求中只能有一个@RequestBody参数。

答案 1 :(得分:2)

是 - 创建一个包装器Request对象。 这不是一种解决方法 - 它实际上是推荐的方法。

你在json中看到了:

{ //wrapper
 {}, //first complex data object / mapped to pojo
 {} //second complex data object / mapped to pojo
}

1)您可以使用@Valid轻松地将验证应用于Request对象,从而验证两个POJO。

2)您不必担心有效载荷中的顺序。

3)您错误地使用了@RequestParam@RequestBody映射整个POST有效负载。您必须删除@RequestParam注释,然后使用@RequestBody