如何为 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 请求映射:
- 反转声明映射的顺序。
- 为两种方法添加 @Order 注释(json-ld 的值为 1,json 方法的值为 2)
- 创建不同的 类 并将 @Order 注释放在 class-level
- 将
Accept=*/*
作为第二个接受 header 添加到 json-ld 映射中确实可以赋予它优先权,但有不需要的 side-affect 所有人都接受 headers 被接受,甚至是不支持的类型,例如 application/xml
。
我能想到的唯一解决方案是创建一个接受两个 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.
中的错误
我有一个 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 请求映射:
- 反转声明映射的顺序。
- 为两种方法添加 @Order 注释(json-ld 的值为 1,json 方法的值为 2)
- 创建不同的 类 并将 @Order 注释放在 class-level
- 将
Accept=*/*
作为第二个接受 header 添加到 json-ld 映射中确实可以赋予它优先权,但有不需要的 side-affect 所有人都接受 headers 被接受,甚至是不支持的类型,例如application/xml
。
我能想到的唯一解决方案是创建一个接受两个 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.