【问题标题】:How to know the name of the resource from an Entity class, to build a Hateoas link to that resource?如何从 Entity 类中知道资源的名称,以建立到该资源的 Hateoas 链接?
【发布时间】:2019-08-29 11:23:13
【问题描述】:

假设我有两个资源PersonArticle

@Entity
@Table(name = "person")
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long person_id;
    private String firstName;
    private String lastName;

    @OneToMany(mappedBy="person", cascade=CascadeType.ALL)
    private List<Article> articles = new ArrayList<>();

}

@Entity
@Table(name="article")
public class Article {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    private String title;
    private String details;

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="person_id")
    private Person person;

}

我现在想将 HATEOAS 支持添加到我正在使用的控制器的响应中 org.springframework.hateoas.ResourceAssembler

public class PersonResourceAssembler implements ResourceAssembler<Person, Resource<Person>>  {

    private EntityLinks entityLinks;

    public UserJobResourceAssembler(EntityLinks entityLinks) {
        this.entityLinks = entityLinks;
    }

    @Override
    public Resource<Person> toResource(Person entity) {
        Resource<UserJob> resource = new Resource<>(entity);
        resource.add(
               entityLinks.linkFor(Person.class).withSelfRel()),
               entityLinks.linkFor(...logic...).withRel("articles")) //here I am hardcoding the relation link name i.e "article"
             );
        return resource;
        }
}

所以,在上面的代码中,“article”是硬编码的链接名称,但我不想这样做。我希望它以Spring-Data-REST 处理它的方式进行,即对于每个关系,它会自动检测Entity 类中使用的变量的名称,例如articles 将从Person 中选择,person 将从中选择Article.

我不知道Spring-Data-REST 是如何处理它的,但是有没有现成/定制的解决方案来满足这个要求?

【问题讨论】:

    标签: spring-boot spring-data spring-data-rest spring-hateoas


    【解决方案1】:

    您可以使用反射 API 来内省实体并找到关联。比如:

    import java.lang.reflect.Field;
    import java.lang.reflect.ParameterizedType;
    import java.util.Arrays;
    import java.util.List;
    import java.util.stream.Collectors;
    import java.util.stream.Stream;
    
    import javax.persistence.OneToMany;
    
    public class AssociationUtility {
    
        public static List<Field> getAssociatedFields(Object entity) {
    
            Stream<Field> fields = Arrays.stream(entity.getClass().getDeclaredFields());
    
            return fields.filter(field -> field.getAnnotation(OneToMany.class) 
                                      != null).collect(Collectors.toList());
        }
    
        public static void main(String[] args) {
            List<Field> fields = getAssociatedFields(new Customer());
            fields.stream().forEach(f -> System.out.println("Make a link for Class: "
                    + ((ParameterizedType) f.getGenericType()).getActualTypeArguments()[0] 
                         + " with rel: " + f.getName()));
    
            System.exit(0);
        }
    }
    

    【讨论】:

    • 谢谢,受您的回答启发,我使用自定义注释写了一个更好的替代方案。完成基本测试后将发布答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-25
    • 1970-01-01
    • 2019-01-03
    • 1970-01-01
    • 2011-03-29
    相关资源
    最近更新 更多