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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35123835/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 16:20:21  来源:igfitidea点击:

Spring RequestMapping for controllers that produce and consume JSON

javajsonspringspring-mvc

提问by Roshan Mathews

With multiple Spring controllers that consume and produce application/json, my code is littered with long annotations like:

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

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

Is there a way to produce a "composite/inherited/aggregated" annotation with defaultvalues for consumesand produces, such that I could instead write something like:

有没有办法用and 的默认值生成“复合/继承/聚合”注释,这样我就可以写一些类似的东西:consumesproduces

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

How do we define something like @JSONRequestMappingabove? Notice the valueand methodpassed in just like in @RequestMapping, also good to be able to pass in consumesor producesif the default isn't suitable.

我们如何定义类似@JSONRequestMapping上面的内容?注意valuemethod就像 in 一样传入@RequestMapping,也可以传入consumes或者produces默认值不合适。

I need to control what I'm returning. I want the produces/consumesannotation-methods so that I get the appropriate Content-Typeheaders.

我需要控制我要返回的内容。我想要produces/ consumesannotation-methods 以便获得适当的Content-Type标题。

采纳答案by Ali Dehghani

As of Spring 4.2.x, you can create custom mapping annotations, using @RequestMappingas a meta-annotation. So:

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

Is there a way to produce a "composite/inherited/aggregated" annotation with default values for consumes and produces, such that I could instead write something like:

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

有没有办法用消费和生产的默认值生成“复合/继承/聚合”注释,这样我就可以写一些类似的东西:

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

Yes, there is such a way. You can create a meta annotation like following:

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

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

Then you can use the default settings or even override them as you want:

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

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

You can read more about AliasForin spring's javadocand github wiki.

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

回答by alexandrum

There are 2 annotations in Spring: @RequestBodyand @ResponseBody. These annotations consumes, respectively produces JSONs. Some more info here.

Spring 中有 2 个注解:@RequestBody@ResponseBody。这些注解分别消费,产生 JSON。这里有更多信息。

回答by Wim Deblauwe

You can use the @RestControllerinstead of @Controllerannotation.

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

回答by FGreg

The simple answer to your question is that there is no Annotation-Inheritance in Java. However, there is a way to use the Spring annotations in a way that I think will help solve your problem.

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

@RequestMappingis supported at both the type level and at the method level.

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

When you put @RequestMappingat the type level, most of the attributes are 'inherited' for each method in that class. This is mentionedin the Spring reference documentation. Look at the api docsfor details on how each attribute is handled when adding @RequestMappingto a type. I've summarized this for each attribute below:

当您放在@RequestMapping类型级别时,该类中的每个方法的大多数属性都是“继承的”。Spring 参考文档中提到了这一点。有关在添加到类型时如何处理每个属性的详细信息,请查看api 文档@RequestMapping。我为下面的每个属性总结了这一点:

  • name: Value at Type level is concatenated with value at method level using '#' as a separator.
  • value: Value at Type level is inherited by method.
  • path: Value at Type level is inherited by method.
  • method: Value at Type level is inherited by method.
  • params: Value at Type level is inherited by method.
  • headers: Value at Type level is inherited by method.
  • consumes: Value at Type level is overridden by method.
  • produces: Value at Type level is overridden by method.
  • name: 类型级别的值使用“#”作为分隔符与方法级别的值连接。
  • value: 类型级别的值由方法继承。
  • path: 类型级别的值由方法继承。
  • method: 类型级别的值由方法继承。
  • params: 类型级别的值由方法继承。
  • headers: 类型级别的值由方法继承。
  • consumes:类型级别的值被方法覆盖。
  • produces:类型级别的值被方法覆盖。

Here is a brief example Controller that showcases how you could use this:

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

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

回答by hyness

You shouldn't need to configure the consumes or produces attribute at all. Spring will automatically serve JSON based on the following factors.

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

  • The accepts header of the request is application/json
  • @ResponseBodyannotated method
  • Hymanson library on classpath
  • 请求的接受头是application/json
  • @ResponseBody注释方法
  • 类路径上的 Hymanson 库

You should also follow Wim's suggestion and define your controller with the @RestControllerannotation. This will save you from annotating each request method with @ResponseBody

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

Another benefit of this approach would be if a client wants XML instead of JSON, they would get it. They would just need to specify xml in the accepts header.

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