用于生成和使用 JSON 的控制器的 Spring RequestMapping

2022-08-31 20:03:31

使用多个消耗和生产的Spring控制器,我的代码中充斥着长注释,例如:application/json

    @RequestMapping(value = "/foo", method = RequestMethod.POST,
            consumes = MediaType.APPLICATION_JSON_VALUE,
            produces = MediaType.APPLICATION_JSON_VALUE)

有没有办法生成一个“复合/继承/聚合”注释,默认值为 和 ,这样我就可以写如下内容:consumesproduces

    @JSONRequestMapping(value = "/foo", method = RequestMethod.POST)

我们如何定义上面这样的东西?注意 和 传入 就像 在 一样,也很好,能够传入或如果默认值不合适。@JSONRequestMappingvaluemethod@RequestMappingconsumesproduces

我需要控制我要返回的内容。我想要/注释方法,以便我得到适当的标头。producesconsumesContent-Type


答案 1

从 Spring 4.2.x 开始,您可以创建自定义映射注释,用作元注释。所以:@RequestMapping

有没有办法生成一个“复合/继承/聚合”注释,其中包含消耗和生成的默认值,这样我就可以写这样的东西:

@JSONRequestMapping(value = "/foo", method = RequestMethod.POST)

是的,有这样一种方式。您可以创建元注释,如下所示:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping(consumes = "application/json", produces = "application/json")
public @interface JsonRequestMapping {
    @AliasFor(annotation = RequestMapping.class, attribute = "value")
    String[] value() default {};

    @AliasFor(annotation = RequestMapping.class, attribute = "method")
    RequestMethod[] method() default {};

    @AliasFor(annotation = RequestMapping.class, attribute = "params")
    String[] params() default {};

    @AliasFor(annotation = RequestMapping.class, attribute = "headers")
    String[] headers() default {};

    @AliasFor(annotation = RequestMapping.class, attribute = "consumes")
    String[] consumes() default {};

    @AliasFor(annotation = RequestMapping.class, attribute = "produces")
    String[] produces() default {};
}

然后,您可以使用默认设置,甚至可以根据需要覆盖它们:

@JsonRequestMapping(method = POST)
public String defaultSettings() {
    return "Default settings";
}

@JsonRequestMapping(value = "/override", method = PUT, produces = "text/plain")
public String overrideSome(@RequestBody String json) {
    return json;
}

你可以在spring的javadocgithub wiki中阅读更多关于的信息。AliasFor


答案 2

你的问题的简单答案是Java中没有注释继承。但是,有一种方法可以以我认为有助于解决您的问题的方式使用Spring注释。

@RequestMapping在类型级别和方法级别均受支持。

在类型级别放置时,大多数属性都是该类中每个方法的“继承”的。这在春季参考文档中有所提及。查看 api 文档,详细了解在添加到类型时如何处理每个属性。我总结了以下每个属性的这一点:@RequestMapping@RequestMapping

  • name:类型级别的值与方法级别的值使用“#”作为分隔符连接。
  • value:类型级别的值由方法继承。
  • path:类型级别的值由方法继承。
  • method:类型级别的值由方法继承。
  • params:类型级别的值由方法继承。
  • headers:类型级别的值由方法继承。
  • consumes:类型级别的值被方法覆盖。
  • produces:类型级别的值被方法覆盖。

下面是一个简短的控制器示例,展示了如何使用它:

package com.example;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(path = "/", 
        consumes = MediaType.APPLICATION_JSON_VALUE, 
        produces = MediaType.APPLICATION_JSON_VALUE, 
        method = {RequestMethod.GET, RequestMethod.POST})
public class JsonProducingEndpoint {

    private FooService fooService;

    @RequestMapping(path = "/foo", method = RequestMethod.POST)
    public String postAFoo(@RequestBody ThisIsAFoo theFoo) {
        fooService.saveTheFoo(theFoo);
        return "http://myservice.com/foo/1";
    }

    @RequestMapping(path = "/foo/{id}", method = RequestMethod.GET)
    public ThisIsAFoo getAFoo(@PathVariable String id) {
        ThisIsAFoo foo = fooService.getAFoo(id);
        return foo;
    }

    @RequestMapping(path = "/foo/{id}", produces = MediaType.APPLICATION_XML_VALUE, method = RequestMethod.GET)
    public ThisIsAFooXML getAFooXml(@PathVariable String id) {
        ThisIsAFooXML foo = fooService.getAFoo(id);
        return foo;
    }
}