Подтвердить что ты не робот

Передача нескольких переменных в @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.

4b9b3361

Ответ 1

Вы правы, ожидается, что аннотированный параметр @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)

Теперь напишите Custom HandlerMethodArgumentResolver, который использует 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. Немного, но это должно работать чисто.

Ответ 2

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

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

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

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

Ответ 3

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

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

Ответ 4

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

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

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

http:/host/form/{params}

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

Ответ 5

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

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

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

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

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

Ответ 6

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

Ответ 7

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

    }

}

Что другое:

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

BR

Ответ 8

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

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

Джава:

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

Ответ 9

Хорошо. Я предлагаю создать объект значения (Vo), который содержит необходимые поля. Код проще, мы не меняем функционирование Джексона и его еще проще понять. С уважением!

Ответ 10

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

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

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

Ответ 11

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