복붙노트

[SPRING] 스프링 데이터 REST 프로젝트에서 DTO를 사용하는 방법은 무엇입니까?

SPRING

스프링 데이터 REST 프로젝트에서 DTO를 사용하는 방법은 무엇입니까?

스프링 데이터 REST는 도메인 객체 만 노출하는 것을 자동화합니다. 하지만 대부분의 경우 데이터 전송 객체를 처리해야합니다. 어떻게 SDR 방식으로이 작업을 수행 할 수 있습니까?

해결법

  1. ==============================

    1.Spring Data REST 프로젝트에서 DTO를 사용하는 방법에 대한 접근법

    Spring Data REST 프로젝트에서 DTO를 사용하는 방법에 대한 접근법

    작업 예제는 여기에 있습니다.

    개체

    엔티티는 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
    }
    

    투영법

    저장소 쿼리 메소드가 반환 할 투영 인터페이스를 만듭니다.

    public interface CategoryProjection {
    
        Category getCategory();
        Long getQuantity();
    }
    

    그것은 DTO의 기반이 될 것입니다. 이 예에서 DTO는 카테고리를 나타내고 제품 수는 그 카테고리에 속합니다.

    저장소 메소드

    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
    }
    

    Annotation Relation은 Spring Data REST가 객체를 렌더링 할 때 사용된다.

    제어 장치

    DTO 요청을 처리 할 사용자 정의 메소드를 RepositoryRestController에 추가하십시오.

    @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 로의 최종 변환을해야합니다 클라이언트에 보내기 전에 ResourceSupport 객체에 '포장'합니다. 이를 위해 우리는 helper method toResource를 사용합니다 : 새로운 DTO를 만들고,이 객체에 필요한 링크를 만들고, 그 다음에 객체와 그 링크로 새로운 Resource를 생성하십시오.

    결과

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

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

    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
        }
    }
    
  2. from https://stackoverflow.com/questions/45401734/how-to-work-with-dto-in-spring-data-rest-projects by cc-by-sa and MIT license