Java Spring RestTemplate post使用HashMap中的参数抛出400个错误请求
当我使用SpringJava Spring RestTemplate post使用HashMap中的参数抛出400个错误请求,java,spring,spring-boot,Java,Spring,Spring Boot,当我使用SpringRestTemplate.postForObject使用HashMap发布参数时,服务器抛出400个错误请求: Map<String, Object> uriVariables = new HashMap<>(); uriVariables.put("param1", "param1val"); restTemplate.postForObject(url, uriVariables, responseType); 但是如果我使用多值映射,它就可以工
RestTemplate.postForObject
使用HashMap
发布参数时,服务器抛出400个错误请求:
Map<String, Object> uriVariables = new HashMap<>();
uriVariables.put("param1", "param1val");
restTemplate.postForObject(url, uriVariables, responseType);
但是如果我使用多值映射
,它就可以工作了
MultiValueMap<String, Object> uriVariables = new LinkedMultiValueMap<>();
uriVariables.add("param1", "param1val");
restTemplate.postForObject(url, uriVariables, responseType);
以下是控制器方法:
@RequestMapping(name = "/test", method = RequestMethod.POST)
@ResponseBody
public String test(@RequestParam("param1") final String param1) {
// some class Test
final Test test = new Test();
test.setName(param1);
return JsonUtils.toJson(test);
}
有人能解释一下为什么使用HashMap传递请求参数不起作用吗?当你说:
它抛出400个错误请求:
你明白它所指的是什么吗?提示:不是SpringREST客户机代码,而是您正在与之交谈的服务器,它不接受您的http请求为有效
您可以激活spring restTemplate使用的httpclient实现的日志记录,以查看从HashMap
到LinkedMultiValueMap
如何更改生成的http请求
您还可以查看SpringRESTTemplate源代码,了解为什么生成不同的请求
编辑:您发布的日志的重要部分:
14:51:20.161[main]调试org.springframework.web.client.restemplate-使用[org.springframework.http.converter.json]编写[{param1=1}]。MappingJackson2HttpMessageConverter@8e24743]
在这里,它无疑是在http请求体上编写json
使用LinkedMultiValueMap时:
14:52:08.502[main]调试org.springframework.web.client.restemplate-使用[org.springframework.http.converter.support]编写[{param1=[1]}]。AllEncompassingFormHttpMessageConverter@4abdb505]
在第一种情况下,您的请求不会有参数param1
,而是请求正文中的所有数据,而在第二种情况下,您会得到一个param1
参数,使请求对服务器有效
应该可以通过扩展/创建消息转换器来配置RestTemplate
,以使用HashMap
,但我建议您继续使用LinkedMultiValueMap
,原因有二:
- 这是默认的弹簧设置。因此,当您需要更新到下一个版本时,迁移将更加容易
- 其他使用您的代码的人不会对RestTemplate处理自定义配置的“新”方式感到惊讶
HttpHeaders
和HttpEntity
和MultiValueMap
或hashMap
。您可以查找此关键字和链接。可能有用
这是示例代码:
HttpHeaders headers = new HttpHeaders();
headers.add("x-sample-session-id", sampleService.getServerSessionId());
MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
map.add("file", new ByteArrayResource(model.getFile().getBytes()));
map.add("apList", model.getApList());
HttpEntity<?> request = new HttpEntity<Object>(map, headers);
String url = sampleService.getContextPath() + "/thirdParty/" + sampleService.getThirdPartyId() + "/child/"
+ childId + "/location?sessionId=" + childSessionId
+ "&op=sendOnDemandLocationResponseWithPhoto&latitude=" + latitude + "&longitude=" + longitude
+ "&datetime=" + datetime + "&provider=" + provider + "&guardianId=" + guardianId + "&cellInfos="
+ cellInfos + "×tamp=" + timestamp + "&battery=" + battery;
RestTemplate rest = new RestTemplate();
try {
// success
return rest.exchange(url, HttpMethod.POST, request, String.class);
} catch (HttpStatusCodeException e) {
// new Error Response
return ResponseEntity.status(e.getStatusCode()).headers(e.getResponseHeaders())
.body(e.getResponseBodyAsString());
}
HttpHeaders=newhttpheaders();
headers.add(“x-sample-session-id”,sampleService.getServerSessionId());
MultiValueMap=新链接的MultiValueMap();
add(“文件”,新的ByteArrayResource(model.getFile().getBytes());
add(“apList”,model.getApList());
HttpEntity请求=新的HttpEntity(映射、头);
字符串url=sampleService.getContextPath()+“/thirdParty/”+sampleService.getThirdPartyId()+“/child/”
+childId+“/location?sessionId=“+childSessionId”
+“&op=sendOnDemandLocationResponseWithPhoto&latitude=“+纬度+”&经度=“+经度
+“&datetime=“+datetime+”&provider=“+provider+”&guardianId=“+guardianId+”&cellInfos=”
+cellInfos+“×tamp=“+timestamp+”&battery=“+battery;
RestTemplate rest=新建RestTemplate();
试一试{
//成功
返回rest.exchange(url,HttpMethod.POST,request,String.class);
}捕获(HttpStatusCodeException){
//新的错误响应
返回ResponseEntity.status(如getStatusCode()).headers(如getResponseHeaders())
.body(例如getResponseBodyAsString());
}
要使用HashMap使其正常工作,请尝试以下方法:-
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
messageConverters.add(new MappingJackson2HttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
类AllEncompassingFormHttpMessageConverter
扩展了FormHttpMessageConverter
,它实现了HttpMessageConverter
,这里需要注意多值映射
而在MappingJackson2HttpMessageConverter
的情况下,它扩展了AbstractJackson2HttpMessageConverter
,它进一步扩展了AbstractGenericHttpMessageConverter
,注意对象
,多值映射的值类型与HashMap不同。可以在其接口定义中看到:
interface MultiValueMap<K, V> extends Map<K, List<V>>
接口多值映射扩展映射
和HashMap:
class HashMap<K,V> extends AbstractMap<K,V>
类HashMap扩展了AbstractMap
您使用put
方法填充HashMap,使用add
方法填充MultiValueMap,因此它看起来很相似,但实际上MultiValueMap包含列表,而不是单个值。可以在您的日志中看到:
哈希映射:
14:51:20.161[main]调试org.springframework.web.client.RestTemplate
-写入[{param1=1}]
多值映射:
14:52:08.502[main]调试org.springframework.web.client.RestTemplate
-写入[{param1=}]
如您所见,{param1=1}
不起作用,{param1=[1]}
起作用
此外,在RestTemplate
中,建议使用多值映射:
实体的主体或请求本身可以是到的多值映射
创建一个多部分请求。多值映射中的值可以是任意值
表示零件主体的对象,或HttpEntity
用主体和标题表示零件。多值映射可以是
使用MultipartBodyBuilder方便地构建
第二个代码段错误且未编译-
MultiValueMap::put
方法接受值列表,而不是单个值:公共列表put(K键,列表值)
。你弄错了吗?对不起,是打字错误。谢谢你的回答。有没有办法让HashMap
处理post请求,因为MultiValueMap
是针对单个参数的多个值,我不需要。我只想针对单个参数传递单个值。否则,我将在整个系统中使用多值映射
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
this.messageConverters.add(new ResourceHttpMessageConverter(false));
this.messageConverters.add(new SourceHttpMessageConverter<>());
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
if (jackson2Present) {
this.messageConverters.add(new MappingJackson2HttpMessageConverter());
}
interface MultiValueMap<K, V> extends Map<K, List<V>>
class HashMap<K,V> extends AbstractMap<K,V>