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

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

回答:

Entities

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

@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

}

Projections

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

public interface CategoryProjection {

Category getCategory();

Long getQuantity();

}

这将是DTO的基础。在此示例中,DTO将代表a Category,而Products 的数量属于它。

Repository methods

Create方法将返回投影:一个投影,一个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);

}

DTO

从其接口实施DTO:

@Relation(value = "category", collectionRelation = "categories")

public class CategoryDto implements CategoryProjection {

private final Category category;

private final Long quantity;

// skipped

}

Relation当Spring Data REST渲染对象时使用注释。

控制者

RepositoryRestController其中添加自定义方法将满足DTO的请求:

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

}

}

从存储库收到Projections时,我们必须先完成从Projection到DTO的转换,然后将其“包装”到ResourceSupport对象,然后再发送给客户端。为此,我们使用辅助方法toResource:创建一个新的DTO,为此对象创建必要的链接,然后Resource使用该对象及其链接创建一个新的。

Result

请参阅Postman网站上的API文档

Singe DTO

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

{

"category": {

"name": "category1"

},

"quantity": 3,

"_links": {

"category": {

"href": "http://localhost:8080/api/categories/6"

},

"self": {

"href": "http://localhost:8080/api/categories/6/dto"

}

}

}

List of DTO

GET http://localhost:8080/api/categories/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"

}

}

}

Paged list of DTO

GET http://localhost:8080/api/categories/dtoPaged

{

"_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/dtoPaged"

}

},

"page": {

"size": 20,

"totalElements": 2,

"totalPages": 1,

"number": 0

}

}

以上是 如何在Spring Data REST项目中使用DTO? 的全部内容, 来源链接: utcz.com/qa/426593.html

回到顶部