Передача нескольких переменных в @RequestBody в контроллер Spring MVC с использованием Ajax

Нужно ли оборачивать подкладочный предмет? Я хочу сделать это:

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

И используйте JSON вот так:

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

Но вместо этого я должен использовать:

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

А затем используйте этот JSON:

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

Это верно? Мой другой вариант будет изменитьRequestMethod вGET и использовать@RequestParam в строке запроса или использовать@PathVariable либо с .RequestMethod

Ответы на вопрос(12)

который содержит необходимые поля. Код проще, мы не меняем функционирование Джексона и его еще проще понять. С уважением!

Я адаптировал решение 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;

    }

}

Какие'Разное: я

м, используя Джексона, чтобы конвертировать JSONЯ неЕсли в аннотации не указано значение, вы можете прочитать имя параметра из MethodParameter.Я также прочитал тип параметра из Methodparameter => поэтому решение должно быть общим (я проверил его с помощью строки и DTO)

BR

Решение Вопроса

Вы правы, ожидается, что аннотированный параметр @RequestBody будет содержать все тело запроса и привязываться к одному объекту, так что вам, по сути, придется идти со своими опциями.

Если вы абсолютно хотите, чтобы ваш подход, есть специальная реализация, которую вы можете сделать, хотя:

Скажите, это ваш JSON:

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

и вы хотите связать это с двумя параметрами здесь:

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

Сначала определите пользовательскую аннотацию, скажем@JsonArgс JSON-путем, например, путем к нужной информации:

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

Теперь напишите CustomHandlerMethodArgumentResolver который используетJsonPath определено выше для разрешения фактического аргумента:

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

    }
}

Теперь просто зарегистрируйте это в Spring MVC. Немного вовлечен, но это должно работать чисто.

 Epono07 июн. 2018 г., 11:09
@SurendraJnawali вы можете сделать это так@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface JsonArg { String value() default ""; }
 Surendra Jnawali10 дек. 2014 г., 08:09
Как мне создать пользовательскую аннотацию, скажите, пожалуйста, @JsonArg?
 Jose Ospina11 нояб. 2016 г., 20:06
Почему это? теперь мне нужно создать множество различных классов-оболочек в бэкэнде. Я переносил приложение Struts2 в Springboot, и было много случаев, когда объекты JSON, отправленные с использованием ajax, на самом деле являются двумя или более объектами модели: например, Пользователь и активность
 Bodil13 мар. 2017 г., 17:54
эта ссылка покажет вам "как зарегистрировать это в Spring MVC geekabyte.blogspot.sg/2014/08/...
 tibi22 мар. 2018 г., 21:37
Все еще интересно, почему эта опция не добавлена к весне. это выглядит логичным вариантом, когда у вас есть 2 long и вы не хотите создавать объект-оболочку для него
 P Satish Patro15 апр. 2019 г., 16:17
Итак, я не могу отправить несколько запросов тела? Я попробовал 2 requestbody предположить int a, int b. Но, в curl это показывает....»Content-Type: application / json " -d "\"3 \ ""», 3 это тело б

Вы также можете использовать@RequestBody Map paramsзатем используйтеparams.get("key") чтобы получить значение параметра

параметр запроса существует как для GET, так и для POST, для Get он будет добавлен в виде строки запроса к URL, но для POST он находится в теле запроса

Не уверен, где вы добавляете JSON, но если я делаю это так с angular, то он работает без запроса.

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

Джава:

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

@RequestParam этоHTTP GET или жеPOST параметр, отправленный клиентом, сопоставление запроса - это сегмент URL, который 'переменная s:

http:/host/form_edit?param1=val1¶m2=val2

var1 & var2 являются параметрами запроса.

http:/host/form/{params}

{params} это отображение запроса. Вы можете позвонить в ваш сервис, как:http:/host/form/user или жеhttp:/host/form/firm где фирма & Пользователь используется как.Pathvariable

 Martijn Pieters11 янв. 2018 г., 04:40
@NimChimpsky: конечно, вы можете. Запрос POST все еще может включать параметры в URL.
 NimChimpsky15 окт. 2012 г., 12:46
