Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
요구사항
기본
API 명세
이번 미션은 아래의 API 스펙과 비교하며 구현해보세요.
API 스펙 v1.1
{% callout(caution) %}
프론트엔드 소스 코드는 참고용으로만 활용하세요. 수정하여 활용하는 경우 이어지는 요구사항 또는 미션을 수행하는 데 어려움이 있을 수 있습니다.
{% endcallout %}
데이터베이스
아래와 같이 데이터베이스 환경을 설정하세요.
ERD를 참고하여 DDL을 작성하고, 테이블을 생성하세요.
/src/main/resources/schema.sql
경로에 포함하세요.PK: Primary Key
UK: Unique Key
NN: Not Null
FK: Foreign Key
ON DELETE CASCADE: 연관 엔티티 삭제 시 같이 삭제
ON DELETE SET NULL: 연관 엔티티 삭제 시 NULL로 변경
Spring Data JPA 적용하기
application.yaml
파일에 작성하세요.application.yaml
파일에 작성하세요.엔티티 정의하기
클래스 다이어그램을 참고해 도메인 모델의 공통 속성을 추상 클래스로 정의하고 상속 관계를 구현하세요.
com.sprint.mission.discodeit.entity.base
JPA의 어노테이션을 활용해
createdAt
,updatedAt
속성이 자동으로 설정되도록 구현하세요.클래스 다이어그램을 참고해 클래스 참조 관계를 수정하세요. 필요한 경우 생성자, update 메소드를 수정할 수 있습니다. 단, 아직 JPA Entity와 관련된 어노테이션은 작성하지 마세요.
ERD와 클래스 다이어그램을 토대로 연관관계 매핑 정보를 표로 정리해보세요.(이 내용은 PR에 첨부해주세요.)
예시
JPA 주요 어노테이션을 활용해 ERD, 연관관계 매핑 정보를 도메인 모델에 반영해보세요.
ERD의 외래키 제약 조건과 연관관계 매핑 정보의 부모-자식 관계를 고려해 영속성 전이와 고아 객체를 정의하세요.
레포지토리와 서비스에 JPA 도입하기
기존의 Repository 인터페이스를 JPARepository로 정의하고 쿼리메소드로 대체하세요.
영속성 컨텍스트의 특징에 맞추어 서비스 레이어를 수정해보세요.
DTO 적극 도입하기
Entity를 Controller 까지 그대로 노출했을 때 발생할 수 있는 문제점에 대해 정리해보세요.
DTO를 적극 도입했을 때 보일러플레이트 코드가 많아지지만, 그럼에도 불구하고 어떤 이점이 있는지 알 수 있을거에요.(이 내용은 PR에 첨부해주세요.)
다음의 클래스 다이어그램을 참고하여 DTO를 정의하세요.
Entity를 DTO로 매핑하는 로직을 책임지는 Mapper 컴포넌트를 정의해 반복되는 코드를 줄여보세요.
com.sprint.mission.discodeit.mapper
BinaryContent 저장 로직 고도화
데이터베이스에 이미지와 같은 파일을 저장하면 성능 상 불리한 점이 많습니다. 따라서 실제 바이너리 데이터는 별도의 공간에 저장하고, 데이터베이스에는 바이너리 데이터에 대한 메타 정보(파일명, 크기, 유형 등)만 저장하는 것이 좋습니다.
BinaryContent의 byte[] 데이터 저장을 담당하는 인터페이스를 설계하세요.
{%callout(info) %}
저장 매체의 확장성(로컬 저장소, 원격 저장소)을 고려해 인터페이스부터 설계합니다.
{%endcallout%}
패키지명:
com.sprint.mission.discodeit.storage
BinaryContentStorage
UUID put(UUID, byte[])
InputStream get(UUID)
ResponseEntity<?> download(BinaryContentDto)
서비스 레이어에서 기존에 BinaryContent를 저장하던 로직을 BinaryContentStorage를 활용하도록 리팩토링하세요.
BinaryContentController에 파일을 다운로드하는 API를 추가하고, BinaryContentStorage에 로직을 위임하세요.
로컬 디스크 저장 방식으로 BinaryContentStorage 구현체를 구현하세요.
ResponseEntity<Resource> donwload(BinaryContentDto)
페이징과 정렬
메시지 목록을 조회할 때 다음의 조건에 따라 페이지네이션 처리를 해보세요.
일관된 페이지네이션 응답을 위해 제네릭을 활용해 DTO로 구현하세요.
com.sprint.mission.discodeit.dto.response
Slice 또는 Page 객체로부터 DTO를 생성하는 Mapper를 구현하세요.
com.sprint.mission.discodeit.mapper
심화
N+1 문제
읽기전용 트랜잭션 활용
다음과 같이 .md 문법으로 작성할 수 있어요:
N+1 문제
읽기전용 트랜잭션 활용
페이지네이션 최적화
[x] 오프셋 페이지네이션과 커서 페이지네이션 방식의 차이에 대해 정리해보세요.
{% callout(info) %}
이 내용은 PR에 첨부해주세요.
{% endcallout %}
[x] 기존에 구현한 오프셋 페이지네이션을 커서 페이지네이션으로 리팩토링하세요.
PageResponse는 다음과 같이 변경하세요.
다음의 API 명세를 준수하세요.
API 스펙 v1.2
API 스펙을 준수한다면, 아래의 프론트엔드 코드와 호환됩니다.
정적 리소스 v1.2.2
소스 코드(참고용) v1.2.2
{% callout(caution) %}
프론트엔드 소스 코드는 참고용으로만 활용하세요. 수정하여 활용하는 경우 이어지는 요구사항 또는 미션을 수행하는 데 어려움이 있을 수 있습니다.
{% endcallout %}
MapStruct 적용
[x] Entity와 DTO를 매핑하는 보일러플레이트 코드를 MapStruct 라이브러리를 활용해 간소화해보세요
멘토에게