为什么RestTemplate不能将响应表示绑定到PagedResources?

37

我正在使用spring-data-rest将实体作为(分页)rest资源公开。一切都运行良好,但是当我通过RestTemplate请求数据时,我会得到一个无用的HATEOAS JSON(我没有要求)。JSON似乎是一个PagedResources。我可以接受这点,但JSON没有正确地转换成一个对象。里面没有content

仓库:

@RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long>
{
    List<Person> findByLastName(@Param("name") String name);
}

客户:

public List<Person> getPersons()
{
    RestTemplate rt = new RestTemplate();
    System.out.println(rt.getForObject(URL, PagedResources.class).getContent().size());
    System.out.println(rt.getForObject(URL, PagedResources.class).getLinks().size());
    System.out.println(rt.getForObject(URL, PagedResources.class).getMetadata().getTotalElements());
    return new ArrayList<Person>(rt.getForObject(URL, PagedResources.class).getContent()); // <-- empty
}

System.out:

0 // getContent().size()
4 // getLinks().size()
2 // getTotalElements()

curl:

C:\...>curl http://localhost:8080/spring-jsf-rest/rest/people
{
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/spring-jsf-rest/rest/people{?page,size,sort}",
      "templated" : true
    },
    "search" : {
      "href" : "http://localhost:8080/spring-jsf-rest/rest/people/search"
    }
  },
  "_embedded" : {
    "people" : [ {
      "firstName" : "John",
      "lastName" : "Rambo",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/spring-jsf-rest/rest/people/1"
        }
      }
    }, {
      "firstName" : "Chuck",
      "lastName" : "Norris",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/spring-jsf-rest/rest/people/2"
        }
      }
    } ]
  },
  "page" : {
    "size" : 20,
    "totalElements" : 2,
    "totalPages" : 1,
    "number" : 0
  }
}

看起来_embedded没有正确映射到内容?!


7
今后你可能需要重新思考一下在这里提问的方式。如果某些东西对你没有用,就不要使用它。如果你明显发出了“GET”请求,请不要声称你没有请求任何内容。和计算机一样,你会精确地得到你所要求的东西。如果你没有指定“Accept”标头,你会得到默认值,即application/hal+json。通常这种负面语气不会激励人回答问题。尽管如此,我还是花了时间回答你。不客气。顺便问一句,什么是HATEOAS JSON? - Oliver Drotbohm
2
@Oliver:我承认,我的语气有点消极。但是这些小障碍很烦人。当然,我尝试了其他接受头部,但结果总是一样的。而且我不是唯一遇到这个问题的人:https://dev59.com/XGAg5IYBdhLWcg3wu87o 。并且我不是选择使用这些东西,我必须使用它们。 - user3563584
5
原文:Ahhhh so that's how you parse an _embedded list on the client, telling RestTemplate to expect one of the hateoas Resources classes. Very useful, the spring-data-rest documentation is rather sparse on the client side翻译:啊哈,这就是在客户端解析嵌入式列表的方法,告诉RestTemplate期望其中一个HATEOAS资源类。非常有用,Spring Data REST文档在客户端方面相对较少。 - dan carter
1个回答

55

正如您正确发现的那样,PagedResources 没有 _embedded 属性,这就是为什么您没有获取到 content 属性的值。

这个困境可以通过以下两种不同的方式解决:

  1. 在一开始提供与表示匹配的类型。因此,可以创建一个自定义类,并且要么坚持使用表示属性名称,要么使用 Jackson 注释等进行自定义。

  2. 设置一个自定义的 MappingJackson2HttpMessageConverter 并定制 ObjectMapper 以获取 Spring HATEOAS 自带的 Jackson2HalModule 配置。

ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.registerModule(new Jackson2HalModule());

MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json"));
converter.setObjectMapper(mapper);

RestTemplate template = new RestTemplate(Collections.<HttpMessageConverter<?>> singletonList(converter));

2
非常感谢您的帮助。选项2看起来不错,但我遇到了“Unrecognized field "templated" (class org.springframework.hateoas.Link), not marked as ignorable (one known property: "href"])”的问题。我想我需要深入挖掘一下。如果我无法让它正常工作,我想我会坚持选项1。 - user3563584
3
我认为你可以通过设置 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 来轻松解决此问题。Jackson 默认情况下非常严格。已相应更新答案。 - Oliver Drotbohm
嗯,如果我这样做,我的事情就会出问题 - 有什么想法吗? - Stefan Falk
@OliverDrotbohm 我遇到了同样的问题,不同之处是我没有使用RestTemplate而是使用FeignClient。我该怎么办? - Soumitri Pattnaik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接