Передача нескольких переменных в @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
.
Ответы
Ответ 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¶m2=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
. Для этого вам следует сделать следующее:
- Объявите параметры RequestParams, которые представляют ваши объекты, и установите для
required
опции значение false, если вы хотите иметь возможность отправлять нулевое значение. - На веб-интерфейсе определите последовательность объектов, которые вы хотите отправить, и включите их в качестве параметров запроса.
- На бэкенде поверните строки JSON обратно в объекты, которые они представляют, используя Jackson ObjectMapper или что-то в этом роде, и вуаля!
Я знаю, это немного взломать, но это работает! ;)
Ответ 11
Вы также можете использовать @RequestBody Map<String, String> params
, а затем использовать params.get("key")
чтобы получить значение параметра