Передача нескольких переменных в @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.
10 ответов:
вы правы, @ 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)теперь напишите пользовательский 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. Немного участвует, но это должно работать штатно.
а это правда, что
@RequestBodyдолжен соответствовать одному объекту, этот объект может бытьMap, Так что это хороший способ получить то, что вы пытаетесь достичь (не нужно писать один от резервного объекта):@RequestMapping(value = "/Test", method = RequestMethod.POST) @ResponseBody public boolean getTest(@RequestBody Map<String, String> json) { //json.get("str1") == "test one" }вы также можете привязать к Джексону ObjectNode если вы хотите полное дерево JSON:
public boolean getTest(@RequestBody ObjectNode json) { //json.get("str1").asText() == "test one"
вы можете перепутать аргумент post, используя переменную body и path для более простых типов данных:
@RequestMapping(value = "new-trade/portfolio/{portfolioId}", method = RequestMethod.POST) public ResponseEntity<List<String>> newTrade(@RequestBody Trade trade, @PathVariable long portfolioId) { ... }
@RequestParam- этоHTTP GETилиPOSTпараметр, отправленный клиентом, отображение запроса-это сегмент URL, который является переменной:http:/host/form_edit?param1=val1¶m2=val2
var1&var2запрос параметров.http:/host/form/{params}
{params}- это сопоставление запросов. вы можете позвонить в свою службу, как:http:/host/form/userилиhttp:/host/form/firmгде фирма и пользователь используются какPathvariable.
вместо использования 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"; }надеюсь, что это поможет вам.
параметры запроса GET и POST ,для его получения будет добавлен в качестве строки запроса в URL, но для модератора это в текст запроса
я адаптировал решение 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 = > поэтому решение должно быть общим (я тестировал его со строкой и DTOs)
BR
Не уверен, где вы добавляете json, но если я делаю это так с угловой он работает без 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); }
хорошо. Я предлагаю создать объект Value (Vo), который содержит необходимые вам поля. Код проще, мы не меняем работу Джексона и его еще проще понять. С уважением!
Вы можете достичь того, чего вы хотите с помощью
@RequestParam. Для этого вы должны сделать следующее:
- объявите параметры RequestParams, которые представляют ваши объекты и установите
requiredопция false, если вы хотите иметь возможность отправить нулевое значение.- на интерфейсе, stringify объекты, которые вы хотите отправить и включить их в качестве параметров запроса.
- на бэкэнде поверните строки JSON обратно в объекты, которые они представляют с помощью Jackson ObjectMapper или что-то в этом роде, и вуаля!
Я знаю, это немного хак, но он работает! ;)
Comments