it-swarm.com.de

Übergeben mehrerer Variablen in @RequestBody an einen Spring MVC-Controller mit Ajax

Ist es notwendig, ein Gegenstandsobjekt einzuwickeln? Ich möchte das machen:

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

Und benutze eine JSON wie folgt:

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

Stattdessen muss ich verwenden: 

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

Und dann benutze diesen JSON:

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

Ist das korrekt? Meine andere Option wäre, RequestMethod in GET zu ändern und @RequestParam in der Abfragezeichenfolge oder @PathVariable mit RequestMethod zu verwenden. 

79
NimChimpsky

Wenn Sie richtig sind, wird erwartet, dass der annotierte @RequestBody-Parameter den gesamten Text der Anforderung enthält und an ein Objekt bindet, sodass Sie im Wesentlichen Ihre Optionen wählen müssen.

Wenn Sie Ihren Ansatz unbedingt wollen, gibt es eine benutzerdefinierte Implementierung, die Sie jedoch ausführen können:

Sag das ist dein Json:

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

und Sie möchten es hier an die beiden Parameter binden:

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

Definieren Sie zuerst eine benutzerdefinierte Anmerkung, beispielsweise @JsonArg, mit dem JSON-Pfad wie dem Pfad zu den gewünschten Informationen:

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

Schreiben Sie nun einen benutzerdefinierten HandlerMethodArgumentResolver , der das oben definierte JsonPath verwendet, um das tatsächliche Argument aufzulösen:

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

    }
}

Jetzt registrieren Sie dies einfach bei Spring MVC. Ein bisschen beteiligt, aber das sollte sauber funktionieren.

69
Biju Kunjummen

Es ist zwar wahr, dass @RequestBody einem einzelnen Objekt zugeordnet werden muss, dieses Objekt kann jedoch eine Map sein. Dadurch erhalten Sie einen guten Weg zu dem, was Sie erreichen möchten (es ist nicht erforderlich, ein einzelnes Objekt aus einem Sicherungsobjekt zu schreiben):

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

Sie können auch an Jacksons ObjectNode binden, wenn Sie einen vollständigen JSON-Baum wünschen:

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

Sie können das Post-Argument mit einfachen Text- und Pfadvariablen für einfachere Datentypen mischen:

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

@RequestParam ist der vom Client gesendete Parameter HTTP GET oder POST, Request Mapping ist ein Segment der URL, dessen Variable:

http:/Host/form_edit?param1=val1&param2=val2

var1 & var2 sind Anforderungsparameter.

http:/Host/form/{params}

{params} ist eine Anforderungszuordnung. Sie können Ihren Dienst wie folgt anrufen: http:/Host/form/user oder http:/Host/form/firm Dabei werden Firma und Benutzer als Pathvariable verwendet.

2
psisodia

Zum Übergeben mehrerer Objekte, Parameter, Variablen usw. Sie können dies dynamisch tun, indem Sie ObjectNode aus der Jackson-Bibliothek als Parameter verwenden. Du kannst es so machen:

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

Ich hoffe diese Hilfe.

1
azwar_akbar

Sie können erreichen, was Sie wollen, indem Sie @RequestParam verwenden. Dafür sollten Sie Folgendes tun:

  1. Deklarieren Sie die RequestParams-Parameter, die Ihre Objekte darstellen, und setzen Sie die Option required auf false, wenn Sie einen Nullwert senden möchten.
  2. Stringifizieren Sie im Frontend die Objekte, die Sie senden möchten, und fügen Sie diese als Anforderungsparameter ein.
  3. Im Backend verwandeln Sie die JSON-Strings wieder in die Objekte, die sie repräsentieren, indem Sie Jackson ObjectMapper oder ähnliches verwenden, und voila!

Ich weiß, es ist ein bisschen ein Hack, aber es funktioniert! ;)

0
Maurice

Ich weiß nicht, wo man den Json hinzufügt, aber wenn ich es so mit eckig mache, funktioniert es auch ohne requestBody: Angluar:

    const params: HttpParams = new HttpParams().set('str1','val1').set('str2', ;val2;);
    return this.http.post<any>( this.urlMatch,  params , { observe: 'response' } );

Java:

@PostMapping(URL_MATCH)
public ResponseEntity<Void> match(Long str1, Long str2) {
  log.debug("found: {} and {}", str1, str2);
}
0
tibi

Gut . Ich empfehle, ein Wertobjekt (Vo) zu erstellen, das die benötigten Felder enthält. Der Code ist einfacher, wir ändern die Funktion von Jackson nicht und es ist sogar noch einfacher zu verstehen.

0
Matias Zamorano

sie können auch @RequestBody Map<String, String> params verwenden und dann params.get("key") verwenden, um den Wert des Parameters abzurufen

0
Will

anforderungsparameter sind sowohl für GET als auch für POST vorhanden. Für Get wird es als Abfragezeichenfolge an die URL angehängt, für POST befindet es sich jedoch innerhalb des Anforderungstextes

0
Kaleem

Ich habe die Lösung von Biju angepasst:

import Java.io.IOException;

import javax.servlet.http.HttpServletRequest;

import org.Apache.commons.io.IOUtils;
import org.springframework.core.MethodParameter;
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.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;


public class JsonPathArgumentResolver implements HandlerMethodArgumentResolver{

    private static final String JSONBODYATTRIBUTE = "JSON_REQUEST_BODY";

    private ObjectMapper om = new ObjectMapper();

    @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 jsonBody = getRequestBody(webRequest);

        JsonNode rootNode = om.readTree(jsonBody);
        JsonNode node = rootNode.path(parameter.getParameterName());    

        return om.readValue(node.toString(), parameter.getParameterType());
    }


    private String getRequestBody(NativeWebRequest webRequest){
        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);

        String jsonBody = (String) webRequest.getAttribute(JSONBODYATTRIBUTE, NativeWebRequest.SCOPE_REQUEST);
        if (jsonBody==null){
            try {
                jsonBody = IOUtils.toString(servletRequest.getInputStream());
                webRequest.setAttribute(JSONBODYATTRIBUTE, jsonBody, NativeWebRequest.SCOPE_REQUEST);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return jsonBody;

    }

}

Was ist der Unterschied:

  • Ich verwende Jackson, um Json zu konvertieren
  • Ich brauche keinen Wert in der Annotation, Sie können den Namen des Parameters Aus dem MethodParameter lesen
  • Ich lese auch den Typ des Parameters aus dem Methodparameter =>, so dass die Lösung generisch sein sollte (ich habe sie mit String und DTOs getestet)

BR

0
user3227576

Anstatt Json zu verwenden, können Sie einfache Dinge tun.

$.post("${pageContext.servletContext.contextPath}/Test",
                {
                "str1": "test one",
                "str2": "two test",

                        <other form data>
                },
                function(j)
                {
                        <j is the string you will return from the controller function.>
                });

Jetzt müssen Sie im Controller die Ajax-Anforderung wie folgt zuordnen:

 @RequestMapping(value="/Test", method=RequestMethod.POST)
    @ResponseBody
    public String calculateTestData(@RequestParam("str1") String str1, @RequestParam("str2") String str2, HttpServletRequest request, HttpServletResponse response){
            <perform the task here and return the String result.>

            return "xyz";
}

Hoffe das hilft dir.

0
Japan Trivedi