【问题标题】:Spring Data Rest HATEOAS Links and HTML Select Drop DownSpring Data Rest HATEOAS Links and HTML Select Drop Down
【发布时间】:2017-06-16 15:09:18
【问题描述】:

这是我几天后关于使用 Spring Data Rest 和 HATEOAS 链接的第二个问题。

tl;dr

我的应用程序如何使用“manyToOne”属性的链接来填充 html 选择下拉菜单的“当前值”?

“Spring data rest”生成的链接与“old school ids”的行为不同。

上下文

  • 将应用程序转换为 Spring JPA 和 Spring Data Rest。
  • 下面的简单“产品/类别”表结构
  • 我已将投影名称“完整”添加到“加入/获取”描述中

表格

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

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

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;
    }


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

        String getProductName() ;
        
        @Value("#{target.productCategory.category}")
        String getCategory();
        
    }

}

产品类别

@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;
    }

}

问题:类别列表、对象中的值之间的阻抗不匹配

当 Angular 客户端检索产品时,产品类别的产品“类别链接”如下所示:

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

当客户端检索到“产品类别”列表时,该类别的链接如下所示:

href": "http://localhost:8080/api/rest/productcat/4"

这是“选择”代码。仅当“product.productCategory”与“options”的值之一匹配时,UI 才会显示选择。

<select ng-model="product.productCategory >
  <option value="http://localhost:8080/api/rest/productcat/1">Foo Product Type
  </option>
  <option value="http://localhost:8080/api/rest/productcat/2">Bar Product Type
  </option>
  <option value="http://localhost:8080/api/rest/productcat/3">Baz Product Type
  </option>
</select>

问题

  • 如何编码我的服务器 API 以制作“生成的链接”客户端 友谊赛?什么是最有弹性的方法?

  • 我是否应该更改 API 以接收更新的“值”而不是“ID/链接”,即类别名称,而不是 ID? (即按名称查找类别并在服务器端更新)

  • 您推荐哪些 javascript/angular 工具和技术来处理链接?

【问题讨论】:

    标签: angularjs spring-data-rest


    【解决方案1】:

    我通过javascript“取消引用”“productCategory”值来解决问题, - 检索“productCategory”属性中的 URL,例如:

    http://localhost:8080/api/rest/products/8/productCategory
    
    • 将“productCategory”属性/url 替换为 HATEOAS 链接中的值。 pItem[pPropName] = data._links.self.href;

    这种方法为简单的下拉菜单带来了很多复杂性。味道不对。

    取消引用代码

    function dereferenceProperty(pItem,pPropName )
    {
    
        var myRef = pItem._links[pPropName];
        if (myRef &&  myRef.href)
        {
            var myUrl = myRef.href;
            $http.get(myUrl).success(function (data, status)
            {
                pItem[pPropName] = data._links.self.href;
            });
        }
    }
    

    用法

    dereferenceProperty(pProduct,"productCategory");
    

    在这个“去参考”之后:

    • Angular/Browser 正确填充了下拉列表
    • HTTP PATCH 正确更新 API(和表)

    【讨论】:

      【解决方案2】:

      我不完全明白你的意思,但是如果你需要在ProductCategory 中获取Product 列表,或者你需要在Product 中隐式获取ProductCategory,你可以使用,例如,@987654321 @:

      @Projection(name = "withProducts", types = ProductCategory.class)
      public interface WithProducts {
      
          String getName();
          Set<Product> getProducts();
      }
      
      @Projection(name = "withCategory", types = Product.class)
      public interface WithCategory {
      
          String getName();
          BigDecimal getPrice();
          ProductCategory getCategory();
      }
      

      然后,如果您 GET http://localhost:8080/api/productCategories/1?projection=withProducts,您将检索到如下内容:

      {
          "_embedded": {
              "products": [
                  {
                      "name": "Product1",
                      "category": {
                          "name": "Category1"
                      },
                      "price": 1,
                      "_links": {
                          "self": {
                              "href": "http://localhost:8080/api/products/1"
                          },
                          "product": {
                              "href": "http://localhost:8080/api/products/1{?projection}",
                              "templated": true
                          },
                          "category": {
                              "href": "http://localhost:8080/api/products/1/category"
                          }
                      }
                  },
                  {
                      "name": "Product2",
                      "category": {
                          "name": "Category1"
                      },
                      "price": 2,
                      "_links": {
                          "self": {
                              "href": "http://localhost:8080/api/products/2"
                          },
                          "product": {
                              "href": "http://localhost:8080/api/products/2{?projection}",
                              "templated": true
                          },
                          "category": {
                              "href": "http://localhost:8080/api/products/2/category"
                          }
                      }
                  }
              ]
          },
          "_links": {
              "self": {
                  "href": "http://localhost:8080/api/productCategories/1/products?projection=withCategory"
              }
          }
      }
      

      或者如果你 GET http://localhost:8080/api/products/1/category?projection=withProducts 你会检索到这样的东西:

      {
          "name": "Category1",
          "products": [
              {
                  "name": "Product1",
                  "price": 1
              },
              {
                  "name": "Product2",
                  "price": 2
              }
          ],
          "_links": {
              "self": {
                  "href": "http://localhost:8080/api/productCategories/1"
              },
              "productCategory": {
                  "href": "http://localhost:8080/api/productCategories/1{?projection}",
                  "templated": true
              },
              "products": {
                  "href": "http://localhost:8080/api/productCategories/1/products"
              }
          }
      }
      

      工作example

      【讨论】:

        猜你喜欢
        • 2013-10-31
        • 2014-03-07
        • 2014-08-16
        • 2016-05-23
        • 2014-07-05
        • 2018-07-23
        • 2018-11-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多