使用RestTemplate消费Spring Hateoas Restservice

6
我有两个应用程序,一个名为bar,它以HAL格式提供资源。另一个是bcm,用于消费该服务。 bar 的响应示例如下:
[
    {
        "name":"Brenner/in",
        "_links":{
            "self":{
                "href":"..host/bbsng-app-rest/betrieb/15"
            }
        }
    },
    {
        "name":"Dienstleistungshelfer/in HW",
        "_links":{
            "self":{
                "href":"..host/bbsng-app-rest/betrieb/4"
            }
        }
    },
    {
        ...

现在我尝试使用Spring RestTemplate从 bcm 消费它。我的解决方案有效,但我对该解决方案并不满意,我想有一种更简洁的方式。

我的客户端代码消费 RestService 如下:

@Autowired private RestTemplate template;

@Override
@SuppressWarnings("unchecked")
public BerufListe findeAlleBerufe() {
    final BerufListe berufListe = new BerufListe();

    final ResponseEntity<List> entity = template.getForEntity(LinkUtils.findBeruf(), List.class);

    if (OK.equals(entity.getStatusCode())) {
        final List<LinkedHashMap> body = entity.getBody();
        for (final LinkedHashMap map : body) {
            final LinkedHashMap idMap = (LinkedHashMap) map.get("_links");
            String id = remove(String.valueOf(idMap.get("self")), "href=");
            id = remove(id, "{");
            id = remove(id, "}");
            final String name = String.valueOf(map.get("name"));
            final Beruf beruf = new Beruf(id, name);
            berufListe.add(beruf);
        }
    }

    return berufListe;
}

你看到了一些丑陋的代码。其中之一是,我没有为我的集合使用任何泛型。另一个问题是,我获取Resource_ID非常复杂,并且我使用StringUtils.remove多次来提取自身网址。
我相信必须有更方便的方法来通过Spring消费HAL-Response。
谢谢。
1个回答

3
请看spring-hateaos的Resource类
该类提供了从响应中提取链接的方法。然而,由于RestTemplate要求您提供该类作为变量,因此除了创建所需实体的子类并将其用于RestTemplate外,我没有找到其他办法。
您的代码可能如下所示:
public class BerufResource extends Resource<Beruf> { }

BerufResource resource = template.getForEntity("http://example.at/berufe/1", BerufResource.class);
Beruf beruf = resource.getContent();
// do something with the entity

如果您想请求完整列表,您需要将实体的数组版本传递给RestTemplate:
BerufResource[] resources = template.getForEntity("http://example.at/berufe", BerufResource[].class);

List<BerufResource> berufResources = Arrays.asList(resources);
for(BerufResource resource : berufResources) {
    Beruf beruf = resource.getContent();
}

很遗憾,我们无法编写Resource<Beruf>.class,这破坏了泛型类的全部目的,因为我们需要再次为每个实体创建子类。这背后的原因是类型擦除。我曾经在某个地方读到过他们计划为RestTemplate引入通用支持,但我不知道任何细节。

解决从URL中提取id的问题:

我建议在客户端使用一个不同的模型,并将id字段的类型更改为字符串,并将整个URL存储在其中。这样,您可以随时轻松重新获取整个实体,而不需要自己构建URL。如果您计划向API提交POST请求,则以后仍然需要URL,因为spring-hateaos要求您发送链接而不是id。典型的POST请求可能如下所示:

{
    "firstname": "Thomas",
    "nachname": "Maier",
    "profession": "http://example.at/professions/1"
}

很遗憾,没有。但是自那时以来我也没有进行过太多的研究。 - Thomas Eizinger
3
您可以使用new ParameterizedTypeReference<Resource<BerufResource>>(){}来避免创建子类。 - afaulconbridge
1
正如Adam所提到的,Spring中有一些功能可以帮助解决类型擦除问题。我自己也在寻找解决方案,并偶然发现了以下文章(也请阅读评论)http://www.java-allandsundry.com/2014/01/consuming-spring-hateoas-rest-service.html - s5b

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