Avec plusieurs contrôleurs Spring qui consomment et produisent application/json
, mon code est jonché de longues annotations telles que:
@RequestMapping(value = "/foo", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
Existe-t-il un moyen de produire une annotation "composite/héritée/agrégée" avec valeur par défaut valeurs pour consumes
et produces
, de sorte que je puisse plutôt écrire quelque chose du type:
@JSONRequestMapping(value = "/foo", method = RequestMethod.POST)
Comment définissons-nous quelque chose comme @JSONRequestMapping
au dessus de? Notez que value
et method
sont passés exactement comme dans @RequestMapping
, aussi bien de pouvoir passer consumes
ou produces
si la valeur par défaut ne convient pas.
J'ai besoin de contrôler ce que je retourne. Je veux les produces
/consumes
méthodes d'annotation afin d'obtenir le Content-Type
en-têtes.
A partir de Spring 4.2.x, vous pouvez créer des annotations de mappage personnalisées à l’aide de @RequestMapping
comme une méta-annotation. Alors:
Existe-t-il un moyen de produire une annotation "composite/héritée/agrégée" avec des valeurs par défaut pour consomme et produit, telle que je pourrais plutôt écrire quelque chose comme:
@JSONRequestMapping(value = "/foo", method = RequestMethod.POST)
Oui, il y a un tel moyen. Vous pouvez créer une méta annotation comme suit:
@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 {};
}
Ensuite, vous pouvez utiliser les paramètres par défaut ou même les remplacer comme vous le souhaitez:
@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;
}
Vous pouvez en savoir plus sur AliasFor
dans le fichier printanier javadoc et github wiki .
La réponse simple à votre question est qu'il n'y a pas de Annotation-Inheritance in Java . Cependant, il existe un moyen d'utiliser les annotations Spring de manière à résoudre, selon moi, votre problème.
@ RequestMapping est pris en charge à la fois au niveau du type et au niveau de la méthode.
Quand vous mettez @RequestMapping
au niveau du type, la plupart des attributs sont "hérités" pour chaque méthode de cette classe. C'est mentionné dans la documentation de référence de Spring. Regardez le api docs pour plus de détails sur la gestion de chaque attribut lors de l’ajout de @RequestMapping
à un type. J'ai résumé ceci pour chaque attribut ci-dessous:
name
: la valeur au niveau type est concaténée à la valeur au niveau méthode en utilisant '#' comme séparateur.value
: la valeur au niveau Type est héritée par méthode.path
: la valeur au niveau Type est héritée par méthode.method
: la valeur au niveau Type est héritée par méthode.params
: la valeur au niveau Type est héritée par méthode.headers
: la valeur au niveau Type est héritée par méthode.consumes
: La valeur au niveau du type est remplacée par la méthode.produces
: La valeur au niveau du type est remplacée par la méthode.Voici un bref exemple de contrôleur qui montre comment vous pouvez utiliser ceci:
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;
}
}
Vous pouvez utiliser le @RestController
au lieu de @Controller
annotation.
Vous ne devriez pas avoir besoin de configurer l'attribut consomme ou produit du tout. Spring servira automatiquement JSON en fonction des facteurs suivants.
Vous devez également suivre la suggestion de Wim et définir votre contrôleur avec l'annotation @ RestController. Cela vous évitera d’annoter chaque méthode de requête avec @ ResponseBody
Un autre avantage de cette approche serait qu'un client souhaite obtenir du XML au lieu de JSON, il l'obtiendra. Ils auraient juste besoin de spécifier XML dans l'en-tête accept.
Il y a 2 annotations dans Spring: @ RequestBody et @ ResponseBody . Ces annotations consomment, produisent respectivement des JSON. Quelques informations supplémentaires ici .