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

时间:2019-04-15 18:39:44

标签: java spring-boot spring-restcontroller request-mapping content-negotiation

我有一个带有RestController的Spring-Boot(v2.0.2)应用程序,其中有2种方法,它们的区别仅在于Accept标头。代码的简化版本是这样:

@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);
    }

这很好。例如,如果我们发送带有接受标头(例如application/json;q=0.5,application/ld+json;q=0.6)的请求,它将返回一个json-ld响应。

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

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

  • 颠倒声明映射的顺序。
  • 在两种方法中都添加一个@Order批注(json-ld的值为1,json方法的值为2)
  • 创建不同的类,并将@Order注释置于类级别
  • Accept=*/*添加为json-ld映射的第二个接受标头确实可以为其赋予优先级,但是具有所有接受标头都被接受的不良影响,即使是application/xml不受支持的类型例子。

我能想到的唯一解决方案是创建一个同时接受两个标头的请求映射方法,然后自己处理accept标头,但我并不喜欢这种解决方案。有没有更好,更简便的方法来赋予json-ld优先权?

2 个答案:

答案 0 :(得分:1)

经过更多搜索之后,this question on configuring custom MediaTypes为我指明了正确的方向。 WebMvcConfigurerAdapter(春季3或4)或WebMvcConfigurer(春季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,它将返回json而不是json-ld!?。我怀疑这是Spring中的错误。

答案 1 :(得分:0)

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

  

格式是单个媒体类型或媒体类型序列,仅当Content-Type与这些媒体类型之一匹配时才映射请求。可以使用“!”取反表达式。运算符,如“!text / plain”中一样,它匹配除Content-Type以外的所有请求,而其内容类型不是“ text / plain”。

在下面的解决方案中,请注意,我已经将消耗数组添加到普通的json请求映射中,这使得客户端只能在具有正确的Content-Type的情况下使用json端点。其他请求将发送到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\"}";
}