Spring - 相同URL但不同produced content type的两个不同POST方法

4

我有以下控制器:

@RequiredArgsConstructor
@RestController
public class OwnerViewController implements ApiOwnerViewController {

    private static final String TEXT_CSV = "text/csv";

    private final PrivateOwnerFacade privateOwnerFacade;

    @PostMapping("/boat/v1/private-owners/search")
    public OwnerViewResponse searchOwners(@Valid @RequestBody SearchOwnersRequest request,
                                          Pageable pageable) {
        return privateOwnerFacade.findOwners(request, pageable);
    }

    @PostMapping(value = "/boat/v1/private-owners/search", produces = TEXT_CSV)
    public ResponseEntity<Resource> exportToCsv(@Valid @RequestBody SearchOwnersRequest request, Pageable pageable)
            throws IOException {

我有两种方法映射到相同的URL,并且两种方法都接受POST请求,但是生成不同的内容类型。第一个方法生成"application/json",而第二个方法生成"text/csv"。
当我尝试发出请求并设置头部 "Accept: text/csv" 时,服务器返回406。
我想知道在Spring中是否真的可以这样做?还是唯一的方法是更改第二个方法,使其接受 GET 请求?
谢谢

2
当您将 produces = APPLICATION_JSON 添加到第一个方法时会发生什么? - JB Nizet
@JBNizet 请您添加您的答案,我会接受它。 - Andrey Yaskulsky
3个回答

3
@RequiredArgsConstructor
@RestController
public class SearchController {

    @PostMapping(value = "/search", produces = {APPLICATION_JSON})
    public SearchResponse search(@Valid @RequestBody SearchRequest request,
                                          Pageable pageable) {
    }

    @PostMapping(value = "/search", produces = {TEXT_CSV})
    public ResponseEntity<Resource> export(@Valid @RequestBody SearchRequest request, Pageable pageable) throws IOException {

    }


}

1
问题在于text/csv请求匹配了两个端点。
你可以在注释中使用负值,这样第一个端点将只匹配非text/csv请求:
@PostMapping(value = "/boat/v1/private-owners/search", produces = "!text/csv")
public OwnerViewResponse searchOwners(@Valid @RequestBody SearchOwnersRequest 
                                      request,
                                      Pageable pageable) {
    return privateOwnerFacade.findOwners(request, pageable);
}

0
只需使用一个带有 @PostMapping 的方法,返回响应实体并动态设置 Content-Type-Response-Header。
@RestController
public class TestController {

    @GetMapping("/api-endpoint")
    public ResponseEntity<String> method(@RequestParam("produces") String produces) {

        HttpHeaders responseHeaders = new HttpHeaders();

        if (produces.equals("text/csv")) {
            responseHeaders.setContentType(new MediaType("text", "csv"));
            return new ResponseEntity<String>("foo;bar", responseHeaders, HttpStatus.OK);
        } else {
            responseHeaders.setContentType(new MediaType("application", "json"));
            return new ResponseEntity<String>("{\"foo\": \"bar\"}", responseHeaders, HttpStatus.OK);
        }
    }
}

这并没有回答问题。首先,在问题中用户尝试执行POST请求,而不是GET请求。其次,问题是“是否可以对相同路径进行不同内容类型的POST映射”,并且正如接受的答案所示,这是可能的。让我们给出全面正确的答案,不要误导人们。 - Vüsal
@Vusal 可以简单地将 @GetMapping 更改为 @PostMapping,并将所需的 RequestParams 添加到方法签名中。我想保持简单,以展示如何使用不同的内容类型具有相同的端点。但是,我同意,被接受的答案比我的方法更整洁。 - phip1611

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接