152 votes

Passage de plusieurs variables dans @RequestBody à un contrôleur Spring MVC en utilisant Ajax

Est-il nécessaire d'envelopper dans un objet de soutien ? Je veux faire ceci :

@RequestMapping(value = "/Test", method = RequestMethod.POST)
@ResponseBody
public boolean getTest(@RequestBody String str1, @RequestBody String str2) {}

Et utiliser un JSON comme ceci :

{
    "str1": "test one",
    "str2": "two test"
}

Mais à la place, je dois utiliser :

@RequestMapping(value = "/Test", method = RequestMethod.POST)
@ResponseBody
public boolean getTest(@RequestBody Holder holder) {}

Et ensuite utiliser ce JSON :

{
    "holder": {
        "str1": "test one",
        "str2": "two test"
    }
}

Est-ce exact ? L'autre option serait de modifier le RequestMethod a GET et utiliser @RequestParam dans la chaîne de requête ou utiliser @PathVariable avec soit RequestMethod .

122voto

Kong Points 1615

S'il est vrai que @RequestBody doit correspondre à un seul objet, cet objet peut être une Map Cela vous permet de vous rapprocher de l'objectif que vous souhaitez atteindre (il n'est pas nécessaire d'écrire un objet de sauvegarde unique) :

@RequestMapping(value = "/Test", method = RequestMethod.POST)
@ResponseBody
public boolean getTest(@RequestBody Map<String, String> json) {
   //json.get("str1") == "test one"
}

Vous pouvez également vous lier à la ObjectNode si vous voulez un arbre JSON complet :

public boolean getTest(@RequestBody ObjectNode json) {
   //json.get("str1").asText() == "test one"

114voto

Biju Kunjummen Points 20258

Vous avez raison, le paramètre annoté @RequestBody est censé contenir l'intégralité du corps de la requête et se lier à un objet. Vous devrez donc essentiellement faire appel à vos options.

Si vous tenez absolument à votre approche, il existe cependant une implémentation personnalisée que vous pouvez réaliser :

Disons que c'est votre json :

{
    "str1": "test one",
    "str2": "two test"
}

et tu veux le lier aux deux paramètres ici :

@RequestMapping(value = "/Test", method = RequestMethod.POST)
public boolean getTest(String str1, String str2)

Définissez d'abord une annotation personnalisée, par exemple @JsonArg avec le chemin JSON comme chemin d'accès à l'information que vous voulez :

public boolean getTest(@JsonArg("/str1") String str1, @JsonArg("/str2") String str2)

Maintenant, écrivez un Custom HandlerMethodArgumentResolver qui utilise le JsonPath défini ci-dessus pour résoudre l'argument réel :

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.IOUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import com.jayway.jsonpath.JsonPath;

public class JsonPathArgumentResolver implements HandlerMethodArgumentResolver{

    private static final String JSONBODYATTRIBUTE = "JSON_REQUEST_BODY";
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(JsonArg.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        String body = getRequestBody(webRequest);
        String val = JsonPath.read(body, parameter.getMethodAnnotation(JsonArg.class).value());
        return val;
    }

    private String getRequestBody(NativeWebRequest webRequest){
        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
        String jsonBody = (String) servletRequest.getAttribute(JSONBODYATTRIBUTE);
        if (jsonBody==null){
            try {
                String body = IOUtils.toString(servletRequest.getInputStream());
                servletRequest.setAttribute(JSONBODYATTRIBUTE, body);
                return body;
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return "";

    }
}

Maintenant, il suffit de l'enregistrer avec Spring MVC. C'est un peu compliqué, mais cela devrait fonctionner proprement.

18voto

azwar_akbar Points 464

Pour passer plusieurs objets, paramètres, variables, etc. Vous pouvez le faire dynamiquement en utilisant ObjectNode de la bibliothèque jackson comme paramètre. Vous pouvez le faire de cette façon :

@RequestMapping(value = "/Test", method = RequestMethod.POST)
@ResponseBody
public boolean getTest(@RequestBody ObjectNode objectNode) {
   // And then you can call parameters from objectNode
   String strOne = objectNode.get("str1").asText();
   String strTwo = objectNode.get("str2").asText();

   // When you using ObjectNode, you can pas other data such as:
   // instance object, array list, nested object, etc.
}

J'espère que cela vous aidera.

15voto

shrikeac Points 121

Vous pouvez mélanger l'argument post en utilisant la variable body et path pour des types de données plus simples :

@RequestMapping(value = "new-trade/portfolio/{portfolioId}", method = RequestMethod.POST)
    public ResponseEntity<List<String>> newTrade(@RequestBody Trade trade, @PathVariable long portfolioId) {
...
}

6voto

Nbenz Points 41

La solution la plus simple consiste à créer une classe de charge utile dont les attributs sont str1 et str2 :

@Getter
@Setter
public class ObjHolder{

String str1;
String str2;

}

Et après vous pouvez passer

@RequestMapping(value = "/Test", method = RequestMethod.POST)
@ResponseBody
public boolean getTest(@RequestBody ObjHolder Str) {}

et le corps de votre demande est :

{
    "str1": "test one",
    "str2": "two test"
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X