Przekazywanie wielu zmiennych w @RequestBody do kontrolera Spring MVC za pomocą Ajax

Czy konieczne jest owijanie w podkład? Chcę to zrobić:

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

I użyj JSON w ten sposób:

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

Ale zamiast tego muszę użyć:

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

A następnie użyj tego JSON:

{
    "holder": {
        "str1": "test one",
        "str2": "two test"
    }
}
Czy to prawda? Inną opcją jest zmiana RequestMethod na GET i użycie @RequestParam w łańcuchu zapytania lub użycie @PathVariable z RequestMethod.
Author: imTachu, 2012-10-15

10 answers

Masz rację, oczekuje się, że parametr @RequestBody adnotowany będzie trzymał całą treść żądania i wiązał się z jednym obiektem, więc zasadniczo będziesz musiał przejść z opcjami.

Jeśli absolutnie chcesz swojego podejścia, istnieje niestandardowa implementacja, którą możesz zrobić: {]}

Powiedz, że to Twój json:

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

I chcesz powiązać to z dwoma paramami tutaj:

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

Najpierw zdefiniuj niestandardową adnotację, powiedzmy @JsonArg, ze ścieżką JSON podobną do ścieżki do informacje, które chcesz:

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

Teraz napisz Niestandardowy HandlerMethodArgumentResolver który używa jsonpath zdefiniowanego powyżej, aby rozwiązać rzeczywisty argument:

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

    }
}

Teraz wystarczy zarejestrować to w Spring MVC. Trochę zaangażowany, ale to powinno działać czysto.

 64
Author: Biju Kunjummen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-04 09:07:08

Chociaż prawdą jest, że @RequestBody musi mapować do pojedynczego obiektu, ten obiekt może być Map, więc to daje Ci dobrą drogę do tego ,co próbujesz osiągnąć (nie musisz pisać jednorazowego obiektu wspierającego):

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

Możesz również powiązać z ObjectNode jeśli chcesz mieć pełne drzewo JSON:

public boolean getTest(@RequestBody ObjectNode json) {
   //json.get("str1").asText() == "test one"
 52
Author: Kong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-17 05:24:43

Możesz pomieszać argument post używając zmiennej body I path dla prostszych typów danych:

@RequestMapping(value = "new-trade/portfolio/{portfolioId}", method = RequestMethod.POST)
    public ResponseEntity<List<String>> newTrade(@RequestBody Trade trade, @PathVariable long portfolioId) {
...
}
 6
Author: shrikeac,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-09 18:35:23

@RequestParam jest parametrem HTTP GET lub POST wysłanym przez Klienta, mapowanie żądań jest segmentem adresu URL, który jest zmienną:

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

var1 & var2 są parami żądań.

http:/host/form/{params}

{params} jest mapowaniem żądań. możesz zadzwonić do swojego serwisu jak: http:/host/form/user lub http:/host/form/firm gdzie Firma i użytkownik są używane jako Pathvariable.

 2
Author: psisodia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-25 08:28:58

Zamiast używać json, możesz zrobić prostą rzecz.

$.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.>
                });

Teraz w kontrolerze musisz odwzorować żądanie ajax jak poniżej:

 @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";
}
Mam nadzieję, że to ci pomoże.
 0
Author: Japan Trivedi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-15 12:15:44

Parametr Request istnieje zarówno dla GET, jak i POST ,dla Get zostanie dołączony jako ciąg zapytania do adresu URL, ale dla POST znajduje się w treści żądania

 0
Author: Kaleem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-16 18:14:58

Zaadaptowałem rozwiązanie Biju:

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;

    }

}

Czym się różni:

  • używam Jacksona do konwersji json
  • nie potrzebuję wartości w adnotacji, możesz odczytać nazwę parametr z MethodParameter
  • odczytałem również typ parametru z Methodparameter = > więc rozwiązanie powinno być ogólne (testowałem je z string i DTOs)

BR

 0
Author: user3227576,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-02 22:58:56

Nie wiem gdzie dodajesz json ale jeśli zrobię to tak z angular to działa bez 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
Author: tibi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-22 20:53:41

Dobrze. Sugeruję stworzenie obiektu wartości (Vo), który zawiera pola, których potrzebujesz. Kod jest prostszy, nie zmieniamy funkcjonowania Jacksona i jest jeszcze łatwiejszy do zrozumienia. Pozdrawiam!

 0
Author: Matias Zamorano,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-20 19:41:12

Możesz osiągnąć to, co chcesz, używając @RequestParam. W tym celu należy wykonać następujące czynności:

  1. Zadeklaruj parametry RequestParams, które reprezentują twoje obiekty i ustaw opcję required na false, jeśli chcesz móc wysłać wartość null.
  2. na interfejsie użytkownika, stringify obiektów, które chcesz wysłać i dołącz je jako parametry żądania.
  3. na backendzie zamień ciągi JSON z powrotem w obiekty, które reprezentują za pomocą Jackson ObjectMapper lub coś w tym stylu, i voila!

Wiem, to trochę hack, ale to działa! ;)

 0
Author: Maurice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-26 19:12:05