如何使用Spring Data REST暴露自定义DTO CRUD存储库?

7
我不想暴露我的模型类(jpa 实体),而是使用不同的数据传输对象(DTO)来展示它们的不同子集属性。 思路是 DTO CrudRepository <-> JpaRepository <-> entities,我希望通过 Spring Data REST 来公开 DTO CrudRepository
例如:
实体:
@Entity
@Table(name = "groups")
public class Group {

    private Long id;
    private String name;
    private Set<User> users;
    // other attributes

    @Id
    @GeneratedValue
    @Column(name = "group_id")
    public Long getId() {
        return id;
    }

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

    @Column(name = "name", nullable = false)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @OneToMany(mappedBy = "group")
    public Set<User> getUsers() {
        return users;
    }

    public void setUsers(Set<User> users) {
        this.users = users;
    }

    // other getters and setters

}

JpaRepository:
@RepositoryRestResource(exported = false)
public interface GroupDao extends JpaRepository<Group, Long> {
}

DTO:
public class GroupWithoutRelationsDto {

    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

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

    @NotBlank
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

DTO CrudRepository:
public interface GroupDtoDao extends CrudRepository<GroupWithoutRelationsDto, Long> {
}

实现:
@Repository
public class GroupDtoDaoImpl extends GenericDtoDao<GroupWithoutRelationsDto, Group, Long> implements GroupDtoDao {

    @Autowired
    private GroupDao groupDao;

    @Override
    protected CrudRepository<Group, Long> getModelDao() {
        return groupDao;
    }

    @Override
    protected <S extends GroupWithoutRelationsDto> Long getDtoId(S dto) {
        return dto.getId();
    }

    @Override
    protected Long getModelId(Group model) {
        return model.getId();
    }

    @Override
    protected <S extends GroupWithoutRelationsDto> S modelToDto(Group model, S dto) {
        dto.setId(model.getId());
        dto.setName(model.getName());
        return dto;
    }

    @Override
    protected <S extends GroupWithoutRelationsDto> Group dtoToModel(S dto, Group model) {
        model.setId(dto.getId());
        model.setName(dto.getName());
        return model;
    }

    @Override
    protected Group newModel() {
        return new Group();
    }

    @Override
    protected GroupWithoutRelationsDto newDto() {
        return new GroupWithoutRelationsDto();
    }

}

GenericDtoDao:
@NoRepositoryBean
public abstract class GenericDtoDao<D, M, ID extends Serializable> implements CrudRepository<D, ID> {

    protected abstract CrudRepository<M, ID> getModelDao();

    protected abstract <S extends D> ID getDtoId(S dto);

    protected abstract ID getModelId(M model);

    protected abstract <S extends D> S modelToDto(M model, S dto);

    protected abstract <S extends D> M dtoToModel(S dto, M model);

    protected abstract M newModel();

    protected abstract D newDto();

    @Override
    public D findOne(ID id) {
        return modelToDto(getModelDao().findOne(id), newDto());
    }

    @Override
    public <S extends D> S save(S entity) {
        Assert.notNull(entity, "The entity must not be null!");
        if (getDtoId(entity) == null) {
            return create(entity);
        }
        return update(entity);
    }

    protected <S extends D> S create(S entity) {
        Assert.notNull(entity, "The entity must not be null!");
        if (getDtoId(entity) != null) {
            Assert.isTrue(!exists(getDtoId(entity)), "The entity ID must be null or not exist!");
        }
        return modelToDto(getModelDao().save(dtoToModel(entity, newModel())), entity);
    }

    protected <S extends D> S update(S entity) {
        Assert.notNull(entity, "The entity must not be null!");
        M model = getModelDao().findOne(getDtoId(entity));
        Assert.notNull(model, "The entity must exist!");
        return modelToDto(getModelDao().save(dtoToModel(entity, model)), entity);
    }

    // other CrudRepository methods

}

在这个例子中,我想使用Spring Data REST来公开GroupDtoDao。
在其他bean中,我可以自动装配GroupDao和GroupDtoDao,因此两者都由Spring的上下文管理。如果我不用@RepositoryRestResource(exported = false)注释GroupDao,则JpaRepository会作为REST服务公开,因此我认为Spring Data REST已经配置好了。
我该如何告诉它公开我的自定义CrudRepository呢?

你最终解决了这个问题吗?我也很感兴趣答案,但是没有一个干净的解决方案。我最好的想法是提供一个自定义的JSON ObjectMapper,在映射到DTO并写出DTO时在Mapper内部执行。 - Jason
我还没有找到自动化的解决方案,我仍然有一个自定义的CrudRestController,它包装了我的DtoDaos方法。 - Francesco Pitzalis
1个回答

2
“现在有一个JIRA问题需要澄清如何做到这一点。
目前,SDR团队表示:“我们通常建议仅使用Jackson mixins来连接自定义序列化程序、自定义输出等。请参见Spring RESTBucks的示例。”

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接