【问题标题】:Send POST and PUT through RestTemplate to a Spring Data Rest Api通过 RestTemplate 将 POST 和 PUT 发送到 Spring Data Rest Api
【发布时间】:2017-07-10 08:45:00
【问题描述】:

我一直在开发一个云应用程序来稍微弄乱 Spring Cloud 等。现在我被困在尝试使用 RestTemplate API 向 Spring Data Rest 后端发送 POST 或 PUT 请求,但我尝试的一切都以错误结束:HttpMessageNotReadableException:无法反序列化 java.lang.String 的实例出 START_OBJECT 令牌,HttpMessageNotReadableException :无法读取文档:无法从 START_ARRAY 令牌中反序列化 java.lang.String 的实例,...来自内容类型为 application/xml;charset=UTF-8! 的请求,错误 400 null ... .经过研究,我发现实际上很难通过 RestTemplate 使用 HAL JSON(如果我没记错的话,它是 3 级 JSON 超媒体),但我想知道这是否可能。

我希望看到一些将 POST 和 PUT 发送到 Spring Data Rest 后端的 RestTemplate 的工作示例(如果可能,请详细说明)。

编辑:我尝试了 postForEntity、postForLocation、exchange,但它只是以不同类型的错误结束。这些是我尝试过的一些sn-ps(还有更多,只是我处理它们)。

我的实体:

@Entity
public class Account implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

@NotNull
@NotEmpty
private String username;

@NotNull
@NotEmpty
private String authorities;

@NotNull
@NotEmpty
private String password;

//Constructor, getter and setter

一些restTemplate尝试:

    public Account create(Account account) {
    //Doesnt work :S
    MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
    map.add("name", account.getName());
    map.add("username", account.getUsername());
    map.add("password", account.getPassword());
    map.add("authorities", account.getAuthorities());

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    final HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<MultiValueMap<String, String>>(map,
            headers);

    return restTemplate.exchange(serviceUrl + "/accounts", HttpMethod.POST, entity, Account.class).getBody();
}

//Also tried with a AccountResource which extends from ResourceSupport and doesn't work either. This one gives me a error saying it cannot deserialize Account["name"].

也尝试过这样,得到一个关于 header 是 application/xml:RestTemplate POSTing entity with associations to Spring Data REST server的错误

其他的只是重复其中一个错误。

【问题讨论】:

  • 愿意分享您的代码吗?我们一定很乐意提供帮助
  • 您确定服务器在您发帖时返回正文吗?
  • 服务器没有返回任何东西,因为 RestTemplate 中断了。它在控制器上给出了错误的请求错误,并且我在 Spring Data Rest 后端的答案中评论了错误。

标签: json spring-data-rest resttemplate spring-hateoas


【解决方案1】:

您需要配置您的 RestTemplate 以便它可以使用 application/hal+json 内容类型。

其他一些帖子(例如this onethat one)以及大量博客帖子(例如here)中已经解决了这个问题。 以下解决方案适用于 Spring Boot 项目:

首先,使用 bean 配置您的 RestTemplate:

// other import directives omitted for the sake of brevity
import static org.springframework.hateoas.MediaTypes.HAL_JSON;

@Configuration
public class RestTemplateConfiguration {

    @Autowired
    private ObjectMapper objectMapper;

    /**
     *
     * @return a {@link RestTemplate} with a HAL converter
     */
    @Bean
    public RestTemplate restTemplate() {

        // converter
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setSupportedMediaTypes(Arrays.asList(HAL_JSON));
        converter.setObjectMapper(objectMapper);

        RestTemplate restTemplate = new RestTemplate(Collections.singletonList(converter));

        return restTemplate;
    }
}

然后,让 Spring 在您需要使用 REST 后端的地方注入 RestTemplate,并使用 RestTemplate#exchange 的众多变体之一:

@Autowired
public RestTemplate restTemplate;

...
// for a single ressource

// GET
Account newAccount = restTemplate.getForObject(url, Account.class);

// POST
Account newAccount = restTemplate.exchange(serviceUrl + "/accounts", HttpMethod.POST, entity, Account.class).getBody();
// or any of the specialized POST methods...
Account newAccount = restTemplate.postForObject(serviceUrl + "/accounts", entity, Account.class);

对于一个集合,你将操作一个PagedResources

// for a collection
ParameterizedTypeReference<PagedResources<Account>> responseType =
        new ParameterizedTypeReference<PagedResources<Account>>() {};

// GET
PagedResources<Account> accounts =
        restTemplate.exchange(url, HttpMethod.GET, null, responseType).getBody();

//

【讨论】:

  • 我记得那个博客,但我没有实现代码,因为我不知道“HAL_JSON”来自哪里。我尝试使用 MediaType.parseMediaType("application/hal+json") 而不是那个 HAL_JSON 并且不起作用。错误是一样的:无法从 START_ARRAY 令牌中反序列化 java.lang.String 的实例
  • 这是确切的轨道:无法读取文档:无法从 [Source: org.apache.catalina.connector.CoyoteInputStream@278f6875; 的 START_ARRAY 令牌中反序列化 java.lang.String 的实例;行:1,列:9](通过引用链:com.example.core.webservicesrepositories.accounts.entities.Account["name"]);嵌套异常是 com.fasterxml.jackson.databind.JsonMappingException:无法反序列化 java.lang.String 的实例出 START_ARRAY 令牌
  • 我设法通过用 postForEntity 替换该 POST 来解决它。我会检查你的答案,因为你指导我解决这个问题太多了。非常感谢!在我提出这个问题之前,我有你建议的 GET,即使没有调整到 RestTemplate,它也能正常工作,你知道为什么吗?
  • @ManuelPáez 对不起,我通常省略导入指令以节省一些空间,但有时静态导入有点难以识别。为了清楚起见,我编辑了我的帖子。
  • 考虑一下,如果你不关心响应头和状态(它可以让你免于调用 getBody()),postForObject 可能更适合这种情况。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-30
  • 1970-01-01
  • 1970-01-01
  • 2012-06-17
  • 2016-08-19
  • 1970-01-01
相关资源
最近更新 更多