【问题标题】:How to loop and retrieve value from HATEOAS _link attribute (e.g. retrieve a description)?如何从 HATEOAS _link 属性循环和检索值(例如检索描述)?
【发布时间】:2017-06-14 21:26:20
【问题描述】:

tl;dr

我的代码从 Restful GET 中获取一组 javascript/json 对象。如何编写代码来循环和检索来自 HATEOAS“_link”属性的描述(或任何值)以供显示?

上下文

我继承了一个基于 Spring 的小型项目——它跟踪服务器、软件安装等,供我们团队内部使用。它使用 Angular 前端和 Spring/java/mysql 后端作为一个安静的后端。

我正在将手动编码的 SQL 转换为 JPA 和“spring starter data rest”

当前的 API 有

当前手工编码的 SQL 连接表以提供“显示友好的结果”。

Product
---------
Product ID
Product Name
Category ID

Category
---------
Category ID
Category Name

“检索产品”sql 将产品和类别连接起来以提供“显示友好名称”。 Rest API 检索附加了此“类别名称”的“产品对象”。

Spring Data Rest 域对象

产品

@Entity
@Table(name="products")
public class Products
{

    private static final long serialVersionUID = 5697367593400296932L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)

    public long id;

    public String product_name;

    @ManyToOne(optional = false,cascade= CascadeType.MERGE)
    @JoinColumn(name = "category_id")
    private ProductCategory productCategory;

    public Products(){}

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public Products(String product_name) {
        this.product_name = product_name;
    }

    public String getProduct_name() {
        return product_name;
    }

    public void setProduct_name(String product_name) {
        this.product_name = product_name;
    }

    public ProductCategory getProductCategory()
    {
        return productCategory;
    }

    public void setProductCategory(ProductCategory pProductCategory)
    {
        productCategory = pProductCategory;
    }
}

产品类别

@Entity
@Table(name="productcat")

public class ProductCategory implements Serializable{

        private static final long serialVersionUID = 890485159724195243L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public long id;
    public String category;

    @OneToMany(mappedBy = "productCategory", cascade = CascadeType.ALL)
    @JsonBackReference
    Set<Products> products;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public Set<Products> getProducts() {
        return products;
    }

}

问题

我删除了连接,并为产品和类别添加了 Spring 存储库。 'get products' RESTful API 现在返回以下列表:

{
      "product_name" : "ForceFive 1.0",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/api/rest/products/8"
        },
        "products" : {
          "href" : "http://localhost:8080/api/rest/products/8"
        },
        "productCategory" : {
          "href" : "http://localhost:8080/api/rest/products/8/productCategory"
        }
      }

问题

如何显示“productCategory”链接的类别名称?

"productCategory" : {
  "href" : "http://localhost:8080/api/rest/products/8/productCategory"
}

我最初认为我可以检索类别,然后构建一个“类别 url”到“描述”的映射。但是网址不同:

“产品类别”网址如下所示: http://localhost:8080/api/rest/productcat/1

而产品有这个: “产品分类” : { "href" : "http://localhost:8080/api/rest/products/8/productCategory" }

问题说明

所以如果 javascript 控制器 http 获取产品:

requests.get(productsUrl, $scope).success(function(data, status){
    $scope.models = data._embedded.products;  
});

然后呢?这些是步骤吗?

javascript 控制器循环遍历每个 data._embedded.products。每个产品的代码

- 将描述存储在某处以在页面上重复使用(即将其添加到 javascript 对象)

如果是这些步骤:

  • 代码很多
  • 对于长列表(例如 50 种产品),还有 100 个 http get 请求。

即使我添加一个调用来获取/缓存所有产品类别,这仍然是额外的 50 个 http 获取

奖励:

  • 易于编码
  • 跑得快

尝试 #01:添加投影

我添加了这个投影:

  public interface ProductRepository extends PagingAndSortingRepository<Products, Long>
    {

       @Projection(name = "dummyNameForProjection", types = { Products.class })
       interface VirtualProjection
       {

          String getProduct_name() ;
          //Get Product Category
          @Value("#{target.productCategory.category}")
          String getCategoryName();
       }
    }

但是这个 url 不返回类别名称:

http://localhost:8080/api/rest/products/4?projection=dummyNameForProjection

返回的 json

{
    "product_name": "Force Five",
    "_links": {
        "self": {
            "href": "http://localhost:8080/api/rest/products/4"
        },
        "products": {
            "href": "http://localhost:8080/api/rest/products/4"
        },
        "productCategory": {
            "href": "http://localhost:8080/api/rest/products/4/productCategory"
        }
    }
}

另外,我为这些设置了调试功能

 logging.level.org.springframework.data=DEBUG
 logging.level.org.springframework.data.rest=DEBUG
 logging.level.org.hibernate=DEBUG

日志/控制台没有提及任何预测。

尝试 #02:固定预测 D'oh 下的文件。我将投影卡在存储库而不是实体上。查看一些示例代码显示了该问题。投影就是门票!

【问题讨论】:

  • 您的响应示例中可能缺少一些数据?很难理解你的问题。
  • 我刚刚添加了“问题说明”。我的一般问题:从这个“规范化”API 循环和获取所有描述的最简单/最快/最好的方法是什么?设置 API 以简化使用的最佳方式是什么?

标签: javascript angularjs spring-data-rest hateoas spring-hateoas


【解决方案1】:

Spring Projection

@Projection(name = "dummyNameForProjection", types = { Product.class })
public interface VirtualProjection {

// this will get the attribute name from the product entity
String getProductName();

//this will get the name of the category entity related to the product
@Value("#{target.category.name}") 
String getCategoryName();

}

只需在您的请求中包含投影名称,例如:/products?projection=dummyNameForProjection

【讨论】:

  • 好的。因此,我已将上述投影添加到我的存储库中。 Spring 似乎忽略了 ' ?projectionName=dummyNameForProjection' 参数并且日志没有给出它识别投影的迹象。我什至没有在“/profile/products”中看到 ALPS 信息。下一步是什么?
  • projection=dummyNameForProjection not "projectionName=dummyNameForProjection" 请告诉我您对邮递员之类的要求
  • 我得到与“projection="...相同的结果。我在上面添加了“尝试#01”部分来记录结果。如果这种格式不起作用,请告诉我其他信息会有所帮助。谢谢
  • 我的错误:我在存储库上进行了投影,而不是在实体上。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-08
  • 1970-01-01
  • 2013-01-02
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多