【问题标题】:Consuming Spring Hateoas Restservice with RestTemplate使用 RestTemplate 使用 Spring Hateoas Restservice
【发布时间】:2015-01-02 14:16:56
【问题描述】:

我有两个应用程序,一个叫做 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 来提取 self url。

我相信 Spring 肯定有更方便的方式来使用 HAL-Response。

谢谢。

【问题讨论】:

    标签: java client resttemplate spring-hateoas hal


    【解决方案1】:

    看看 spring-hateos 的 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&lt;Beruf&gt;.class,这违背了泛型类的全部目的,因为我们需要再次为每个实体创建一个子类。其背后的原因称为类型擦除。我在某处读到他们计划引入对 RestTemplate 的通用支持,但我不知道任何细节。

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

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

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

    【讨论】:

    • 很遗憾没有。但从那以后我也没有做太多研究。
    • 您可以使用new ParameterizedTypeReference&lt;Resource&lt;BerufResource&gt;&gt;(){} 来避免子类化。
    • 正如 Adam 所提到的,Spring 中有一些特性可以帮助解决 类型擦除 问题。我自己也在寻找解决方案,偶然发现了以下文章(也请阅读 cmets)java-allandsundry.com/2014/01/…
    猜你喜欢
    • 1970-01-01
    • 2016-07-07
    • 2015-03-22
    • 2018-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-13
    • 1970-01-01
    相关资源
    最近更新 更多