web-dev-qa-db-fra.com

Spring RequestMapping pour les contrôleurs produisant et consommant JSON

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.

36
Roshan Mathews

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 .

54
Ali Dehghani

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

Vous pouvez utiliser le @RestController au lieu de @Controller annotation.

9
Wim Deblauwe

Vous ne devriez pas avoir besoin de configurer l'attribut consomme ou produit du tout. Spring servira automatiquement JSON en fonction des facteurs suivants.

  • L'en-tête accepte de la demande est application/json
  • @ ResponseBody méthode annotée
  • Bibliothèque Jackson sur classpath

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.

6
hyness

Il y a 2 annotations dans Spring: @ RequestBody et @ ResponseBody . Ces annotations consomment, produisent respectivement des JSON. Quelques informations supplémentaires ici .

0
alexandrum