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

Ros*_*ews 36 java spring json spring-mvc

有了多个消耗和生成的Spring控制器application/json,我的代码充满了长注释,如:

    @RequestMapping(value = "/foo", method = RequestMethod.POST,
            consumes = MediaType.APPLICATION_JSON_VALUE,
            produces = MediaType.APPLICATION_JSON_VALUE)
Run Code Online (Sandbox Code Playgroud)

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

    @JSONRequestMapping(value = "/foo", method = RequestMethod.POST)
Run Code Online (Sandbox Code Playgroud)

我们如何定义@JSONRequestMapping上面的内容?注意valuemethod传入就像@RequestMapping,也可以传入consumesproduces默认不适合.

我需要控制我要回来的东西.我想要produces/ consumesannotation-methods,以便获得适当的Content-Type头文件.

Ali*_*ani 55

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

有没有办法生成一个"复合/继承/聚合"注释,其中包含消耗和生成的默认值,这样我就可以编写如下内容:

@JSONRequestMapping(value = "/foo", method = RequestMethod.POST)
Run Code Online (Sandbox Code Playgroud)

是的,有这样的方式.您可以创建如下的元注释:

@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 {};
}
Run Code Online (Sandbox Code Playgroud)

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

@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;
}
Run Code Online (Sandbox Code Playgroud)

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

  • 这真的很有趣; 不知道这个新功能.[JavaDoc for @AliasFor](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AliasFor.html)真的很棒.还有一个[wiki页面](https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model)更详细地描述了Spring的注释模型. (2认同)

FGr*_*reg 20

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

类型级别和方法级别都支持@RequestMapping.

当你放入@RequestMapping类型级别时,大多数属性都是为该类中的每个方法"继承"的.这在Spring参考文档中提到.查看api文档,了解添加@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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 从技术上讲,Ali Dehghani的回答最能回答我提出的问题,所以我已将其标记为已被接受.但我最终使用你的建议,在某种意义上看起来更干净,所以我也给你一个赏金,(+ 100,因为我不能做+50两次).谢谢. (2认同)

Wim*_*uwe 9

您可以使用@RestController而不是@Controller注释.


hyn*_*ess 7

您根本不需要配置消耗或生成属性.Spring将根据以下因素自动提供JSON.

  • 请求的接受标头是application/json
  • @ResponseBody注释方法
  • 类路径的杰克逊图书馆

您还应该遵循Wim的建议并使用@RestController注释定义控制器.这将使您免于使用@ResponseBody注释每个请求方法

这种方法的另一个好处是,如果客户端需要XML而不是JSON,他们就会得到它.他们只需要在接受标头中指定xml.