我正在尝试将带有JSON有效负载的POST请求发送到远程服务器。
这个GET curl命令工作正常:
curl -H "Accept:application/json" --user aaa@aaa.com:aaa "http://www.aaa.com:8080/aaa-project-rest/api/users/1" -i
这个POST也可以正常工作:
curl -H "Accept:application/json" -H "Content-Type: application/json" "http://www.aaa.com:8080/aaa-project-rest/api/users/login" -X POST -d "{ \"email\" : \"aaa@aaa.com\", \"password\" : \"aaa\" }" -i
所以我试图在我的Android应用程序中模仿它。
该应用程序在第一个GET请求中正常工作,但在第二个POST请求上提供了400个错误请求。
以下是适用于GET请求的代码:
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
HttpHeaders httpHeaders = Common.createAuthenticationHeaders("aaa@aaa.com" + ":" + "aaa");
User user = null;
ResponseEntity<User> responseEntity = restTemplate.exchange("http://" + REST_HOST + ":8080/aaa-project-rest/api/users/" + 1L, HttpMethod.GET, new HttpEntity<Object>(httpHeaders), User.class);
以下是POST请求的源代码:
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
User user = null;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
JSONObject jsonCredentials = new JSONObject();
jsonCredentials.put("email", REST_LOGIN);
jsonCredentials.put("password", REST_PASSWORD);
ResponseEntity<User> responseEntity = restTemplate.exchange("http://" + REST_HOST + ":" + REST_PORT + "/" + REST_APP + "/api/users/login",
HttpMethod.POST, new HttpEntity<Object>(jsonCredentials, httpHeaders), User.class);
但它给出的信息是:
Could not write request: no suitable HttpMessageConverter found for request type [org.json.JSONObject] and content type [application/json]
这是Spring REST控制器:
@RequestMapping(value = RESTConstants.SLASH + RESTConstants.LOGIN, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity<UserResource> login(@Valid @RequestBody CredentialsResource credentialsResource, UriComponentsBuilder builder) {
HttpHeaders responseHeaders = new HttpHeaders();
User user = credentialsService.checkPassword(credentialsResource);
userService.clearReadablePassword(user);
if (user == null) {
return new ResponseEntity<UserResource>(responseHeaders, HttpStatus.NOT_FOUND);
} else {
tokenAuthenticationService.addTokenToResponseHeader(responseHeaders, credentialsResource.getEmail());
responseHeaders.setLocation(builder.path(RESTConstants.SLASH + RESTConstants.USERS + RESTConstants.SLASH + "{id}").buildAndExpand(user.getId()).toUri());
UserResource createdUserResource = userResourceAssembler.toResource(user);
ResponseEntity<UserResource> responseEntity = new ResponseEntity<UserResource>(createdUserResource, responseHeaders, HttpStatus.CREATED);
return responseEntity;
}
}
@RequestMapping(value = RESTConstants.SLASH + "{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity<UserResource> findById(@PathVariable Long id, UriComponentsBuilder builder) {
HttpHeaders responseHeaders = new HttpHeaders();
User user = userService.findById(id);
if (user == null) {
return new ResponseEntity<UserResource>(responseHeaders, HttpStatus.NOT_FOUND);
} else {
UserResource userResource = userResourceAssembler.toResource(user);
responseHeaders.setLocation(builder.path(RESTConstants.SLASH + RESTConstants.USERS + RESTConstants.SLASH + "{id}").buildAndExpand(user.getId()).toUri());
ResponseEntity<UserResource> responseEntity = new ResponseEntity<UserResource>(userResource, responseHeaders, HttpStatus.OK);
return responseEntity;
}
}
CredentialsResource类代码:
public class CredentialsResource extends ResourceSupport {
@NotEmpty
@Email
private String email;
@NotEmpty
private String password;
public CredentialsResource() {
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
答案 0 :(得分:14)
很晚才回复,虽然我刚刚遇到同样的问题并花了一些时间来解决它。所以,我想我最好分享它并跟踪我的解决方案。
实际上,抛出的异常完全是误导性的。原来问题不在于MappingJackson2HttpMessageConverter
不知道如何编组我的对象 - 听起来很奇怪,是JSON-,而是基础ObjectMapper
的配置。
我所做的是禁用属性SerializationFeature.FAIL_ON_EMPTY_BEANS
,就像那样
restTemplate = new RestTemplate();
MappingJackson2HttpMessageConverter jsonHttpMessageConverter = new MappingJackson2HttpMessageConverter();
jsonHttpMessageConverter.getObjectMapper().configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
restTemplate.getMessageConverters().add(jsonHttpMessageConverter);
并且一切都按预期开始工作。
答案 1 :(得分:5)
我必须做一些事情才能让它发挥作用。
首先,我必须将JSONObject转换为字符串,如:
HttpEntity<String> entityCredentials = new HttpEntity<String>(jsonCredentials.toString(), httpHeaders);
原因是JSONObject类没有映射消息转换器,而String类有一个。
第二,我必须将一个真值传递给RestTemplate构造函数。如果不这样做,我会收到400 Bad Request。
RestTemplate restTemplate = new RestTemplate(true);
true值告诉其余模板使用默认转换器。如果有人知道为什么会这样,我会很高兴知道更多。
第三,我删除了不需要的Jackson转换器:
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
完成这些工作后,请求就可以了。
以下是完整代码:
RestTemplate restTemplate = new RestTemplate(true);
User user = null;
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
try {
JSONObject jsonCredentials = new JSONObject();
jsonCredentials.put("email", REST_LOGIN);
jsonCredentials.put("password", REST_PASSWORD);
Log.e(Constants.APP_NAME, ">>>>>>>>>>>>>>>> JSON credentials " + jsonCredentials.toString());
HttpEntity<String> entityCredentials = new HttpEntity<String>(jsonCredentials.toString(), httpHeaders);
ResponseEntity<User> responseEntity = restTemplate.exchange("http://" + REST_HOST + ":" + REST_PORT + "/" + REST_APP + "/api/users/login",
HttpMethod.POST, entityCredentials, User.class);
if (responseEntity != null) {
user = responseEntity.getBody();
}
return user;
} catch (Exception e) {
Log.e(Constants.APP_NAME, ">>>>>>>>>>>>>>>> " + e.getLocalizedMessage());
}
return null;
我怀疑可能有办法明确使用Jackson转换器并跳过其余模板构造函数中的真值,但这只是猜测。
答案 2 :(得分:0)
异常&#34;找不到合适的HTTPMessageConverter&#34;抛出,如果不是类路径中存在JSON实现。看看RestTemplate源代码:
public RestTemplate() {
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
this.messageConverters.add(new ResourceHttpMessageConverter());
this.messageConverters.add(new SourceHttpMessageConverter<Source>());
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
if (romePresent) {
this.messageConverters.add(new AtomFeedHttpMessageConverter());
this.messageConverters.add(new RssChannelHttpMessageConverter());
}
if (jackson2XmlPresent) {
this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
}
else if (jaxb2Present) {
this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (jackson2Present) {
this.messageConverters.add(new MappingJackson2HttpMessageConverter());
}
else if (gsonPresent) {
this.messageConverters.add(new GsonHttpMessageConverter());
}
}
将JSON实现添加到类路径中。 E. g。:
implementation "com.fasterxml.jackson.core:jackson-databind:2.9.0"
答案 3 :(得分:0)
我知道......为时已晚。但我在这里。
我修复了这个发送Java对象而不是JSONObject,如下所示:
JSONObject jsonCredentials = new JSONObject();
jsonCredentials.put("email", REST_LOGIN);
jsonCredentials.put("password", REST_PASSWORD);
// Generic Object. It might be a DTO.
Object jsonCredentialsObj = JsonUtils.stringToObject(jsonCredentials.toString(), Object.class);
ResponseEntity<User> responseEntity = restTemplate.exchange("http://" + REST_HOST + ":" + REST_PORT + "/" + REST_APP + "/api/users/login",
HttpMethod.POST, new HttpEntity<Object>(jsonCredentialsObj, httpHeaders), User.class);
JsonUtils.stringToObject 是我自己的转换实用程序。
答案 4 :(得分:0)
Spring的RestTemplate不知道如何序列化Android org.json.JSONObject类。 (org.json.JSONObject在“普通” /桌面Java中不可用)
RestTemplate for Android支持
Jackson JSON处理器,Jackson 2.x和Google Gson。
每个:https://docs.spring.io/autorepo/docs/spring-android/1.0.1.RELEASE/reference/html/rest-template.html
在Jackson类路径上,RestTemplate应该了解如何序列化Java bean。
CredentialsResource cr = new CredentialsResource();
cr.setEmail(...);
cr.setPassword(...);
HttpEntity<CredentialsResource> entityCredentials = new HttpEntity<CredentialsResource>(cr, httpHeaders);
P.S。如果要继续使用JSONObject,编写自己的JSONObjectHttpMessageConverter很容易,您的转换器只需要调用.toString()