如何在Spring Data REST项目中使用DTO?

时间:2017-07-30 15:51:59

标签: spring spring-data-rest projection dto

Spring Data REST自动仅公开域对象。但大多数情况下,我们必须处理数据传输对象。那么如何以SDR方式做到这一点?

1 个答案:

答案 0 :(得分:22)

如何在DTO项目中使用Spring Data REST的方法

工作示例为here

<强>实体

实体必须实现Identifiable接口。例如:

Stream

<强>预测

创建一个projection接口,存储库查询方法将返回:

@Entity
public class Category implements Identifiable<Integer> {

    @Id
    @GeneratedValue
    private final Integer id;

    private final String name;

    @OneToMany
    private final Set<Product> products = new HashSet<>();

    // skipped
}

@Entity
public class Product implements Identifiable<Integer> {

    @Id
    @GeneratedValue
    private final Integer id;

    private final String name;

    // skipped
}

它将是DTO的地下室。在此示例中,DTO将代表public interface CategoryProjection { Category getCategory(); Long getQuantity(); } ,并且Category的数量属于它。

存储库方法

创建方法返回投影:单个,DTO列表和DTO的分页列表。

Product

DTO

从其界面实施DTO:

@RepositoryRestResource
public interface CategoryRepo extends JpaRepository<Category, Integer> {

    @RestResource(exported = false)
    @Query("select c as category, count(p) as quantity from Category c join c.products p where c.id = ?1 group by c")
    CategoryProjection getDto(Integer categoryId);

    @RestResource(exported = false)
    @Query("select c as category, count(p) as quantity from Category c join c.products p group by c")
    List<CategoryProjection> getDtos();

    @RestResource(exported = false)
    @Query("select c as category, count(p) as quantity from Category c join c.products p group by c")
    Page<CategoryProjection> getDtos(Pageable pageable);
}

Spring Data REST渲染对象时使用注释@Relation(value = "category", collectionRelation = "categories") public class CategoryDto implements CategoryProjection { private final Category category; private final Long quantity; // skipped }

<强>控制器

Relation添加自定义方法,以便为DTO的请求提供服务:

RepositoryRestController

当从存储库收到预测时,我们必须从Projection到DTO进行最终转换 并在发送给客户端之前将其“包装”到ResourceSupport对象。 为此,我们使用辅助方法@RepositoryRestController @RequestMapping("/categories") public class CategoryController { @Autowired private CategoryRepo repo; @Autowired private RepositoryEntityLinks links; @Autowired private PagedResourcesAssembler<CategoryProjection> assembler; /** * Single DTO */ @GetMapping("/{id}/dto") public ResponseEntity<?> getDto(@PathVariable("id") Integer categoryId) { CategoryProjection dto = repo.getDto(categoryId); return ResponseEntity.ok(toResource(dto)); } /** * List of DTO */ @GetMapping("/dto") public ResponseEntity<?> getDtos() { List<CategoryProjection> dtos = repo.getDtos(); Link listSelfLink = links.linkFor(Category.class).slash("/dto").withSelfRel(); List<?> resources = dtos.stream().map(this::toResource).collect(toList()); return ResponseEntity.ok(new Resources<>(resources, listSelfLink)); } /** * Paged list of DTO */ @GetMapping("/dtoPaged") public ResponseEntity<?> getDtosPaged(Pageable pageable) { Page<CategoryProjection> dtos = repo.getDtos(pageable); Link pageSelfLink = links.linkFor(Category.class).slash("/dtoPaged").withSelfRel(); PagedResources<?> resources = assembler.toResource(dtos, this::toResource, pageSelfLink); return ResponseEntity.ok(resources); } private ResourceSupport toResource(CategoryProjection projection) { CategoryDto dto = new CategoryDto(projection.getCategory(), projection.getQuantity()); Link categoryLink = links.linkForSingleResource(projection.getCategory()).withRel("category"); Link selfLink = links.linkForSingleResource(projection.getCategory()).slash("/dto").withSelfRel(); return new Resource<>(dto, categoryLink, selfLink); } } :我们创建一个新的DTO,为这个对象创建必要的链接, 然后使用对象及其链接创建一个新的toResource

<强>结果

请参阅Postman site

上的API文档

感谢DTO

Resource
GET http://localhost:8080/api/categories/6/dto

DTO列表

{
    "category": {
        "name": "category1"
    },
    "quantity": 3,
    "_links": {
        "category": {
            "href": "http://localhost:8080/api/categories/6"
        },
        "self": {
            "href": "http://localhost:8080/api/categories/6/dto"
        }
    }
}
GET http://localhost:8080/api/categories/dto

DTO的分页列表

{
    "_embedded": {
        "categories": [
            {
                "category": {
                    "name": "category1"
                },
                "quantity": 3,
                "_links": {
                    "category": {
                        "href": "http://localhost:8080/api/categories/6"
                    },
                    "self": {
                        "href": "http://localhost:8080/api/categories/6/dto"
                    }
                }
            },
            {
                "category": {
                    "name": "category2"
                },
                "quantity": 2,
                "_links": {
                    "category": {
                        "href": "http://localhost:8080/api/categories/7"
                    },
                    "self": {
                        "href": "http://localhost:8080/api/categories/7/dto"
                    }
                }
            }
        ]
    },
    "_links": {
        "self": {
            "href": "http://localhost:8080/api/categories/dto"
        }
    }
}
GET http://localhost:8080/api/categories/dtoPaged