это нене ответить на вопрос, и это неправильно, вы неиспользовать строку запроса с запросами POST

Пока этоправда что@RequestBody должен отображаться на один объект, этот объект может бытьMapТаким образом, это дает вам хороший путь к тому, чего вы пытаетесь достичь (не нужно писать один объект поддержки):

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

Вы также можете привязать к ДжексонуObjectNode если вы хотите полное дерево JSON:

public boolean getTest(@RequestBody ObjectNode json) {
   //json.get("str1").asText() == "test one"
 stratovarius15 нояб. 2018 г., 10:30
Я думаю, что оборотная сторонадинамический подход какMap is: библиотеки документации API (swagger / springfox и т. д.), вероятно, не смогут проанализировать вашу схему запроса / ответа из вашего исходного кода.
 Ben Cheng10 июл. 2018 г., 15:52
@JoseOspina, почему не могу этого сделать. Любой риск, связанный с картой <Строка, Объект> с запросом тела
 Jose Ospina11 июл. 2018 г., 10:41
@ Я имею в виду, вы можете использовать одинMap объект для хранения любого количества объектов внутри него, но объект верхнего уровня все еще должен быть только один, не может быть двух объектов верхнего уровня.
 Osama Abdulsattar21 июл. 2017 г., 16:45
Большое спасибо, у меня сработало
 Jose Ospina11 нояб. 2016 г., 19:58
но это не может быть сделано в целом для двух объектов JSON Map <Строка, Объект>...

Вместо использования JSON вы можете сделать простую вещь.

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

                        
                },
                function(j)
                {
                        
                });

Теперь в контроллере вам нужно отобразить запрос ajax, как показано ниже:

 @RequestMapping(value="/Test", method=RequestMethod.POST)
    @ResponseBody
    public String calculateTestData(@RequestParam("str1") String str1, @RequestParam("str2") String str2, HttpServletRequest request, HttpServletResponse response){
            

            return "xyz";
}

Надеюсь, это поможет вам.

 Japan Trivedi15 окт. 2012 г., 14:26
Видите, у меня нетt использовал формат JSON в вызове ajax. Я просто использовал два параметра запроса, и в контроллере мы можем получить эти параметры с помощью аннотации @RequestParam. Это работает. Я использую это. Просто попробуйте.
 Japan Trivedi16 окт. 2012 г., 10:02
Okies. нет проблем.
 NimChimpsky16 окт. 2012 г., 09:48
Я указал это в своем вопросе. Ваш ответ нене работает, requestbody привязывается к одному объекту.
 NimChimpsky15 окт. 2012 г., 14:16
Это JSON, и это нет работа. Вы указываете requestparam в методе, но определяете equestbody с помощью json в пост-запросе ajax.
 Japan Trivedi16 окт. 2012 г., 07:07
Пожалуйста, укажите, что именно вы пробовали. Покажите это в вашем вопросе. Я думаю, что у тебя другое требование, чем у меняЯ понял.
 NimChimpsky15 окт. 2012 г., 14:41
Я пробовал это, это вопрос квеста. Это нетак не работает.
 tibi22 мар. 2018 г., 21:34
RequestParam со мной работает, только если я добавлю такие параметры, как? Str1 = bar &str2 = Foo

Вы можете достичь того, что вы хотите с помощью@RequestParam, Для этого вам следует сделать следующее:

Объявите параметры RequestParams, которые представляют ваши объекты, и установитеrequired параметр false, если вы хотите иметь возможность отправить нулевое значение.На веб-интерфейсе, зафиксируйте объекты, которые вы хотите отправить, и включите их в качестве параметров запроса.На бэкенде поверните строки JSON обратно в объекты, которые они представляют, используя Jackson ObjectMapper или что-то в этом роде, и вуаля!

Я знаю, это немного взломать, но это работает! ;)

Для передачи нескольких объектов, параметров, переменных и так далее. Вы можете сделать это динамически, используя ObjectNode из библиотеки Джексона в качестве параметра. Вы можете сделать это следующим образом:

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

Я надеюсь, что это поможет.

используя переменную body и path для более простых типов данных:

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

Ваш ответ на вопрос