无法写入请求:找不到合适的HttpMessageConverter请求类型[org.json.JSONObject]和内容类型[application/json]

Ste*_*ane 14 post android resttemplate

我正在尝试将具有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
Run Code Online (Sandbox Code Playgroud)

而这个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
Run Code Online (Sandbox Code Playgroud)

所以我试图在我的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);
Run Code Online (Sandbox Code Playgroud)

以下是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);
Run Code Online (Sandbox Code Playgroud)

但它给出的信息是:

Could not write request: no suitable HttpMessageConverter found for request type [org.json.JSONObject] and content type [application/json]
Run Code Online (Sandbox Code Playgroud)

这是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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)

Ste*_*ola 17

很晚才回复,虽然我刚刚遇到同样的问题并花了一些时间来解决它.所以,我想我最好分享它并跟踪我的解决方案.

实际上,抛出的异常完全是误导性的.原来问题不是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);
Run Code Online (Sandbox Code Playgroud)

一切都按预期开始了.

  • 我遇到了同样的问题并且发现它是因为我没有尝试"jsonify"的POJO的getter和setter.添加getter和setter后,默认的MappingJackson2HttpMessageConverter()工作得很好. (3认同)

Ste*_*ane 6

我必须做一些事情才能使其正常工作。

首先,我必须将JSONObject转换为字符串,如下所示:

HttpEntity<String> entityCredentials = new HttpEntity<String>(jsonCredentials.toString(), httpHeaders);
Run Code Online (Sandbox Code Playgroud)

原因是JSONObject类没有映射消息转换器,而String类有一个映射消息转换器。

其次,我必须将一个真实值传递给RestTemplate构造函数。否则,我将收到400错误的请求。

RestTemplate restTemplate = new RestTemplate(true);
Run Code Online (Sandbox Code Playgroud)

true值指示其余模板使用默认转换器。如果有人知道为什么会这样,我很乐意进一步了解。

第三,我删除了不需要的杰克逊转换器:

restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
Run Code Online (Sandbox Code Playgroud)

完成这些操作后,请求就可以正常工作。

这是完整的代码:

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;
Run Code Online (Sandbox Code Playgroud)

我怀疑可能有一种方法可以显式地使用Jackson转换器并跳过其余模板构造函数中的真实值,但这只是一个猜测。