- LikeyouPost는 모든 사용자가 사용할 수 있어야 합니다
- 회원은 일반회원, 정회원, 특별회원, 외부사용자가 있습니다.
- 회원은 글을 작성할 수 있으나, 외부사용자는 작성할 수 없습니다.
- 글 목록에서 사용자들의 권한이 표시되어야 합니다.
- 글 목록에서 좋아요의 개수를 카운팅하여 보여주어야 합니다.
- 글에 좋아요는 하나의 계정당 하나의 글에만 가능합니다. (1개의 글에 동일한 사용자가 2번 이상은 불가능)
Feature | Request | API | 설명 |
---|---|---|---|
글 목록보기 | GET | /api/posts | 글 목록을 조회합니다. 자신이 좋아요를 누른 게시물인지 알 수 있습니다. |
글 작성하기 | POST | /api/posts | 글을 작성합니다. 로그인 한 사용자만 이용 가능합니다. |
글 수정하기 | PUT | /api/posts/{postId} | 글을 수정합니다. 자신의 게시글만 수정이 가능합니다. |
글 삭제하기 | DELETE | /api/posts/{postId} | 글을 삭제합니다. 자신의 게시글만 삭제가 가능합니다. |
글 좋아요 | POST | /api/posts/{postId}/like | 글을 좋아요 합니다. 좋아요는 게시글당 한번만 누를 수 있습니다. |
1.인증 과정은 로그인이 됐다는 가정하에 header에 실린 인증 정보를 파싱하여, 해당 로그인 정보가 정상적인지 판단하였습니다.
- 이 판단 과정은 인터셉터에서 controller에 가기 전에 담당하여 글 목록(GET Method)를 제외하고 모든 컨트롤러에서 거쳐갑니다.
- 하지만 글 목록 구현 과정에서 내가 좋아요를 누른 글을 확인해야 하기 때문에, 이 경우에는 인증 정보를 보낼 필요가 있어 따로 예외처리를 하였습니다.
2.BaseDate라는 대부분에 들어가는 날짜 정보에는 생성일시, 수정일시, 삭제일시가 들어갑니다.
- User와 Post는 이 정보가 필요하다고 생각하여 공통 클래스로 빼어 관리하게 만들었고, 해당 클래스를 extends하였습니다.
- 이걸 위해서 @EnableJpaAudting을 통해 JPA가 감시하도록 설정하고, @MappedSuperClass를 사용해서 Jpa Entity들이 해당 클래스를 상속할 경우 필드를 인식하도록 하였습니다.
- @EntityListeners(AuditingEntityListener.class)를 통해 해당 클래스가 callback listener로 지정하여 Entity에서 이벤트가 발생할 때마다 (Update, Create) 해당 정보를 Update 시키도록 구현했습니다.
3.User와 Post에 ManyToOne, OneToMany와 Like를 통해서 ManyToMany를 쪼개어 분리한 이유는
- 다대다는 좋아요 누른 사용자 목록을 구현하기 위함이고
- 다대일은 현재 글을 작성한 사람을 구현하기 위함입니다.
4.entity에 @NoArgsConstructor(access = PROTECTED)를 한 이유는 hibernate에서 프록시를 통해서 지연로딩 등의 기능을 사용하는데,
- 엔티티의 생성자를 public으로 열어두게 된다면 정적 팩토리 메서드를 통하지 않고 다른 개발자(처음 이 프로젝트를 유지보수하게 되는)가 생성자를 통하여 엔티티를 건드릴 수 있기 때문입니다.
5.프로젝트의 구조는 최대한 new entity()를 쓰지 못하게 하고,
- 정적 팩토리 메서드를 통해서만 해당 로직에 접근할 수 있도록 하기 위함입니다.
6.로그인 된 사용자 정보를 쉽게 관리하고, 정보를 파싱하는 방법이 달라졌을때를 위해
- 최대한 변경점을 줄이려 ArgumentResolver를 통해서 로그인 된 사용자 정보를 받았습니다.
- 하지만 글 목록을 보는 경우를 생각해서 유저가 맞는지는 확인하지만, exception은 별도 발생시키지는 않았습니다.
7.HandlerInterceptor를 구현한 AuthInterceptor에서는 로그인 인증 과정에서
- userRepository를 불러와 header에서 넘겨지는 authentication가 정상적인지 항상 확인합니다.
- 하지만 이 과정은 매 요청시 db를 조회하게 된다면 큰 리소스 낭비로 이어지기 때문에
- redis를 사용하여 key, value(userId, User 클래스)를 통하여 저장하였습니다.
- 이 과정에서 User클래스를 Serialize 하여 저장하였습니다. 실제 개발시 dto를 만들어 필요한 정보만 저장하는게 가장 효과적입니다.
8.isLiked(해당 글에 내가 좋아요를 했는지 여부를 나타내는 필드)는 스트림을 통해
- 글 목록을 구하여 해당 글을 뽑아내고, 그 글에 좋아요를 누른 유저들을 탐색하여
- 현재 로그인한 유저와 동일한지를 판단하는 로직을 담고 있습니다. (PostService Line 83)
9.텍스트(문자열), 에러 메시지 등은 Const하게 만들어 타이핑 실수를 줄이도록 구성하였고
- 각 Dto에는 빈 값이 들어오지 않도록 validation을,
- accountType은 Enum으로 만들어 다른 타입이 추가되어도 문제없이 사용자에게 보여질때는
- 한글로 보여질 수 있게 그리고 입력 받을때는 영문으로 입력받을 수 있도록 작성하였습니다.
10.에러들은 최대한 세분화하여 에러 class만 보고 어디서 에러가 났는지 확인할 수 있도록 하였고
- 에러들은 ControllerAdvice를 이용해 한곳에서 관리하도록 만들었습니다.
etc. 그외에 orphanRemoval = true 옵션이나 양방향 연관관계는 추후 개발시 꼭 구현해야하는 기능일거라 생각하여 따로 제외하지는 않았습니다.
jar 파일로 프로젝트 빌드
java -jar [빌드된 파일명]
- run.postman_collection을 postman에서 import 후 실행