如何为 Spring-Boot 请求映射方法设置优先级

How to set priority to Spring-Boot request mapping methods

我有一个 Spring-Boot (v2.0.2) 应用程序,它的 RestController 有两个方法,仅在 Accept header 上有所不同。代码的简化版本是这样的:

@RestController
@RequestMapping("/myapp")
public class FooController {

    @GetMapping(value = "/foo/{id}", headers = "Accept=application/json", produces = "application/json;charset=UTF-8")
    public ResponseEntity<String> fooJson(@PathVariable id) {
        return foo(pageId, true);
    }

    @GetMapping(value = "/foo/{id}", headers = "Accept=application/ld+json", produces = "application/ld+json;charset=UTF-8")
    public ResponseEntity<String> fooJsonLd(@PathVariable id) {
        return foo(pageId, false);
    }

    private ResponseEntity<String> foo(String id, boolean isJson) {
        String result = generateBasicResponse(id);
        if (isJson) {
            return result
        }
        return addJsonLdContext(result);
    }

这很好用。例如,如果我们发送一个接受 header 的请求,例如 application/json;q=0.5,application/ld+json;q=0.6,它将 return 一个 json-ld 响应。

我的问题是,如果我们发送的请求没有接受 header、空接受 header 或通配符 */* 那么默认情况下它将始终 return json 响应,而我希望默认响应为 json-ld。

我尝试了各种方法使 json-ld 请求映射优先于 json 请求映射:

我能想到的唯一解决方案是创建一个接受两个 header 的 request-mapping 方法,然后我们自己处理接受 header,但我不太喜欢那样解决方案。有没有更好、更简单的方法来优先 json-ld?

我使用 @GetMapping 注释中的 consumes 解决了这个问题。 According to the official documentation:

The format is a single media type or a sequence of media types, with a request only mapped if the Content-Type matches one of these media types. Expressions can be negated by using the "!" operator, as in "!text/plain", which matches all requests with a Content-Type other than "text/plain".

在下面的解决方案中,请注意我已将消耗数组添加到正常的 json 请求映射中,使客户端只有在具有正确的 json 端点时才能使用Content-Type。其他请求转到 ld+json 端点。

@GetMapping(value = "/json", headers = "Accept=application/json", consumes = {"application/json"})
@ResponseBody
public String testJson() {
    return "{\"type\":\"json\"}";
}

@GetMapping(value = "/json", headers = "Accept=application/ld+json")
@ResponseBody
public String textLDJson() {
    return "{\"type\":\"ld\"}";
}

经过更多搜索 this question on configuring custom MediaTypes 为我指出了正确的方向。 WebMvcConfigurerAdapter(Spring 3 或 4)或 WebMvcConfigurer(Spring 5)允许您像这样设置默认媒体类型:

public static final String MEDIA_TYPE_JSONLD  = "application/ld+json";

@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.defaultContentType(MediaType.valueOf(MEDIA_TYPE_JSONLD));
    }
}

这对于没有接受头或接受头为空的请求以及 accept: */* 非常有用。但是,当您将不受支持的类型与通配符组合时,例如 accept: */*,text/plain 它将 return json 而不是 json-ld!?我怀疑这是 Spring.

中的错误