You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring RestTemplate消费HAL API时自动填充关联对象及缓存诉求

Awesome question—you’re absolutely right to look for existing solutions instead of building this from scratch! The Spring ecosystem has dedicated tools to handle HAL hypermedia interactions, automatic link following, and caching of repeated resource requests. Here’s how to implement both requirements:

Spring HATEOAS is built explicitly for working with hypermedia APIs like HAL. It eliminates manual link parsing and exchange() calls by providing utilities to discover and follow links automatically.

Step 1: Add Spring HATEOAS Dependency

First, include the Spring HATEOAS starter in your project (Maven example):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>

The Traverson class simplifies navigating hypermedia links. It handles link discovery and resource fetching out of the box. Here’s a refactored version of your method:

import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Traverson;
import org.springframework.http.ParameterizedTypeReference;
import java.net.URI;

public Item getItemById(Integer itemId) {
    // Initialize Traverson with your API base URI and HAL media type
    Traverson traverson = new Traverson(URI.create("http://my.rest.service"), MediaTypes.HAL_JSON);
    
    // Follow the path to the target item and fetch its resource
    Traverson.TraversalBuilder itemTraversal = traverson.follow("items", String.valueOf(itemId));
    Resource<Item> itemResource = itemTraversal.toObject(new ParameterizedTypeReference<Resource<Item>>() {});
    Item item = itemResource.getContent();
    
    // Automatically follow the "category" link to fetch the associated resource
    Resource<Category> categoryResource = itemTraversal.follow("category")
            .toObject(new ParameterizedTypeReference<Resource<Category>>() {});
    item.setCategory(categoryResource.getContent());
    
    return item;
}

Bonus: Full Automation with Custom Assemblers

For even less manual work, you can use Spring HATEOAS’s ResourceAssembler or HypermediaBeanDeserializer to map HAL links directly to your entity fields. Annotate your entity classes (e.g., @Relation(collectionRelation = "categories") on Category) to link fields to HAL relation names, and the framework will handle population automatically.

2. Caching Repeated Resource Requests

To avoid re-fetching the same resource (like Category 8 for 30 items), use Spring Cache. It integrates seamlessly with Spring HATEOAS and lets you cache responses using the resource URL as a unique key.

Step 1: Enable Caching

Add @EnableCaching to your Spring configuration class to activate caching support:

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableCaching
public class CacheConfig {}

Step 2: Create a Cached Resource Fetcher

Wrap your resource-fetching logic in a component with @Cacheable to cache responses by their full URL:

import org.springframework.cache.annotation.Cacheable;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Traverson;
import org.springframework.http.ParameterizedTypeReference;
import org.springframework.stereotype.Component;
import java.net.URI;

@Component
public class CachedHalResourceFetcher {

    private final Traverson traverson;

    public CachedHalResourceFetcher() {
        this.traverson = new Traverson(URI.create("http://my.rest.service"), MediaTypes.HAL_JSON);
    }

    // Cache resources using their full URL as the unique key
    @Cacheable(value = "halResources", key = "#resourceUrl")
    public <T> Resource<T> fetchResource(String resourceUrl, ParameterizedTypeReference<Resource<T>> typeRef) {
        // Extract the path segment from the URL to use with Traverson
        String path = URI.create(resourceUrl).getPath().substring(1); // Remove leading slash
        return traverson.follow(path.split("/")).toObject(typeRef);
    }
}

Step 3: Use the Cached Fetcher in Your Service

Inject the cached fetcher into your service—duplicate requests for the same category URL will hit the cache instead of making a new API call:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.Resource;
import org.springframework.http.ParameterizedTypeReference;

public class ItemService {

    @Autowired
    private CachedHalResourceFetcher resourceFetcher;

    public Item getItemById(Integer itemId) {
        // Fetch the item (cached if requested again)
        String itemUrl = "http://my.rest.service/items/" + itemId;
        Resource<Item> itemResource = resourceFetcher.fetchResource(
                itemUrl,
                new ParameterizedTypeReference<Resource<Item>>() {}
        );
        Item item = itemResource.getContent();
        
        // Fetch the category—cache reuses existing data if already fetched
        String categoryUrl = itemResource.getLink("category").getHref();
        Resource<Category> categoryResource = resourceFetcher.fetchResource(
                categoryUrl,
                new ParameterizedTypeReference<Resource<Category>>() {}
        );
        item.setCategory(categoryResource.getContent());
        
        return item;
    }
}

Caching Notes

  • Spring Boot auto-configures Caffeine as the default cache provider (you can switch to Ehcache, Redis, etc., based on your needs).
  • Adjust cache expiration using @Cacheable attributes like expireAfterWrite to balance freshness and performance.

内容的提问来源于stack exchange,提问作者ahuemmer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:28:14