From d6292f7c5c61d8d309620e8e5b45a820dc7b9b9c Mon Sep 17 00:00:00 2001 From: ymkim97 Date: Mon, 31 Jul 2023 15:24:15 +0900 Subject: [PATCH 01/23] =?UTF-8?q?init:=20=ED=94=84=EB=A1=9C=EC=A0=9D?= =?UTF-8?q?=ED=8A=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 43 +++++++++++++++++++ build.gradle | 37 ++++++++++++++++ settings.gradle | 1 + .../com/prgrms/board/BoardApplication.java | 13 ++++++ src/main/resources/application.properties | 1 + .../prgrms/board/BoardApplicationTests.java | 13 ++++++ 6 files changed, 108 insertions(+) create mode 100644 .gitignore create mode 100644 build.gradle create mode 100644 settings.gradle create mode 100644 src/main/java/com/prgrms/board/BoardApplication.java create mode 100644 src/main/resources/application.properties create mode 100644 src/test/java/com/prgrms/board/BoardApplicationTests.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..cbca2e05f --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ +gradlew +gradlew.bat +gradle + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store diff --git a/build.gradle b/build.gradle new file mode 100644 index 000000000..470e55bbe --- /dev/null +++ b/build.gradle @@ -0,0 +1,37 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.1.2' + id 'io.spring.dependency-management' version '1.1.2' +} + +group = 'com.prgrms' +version = '0.0.1-SNAPSHOT' + +java { + sourceCompatibility = '17' +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springframework.boot:spring-boot-starter-web' + compileOnly 'org.projectlombok:lombok' + runtimeOnly 'com.h2database:h2' + runtimeOnly 'com.mysql:mysql-connector-j' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 000000000..5f717a7cc --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'board' diff --git a/src/main/java/com/prgrms/board/BoardApplication.java b/src/main/java/com/prgrms/board/BoardApplication.java new file mode 100644 index 000000000..937f9dc6a --- /dev/null +++ b/src/main/java/com/prgrms/board/BoardApplication.java @@ -0,0 +1,13 @@ +package com.prgrms.board; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class BoardApplication { + + public static void main(String[] args) { + SpringApplication.run(BoardApplication.class, args); + } + +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/src/test/java/com/prgrms/board/BoardApplicationTests.java b/src/test/java/com/prgrms/board/BoardApplicationTests.java new file mode 100644 index 000000000..fc6efcf6e --- /dev/null +++ b/src/test/java/com/prgrms/board/BoardApplicationTests.java @@ -0,0 +1,13 @@ +package com.prgrms.board; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class BoardApplicationTests { + + @Test + void contextLoads() { + } + +} From a3915714f0290fd92a215f4c2c947edba2fd1a2a Mon Sep 17 00:00:00 2001 From: ymkim97 Date: Mon, 31 Jul 2023 15:51:38 +0900 Subject: [PATCH 02/23] =?UTF-8?q?init:=20Datasource=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.properties | 1 - src/main/resources/application.yml | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) delete mode 100644 src/main/resources/application.properties create mode 100644 src/main/resources/application.yml diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index 8b1378917..000000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 000000000..f971a9efa --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,17 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3306/board?serverTimezone=Asia/Seoul&characterEncoding=UTF-8 + username: root + password: 1234 + + jpa: + open-in-view: true + show-sql: true + properties: + hibernate: + format_sql: true + hbm2ddl: + auto: create + database: mysql + generate-ddl: true From edf5650027552a7f1b666cfd2244e1e766e902b3 Mon Sep 17 00:00:00 2001 From: ymkim97 Date: Mon, 31 Jul 2023 15:54:54 +0900 Subject: [PATCH 03/23] =?UTF-8?q?feat:=20Entity=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/prgrms/board/BoardApplication.java | 7 ++-- .../prgrms/board/domain/post/entity/Post.java | 39 +++++++++++++++++++ .../prgrms/board/domain/user/entity/User.java | 34 ++++++++++++++++ .../board/global/common/BaseEntity.java | 31 +++++++++++++++ 4 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/prgrms/board/domain/post/entity/Post.java create mode 100644 src/main/java/com/prgrms/board/domain/user/entity/User.java create mode 100644 src/main/java/com/prgrms/board/global/common/BaseEntity.java diff --git a/src/main/java/com/prgrms/board/BoardApplication.java b/src/main/java/com/prgrms/board/BoardApplication.java index 937f9dc6a..81231c991 100644 --- a/src/main/java/com/prgrms/board/BoardApplication.java +++ b/src/main/java/com/prgrms/board/BoardApplication.java @@ -6,8 +6,7 @@ @SpringBootApplication public class BoardApplication { - public static void main(String[] args) { - SpringApplication.run(BoardApplication.class, args); - } - + public static void main(String[] args) { + SpringApplication.run(BoardApplication.class, args); + } } diff --git a/src/main/java/com/prgrms/board/domain/post/entity/Post.java b/src/main/java/com/prgrms/board/domain/post/entity/Post.java new file mode 100644 index 000000000..77658a79a --- /dev/null +++ b/src/main/java/com/prgrms/board/domain/post/entity/Post.java @@ -0,0 +1,39 @@ +package com.prgrms.board.domain.post.entity; + +import com.prgrms.board.domain.user.entity.User; +import com.prgrms.board.global.common.BaseEntity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@Table(name = "post") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Post extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "post_id") + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private User user; + + @Column(name = "title", length = 30, nullable = false) + private String title; + + @Column(name = "content", nullable = false, columnDefinition = "text") + private String content; +} diff --git a/src/main/java/com/prgrms/board/domain/user/entity/User.java b/src/main/java/com/prgrms/board/domain/user/entity/User.java new file mode 100644 index 000000000..2c8056fa7 --- /dev/null +++ b/src/main/java/com/prgrms/board/domain/user/entity/User.java @@ -0,0 +1,34 @@ +package com.prgrms.board.domain.user.entity; + +import com.prgrms.board.global.common.BaseEntity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@Table(name = "user") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class User extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "user_id") + private Long id; + + @Column(name = "name", length = 30, nullable = false) + private String name; + + @Column(name = "age", nullable = false) + private int age; + + @Column(name = "hobby", length = 50) + private String hobby; +} diff --git a/src/main/java/com/prgrms/board/global/common/BaseEntity.java b/src/main/java/com/prgrms/board/global/common/BaseEntity.java new file mode 100644 index 000000000..85c6cc352 --- /dev/null +++ b/src/main/java/com/prgrms/board/global/common/BaseEntity.java @@ -0,0 +1,31 @@ +package com.prgrms.board.global.common; + +import java.time.LocalDateTime; + +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import jakarta.persistence.Column; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.MappedSuperclass; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public abstract class BaseEntity { + + @CreatedDate + @Column(name = "created_at", nullable = false, updatable = false, columnDefinition = "timestamp") + private LocalDateTime createdAt; + + @LastModifiedDate + @Column(name = "updated_at", nullable = false, columnDefinition = "timestamp") + private LocalDateTime updatedAt; +} From a53614374a97bd77bd763885bc3b5ff20dfd193e Mon Sep 17 00:00:00 2001 From: ymkim97 Date: Mon, 31 Jul 2023 17:10:01 +0900 Subject: [PATCH 04/23] =?UTF-8?q?feat:=20=EC=A0=84=EC=B2=B4=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../post/controller/ApiPostController.java | 45 +++++++++++++++++++ .../domain/post/dto/request/PostsRequest.java | 18 ++++++++ .../post/repository/PostRepository.java | 8 ++++ .../domain/post/service/PostService.java | 37 +++++++++++++++ .../user/repository/UserRepository.java | 8 ++++ .../board/global/common/BaseResponse.java | 29 ++++++++++++ .../board/global/common/PageResponse.java | 16 +++++++ .../board/global/common/SuccessMessage.java | 14 ++++++ 8 files changed, 175 insertions(+) create mode 100644 src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java create mode 100644 src/main/java/com/prgrms/board/domain/post/dto/request/PostsRequest.java create mode 100644 src/main/java/com/prgrms/board/domain/post/repository/PostRepository.java create mode 100644 src/main/java/com/prgrms/board/domain/post/service/PostService.java create mode 100644 src/main/java/com/prgrms/board/domain/user/repository/UserRepository.java create mode 100644 src/main/java/com/prgrms/board/global/common/BaseResponse.java create mode 100644 src/main/java/com/prgrms/board/global/common/PageResponse.java create mode 100644 src/main/java/com/prgrms/board/global/common/SuccessMessage.java diff --git a/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java b/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java new file mode 100644 index 000000000..d92e6d45e --- /dev/null +++ b/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java @@ -0,0 +1,45 @@ +package com.prgrms.board.domain.post.controller; + +import static com.prgrms.board.global.common.SuccessMessage.*; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.prgrms.board.domain.post.dto.request.PostsRequest; +import com.prgrms.board.domain.post.entity.Post; +import com.prgrms.board.domain.post.service.PostService; +import com.prgrms.board.global.common.BaseResponse; +import com.prgrms.board.global.common.PageResponse; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/posts") +public class ApiPostController { + + private final PostService postService; + + @GetMapping + public BaseResponse> getPosts(@Valid PostsRequest request) { + PageResponse data = postService.getPosts(request); + return BaseResponse.ok(GET_POSTS_SUCCESS, data); + } + + // @GetMapping("/{postId}") + // public Post getPost() { + // return null; + // } + // + // @PostMapping + // public Post createPost() { + // return null; + // } + // + // @PatchMapping("/{postId}") + // public Post updatePost() { + // return null; + // } +} diff --git a/src/main/java/com/prgrms/board/domain/post/dto/request/PostsRequest.java b/src/main/java/com/prgrms/board/domain/post/dto/request/PostsRequest.java new file mode 100644 index 000000000..e58d9127d --- /dev/null +++ b/src/main/java/com/prgrms/board/domain/post/dto/request/PostsRequest.java @@ -0,0 +1,18 @@ +package com.prgrms.board.domain.post.dto.request; + +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; + +import jakarta.validation.constraints.PositiveOrZero; + +public record PostsRequest( + @PositiveOrZero(message = "페이지는 양수여야 합니다.") + int page, + + @PositiveOrZero(message = "한 페이지 당 게시물의 개수는 양수여야 합니다.") + int rowsPerPage +) { + public Pageable toPage() { + return PageRequest.of(page, rowsPerPage); + } +} diff --git a/src/main/java/com/prgrms/board/domain/post/repository/PostRepository.java b/src/main/java/com/prgrms/board/domain/post/repository/PostRepository.java new file mode 100644 index 000000000..4c4f94043 --- /dev/null +++ b/src/main/java/com/prgrms/board/domain/post/repository/PostRepository.java @@ -0,0 +1,8 @@ +package com.prgrms.board.domain.post.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.prgrms.board.domain.post.entity.Post; + +public interface PostRepository extends JpaRepository { +} diff --git a/src/main/java/com/prgrms/board/domain/post/service/PostService.java b/src/main/java/com/prgrms/board/domain/post/service/PostService.java new file mode 100644 index 000000000..4c50c78cf --- /dev/null +++ b/src/main/java/com/prgrms/board/domain/post/service/PostService.java @@ -0,0 +1,37 @@ +package com.prgrms.board.domain.post.service; + +import org.springframework.data.domain.Page; +import org.springframework.stereotype.Service; + +import com.prgrms.board.domain.post.dto.request.PostsRequest; +import com.prgrms.board.domain.post.entity.Post; +import com.prgrms.board.domain.post.repository.PostRepository; +import com.prgrms.board.global.common.PageResponse; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class PostService { + + private final PostRepository postRepository; + + public PageResponse getPosts(PostsRequest request) { + Page posts = postRepository.findAll(request.toPage()); + return PageResponse.from(posts); + } + + // public getPost() { + // + // } + // + // @Transactional + // public createPost() { + // + // } + // + // @Transactional + // public updatePost() { + // + // } +} diff --git a/src/main/java/com/prgrms/board/domain/user/repository/UserRepository.java b/src/main/java/com/prgrms/board/domain/user/repository/UserRepository.java new file mode 100644 index 000000000..c048c831d --- /dev/null +++ b/src/main/java/com/prgrms/board/domain/user/repository/UserRepository.java @@ -0,0 +1,8 @@ +package com.prgrms.board.domain.user.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.prgrms.board.domain.user.entity.User; + +public interface UserRepository extends JpaRepository { +} diff --git a/src/main/java/com/prgrms/board/global/common/BaseResponse.java b/src/main/java/com/prgrms/board/global/common/BaseResponse.java new file mode 100644 index 000000000..3ffaf1660 --- /dev/null +++ b/src/main/java/com/prgrms/board/global/common/BaseResponse.java @@ -0,0 +1,29 @@ +package com.prgrms.board.global.common; + +import static com.fasterxml.jackson.annotation.JsonInclude.Include.*; +import static org.springframework.http.HttpStatus.*; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; + +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class BaseResponse { + + private final int status; + private final String message; + + @JsonInclude(NON_NULL) + private T data; + + public static BaseResponse ok(SuccessMessage message) { + return new BaseResponse<>(OK.value(), message.getValue()); + } + + public static BaseResponse ok(SuccessMessage message, T data) { + return new BaseResponse<>(OK.value(), message.getValue(), data); + } +} diff --git a/src/main/java/com/prgrms/board/global/common/PageResponse.java b/src/main/java/com/prgrms/board/global/common/PageResponse.java new file mode 100644 index 000000000..18e858310 --- /dev/null +++ b/src/main/java/com/prgrms/board/global/common/PageResponse.java @@ -0,0 +1,16 @@ +package com.prgrms.board.global.common; + +import java.util.List; + +import org.springframework.data.domain.Page; + +public record PageResponse( + int total, + int page, + int rowsPerPage, + List items +) { + public static PageResponse from(Page page) { + return new PageResponse<>(page.getTotalPages(), page.getNumber(), page.getSize(), page.getContent()); + } +} diff --git a/src/main/java/com/prgrms/board/global/common/SuccessMessage.java b/src/main/java/com/prgrms/board/global/common/SuccessMessage.java new file mode 100644 index 000000000..6df80870d --- /dev/null +++ b/src/main/java/com/prgrms/board/global/common/SuccessMessage.java @@ -0,0 +1,14 @@ +package com.prgrms.board.global.common; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public enum SuccessMessage { + GET_POSTS_SUCCESS("게시물 조회 성공"), + ; + + private final String value; +} From 7e702812b7958b22fb34b5c813221140cb0d6e16 Mon Sep 17 00:00:00 2001 From: ymkim97 Date: Mon, 31 Jul 2023 17:56:29 +0900 Subject: [PATCH 05/23] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EB=AC=BC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../post/controller/ApiPostController.java | 16 +++++++++--- .../post/dto/request/PostCreateRequest.java | 24 ++++++++++++++++++ .../post/dto/response/PostResponse.java | 12 +++++++++ .../prgrms/board/domain/post/entity/Post.java | 6 +++++ .../domain/post/service/PostService.java | 18 ++++++++++--- .../user/exception/UserNotFoundException.java | 11 ++++++++ .../domain/user/service/UserService.java | 25 +++++++++++++++++++ .../board/global/common/BaseResponse.java | 4 +++ .../prgrms/board/global/common/ErrorCode.java | 23 +++++++++++++++++ .../board/global/common/SuccessMessage.java | 1 + .../global/exception/CustomException.java | 13 ++++++++++ 11 files changed, 145 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/prgrms/board/domain/post/dto/request/PostCreateRequest.java create mode 100644 src/main/java/com/prgrms/board/domain/post/dto/response/PostResponse.java create mode 100644 src/main/java/com/prgrms/board/domain/user/exception/UserNotFoundException.java create mode 100644 src/main/java/com/prgrms/board/domain/user/service/UserService.java create mode 100644 src/main/java/com/prgrms/board/global/common/ErrorCode.java create mode 100644 src/main/java/com/prgrms/board/global/exception/CustomException.java diff --git a/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java b/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java index d92e6d45e..e35e9786d 100644 --- a/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java +++ b/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java @@ -1,12 +1,18 @@ package com.prgrms.board.domain.post.controller; import static com.prgrms.board.global.common.SuccessMessage.*; +import static org.springframework.http.HttpStatus.*; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; +import com.prgrms.board.domain.post.dto.request.PostCreateRequest; import com.prgrms.board.domain.post.dto.request.PostsRequest; +import com.prgrms.board.domain.post.dto.response.PostResponse; import com.prgrms.board.domain.post.entity.Post; import com.prgrms.board.domain.post.service.PostService; import com.prgrms.board.global.common.BaseResponse; @@ -33,10 +39,12 @@ public BaseResponse> getPosts(@Valid PostsRequest request) { // return null; // } // - // @PostMapping - // public Post createPost() { - // return null; - // } + @PostMapping + @ResponseStatus(CREATED) + public BaseResponse createPost(@Valid @RequestBody PostCreateRequest request) { + PostResponse data = postService.createPost(request); + return BaseResponse.created(CREATE_POST_SUCCESS, data); + } // // @PatchMapping("/{postId}") // public Post updatePost() { diff --git a/src/main/java/com/prgrms/board/domain/post/dto/request/PostCreateRequest.java b/src/main/java/com/prgrms/board/domain/post/dto/request/PostCreateRequest.java new file mode 100644 index 000000000..a99b1e9e7 --- /dev/null +++ b/src/main/java/com/prgrms/board/domain/post/dto/request/PostCreateRequest.java @@ -0,0 +1,24 @@ +package com.prgrms.board.domain.post.dto.request; + +import com.prgrms.board.domain.post.entity.Post; +import com.prgrms.board.domain.user.entity.User; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +public record PostCreateRequest( + @NotNull(message = "유저 아이디는 필수입니다.") + Long userId, + + @NotBlank(message = "제목은 필수입니다.") + @Size(max = 30, message = "제목은 최대 30자까지 가능합니다.") + String title, + + @NotBlank(message = "내용은 필수입니다.") + String content +) { + public Post toEntity(User user) { + return Post.create(user, title, content); + } +} diff --git a/src/main/java/com/prgrms/board/domain/post/dto/response/PostResponse.java b/src/main/java/com/prgrms/board/domain/post/dto/response/PostResponse.java new file mode 100644 index 000000000..c8018d18b --- /dev/null +++ b/src/main/java/com/prgrms/board/domain/post/dto/response/PostResponse.java @@ -0,0 +1,12 @@ +package com.prgrms.board.domain.post.dto.response; + +import com.prgrms.board.domain.post.entity.Post; + +public record PostResponse( + Long postId, + String title +) { + public static PostResponse from(Post post) { + return new PostResponse(post.getId(), post.getTitle()); + } +} diff --git a/src/main/java/com/prgrms/board/domain/post/entity/Post.java b/src/main/java/com/prgrms/board/domain/post/entity/Post.java index 77658a79a..4f31e013a 100644 --- a/src/main/java/com/prgrms/board/domain/post/entity/Post.java +++ b/src/main/java/com/prgrms/board/domain/post/entity/Post.java @@ -13,12 +13,14 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @Entity @Getter @Table(name = "post") +@AllArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Post extends BaseEntity { @@ -36,4 +38,8 @@ public class Post extends BaseEntity { @Column(name = "content", nullable = false, columnDefinition = "text") private String content; + + public static Post create(User user, String title, String content) { + return new Post(null, user, title, content); + } } diff --git a/src/main/java/com/prgrms/board/domain/post/service/PostService.java b/src/main/java/com/prgrms/board/domain/post/service/PostService.java index 4c50c78cf..06cde74f2 100644 --- a/src/main/java/com/prgrms/board/domain/post/service/PostService.java +++ b/src/main/java/com/prgrms/board/domain/post/service/PostService.java @@ -2,19 +2,26 @@ import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import com.prgrms.board.domain.post.dto.request.PostCreateRequest; import com.prgrms.board.domain.post.dto.request.PostsRequest; +import com.prgrms.board.domain.post.dto.response.PostResponse; import com.prgrms.board.domain.post.entity.Post; import com.prgrms.board.domain.post.repository.PostRepository; +import com.prgrms.board.domain.user.entity.User; +import com.prgrms.board.domain.user.service.UserService; import com.prgrms.board.global.common.PageResponse; import lombok.RequiredArgsConstructor; @Service @RequiredArgsConstructor +@Transactional(readOnly = true) public class PostService { private final PostRepository postRepository; + private final UserService userService; public PageResponse getPosts(PostsRequest request) { Page posts = postRepository.findAll(request.toPage()); @@ -25,10 +32,13 @@ public PageResponse getPosts(PostsRequest request) { // // } // - // @Transactional - // public createPost() { - // - // } + @Transactional + public PostResponse createPost(PostCreateRequest request) { + User user = userService.findUserOrThrow(request.userId()); + Post post = postRepository.save(request.toEntity(user)); + return PostResponse.from(post); + } + // // @Transactional // public updatePost() { diff --git a/src/main/java/com/prgrms/board/domain/user/exception/UserNotFoundException.java b/src/main/java/com/prgrms/board/domain/user/exception/UserNotFoundException.java new file mode 100644 index 000000000..871d18265 --- /dev/null +++ b/src/main/java/com/prgrms/board/domain/user/exception/UserNotFoundException.java @@ -0,0 +1,11 @@ +package com.prgrms.board.domain.user.exception; + +import com.prgrms.board.global.common.ErrorCode; +import com.prgrms.board.global.exception.CustomException; + +public class UserNotFoundException extends CustomException { + + public UserNotFoundException(ErrorCode error) { + super(error); + } +} diff --git a/src/main/java/com/prgrms/board/domain/user/service/UserService.java b/src/main/java/com/prgrms/board/domain/user/service/UserService.java new file mode 100644 index 000000000..fcc7d8d69 --- /dev/null +++ b/src/main/java/com/prgrms/board/domain/user/service/UserService.java @@ -0,0 +1,25 @@ +package com.prgrms.board.domain.user.service; + +import static com.prgrms.board.global.common.ErrorCode.*; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.prgrms.board.domain.user.entity.User; +import com.prgrms.board.domain.user.exception.UserNotFoundException; +import com.prgrms.board.domain.user.repository.UserRepository; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class UserService { + + private final UserRepository userRepository; + + public User findUserOrThrow(Long userId) { + return userRepository.findById(userId) + .orElseThrow(() -> new UserNotFoundException(NO_USER)); + } +} diff --git a/src/main/java/com/prgrms/board/global/common/BaseResponse.java b/src/main/java/com/prgrms/board/global/common/BaseResponse.java index 3ffaf1660..354a3d6e4 100644 --- a/src/main/java/com/prgrms/board/global/common/BaseResponse.java +++ b/src/main/java/com/prgrms/board/global/common/BaseResponse.java @@ -26,4 +26,8 @@ public static BaseResponse ok(SuccessMessage message) { public static BaseResponse ok(SuccessMessage message, T data) { return new BaseResponse<>(OK.value(), message.getValue(), data); } + + public static BaseResponse created(SuccessMessage message, T data) { + return new BaseResponse<>(CREATED.value(), message.getValue(), data); + } } diff --git a/src/main/java/com/prgrms/board/global/common/ErrorCode.java b/src/main/java/com/prgrms/board/global/common/ErrorCode.java new file mode 100644 index 000000000..9d220790a --- /dev/null +++ b/src/main/java/com/prgrms/board/global/common/ErrorCode.java @@ -0,0 +1,23 @@ +package com.prgrms.board.global.common; + +import static org.springframework.http.HttpStatus.*; + +import org.springframework.http.HttpStatus; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public enum ErrorCode { + NO_USER(NOT_FOUND, "존재하지 않는 유저입니다."), + ; + + private final HttpStatus status; + private final String message; + + public int getStatusCode() { + return status.value(); + } +} diff --git a/src/main/java/com/prgrms/board/global/common/SuccessMessage.java b/src/main/java/com/prgrms/board/global/common/SuccessMessage.java index 6df80870d..bca69944e 100644 --- a/src/main/java/com/prgrms/board/global/common/SuccessMessage.java +++ b/src/main/java/com/prgrms/board/global/common/SuccessMessage.java @@ -8,6 +8,7 @@ @AllArgsConstructor(access = AccessLevel.PRIVATE) public enum SuccessMessage { GET_POSTS_SUCCESS("게시물 조회 성공"), + CREATE_POST_SUCCESS("게시물 생성 성공"), ; private final String value; diff --git a/src/main/java/com/prgrms/board/global/exception/CustomException.java b/src/main/java/com/prgrms/board/global/exception/CustomException.java new file mode 100644 index 000000000..c4be84b7c --- /dev/null +++ b/src/main/java/com/prgrms/board/global/exception/CustomException.java @@ -0,0 +1,13 @@ +package com.prgrms.board.global.exception; + +import com.prgrms.board.global.common.ErrorCode; + +public class CustomException extends RuntimeException { + + private final ErrorCode error; + + public CustomException(ErrorCode error) { + super(error.getMessage()); + this.error = error; + } +} From d9519aad0160137e007c3add1a4056516c6d1c47 Mon Sep 17 00:00:00 2001 From: kmebin Date: Mon, 31 Jul 2023 18:23:43 +0900 Subject: [PATCH 06/23] =?UTF-8?q?feat:=20=EC=A0=84=EC=97=AD=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../board/global/common/BaseResponse.java | 34 +++++++++------- .../global/exception/CustomException.java | 3 ++ .../exception/ExceptionControllerAdvice.java | 39 +++++++++++++++++++ 3 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/prgrms/board/global/exception/ExceptionControllerAdvice.java diff --git a/src/main/java/com/prgrms/board/global/common/BaseResponse.java b/src/main/java/com/prgrms/board/global/common/BaseResponse.java index 354a3d6e4..812ab0c3f 100644 --- a/src/main/java/com/prgrms/board/global/common/BaseResponse.java +++ b/src/main/java/com/prgrms/board/global/common/BaseResponse.java @@ -3,31 +3,39 @@ import static com.fasterxml.jackson.annotation.JsonInclude.Include.*; import static org.springframework.http.HttpStatus.*; +import org.springframework.http.HttpStatus; + import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AccessLevel; import lombok.AllArgsConstructor; +import lombok.Getter; import lombok.RequiredArgsConstructor; +@Getter @AllArgsConstructor(access = AccessLevel.PRIVATE) @RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class BaseResponse { - private final int status; - private final String message; + private final int status; + private final String message; + + @JsonInclude(NON_NULL) + private T data; - @JsonInclude(NON_NULL) - private T data; + public static BaseResponse ok(SuccessMessage message, T data) { + return new BaseResponse<>(OK.value(), message.getValue(), data); + } - public static BaseResponse ok(SuccessMessage message) { - return new BaseResponse<>(OK.value(), message.getValue()); - } + public static BaseResponse created(SuccessMessage message, T data) { + return new BaseResponse<>(CREATED.value(), message.getValue(), data); + } - public static BaseResponse ok(SuccessMessage message, T data) { - return new BaseResponse<>(OK.value(), message.getValue(), data); - } + public static BaseResponse error(ErrorCode error) { + return new BaseResponse<>(error.getStatusCode(), error.getMessage()); + } - public static BaseResponse created(SuccessMessage message, T data) { - return new BaseResponse<>(CREATED.value(), message.getValue(), data); - } + public static BaseResponse error(HttpStatus status, String message) { + return new BaseResponse<>(status.value(), message); + } } diff --git a/src/main/java/com/prgrms/board/global/exception/CustomException.java b/src/main/java/com/prgrms/board/global/exception/CustomException.java index c4be84b7c..9ddc81f03 100644 --- a/src/main/java/com/prgrms/board/global/exception/CustomException.java +++ b/src/main/java/com/prgrms/board/global/exception/CustomException.java @@ -2,6 +2,9 @@ import com.prgrms.board.global.common.ErrorCode; +import lombok.Getter; + +@Getter public class CustomException extends RuntimeException { private final ErrorCode error; diff --git a/src/main/java/com/prgrms/board/global/exception/ExceptionControllerAdvice.java b/src/main/java/com/prgrms/board/global/exception/ExceptionControllerAdvice.java new file mode 100644 index 000000000..c6452f376 --- /dev/null +++ b/src/main/java/com/prgrms/board/global/exception/ExceptionControllerAdvice.java @@ -0,0 +1,39 @@ +package com.prgrms.board.global.exception; + +import static org.springframework.http.HttpStatus.*; + +import java.util.Optional; + +import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import com.prgrms.board.domain.user.exception.UserNotFoundException; +import com.prgrms.board.global.common.BaseResponse; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RestControllerAdvice +public class ExceptionControllerAdvice { + + @ResponseStatus(BAD_REQUEST) + @ExceptionHandler(UserNotFoundException.class) + public BaseResponse handleBadRequest(CustomException exception) { + log.error("[BadRequest] => ", exception); + return BaseResponse.error(exception.getError()); + } + + @ResponseStatus(BAD_REQUEST) + @ExceptionHandler(MethodArgumentNotValidException.class) + public BaseResponse handleBadRequestException(MethodArgumentNotValidException exception) { + log.error("[BadRequest] => ", exception); + + String errorMessage = Optional.ofNullable(exception.getBindingResult().getFieldError()) + .map(DefaultMessageSourceResolvable::getDefaultMessage) + .orElse("입력 값이 올바르지 않습니다."); + return BaseResponse.error(BAD_REQUEST, errorMessage); + } +} From 93e8a49e70f9f31c2bd6dae2a05a9f28896cd681 Mon Sep 17 00:00:00 2001 From: kmebin Date: Mon, 31 Jul 2023 18:44:57 +0900 Subject: [PATCH 07/23] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EB=AC=BC=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C/=EC=88=98=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../post/controller/ApiPostController.java | 54 ++++++++-------- .../post/dto/request/PostUpdateRequest.java | 14 +++++ .../domain/post/dto/request/PostsRequest.java | 14 ++--- .../post/dto/response/PostDetailResponse.java | 24 ++++++++ .../post/dto/response/PostResponse.java | 11 ++-- .../prgrms/board/domain/post/entity/Post.java | 33 +++++----- .../post/exception/PostNotFoundException.java | 11 ++++ .../domain/post/service/PostService.java | 61 +++++++++++-------- .../prgrms/board/global/common/ErrorCode.java | 15 ++--- .../board/global/common/SuccessMessage.java | 10 +-- .../exception/ExceptionControllerAdvice.java | 6 +- 11 files changed, 167 insertions(+), 86 deletions(-) create mode 100644 src/main/java/com/prgrms/board/domain/post/dto/request/PostUpdateRequest.java create mode 100644 src/main/java/com/prgrms/board/domain/post/dto/response/PostDetailResponse.java create mode 100644 src/main/java/com/prgrms/board/domain/post/exception/PostNotFoundException.java diff --git a/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java b/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java index e35e9786d..2bb7e5a10 100644 --- a/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java +++ b/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java @@ -4,6 +4,8 @@ import static org.springframework.http.HttpStatus.*; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -11,7 +13,9 @@ import org.springframework.web.bind.annotation.RestController; import com.prgrms.board.domain.post.dto.request.PostCreateRequest; +import com.prgrms.board.domain.post.dto.request.PostUpdateRequest; import com.prgrms.board.domain.post.dto.request.PostsRequest; +import com.prgrms.board.domain.post.dto.response.PostDetailResponse; import com.prgrms.board.domain.post.dto.response.PostResponse; import com.prgrms.board.domain.post.entity.Post; import com.prgrms.board.domain.post.service.PostService; @@ -26,28 +30,30 @@ @RequestMapping("/api/v1/posts") public class ApiPostController { - private final PostService postService; - - @GetMapping - public BaseResponse> getPosts(@Valid PostsRequest request) { - PageResponse data = postService.getPosts(request); - return BaseResponse.ok(GET_POSTS_SUCCESS, data); - } - - // @GetMapping("/{postId}") - // public Post getPost() { - // return null; - // } - // - @PostMapping - @ResponseStatus(CREATED) - public BaseResponse createPost(@Valid @RequestBody PostCreateRequest request) { - PostResponse data = postService.createPost(request); - return BaseResponse.created(CREATE_POST_SUCCESS, data); - } - // - // @PatchMapping("/{postId}") - // public Post updatePost() { - // return null; - // } + private final PostService postService; + + @GetMapping + public BaseResponse> getPosts(@Valid PostsRequest request) { + PageResponse data = postService.getPosts(request); + return BaseResponse.ok(GET_POSTS_SUCCESS, data); + } + + @GetMapping("/{postId}") + public BaseResponse getPost(@PathVariable Long postId) { + PostDetailResponse data = postService.getPost(postId); + return BaseResponse.ok(GET_POST_SUCCESS, data); + } + + @PostMapping + @ResponseStatus(CREATED) + public BaseResponse createPost(@Valid @RequestBody PostCreateRequest request) { + PostResponse data = postService.createPost(request); + return BaseResponse.created(CREATE_POST_SUCCESS, data); + } + + @PatchMapping("/{postId}") + public BaseResponse updatePost(@PathVariable Long postId, @RequestBody PostUpdateRequest request) { + PostResponse data = postService.updatePost(postId, request); + return BaseResponse.ok(UPDATE_POST_SUCCESS, data); + } } diff --git a/src/main/java/com/prgrms/board/domain/post/dto/request/PostUpdateRequest.java b/src/main/java/com/prgrms/board/domain/post/dto/request/PostUpdateRequest.java new file mode 100644 index 000000000..d7f14e6e8 --- /dev/null +++ b/src/main/java/com/prgrms/board/domain/post/dto/request/PostUpdateRequest.java @@ -0,0 +1,14 @@ +package com.prgrms.board.domain.post.dto.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +public record PostUpdateRequest( + @NotBlank(message = "제목은 필수입니다.") + @Size(max = 30, message = "제목은 최대 30자까지 가능합니다.") + String title, + + @NotBlank(message = "내용은 필수입니다.") + String content +) { +} diff --git a/src/main/java/com/prgrms/board/domain/post/dto/request/PostsRequest.java b/src/main/java/com/prgrms/board/domain/post/dto/request/PostsRequest.java index e58d9127d..6286ff4ec 100644 --- a/src/main/java/com/prgrms/board/domain/post/dto/request/PostsRequest.java +++ b/src/main/java/com/prgrms/board/domain/post/dto/request/PostsRequest.java @@ -6,13 +6,13 @@ import jakarta.validation.constraints.PositiveOrZero; public record PostsRequest( - @PositiveOrZero(message = "페이지는 양수여야 합니다.") - int page, + @PositiveOrZero(message = "페이지는 양수여야 합니다.") + int page, - @PositiveOrZero(message = "한 페이지 당 게시물의 개수는 양수여야 합니다.") - int rowsPerPage + @PositiveOrZero(message = "한 페이지 당 게시물의 개수는 양수여야 합니다.") + int rowsPerPage ) { - public Pageable toPage() { - return PageRequest.of(page, rowsPerPage); - } + public Pageable toPageable() { + return PageRequest.of(page, rowsPerPage); + } } diff --git a/src/main/java/com/prgrms/board/domain/post/dto/response/PostDetailResponse.java b/src/main/java/com/prgrms/board/domain/post/dto/response/PostDetailResponse.java new file mode 100644 index 000000000..9d7704803 --- /dev/null +++ b/src/main/java/com/prgrms/board/domain/post/dto/response/PostDetailResponse.java @@ -0,0 +1,24 @@ +package com.prgrms.board.domain.post.dto.response; + +import com.prgrms.board.domain.post.entity.Post; + +import lombok.Builder; + +@Builder +public record PostDetailResponse( + Long postId, + Long userId, + String username, + String title, + String content +) { + public static PostDetailResponse from(Post post) { + return PostDetailResponse.builder() + .postId(post.getId()) + .userId(post.getUser().getId()) + .username(post.getUser().getName()) + .title(post.getTitle()) + .content(post.getContent()) + .build(); + } +} diff --git a/src/main/java/com/prgrms/board/domain/post/dto/response/PostResponse.java b/src/main/java/com/prgrms/board/domain/post/dto/response/PostResponse.java index c8018d18b..0218149fb 100644 --- a/src/main/java/com/prgrms/board/domain/post/dto/response/PostResponse.java +++ b/src/main/java/com/prgrms/board/domain/post/dto/response/PostResponse.java @@ -3,10 +3,11 @@ import com.prgrms.board.domain.post.entity.Post; public record PostResponse( - Long postId, - String title + Long postId, + String title, + String content ) { - public static PostResponse from(Post post) { - return new PostResponse(post.getId(), post.getTitle()); - } + public static PostResponse from(Post post) { + return new PostResponse(post.getId(), post.getTitle(), post.getContent()); + } } diff --git a/src/main/java/com/prgrms/board/domain/post/entity/Post.java b/src/main/java/com/prgrms/board/domain/post/entity/Post.java index 4f31e013a..b737ab05c 100644 --- a/src/main/java/com/prgrms/board/domain/post/entity/Post.java +++ b/src/main/java/com/prgrms/board/domain/post/entity/Post.java @@ -24,22 +24,27 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Post extends BaseEntity { - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - @Column(name = "post_id") - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "post_id") + private Long id; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "user_id", nullable = false) - private User user; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private User user; - @Column(name = "title", length = 30, nullable = false) - private String title; + @Column(name = "title", length = 30, nullable = false) + private String title; - @Column(name = "content", nullable = false, columnDefinition = "text") - private String content; + @Column(name = "content", nullable = false, columnDefinition = "text") + private String content; - public static Post create(User user, String title, String content) { - return new Post(null, user, title, content); - } + public static Post create(User user, String title, String content) { + return new Post(null, user, title, content); + } + + public void update(String title, String content) { + this.title = title; + this.content = content; + } } diff --git a/src/main/java/com/prgrms/board/domain/post/exception/PostNotFoundException.java b/src/main/java/com/prgrms/board/domain/post/exception/PostNotFoundException.java new file mode 100644 index 000000000..c7518bdea --- /dev/null +++ b/src/main/java/com/prgrms/board/domain/post/exception/PostNotFoundException.java @@ -0,0 +1,11 @@ +package com.prgrms.board.domain.post.exception; + +import com.prgrms.board.global.common.ErrorCode; +import com.prgrms.board.global.exception.CustomException; + +public class PostNotFoundException extends CustomException { + + public PostNotFoundException(ErrorCode error) { + super(error); + } +} diff --git a/src/main/java/com/prgrms/board/domain/post/service/PostService.java b/src/main/java/com/prgrms/board/domain/post/service/PostService.java index 06cde74f2..652f30d4d 100644 --- a/src/main/java/com/prgrms/board/domain/post/service/PostService.java +++ b/src/main/java/com/prgrms/board/domain/post/service/PostService.java @@ -1,13 +1,18 @@ package com.prgrms.board.domain.post.service; +import static com.prgrms.board.global.common.ErrorCode.*; + import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.prgrms.board.domain.post.dto.request.PostCreateRequest; +import com.prgrms.board.domain.post.dto.request.PostUpdateRequest; import com.prgrms.board.domain.post.dto.request.PostsRequest; +import com.prgrms.board.domain.post.dto.response.PostDetailResponse; import com.prgrms.board.domain.post.dto.response.PostResponse; import com.prgrms.board.domain.post.entity.Post; +import com.prgrms.board.domain.post.exception.PostNotFoundException; import com.prgrms.board.domain.post.repository.PostRepository; import com.prgrms.board.domain.user.entity.User; import com.prgrms.board.domain.user.service.UserService; @@ -20,28 +25,36 @@ @Transactional(readOnly = true) public class PostService { - private final PostRepository postRepository; - private final UserService userService; - - public PageResponse getPosts(PostsRequest request) { - Page posts = postRepository.findAll(request.toPage()); - return PageResponse.from(posts); - } - - // public getPost() { - // - // } - // - @Transactional - public PostResponse createPost(PostCreateRequest request) { - User user = userService.findUserOrThrow(request.userId()); - Post post = postRepository.save(request.toEntity(user)); - return PostResponse.from(post); - } - - // - // @Transactional - // public updatePost() { - // - // } + private final PostRepository postRepository; + private final UserService userService; + + public PageResponse getPosts(PostsRequest request) { + Page posts = postRepository.findAll(request.toPageable()); + return PageResponse.from(posts); + } + + public PostDetailResponse getPost(Long postId) { + Post post = findPostOrThrow(postId); + return PostDetailResponse.from(post); + } + + @Transactional + public PostResponse createPost(PostCreateRequest request) { + User user = userService.findUserOrThrow(request.userId()); + Post post = postRepository.save(request.toEntity(user)); + return PostResponse.from(post); + } + + @Transactional + public PostResponse updatePost(Long postId, PostUpdateRequest request) { + Post post = findPostOrThrow(postId); + post.update(request.title(), request.content()); + return PostResponse.from(post); + } + + private Post findPostOrThrow(Long postId) { + return postRepository.findById(postId) + .orElseThrow(() -> new PostNotFoundException(NO_POST)); + } + } diff --git a/src/main/java/com/prgrms/board/global/common/ErrorCode.java b/src/main/java/com/prgrms/board/global/common/ErrorCode.java index 9d220790a..fdc57e5dd 100644 --- a/src/main/java/com/prgrms/board/global/common/ErrorCode.java +++ b/src/main/java/com/prgrms/board/global/common/ErrorCode.java @@ -11,13 +11,14 @@ @Getter @AllArgsConstructor(access = AccessLevel.PRIVATE) public enum ErrorCode { - NO_USER(NOT_FOUND, "존재하지 않는 유저입니다."), - ; + NO_USER(NOT_FOUND, "존재하지 않는 유저입니다."), + NO_POST(NOT_FOUND, "존재하지 않는 게시물입니다."), + ; - private final HttpStatus status; - private final String message; + private final HttpStatus status; + private final String message; - public int getStatusCode() { - return status.value(); - } + public int getStatusCode() { + return status.value(); + } } diff --git a/src/main/java/com/prgrms/board/global/common/SuccessMessage.java b/src/main/java/com/prgrms/board/global/common/SuccessMessage.java index bca69944e..829340287 100644 --- a/src/main/java/com/prgrms/board/global/common/SuccessMessage.java +++ b/src/main/java/com/prgrms/board/global/common/SuccessMessage.java @@ -7,9 +7,11 @@ @Getter @AllArgsConstructor(access = AccessLevel.PRIVATE) public enum SuccessMessage { - GET_POSTS_SUCCESS("게시물 조회 성공"), - CREATE_POST_SUCCESS("게시물 생성 성공"), - ; + GET_POSTS_SUCCESS("게시물 전체 조회 성공"), + GET_POST_SUCCESS("게시물 조회 성공"), + CREATE_POST_SUCCESS("게시물 생성 성공"), + UPDATE_POST_SUCCESS("게시물 수정 성공"), + ; - private final String value; + private final String value; } diff --git a/src/main/java/com/prgrms/board/global/exception/ExceptionControllerAdvice.java b/src/main/java/com/prgrms/board/global/exception/ExceptionControllerAdvice.java index c6452f376..62326012f 100644 --- a/src/main/java/com/prgrms/board/global/exception/ExceptionControllerAdvice.java +++ b/src/main/java/com/prgrms/board/global/exception/ExceptionControllerAdvice.java @@ -10,6 +10,7 @@ import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; +import com.prgrms.board.domain.post.exception.PostNotFoundException; import com.prgrms.board.domain.user.exception.UserNotFoundException; import com.prgrms.board.global.common.BaseResponse; @@ -20,7 +21,10 @@ public class ExceptionControllerAdvice { @ResponseStatus(BAD_REQUEST) - @ExceptionHandler(UserNotFoundException.class) + @ExceptionHandler({ + UserNotFoundException.class, + PostNotFoundException.class, + }) public BaseResponse handleBadRequest(CustomException exception) { log.error("[BadRequest] => ", exception); return BaseResponse.error(exception.getError()); From 5f9a6534d0eae0fa65a35e776f0a1f39c26fdea8 Mon Sep 17 00:00:00 2001 From: kmebin Date: Mon, 31 Jul 2023 18:55:24 +0900 Subject: [PATCH 08/23] =?UTF-8?q?chore:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=A4=84=EB=B0=94=EA=BF=88=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/prgrms/board/domain/post/service/PostService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/prgrms/board/domain/post/service/PostService.java b/src/main/java/com/prgrms/board/domain/post/service/PostService.java index 652f30d4d..733581125 100644 --- a/src/main/java/com/prgrms/board/domain/post/service/PostService.java +++ b/src/main/java/com/prgrms/board/domain/post/service/PostService.java @@ -56,5 +56,4 @@ private Post findPostOrThrow(Long postId) { return postRepository.findById(postId) .orElseThrow(() -> new PostNotFoundException(NO_POST)); } - } From 1258eaea39b17ee921e8349887ede15c32a4b780 Mon Sep 17 00:00:00 2001 From: ymkim97 Date: Tue, 1 Aug 2023 23:08:04 +0900 Subject: [PATCH 09/23] feat: createPost RestDoc --- build.gradle | 42 +++++++++++- src/docs/asciidoc/index.adoc | 13 ++++ .../prgrms/board/domain/user/entity/User.java | 3 +- .../board/global/configuration/JpaConfig.java | 9 +++ .../exception/ExceptionControllerAdvice.java | 40 ++++++------ .../prgrms/board/BoardApplicationTests.java | 13 ---- .../controller/ApiPostControllerTest.java | 64 +++++++++++++++++++ .../com/prgrms/board/support/UserFixture.java | 10 +++ 8 files changed, 159 insertions(+), 35 deletions(-) create mode 100644 src/docs/asciidoc/index.adoc create mode 100644 src/main/java/com/prgrms/board/global/configuration/JpaConfig.java delete mode 100644 src/test/java/com/prgrms/board/BoardApplicationTests.java create mode 100644 src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java create mode 100644 src/test/java/com/prgrms/board/support/UserFixture.java diff --git a/build.gradle b/build.gradle index 470e55bbe..d95213b99 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,7 @@ plugins { id 'java' id 'org.springframework.boot' version '3.1.2' id 'io.spring.dependency-management' version '1.1.2' + id "org.asciidoctor.jvm.convert" version "3.3.2" } group = 'com.prgrms' @@ -17,21 +18,60 @@ configurations { } } +ext { + snippetsDir = file('build/generated-snippets') +} + +bootJar { + dependsOn asciidoctor + copy { + from "${asciidoctor.outputDir}" + into 'BOOT-INF/classes/static/docs' + } +} + repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springframework.boot:spring-boot-starter-web' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + runtimeOnly 'com.h2database:h2' + runtimeOnly 'com.mysql:mysql-connector-j' - annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + + testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' } tasks.named('test') { useJUnitPlatform() } + +asciidoctor { + dependsOn test + inputs.dir snippetsDir +} + +asciidoctor.doFirst { + delete file('src/main/resources/static/docs') +} + +tasks.register('copyDocument', Copy) { + dependsOn asciidoctor + from file("build/docs/asciidoc") + into file("src/main/resources/static/docs") +} + +build { + dependsOn copyDocument +} diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc new file mode 100644 index 000000000..456c5c2d6 --- /dev/null +++ b/src/docs/asciidoc/index.adoc @@ -0,0 +1,13 @@ += Board REST API + +== 게시판 생성 하기 + +=== REQUEST + +include::{snippets}/posts/createPost/http-request.adoc[] + +=== RESPONSE + +include::{snippets}/posts/createPost/http-response.adoc[] + + diff --git a/src/main/java/com/prgrms/board/domain/user/entity/User.java b/src/main/java/com/prgrms/board/domain/user/entity/User.java index 2c8056fa7..827b3efda 100644 --- a/src/main/java/com/prgrms/board/domain/user/entity/User.java +++ b/src/main/java/com/prgrms/board/domain/user/entity/User.java @@ -1,7 +1,6 @@ package com.prgrms.board.domain.user.entity; import com.prgrms.board.global.common.BaseEntity; - import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -9,12 +8,14 @@ import jakarta.persistence.Id; import jakarta.persistence.Table; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @Entity @Getter @Table(name = "user") +@AllArgsConstructor @NoArgsConstructor(access = AccessLevel.PROTECTED) public class User extends BaseEntity { diff --git a/src/main/java/com/prgrms/board/global/configuration/JpaConfig.java b/src/main/java/com/prgrms/board/global/configuration/JpaConfig.java new file mode 100644 index 000000000..6d6d77515 --- /dev/null +++ b/src/main/java/com/prgrms/board/global/configuration/JpaConfig.java @@ -0,0 +1,9 @@ +package com.prgrms.board.global.configuration; + +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; + +@Configuration +@EnableJpaAuditing +public class JpaConfig { +} diff --git a/src/main/java/com/prgrms/board/global/exception/ExceptionControllerAdvice.java b/src/main/java/com/prgrms/board/global/exception/ExceptionControllerAdvice.java index 62326012f..22a03031d 100644 --- a/src/main/java/com/prgrms/board/global/exception/ExceptionControllerAdvice.java +++ b/src/main/java/com/prgrms/board/global/exception/ExceptionControllerAdvice.java @@ -20,24 +20,24 @@ @RestControllerAdvice public class ExceptionControllerAdvice { - @ResponseStatus(BAD_REQUEST) - @ExceptionHandler({ - UserNotFoundException.class, - PostNotFoundException.class, - }) - public BaseResponse handleBadRequest(CustomException exception) { - log.error("[BadRequest] => ", exception); - return BaseResponse.error(exception.getError()); - } - - @ResponseStatus(BAD_REQUEST) - @ExceptionHandler(MethodArgumentNotValidException.class) - public BaseResponse handleBadRequestException(MethodArgumentNotValidException exception) { - log.error("[BadRequest] => ", exception); - - String errorMessage = Optional.ofNullable(exception.getBindingResult().getFieldError()) - .map(DefaultMessageSourceResolvable::getDefaultMessage) - .orElse("입력 값이 올바르지 않습니다."); - return BaseResponse.error(BAD_REQUEST, errorMessage); - } + @ResponseStatus(NOT_FOUND) + @ExceptionHandler({ + UserNotFoundException.class, + PostNotFoundException.class, + }) + public BaseResponse handleNotFound(CustomException exception) { + log.error("[NotFound] => ", exception); + return BaseResponse.error(exception.getError()); + } + + @ResponseStatus(BAD_REQUEST) + @ExceptionHandler(MethodArgumentNotValidException.class) + public BaseResponse handleBadRequestException(MethodArgumentNotValidException exception) { + log.error("[BadRequest] => ", exception); + + String errorMessage = Optional.ofNullable(exception.getBindingResult().getFieldError()) + .map(DefaultMessageSourceResolvable::getDefaultMessage) + .orElse("입력 값이 올바르지 않습니다."); + return BaseResponse.error(BAD_REQUEST, errorMessage); + } } diff --git a/src/test/java/com/prgrms/board/BoardApplicationTests.java b/src/test/java/com/prgrms/board/BoardApplicationTests.java deleted file mode 100644 index fc6efcf6e..000000000 --- a/src/test/java/com/prgrms/board/BoardApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.prgrms.board; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class BoardApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java b/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java new file mode 100644 index 000000000..981e12c33 --- /dev/null +++ b/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java @@ -0,0 +1,64 @@ +package com.prgrms.board.domain.post.controller; + +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.prgrms.board.domain.post.dto.request.PostCreateRequest; +import com.prgrms.board.domain.post.service.PostService; +import com.prgrms.board.domain.user.entity.User; +import com.prgrms.board.domain.user.repository.UserRepository; +import com.prgrms.board.support.UserFixture; + +@SpringBootTest +@AutoConfigureMockMvc +@AutoConfigureRestDocs +class ApiPostControllerTest { + + @Autowired + MockMvc mockMvc; + + @Autowired + PostService postService; + + @Autowired + ObjectMapper objectMapper; + + @Autowired + UserRepository userRepository; + + User user; + + @BeforeEach + void init() { + user = UserFixture.create(); + userRepository.save(user); + } + + @Test + @DisplayName("게시물 생성에 성공한다.") + void create_post_success() throws Exception { + // given + PostCreateRequest request = new PostCreateRequest(user.getId(), "title", "content"); + + // when & then + mockMvc.perform(post("/api/v1/posts") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andDo(print()) + .andDo(document("posts/createPost")) + .andExpect(status().isCreated()); + } +} \ No newline at end of file diff --git a/src/test/java/com/prgrms/board/support/UserFixture.java b/src/test/java/com/prgrms/board/support/UserFixture.java new file mode 100644 index 000000000..cc3c519b4 --- /dev/null +++ b/src/test/java/com/prgrms/board/support/UserFixture.java @@ -0,0 +1,10 @@ +package com.prgrms.board.support; + +import com.prgrms.board.domain.user.entity.User; + +public class UserFixture { + + public static User create() { + return new User(1L, "test", 10, "post"); + } +} From b7d51289378fc0a30631d126bb8b84738108652d Mon Sep 17 00:00:00 2001 From: ymkim97 Date: Wed, 2 Aug 2023 16:55:15 +0900 Subject: [PATCH 10/23] =?UTF-8?q?test:=20PostController=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../post/controller/ApiPostController.java | 59 +++++++++-------- .../domain/post/dto/request/PostsRequest.java | 18 ----- .../domain/post/service/PostService.java | 65 +++++++++---------- .../board/global/common/PageResponse.java | 17 +++-- .../controller/ApiPostControllerTest.java | 60 +++++++++++++++++ .../com/prgrms/board/support/PostFixture.java | 11 ++++ 6 files changed, 146 insertions(+), 84 deletions(-) delete mode 100644 src/main/java/com/prgrms/board/domain/post/dto/request/PostsRequest.java create mode 100644 src/test/java/com/prgrms/board/support/PostFixture.java diff --git a/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java b/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java index 2bb7e5a10..5abc9e1a4 100644 --- a/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java +++ b/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java @@ -3,6 +3,9 @@ import static com.prgrms.board.global.common.SuccessMessage.*; import static org.springframework.http.HttpStatus.*; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.web.PageableDefault; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -14,14 +17,12 @@ import com.prgrms.board.domain.post.dto.request.PostCreateRequest; import com.prgrms.board.domain.post.dto.request.PostUpdateRequest; -import com.prgrms.board.domain.post.dto.request.PostsRequest; import com.prgrms.board.domain.post.dto.response.PostDetailResponse; import com.prgrms.board.domain.post.dto.response.PostResponse; import com.prgrms.board.domain.post.entity.Post; import com.prgrms.board.domain.post.service.PostService; import com.prgrms.board.global.common.BaseResponse; import com.prgrms.board.global.common.PageResponse; - import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -30,30 +31,32 @@ @RequestMapping("/api/v1/posts") public class ApiPostController { - private final PostService postService; - - @GetMapping - public BaseResponse> getPosts(@Valid PostsRequest request) { - PageResponse data = postService.getPosts(request); - return BaseResponse.ok(GET_POSTS_SUCCESS, data); - } - - @GetMapping("/{postId}") - public BaseResponse getPost(@PathVariable Long postId) { - PostDetailResponse data = postService.getPost(postId); - return BaseResponse.ok(GET_POST_SUCCESS, data); - } - - @PostMapping - @ResponseStatus(CREATED) - public BaseResponse createPost(@Valid @RequestBody PostCreateRequest request) { - PostResponse data = postService.createPost(request); - return BaseResponse.created(CREATE_POST_SUCCESS, data); - } - - @PatchMapping("/{postId}") - public BaseResponse updatePost(@PathVariable Long postId, @RequestBody PostUpdateRequest request) { - PostResponse data = postService.updatePost(postId, request); - return BaseResponse.ok(UPDATE_POST_SUCCESS, data); - } + private final PostService postService; + + @GetMapping + public BaseResponse> getPosts( + @PageableDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable + ) { + PageResponse data = postService.getPosts(pageable); + return BaseResponse.ok(GET_POSTS_SUCCESS, data); + } + + @GetMapping("/{postId}") + public BaseResponse getPost(@PathVariable Long postId) { + PostDetailResponse data = postService.getPost(postId); + return BaseResponse.ok(GET_POST_SUCCESS, data); + } + + @PostMapping + @ResponseStatus(CREATED) + public BaseResponse createPost(@Valid @RequestBody PostCreateRequest request) { + PostResponse data = postService.createPost(request); + return BaseResponse.created(CREATE_POST_SUCCESS, data); + } + + @PatchMapping("/{postId}") + public BaseResponse updatePost(@PathVariable Long postId, @RequestBody PostUpdateRequest request) { + PostResponse data = postService.updatePost(postId, request); + return BaseResponse.ok(UPDATE_POST_SUCCESS, data); + } } diff --git a/src/main/java/com/prgrms/board/domain/post/dto/request/PostsRequest.java b/src/main/java/com/prgrms/board/domain/post/dto/request/PostsRequest.java deleted file mode 100644 index 6286ff4ec..000000000 --- a/src/main/java/com/prgrms/board/domain/post/dto/request/PostsRequest.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.prgrms.board.domain.post.dto.request; - -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; - -import jakarta.validation.constraints.PositiveOrZero; - -public record PostsRequest( - @PositiveOrZero(message = "페이지는 양수여야 합니다.") - int page, - - @PositiveOrZero(message = "한 페이지 당 게시물의 개수는 양수여야 합니다.") - int rowsPerPage -) { - public Pageable toPageable() { - return PageRequest.of(page, rowsPerPage); - } -} diff --git a/src/main/java/com/prgrms/board/domain/post/service/PostService.java b/src/main/java/com/prgrms/board/domain/post/service/PostService.java index 733581125..7d15052a4 100644 --- a/src/main/java/com/prgrms/board/domain/post/service/PostService.java +++ b/src/main/java/com/prgrms/board/domain/post/service/PostService.java @@ -3,12 +3,12 @@ import static com.prgrms.board.global.common.ErrorCode.*; import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.prgrms.board.domain.post.dto.request.PostCreateRequest; import com.prgrms.board.domain.post.dto.request.PostUpdateRequest; -import com.prgrms.board.domain.post.dto.request.PostsRequest; import com.prgrms.board.domain.post.dto.response.PostDetailResponse; import com.prgrms.board.domain.post.dto.response.PostResponse; import com.prgrms.board.domain.post.entity.Post; @@ -17,7 +17,6 @@ import com.prgrms.board.domain.user.entity.User; import com.prgrms.board.domain.user.service.UserService; import com.prgrms.board.global.common.PageResponse; - import lombok.RequiredArgsConstructor; @Service @@ -25,35 +24,35 @@ @Transactional(readOnly = true) public class PostService { - private final PostRepository postRepository; - private final UserService userService; - - public PageResponse getPosts(PostsRequest request) { - Page posts = postRepository.findAll(request.toPageable()); - return PageResponse.from(posts); - } - - public PostDetailResponse getPost(Long postId) { - Post post = findPostOrThrow(postId); - return PostDetailResponse.from(post); - } - - @Transactional - public PostResponse createPost(PostCreateRequest request) { - User user = userService.findUserOrThrow(request.userId()); - Post post = postRepository.save(request.toEntity(user)); - return PostResponse.from(post); - } - - @Transactional - public PostResponse updatePost(Long postId, PostUpdateRequest request) { - Post post = findPostOrThrow(postId); - post.update(request.title(), request.content()); - return PostResponse.from(post); - } - - private Post findPostOrThrow(Long postId) { - return postRepository.findById(postId) - .orElseThrow(() -> new PostNotFoundException(NO_POST)); - } + private final PostRepository postRepository; + private final UserService userService; + + public PageResponse getPosts(Pageable pageable) { + Page posts = postRepository.findAll(pageable); + return PageResponse.from(posts); + } + + public PostDetailResponse getPost(Long postId) { + Post post = findPostOrThrow(postId); + return PostDetailResponse.from(post); + } + + @Transactional + public PostResponse createPost(PostCreateRequest request) { + User user = userService.findUserOrThrow(request.userId()); + Post post = postRepository.save(request.toEntity(user)); + return PostResponse.from(post); + } + + @Transactional + public PostResponse updatePost(Long postId, PostUpdateRequest request) { + Post post = findPostOrThrow(postId); + post.update(request.title(), request.content()); + return PostResponse.from(post); + } + + private Post findPostOrThrow(Long postId) { + return postRepository.findById(postId) + .orElseThrow(() -> new PostNotFoundException(NO_POST)); + } } diff --git a/src/main/java/com/prgrms/board/global/common/PageResponse.java b/src/main/java/com/prgrms/board/global/common/PageResponse.java index 18e858310..821c10be4 100644 --- a/src/main/java/com/prgrms/board/global/common/PageResponse.java +++ b/src/main/java/com/prgrms/board/global/common/PageResponse.java @@ -1,16 +1,23 @@ package com.prgrms.board.global.common; -import java.util.List; - import org.springframework.data.domain.Page; +import java.util.List; + public record PageResponse( - int total, + long totalCount, + int totalPage, int page, - int rowsPerPage, + int size, List items ) { public static PageResponse from(Page page) { - return new PageResponse<>(page.getTotalPages(), page.getNumber(), page.getSize(), page.getContent()); + return new PageResponse<>( + page.getTotalElements(), + page.getTotalPages(), + page.getNumber(), + page.getSize(), + page.getContent() + ); } } diff --git a/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java b/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java index 981e12c33..ad5673092 100644 --- a/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java +++ b/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java @@ -17,9 +17,13 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.prgrms.board.domain.post.dto.request.PostCreateRequest; +import com.prgrms.board.domain.post.dto.request.PostUpdateRequest; +import com.prgrms.board.domain.post.entity.Post; +import com.prgrms.board.domain.post.repository.PostRepository; import com.prgrms.board.domain.post.service.PostService; import com.prgrms.board.domain.user.entity.User; import com.prgrms.board.domain.user.repository.UserRepository; +import com.prgrms.board.support.PostFixture; import com.prgrms.board.support.UserFixture; @SpringBootTest @@ -36,6 +40,9 @@ class ApiPostControllerTest { @Autowired ObjectMapper objectMapper; + @Autowired + PostRepository postRepository; + @Autowired UserRepository userRepository; @@ -61,4 +68,57 @@ void create_post_success() throws Exception { .andDo(document("posts/createPost")) .andExpect(status().isCreated()); } + + @Test + @DisplayName("게시물 전체 조회에 성공한다.") + void get_posts_success() throws Exception { + // given + postRepository.save(PostFixture.create(user, "Title1", "내용1")); + postRepository.save(PostFixture.create(user, "Title2", "내용2")); + postRepository.save(PostFixture.create(user, "Title3", "내용3")); + + // when & then + mockMvc.perform(get("/api/v1/posts") + .param("page", "1") + .param("size", "2") + ) + .andDo(print()) + .andDo(document("posts/getPosts")) + .andExpect(status().isOk()); + } + + @Test + @DisplayName("게시물 조회에 성공한다.") + void get_post_success() throws Exception { + // given + Post post = PostFixture.create(user, "제목", "내용"); + postRepository.save(post); + + // when & then + mockMvc.perform(get("/api/v1/posts/" + post.getId()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(post)) + ) + .andDo(print()) + .andDo(document("posts/getPost")) + .andExpect(status().isOk()); + } + + @Test + @DisplayName("게시물 수정에 성공한다.") + void update_post_success() throws Exception { + // given + Post post = PostFixture.create(user, "제목", "내용"); + postRepository.save(post); + PostUpdateRequest request = new PostUpdateRequest("수정한 제목", "수정한 내용"); + + // when & then + mockMvc.perform(patch("/api/v1/posts/" + post.getId()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request)) + ) + .andDo(print()) + .andDo(document("posts/updatePost")) + .andExpect(status().isOk()); + } } \ No newline at end of file diff --git a/src/test/java/com/prgrms/board/support/PostFixture.java b/src/test/java/com/prgrms/board/support/PostFixture.java new file mode 100644 index 000000000..59a3d72b4 --- /dev/null +++ b/src/test/java/com/prgrms/board/support/PostFixture.java @@ -0,0 +1,11 @@ +package com.prgrms.board.support; + +import com.prgrms.board.domain.post.entity.Post; +import com.prgrms.board.domain.user.entity.User; + +public class PostFixture { + + public static Post create(User user, String title, String content) { + return Post.create(user, title, content); + } +} From 1bd1b3065c07c49d7b1dc519e17d756dce082da3 Mon Sep 17 00:00:00 2001 From: kmebin Date: Wed, 2 Aug 2023 17:49:58 +0900 Subject: [PATCH 11/23] =?UTF-8?q?fix:=20UserFixture=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../prgrms/board/domain/user/entity/User.java | 26 ++- .../board/global/common/PageResponse.java | 33 ++-- .../controller/ApiPostControllerTest.java | 186 +++++++++--------- .../com/prgrms/board/support/UserFixture.java | 6 +- 4 files changed, 130 insertions(+), 121 deletions(-) diff --git a/src/main/java/com/prgrms/board/domain/user/entity/User.java b/src/main/java/com/prgrms/board/domain/user/entity/User.java index 827b3efda..166d2f693 100644 --- a/src/main/java/com/prgrms/board/domain/user/entity/User.java +++ b/src/main/java/com/prgrms/board/domain/user/entity/User.java @@ -1,6 +1,7 @@ package com.prgrms.board.domain.user.entity; import com.prgrms.board.global.common.BaseEntity; + import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -19,17 +20,22 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class User extends BaseEntity { - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - @Column(name = "user_id") - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "user_id") + private Long id; + + @Column(name = "name", length = 30, nullable = false) + private String name; + + @Column(name = "age", nullable = false) + private int age; - @Column(name = "name", length = 30, nullable = false) - private String name; + @Column(name = "hobby", length = 50) + private String hobby; - @Column(name = "age", nullable = false) - private int age; + public static User create(String name, int age, String hobby) { + return new User(null, name, age, hobby); + } - @Column(name = "hobby", length = 50) - private String hobby; } diff --git a/src/main/java/com/prgrms/board/global/common/PageResponse.java b/src/main/java/com/prgrms/board/global/common/PageResponse.java index 821c10be4..10e59ed2c 100644 --- a/src/main/java/com/prgrms/board/global/common/PageResponse.java +++ b/src/main/java/com/prgrms/board/global/common/PageResponse.java @@ -1,23 +1,24 @@ package com.prgrms.board.global.common; -import org.springframework.data.domain.Page; - import java.util.List; +import org.springframework.data.domain.Page; + public record PageResponse( - long totalCount, - int totalPage, - int page, - int size, - List items + long totalCount, + int totalPage, + int page, + int size, + List items ) { - public static PageResponse from(Page page) { - return new PageResponse<>( - page.getTotalElements(), - page.getTotalPages(), - page.getNumber(), - page.getSize(), - page.getContent() - ); - } + public static PageResponse from(Page page) { + System.out.println(page); + return new PageResponse<>( + page.getTotalElements(), + page.getTotalPages(), + page.getNumber(), + page.getSize(), + page.getContent() + ); + } } diff --git a/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java b/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java index ad5673092..909409ba4 100644 --- a/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java +++ b/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java @@ -14,6 +14,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.transaction.annotation.Transactional; import com.fasterxml.jackson.databind.ObjectMapper; import com.prgrms.board.domain.post.dto.request.PostCreateRequest; @@ -26,99 +27,100 @@ import com.prgrms.board.support.PostFixture; import com.prgrms.board.support.UserFixture; +@Transactional @SpringBootTest -@AutoConfigureMockMvc @AutoConfigureRestDocs +@AutoConfigureMockMvc class ApiPostControllerTest { - @Autowired - MockMvc mockMvc; - - @Autowired - PostService postService; - - @Autowired - ObjectMapper objectMapper; - - @Autowired - PostRepository postRepository; - - @Autowired - UserRepository userRepository; - - User user; - - @BeforeEach - void init() { - user = UserFixture.create(); - userRepository.save(user); - } - - @Test - @DisplayName("게시물 생성에 성공한다.") - void create_post_success() throws Exception { - // given - PostCreateRequest request = new PostCreateRequest(user.getId(), "title", "content"); - - // when & then - mockMvc.perform(post("/api/v1/posts") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(request))) - .andDo(print()) - .andDo(document("posts/createPost")) - .andExpect(status().isCreated()); - } - - @Test - @DisplayName("게시물 전체 조회에 성공한다.") - void get_posts_success() throws Exception { - // given - postRepository.save(PostFixture.create(user, "Title1", "내용1")); - postRepository.save(PostFixture.create(user, "Title2", "내용2")); - postRepository.save(PostFixture.create(user, "Title3", "내용3")); - - // when & then - mockMvc.perform(get("/api/v1/posts") - .param("page", "1") - .param("size", "2") - ) - .andDo(print()) - .andDo(document("posts/getPosts")) - .andExpect(status().isOk()); - } - - @Test - @DisplayName("게시물 조회에 성공한다.") - void get_post_success() throws Exception { - // given - Post post = PostFixture.create(user, "제목", "내용"); - postRepository.save(post); - - // when & then - mockMvc.perform(get("/api/v1/posts/" + post.getId()) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(post)) - ) - .andDo(print()) - .andDo(document("posts/getPost")) - .andExpect(status().isOk()); - } - - @Test - @DisplayName("게시물 수정에 성공한다.") - void update_post_success() throws Exception { - // given - Post post = PostFixture.create(user, "제목", "내용"); - postRepository.save(post); - PostUpdateRequest request = new PostUpdateRequest("수정한 제목", "수정한 내용"); - - // when & then - mockMvc.perform(patch("/api/v1/posts/" + post.getId()) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(request)) - ) - .andDo(print()) - .andDo(document("posts/updatePost")) - .andExpect(status().isOk()); - } -} \ No newline at end of file + @Autowired + MockMvc mockMvc; + + @Autowired + PostService postService; + + @Autowired + ObjectMapper objectMapper; + + @Autowired + PostRepository postRepository; + + @Autowired + UserRepository userRepository; + + User user; + + @BeforeEach + void init() { + user = UserFixture.create(); + userRepository.save(user); + } + + @Test + @DisplayName("게시물 생성에 성공한다.") + void create_post_success() throws Exception { + // given + PostCreateRequest request = new PostCreateRequest(user.getId(), "title", "content"); + + // when & then + mockMvc.perform(post("/api/v1/posts") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andDo(print()) + .andDo(document("posts/createPost")) + .andExpect(status().isCreated()); + } + + @Test + @DisplayName("게시물 전체 조회에 성공한다.") + void get_posts_success() throws Exception { + // given + postRepository.save(PostFixture.create(user, "Title1", "내용1")); + postRepository.save(PostFixture.create(user, "Title2", "내용2")); + postRepository.save(PostFixture.create(user, "Title3", "내용3")); + + // when & then + mockMvc.perform(get("/api/v1/posts") + .param("page", "1") + .param("size", "2") + ) + .andDo(print()) + .andDo(document("posts/getPosts")) + .andExpect(status().isOk()); + } + + @Test + @DisplayName("게시물 조회에 성공한다.") + void get_post_success() throws Exception { + // given + Post post = PostFixture.create(user, "제목", "내용"); + postRepository.save(post); + + // when & then + mockMvc.perform(get("/api/v1/posts/" + post.getId()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(post)) + ) + .andDo(print()) + .andDo(document("posts/getPost")) + .andExpect(status().isOk()); + } + + @Test + @DisplayName("게시물 수정에 성공한다.") + void update_post_success() throws Exception { + // given + Post post = PostFixture.create(user, "제목", "내용"); + postRepository.save(post); + PostUpdateRequest request = new PostUpdateRequest("수정한 제목", "수정한 내용"); + + // when & then + mockMvc.perform(patch("/api/v1/posts/" + post.getId()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request)) + ) + .andDo(print()) + .andDo(document("posts/updatePost")) + .andExpect(status().isOk()); + } +} diff --git a/src/test/java/com/prgrms/board/support/UserFixture.java b/src/test/java/com/prgrms/board/support/UserFixture.java index cc3c519b4..25069444d 100644 --- a/src/test/java/com/prgrms/board/support/UserFixture.java +++ b/src/test/java/com/prgrms/board/support/UserFixture.java @@ -4,7 +4,7 @@ public class UserFixture { - public static User create() { - return new User(1L, "test", 10, "post"); - } + public static User create() { + return User.create("test", 10, "post"); + } } From baf19ea8175c363fefe64234750332247772a7c3 Mon Sep 17 00:00:00 2001 From: kmebin Date: Wed, 2 Aug 2023 17:56:38 +0900 Subject: [PATCH 12/23] =?UTF-8?q?feat:=20prettyPrint=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/docs/asciidoc/index.adoc | 30 ++++++++++++++++++- .../prgrms/board/domain/post/entity/Post.java | 2 ++ .../controller/ApiPostControllerTest.java | 26 +++++++++++----- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc index 456c5c2d6..4d685a0df 100644 --- a/src/docs/asciidoc/index.adoc +++ b/src/docs/asciidoc/index.adoc @@ -1,6 +1,6 @@ = Board REST API -== 게시판 생성 하기 +== 게시물 생성 === REQUEST @@ -10,4 +10,32 @@ include::{snippets}/posts/createPost/http-request.adoc[] include::{snippets}/posts/createPost/http-response.adoc[] +== 게시물 전체 조회 +=== REQUEST + +include::{snippets}/posts/getPosts/http-request.adoc[] + +=== RESPONSE + +include::{snippets}/posts/getPosts/http-response.adoc[] + +== 게시물 조회 + +=== REQUEST + +include::{snippets}/posts/getPost/http-request.adoc[] + +=== RESPONSE + +include::{snippets}/posts/getPost/http-response.adoc[] + +== 게시물 수정 + +=== REQUEST + +include::{snippets}/posts/updatePost/http-request.adoc[] + +=== RESPONSE + +include::{snippets}/posts/updatePost/http-response.adoc[] diff --git a/src/main/java/com/prgrms/board/domain/post/entity/Post.java b/src/main/java/com/prgrms/board/domain/post/entity/Post.java index b737ab05c..50972dc32 100644 --- a/src/main/java/com/prgrms/board/domain/post/entity/Post.java +++ b/src/main/java/com/prgrms/board/domain/post/entity/Post.java @@ -1,5 +1,6 @@ package com.prgrms.board.domain.post.entity; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.prgrms.board.domain.user.entity.User; import com.prgrms.board.global.common.BaseEntity; @@ -29,6 +30,7 @@ public class Post extends BaseEntity { @Column(name = "post_id") private Long id; + @JsonIgnore @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id", nullable = false) private User user; diff --git a/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java b/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java index 909409ba4..7e307b4dc 100644 --- a/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java +++ b/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java @@ -1,6 +1,7 @@ package com.prgrms.board.domain.post.controller; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @@ -67,7 +68,10 @@ void create_post_success() throws Exception { .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andDo(print()) - .andDo(document("posts/createPost")) + .andDo(document("posts/createPost", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint())) + ) .andExpect(status().isCreated()); } @@ -85,7 +89,10 @@ void get_posts_success() throws Exception { .param("size", "2") ) .andDo(print()) - .andDo(document("posts/getPosts")) + .andDo(document("posts/getPosts", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint())) + ) .andExpect(status().isOk()); } @@ -97,12 +104,12 @@ void get_post_success() throws Exception { postRepository.save(post); // when & then - mockMvc.perform(get("/api/v1/posts/" + post.getId()) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(post)) - ) + mockMvc.perform(get("/api/v1/posts/" + post.getId())) .andDo(print()) - .andDo(document("posts/getPost")) + .andDo(document("posts/getPost", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint())) + ) .andExpect(status().isOk()); } @@ -120,7 +127,10 @@ void update_post_success() throws Exception { .content(objectMapper.writeValueAsString(request)) ) .andDo(print()) - .andDo(document("posts/updatePost")) + .andDo(document("posts/updatePost", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint())) + ) .andExpect(status().isOk()); } } From 334342ef809646b3e96099dcedbde135de0fb8e9 Mon Sep 17 00:00:00 2001 From: kmebin Date: Wed, 2 Aug 2023 18:00:46 +0900 Subject: [PATCH 13/23] =?UTF-8?q?feat:=20User=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20=EC=83=9D=EC=84=B1=EC=9E=90=20private=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/prgrms/board/domain/user/entity/User.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/prgrms/board/domain/user/entity/User.java b/src/main/java/com/prgrms/board/domain/user/entity/User.java index 166d2f693..f9f74ed64 100644 --- a/src/main/java/com/prgrms/board/domain/user/entity/User.java +++ b/src/main/java/com/prgrms/board/domain/user/entity/User.java @@ -16,7 +16,7 @@ @Entity @Getter @Table(name = "user") -@AllArgsConstructor +@AllArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PROTECTED) public class User extends BaseEntity { @@ -37,5 +37,4 @@ public class User extends BaseEntity { public static User create(String name, int age, String hobby) { return new User(null, name, age, hobby); } - } From 1d18dd7ca96b4add5eccd178cf44111e3ebd7d3d Mon Sep 17 00:00:00 2001 From: kmebin Date: Thu, 3 Aug 2023 14:13:26 +0900 Subject: [PATCH 14/23] =?UTF-8?q?feat:=20response=20jsonPath=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../post/dto/response/PostDetailResponse.java | 8 ++- .../controller/ApiPostControllerTest.java | 56 ++++++++++++++----- .../com/prgrms/board/support/UserFixture.java | 2 +- 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/prgrms/board/domain/post/dto/response/PostDetailResponse.java b/src/main/java/com/prgrms/board/domain/post/dto/response/PostDetailResponse.java index 9d7704803..b6d6f9344 100644 --- a/src/main/java/com/prgrms/board/domain/post/dto/response/PostDetailResponse.java +++ b/src/main/java/com/prgrms/board/domain/post/dto/response/PostDetailResponse.java @@ -1,5 +1,7 @@ package com.prgrms.board.domain.post.dto.response; +import java.time.LocalDateTime; + import com.prgrms.board.domain.post.entity.Post; import lombok.Builder; @@ -10,7 +12,9 @@ public record PostDetailResponse( Long userId, String username, String title, - String content + String content, + LocalDateTime createdAt, + LocalDateTime updatedAt ) { public static PostDetailResponse from(Post post) { return PostDetailResponse.builder() @@ -19,6 +23,8 @@ public static PostDetailResponse from(Post post) { .username(post.getUser().getName()) .title(post.getTitle()) .content(post.getContent()) + .createdAt(post.getCreatedAt()) + .updatedAt(post.getUpdatedAt()) .build(); } } diff --git a/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java b/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java index 7e307b4dc..293ec9664 100644 --- a/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java +++ b/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java @@ -6,6 +6,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import java.util.List; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -22,7 +24,6 @@ import com.prgrms.board.domain.post.dto.request.PostUpdateRequest; import com.prgrms.board.domain.post.entity.Post; import com.prgrms.board.domain.post.repository.PostRepository; -import com.prgrms.board.domain.post.service.PostService; import com.prgrms.board.domain.user.entity.User; import com.prgrms.board.domain.user.repository.UserRepository; import com.prgrms.board.support.PostFixture; @@ -37,9 +38,6 @@ class ApiPostControllerTest { @Autowired MockMvc mockMvc; - @Autowired - PostService postService; - @Autowired ObjectMapper objectMapper; @@ -61,7 +59,7 @@ void init() { @DisplayName("게시물 생성에 성공한다.") void create_post_success() throws Exception { // given - PostCreateRequest request = new PostCreateRequest(user.getId(), "title", "content"); + PostCreateRequest request = new PostCreateRequest(user.getId(), "제목", "내용"); // when & then mockMvc.perform(post("/api/v1/posts") @@ -72,28 +70,46 @@ void create_post_success() throws Exception { preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint())) ) - .andExpect(status().isCreated()); + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.message").value("게시물 생성 성공")) + .andExpect(jsonPath("$.data.postId").exists()) + .andExpect(jsonPath("$.data.title").value(request.title())) + .andExpect(jsonPath("$.data.content").value(request.content())); } @Test @DisplayName("게시물 전체 조회에 성공한다.") void get_posts_success() throws Exception { // given - postRepository.save(PostFixture.create(user, "Title1", "내용1")); - postRepository.save(PostFixture.create(user, "Title2", "내용2")); - postRepository.save(PostFixture.create(user, "Title3", "내용3")); + Post post1 = PostFixture.create(user, "제목1", "내용1"); + Post post2 = PostFixture.create(user, "제목2", "내용2"); + Post post3 = PostFixture.create(user, "제목3", "내용3"); + List posts = List.of(post1, post2, post3); + postRepository.saveAll(posts); + + int page = 0; + int size = 2; + int totalCount = posts.size(); + int totalPage = (int)Math.ceil((double)posts.size() / size); // when & then mockMvc.perform(get("/api/v1/posts") - .param("page", "1") - .param("size", "2") + .param("page", String.valueOf(page)) + .param("size", String.valueOf(size)) ) .andDo(print()) .andDo(document("posts/getPosts", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint())) ) - .andExpect(status().isOk()); + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").value("게시물 전체 조회 성공")) + .andExpect(jsonPath("$.data.totalCount").value(totalCount)) + .andExpect(jsonPath("$.data.totalPage").value(totalPage)) + .andExpect(jsonPath("$.data.page").value(page)) + .andExpect(jsonPath("$.data.size").value(size)) + .andExpect(jsonPath("$.data.items").isArray()) + .andExpect(jsonPath("$.data.items.length()").value(size)); } @Test @@ -110,7 +126,15 @@ void get_post_success() throws Exception { preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint())) ) - .andExpect(status().isOk()); + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").value("게시물 조회 성공")) + .andExpect(jsonPath("$.data.postId").value(post.getId())) + .andExpect(jsonPath("$.data.title").value(post.getTitle())) + .andExpect(jsonPath("$.data.content").value(post.getContent())) + .andExpect(jsonPath("$.data.userId").value(user.getId())) + .andExpect(jsonPath("$.data.username").value(user.getName())) + .andExpect(jsonPath("$.data.createdAt").exists()) + .andExpect(jsonPath("$.data.updatedAt").exists()); } @Test @@ -131,6 +155,10 @@ void update_post_success() throws Exception { preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint())) ) - .andExpect(status().isOk()); + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").value("게시물 수정 성공")) + .andExpect(jsonPath("$.data.postId").value(post.getId())) + .andExpect(jsonPath("$.data.title").value(request.title())) + .andExpect(jsonPath("$.data.content").value(request.content())); } } diff --git a/src/test/java/com/prgrms/board/support/UserFixture.java b/src/test/java/com/prgrms/board/support/UserFixture.java index 25069444d..26a725ca2 100644 --- a/src/test/java/com/prgrms/board/support/UserFixture.java +++ b/src/test/java/com/prgrms/board/support/UserFixture.java @@ -5,6 +5,6 @@ public class UserFixture { public static User create() { - return User.create("test", 10, "post"); + return User.create("이름", 10, "취미"); } } From a2de51de01e937464949ed98f7b3f44953a551bf Mon Sep 17 00:00:00 2001 From: kmebin Date: Thu, 3 Aug 2023 14:44:28 +0900 Subject: [PATCH 15/23] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EB=AC=BC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ApiPostControllerTest.java | 10 ++-- .../domain/post/service/PostServiceTest.java | 57 +++++++++++++++++++ 2 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java diff --git a/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java b/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java index 293ec9664..2d11a898f 100644 --- a/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java +++ b/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java @@ -36,18 +36,18 @@ class ApiPostControllerTest { @Autowired - MockMvc mockMvc; + private MockMvc mockMvc; @Autowired - ObjectMapper objectMapper; + private ObjectMapper objectMapper; @Autowired - PostRepository postRepository; + private PostRepository postRepository; @Autowired - UserRepository userRepository; + private UserRepository userRepository; - User user; + private User user; @BeforeEach void init() { diff --git a/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java b/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java new file mode 100644 index 000000000..2fef078f7 --- /dev/null +++ b/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java @@ -0,0 +1,57 @@ +package com.prgrms.board.domain.post.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.BDDMockito.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.prgrms.board.domain.post.dto.request.PostCreateRequest; +import com.prgrms.board.domain.post.dto.response.PostResponse; +import com.prgrms.board.domain.post.entity.Post; +import com.prgrms.board.domain.post.repository.PostRepository; +import com.prgrms.board.domain.user.entity.User; +import com.prgrms.board.domain.user.service.UserService; +import com.prgrms.board.support.PostFixture; +import com.prgrms.board.support.UserFixture; + +@ExtendWith(MockitoExtension.class) +class PostServiceTest { + + @InjectMocks + private PostService postService; + + @Mock + private PostRepository postRepository; + + @Mock + private UserService userService; + + private User user; + + @BeforeEach + void init() { + user = UserFixture.create(); + } + + @Test + @DisplayName("게시물 생성에 성공한다.") + void create_post_success() { + // given + PostCreateRequest request = new PostCreateRequest(user.getId(), "제목", "내용"); + Post post = PostFixture.create(user, "제목", "내용"); + given(postRepository.save(any(Post.class))).willReturn(post); + + // when + PostResponse result = postService.createPost(request); + + // then + assertThat(result.title()).isEqualTo("제목"); + } +} From 70e06c0d3996880c3fc87449cbebceaf11754e0d Mon Sep 17 00:00:00 2001 From: kmebin Date: Thu, 3 Aug 2023 15:00:50 +0900 Subject: [PATCH 16/23] =?UTF-8?q?feat:=20=EC=A0=84=EC=B2=B4=20=EA=B2=8C?= =?UTF-8?q?=EC=8B=9C=EB=AC=BC=20=EC=A1=B0=ED=9A=8C=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/post/service/PostServiceTest.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java b/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java index 2fef078f7..93a5a98aa 100644 --- a/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java +++ b/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java @@ -4,6 +4,8 @@ import static org.mockito.ArgumentMatchers.*; import static org.mockito.BDDMockito.*; +import java.util.List; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -11,6 +13,10 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import com.prgrms.board.domain.post.dto.request.PostCreateRequest; import com.prgrms.board.domain.post.dto.response.PostResponse; @@ -18,6 +24,7 @@ import com.prgrms.board.domain.post.repository.PostRepository; import com.prgrms.board.domain.user.entity.User; import com.prgrms.board.domain.user.service.UserService; +import com.prgrms.board.global.common.PageResponse; import com.prgrms.board.support.PostFixture; import com.prgrms.board.support.UserFixture; @@ -54,4 +61,25 @@ void create_post_success() { // then assertThat(result.title()).isEqualTo("제목"); } + + @Test + @DisplayName("전체 게시물 조회에 성공한다.") + void get_posts_success() { + // given + Post post1 = PostFixture.create(user, "제목1", "내용1"); + Post post2 = PostFixture.create(user, "제목2", "내용2"); + Post post3 = PostFixture.create(user, "제목3", "내용3"); + List posts = List.of(post1, post2, post3); + + Pageable pageable = PageRequest.of(0, 2); + Page page = new PageImpl<>(posts.subList(0, 2), pageable, posts.size()); + given(postRepository.findAll(any(Pageable.class))).willReturn(page); + + // when + PageResponse result = postService.getPosts(pageable); + + // then + assertThat(result.totalCount()).isEqualTo(3); + assertThat(result.items()).hasSize(2); + } } From b81b0a49797e1db9112b89a92154885705c20e8c Mon Sep 17 00:00:00 2001 From: kmebin Date: Thu, 3 Aug 2023 15:32:32 +0900 Subject: [PATCH 17/23] =?UTF-8?q?feat:=20PostService=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../prgrms/board/domain/post/entity/Post.java | 2 + .../prgrms/board/domain/user/entity/User.java | 2 + .../domain/post/service/PostServiceTest.java | 57 ++++++++++++++++++- .../com/prgrms/board/support/PostFixture.java | 15 ++++- .../com/prgrms/board/support/UserFixture.java | 9 +++ 5 files changed, 80 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/prgrms/board/domain/post/entity/Post.java b/src/main/java/com/prgrms/board/domain/post/entity/Post.java index 50972dc32..d4dc83a25 100644 --- a/src/main/java/com/prgrms/board/domain/post/entity/Post.java +++ b/src/main/java/com/prgrms/board/domain/post/entity/Post.java @@ -15,12 +15,14 @@ import jakarta.persistence.Table; import lombok.AccessLevel; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @Entity @Getter @Table(name = "post") +@Builder @AllArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Post extends BaseEntity { diff --git a/src/main/java/com/prgrms/board/domain/user/entity/User.java b/src/main/java/com/prgrms/board/domain/user/entity/User.java index f9f74ed64..e2197a404 100644 --- a/src/main/java/com/prgrms/board/domain/user/entity/User.java +++ b/src/main/java/com/prgrms/board/domain/user/entity/User.java @@ -10,12 +10,14 @@ import jakarta.persistence.Table; import lombok.AccessLevel; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @Entity @Getter @Table(name = "user") +@Builder @AllArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PROTECTED) public class User extends BaseEntity { diff --git a/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java b/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java index 93a5a98aa..86fb4eac6 100644 --- a/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java +++ b/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java @@ -5,6 +5,7 @@ import static org.mockito.BDDMockito.*; import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -19,8 +20,11 @@ import org.springframework.data.domain.Pageable; import com.prgrms.board.domain.post.dto.request.PostCreateRequest; +import com.prgrms.board.domain.post.dto.request.PostUpdateRequest; +import com.prgrms.board.domain.post.dto.response.PostDetailResponse; import com.prgrms.board.domain.post.dto.response.PostResponse; import com.prgrms.board.domain.post.entity.Post; +import com.prgrms.board.domain.post.exception.PostNotFoundException; import com.prgrms.board.domain.post.repository.PostRepository; import com.prgrms.board.domain.user.entity.User; import com.prgrms.board.domain.user.service.UserService; @@ -44,7 +48,7 @@ class PostServiceTest { @BeforeEach void init() { - user = UserFixture.create(); + user = UserFixture.createByBuilder(); } @Test @@ -52,7 +56,9 @@ void init() { void create_post_success() { // given PostCreateRequest request = new PostCreateRequest(user.getId(), "제목", "내용"); - Post post = PostFixture.create(user, "제목", "내용"); + Post post = PostFixture.createByBuilder(user, "제목", "내용"); + + given(userService.findUserOrThrow(any(Long.class))).willReturn(user); given(postRepository.save(any(Post.class))).willReturn(post); // when @@ -60,6 +66,7 @@ void create_post_success() { // then assertThat(result.title()).isEqualTo("제목"); + assertThat(result.content()).isEqualTo("내용"); } @Test @@ -80,6 +87,52 @@ void get_posts_success() { // then assertThat(result.totalCount()).isEqualTo(3); + assertThat(result.totalPage()).isEqualTo(2); assertThat(result.items()).hasSize(2); } + + @Test + @DisplayName("특정 게시물 조회에 성공한다.") + void get_post_success() { + // given + Post post = PostFixture.createByBuilder(user, "제목1", "내용1"); + given(postRepository.findById(any(Long.class))).willReturn(Optional.of(post)); + + // when + PostDetailResponse postDetailResponse = postService.getPost(post.getId()); + + // then + assertThat(postDetailResponse.title()).isEqualTo("제목1"); + assertThat(postDetailResponse.content()).isEqualTo("내용1"); + } + + @Test + @DisplayName("게시물 수정에 성공한다.") + void update_post_success() { + // given + PostUpdateRequest request = new PostUpdateRequest("수정한 제목", "수정한 내용"); + Post post = PostFixture.createByBuilder(user, "제목", "내용"); + + given(postRepository.findById(any(Long.class))).willReturn(Optional.of(post)); + + // when + PostResponse result = postService.updatePost(post.getId(), request); + + // then + assertThat(result.title()).isEqualTo("수정한 제목"); + assertThat(result.content()).isEqualTo("수정한 내용"); + } + + @Test + @DisplayName("존재하는 게시물이 없는 경우 예외가 발생한다.") + void get_post_not_found() { + // given + Post post = PostFixture.createByBuilder(user, "제목1", "내용1"); + given(postRepository.findById(any(Long.class))).willReturn(Optional.empty()); + + // when, then + assertThatThrownBy(() -> postService.getPost(post.getId())) + .isInstanceOf(PostNotFoundException.class) + .hasMessage("존재하지 않는 게시물입니다."); + } } diff --git a/src/test/java/com/prgrms/board/support/PostFixture.java b/src/test/java/com/prgrms/board/support/PostFixture.java index 59a3d72b4..870c5ec53 100644 --- a/src/test/java/com/prgrms/board/support/PostFixture.java +++ b/src/test/java/com/prgrms/board/support/PostFixture.java @@ -5,7 +5,16 @@ public class PostFixture { - public static Post create(User user, String title, String content) { - return Post.create(user, title, content); - } + public static Post create(User user, String title, String content) { + return Post.create(user, title, content); + } + + public static Post createByBuilder(User user, String title, String content) { + return Post.builder() + .id(1L) + .user(user) + .title(title) + .content(content) + .build(); + } } diff --git a/src/test/java/com/prgrms/board/support/UserFixture.java b/src/test/java/com/prgrms/board/support/UserFixture.java index 26a725ca2..fc8d7cf35 100644 --- a/src/test/java/com/prgrms/board/support/UserFixture.java +++ b/src/test/java/com/prgrms/board/support/UserFixture.java @@ -7,4 +7,13 @@ public class UserFixture { public static User create() { return User.create("이름", 10, "취미"); } + + public static User createByBuilder() { + return User.builder() + .id(1L) + .name("이름") + .age(10) + .hobby("취미") + .build(); + } } From bf72ce01a4a84e27fc40d15e5303ac98bf03d8f6 Mon Sep 17 00:00:00 2001 From: kmebin Date: Thu, 3 Aug 2023 15:50:38 +0900 Subject: [PATCH 18/23] =?UTF-8?q?chore:=20=EC=BD=94=EB=93=9C=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BOOT-INF/classes/static/docs/index.html | 523 ++++++++++++++++++ .../post/controller/ApiPostController.java | 61 +- .../post/dto/request/PostCreateRequest.java | 20 +- .../prgrms/board/domain/post/entity/Post.java | 6 +- .../domain/post/service/PostService.java | 65 +-- .../prgrms/board/domain/user/entity/User.java | 6 +- .../prgrms/board/global/common/ErrorCode.java | 1 + .../board/global/common/PageResponse.java | 24 - .../board/global/common/SuccessMessage.java | 1 + .../global/common/{ => dto}/BaseResponse.java | 4 +- .../board/global/common/dto/PageResponse.java | 26 + .../exception/ExceptionControllerAdvice.java | 42 +- .../domain/post/service/PostServiceTest.java | 2 +- 13 files changed, 660 insertions(+), 121 deletions(-) create mode 100644 BOOT-INF/classes/static/docs/index.html delete mode 100644 src/main/java/com/prgrms/board/global/common/PageResponse.java rename src/main/java/com/prgrms/board/global/common/{ => dto}/BaseResponse.java (89%) create mode 100644 src/main/java/com/prgrms/board/global/common/dto/PageResponse.java diff --git a/BOOT-INF/classes/static/docs/index.html b/BOOT-INF/classes/static/docs/index.html new file mode 100644 index 000000000..7da70086b --- /dev/null +++ b/BOOT-INF/classes/static/docs/index.html @@ -0,0 +1,523 @@ + + + + + + + +Board REST API + + + + + +
+
+

게시물 생성

+
+
+

REQUEST

+
+

Unresolved directive in index.adoc - include::{snippets}/posts/createPost/http-request.adoc[]

+
+
+
+

RESPONSE

+
+

Unresolved directive in index.adoc - include::{snippets}/posts/createPost/http-response.adoc[]

+
+
+
+
+
+

게시물 전체 조회

+
+
+

REQUEST

+
+

Unresolved directive in index.adoc - include::{snippets}/posts/getPosts/http-request.adoc[]

+
+
+
+

RESPONSE

+
+

Unresolved directive in index.adoc - include::{snippets}/posts/getPosts/http-response.adoc[]

+
+
+
+
+
+

게시물 조회

+
+
+

REQUEST

+
+

Unresolved directive in index.adoc - include::{snippets}/posts/getPost/http-request.adoc[]

+
+
+
+

RESPONSE

+
+

Unresolved directive in index.adoc - include::{snippets}/posts/getPost/http-response.adoc[]

+
+
+
+
+
+

게시물 수정

+
+
+

REQUEST

+
+

Unresolved directive in index.adoc - include::{snippets}/posts/updatePost/http-request.adoc[]

+
+
+
+

RESPONSE

+
+

Unresolved directive in index.adoc - include::{snippets}/posts/updatePost/http-response.adoc[]

+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java b/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java index 5abc9e1a4..510be7575 100644 --- a/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java +++ b/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java @@ -21,8 +21,9 @@ import com.prgrms.board.domain.post.dto.response.PostResponse; import com.prgrms.board.domain.post.entity.Post; import com.prgrms.board.domain.post.service.PostService; -import com.prgrms.board.global.common.BaseResponse; -import com.prgrms.board.global.common.PageResponse; +import com.prgrms.board.global.common.dto.BaseResponse; +import com.prgrms.board.global.common.dto.PageResponse; + import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -31,32 +32,32 @@ @RequestMapping("/api/v1/posts") public class ApiPostController { - private final PostService postService; - - @GetMapping - public BaseResponse> getPosts( - @PageableDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable - ) { - PageResponse data = postService.getPosts(pageable); - return BaseResponse.ok(GET_POSTS_SUCCESS, data); - } - - @GetMapping("/{postId}") - public BaseResponse getPost(@PathVariable Long postId) { - PostDetailResponse data = postService.getPost(postId); - return BaseResponse.ok(GET_POST_SUCCESS, data); - } - - @PostMapping - @ResponseStatus(CREATED) - public BaseResponse createPost(@Valid @RequestBody PostCreateRequest request) { - PostResponse data = postService.createPost(request); - return BaseResponse.created(CREATE_POST_SUCCESS, data); - } - - @PatchMapping("/{postId}") - public BaseResponse updatePost(@PathVariable Long postId, @RequestBody PostUpdateRequest request) { - PostResponse data = postService.updatePost(postId, request); - return BaseResponse.ok(UPDATE_POST_SUCCESS, data); - } + private final PostService postService; + + @GetMapping + public BaseResponse> getPosts( + @PageableDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable + ) { + PageResponse data = postService.getPosts(pageable); + return BaseResponse.ok(GET_POSTS_SUCCESS, data); + } + + @GetMapping("/{postId}") + public BaseResponse getPost(@PathVariable Long postId) { + PostDetailResponse data = postService.getPost(postId); + return BaseResponse.ok(GET_POST_SUCCESS, data); + } + + @PostMapping + @ResponseStatus(CREATED) + public BaseResponse createPost(@Valid @RequestBody PostCreateRequest request) { + PostResponse data = postService.createPost(request); + return BaseResponse.created(CREATE_POST_SUCCESS, data); + } + + @PatchMapping("/{postId}") + public BaseResponse updatePost(@PathVariable Long postId, @RequestBody PostUpdateRequest request) { + PostResponse data = postService.updatePost(postId, request); + return BaseResponse.ok(UPDATE_POST_SUCCESS, data); + } } diff --git a/src/main/java/com/prgrms/board/domain/post/dto/request/PostCreateRequest.java b/src/main/java/com/prgrms/board/domain/post/dto/request/PostCreateRequest.java index a99b1e9e7..8eeead708 100644 --- a/src/main/java/com/prgrms/board/domain/post/dto/request/PostCreateRequest.java +++ b/src/main/java/com/prgrms/board/domain/post/dto/request/PostCreateRequest.java @@ -8,17 +8,17 @@ import jakarta.validation.constraints.Size; public record PostCreateRequest( - @NotNull(message = "유저 아이디는 필수입니다.") - Long userId, + @NotNull(message = "유저 아이디는 필수입니다.") + Long userId, - @NotBlank(message = "제목은 필수입니다.") - @Size(max = 30, message = "제목은 최대 30자까지 가능합니다.") - String title, + @NotBlank(message = "제목은 필수입니다.") + @Size(max = 30, message = "제목은 최대 30자까지 가능합니다.") + String title, - @NotBlank(message = "내용은 필수입니다.") - String content + @NotBlank(message = "내용은 필수입니다.") + String content ) { - public Post toEntity(User user) { - return Post.create(user, title, content); - } + public Post toEntity(User user) { + return Post.create(user, title, content); + } } diff --git a/src/main/java/com/prgrms/board/domain/post/entity/Post.java b/src/main/java/com/prgrms/board/domain/post/entity/Post.java index d4dc83a25..d0254d6fe 100644 --- a/src/main/java/com/prgrms/board/domain/post/entity/Post.java +++ b/src/main/java/com/prgrms/board/domain/post/entity/Post.java @@ -44,7 +44,11 @@ public class Post extends BaseEntity { private String content; public static Post create(User user, String title, String content) { - return new Post(null, user, title, content); + return Post.builder() + .user(user) + .title(title) + .content(content) + .build(); } public void update(String title, String content) { diff --git a/src/main/java/com/prgrms/board/domain/post/service/PostService.java b/src/main/java/com/prgrms/board/domain/post/service/PostService.java index 7d15052a4..cd472e0f7 100644 --- a/src/main/java/com/prgrms/board/domain/post/service/PostService.java +++ b/src/main/java/com/prgrms/board/domain/post/service/PostService.java @@ -16,7 +16,8 @@ import com.prgrms.board.domain.post.repository.PostRepository; import com.prgrms.board.domain.user.entity.User; import com.prgrms.board.domain.user.service.UserService; -import com.prgrms.board.global.common.PageResponse; +import com.prgrms.board.global.common.dto.PageResponse; + import lombok.RequiredArgsConstructor; @Service @@ -24,35 +25,35 @@ @Transactional(readOnly = true) public class PostService { - private final PostRepository postRepository; - private final UserService userService; - - public PageResponse getPosts(Pageable pageable) { - Page posts = postRepository.findAll(pageable); - return PageResponse.from(posts); - } - - public PostDetailResponse getPost(Long postId) { - Post post = findPostOrThrow(postId); - return PostDetailResponse.from(post); - } - - @Transactional - public PostResponse createPost(PostCreateRequest request) { - User user = userService.findUserOrThrow(request.userId()); - Post post = postRepository.save(request.toEntity(user)); - return PostResponse.from(post); - } - - @Transactional - public PostResponse updatePost(Long postId, PostUpdateRequest request) { - Post post = findPostOrThrow(postId); - post.update(request.title(), request.content()); - return PostResponse.from(post); - } - - private Post findPostOrThrow(Long postId) { - return postRepository.findById(postId) - .orElseThrow(() -> new PostNotFoundException(NO_POST)); - } + private final PostRepository postRepository; + private final UserService userService; + + public PageResponse getPosts(Pageable pageable) { + Page posts = postRepository.findAll(pageable); + return PageResponse.from(posts); + } + + public PostDetailResponse getPost(Long postId) { + Post post = findPostOrThrow(postId); + return PostDetailResponse.from(post); + } + + @Transactional + public PostResponse createPost(PostCreateRequest request) { + User user = userService.findUserOrThrow(request.userId()); + Post post = postRepository.save(request.toEntity(user)); + return PostResponse.from(post); + } + + @Transactional + public PostResponse updatePost(Long postId, PostUpdateRequest request) { + Post post = findPostOrThrow(postId); + post.update(request.title(), request.content()); + return PostResponse.from(post); + } + + private Post findPostOrThrow(Long postId) { + return postRepository.findById(postId) + .orElseThrow(() -> new PostNotFoundException(NO_POST)); + } } diff --git a/src/main/java/com/prgrms/board/domain/user/entity/User.java b/src/main/java/com/prgrms/board/domain/user/entity/User.java index e2197a404..c6c7916e8 100644 --- a/src/main/java/com/prgrms/board/domain/user/entity/User.java +++ b/src/main/java/com/prgrms/board/domain/user/entity/User.java @@ -37,6 +37,10 @@ public class User extends BaseEntity { private String hobby; public static User create(String name, int age, String hobby) { - return new User(null, name, age, hobby); + return User.builder() + .name(name) + .age(age) + .hobby(hobby) + .build(); } } diff --git a/src/main/java/com/prgrms/board/global/common/ErrorCode.java b/src/main/java/com/prgrms/board/global/common/ErrorCode.java index fdc57e5dd..d39fd5393 100644 --- a/src/main/java/com/prgrms/board/global/common/ErrorCode.java +++ b/src/main/java/com/prgrms/board/global/common/ErrorCode.java @@ -11,6 +11,7 @@ @Getter @AllArgsConstructor(access = AccessLevel.PRIVATE) public enum ErrorCode { + NO_USER(NOT_FOUND, "존재하지 않는 유저입니다."), NO_POST(NOT_FOUND, "존재하지 않는 게시물입니다."), ; diff --git a/src/main/java/com/prgrms/board/global/common/PageResponse.java b/src/main/java/com/prgrms/board/global/common/PageResponse.java deleted file mode 100644 index 10e59ed2c..000000000 --- a/src/main/java/com/prgrms/board/global/common/PageResponse.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.prgrms.board.global.common; - -import java.util.List; - -import org.springframework.data.domain.Page; - -public record PageResponse( - long totalCount, - int totalPage, - int page, - int size, - List items -) { - public static PageResponse from(Page page) { - System.out.println(page); - return new PageResponse<>( - page.getTotalElements(), - page.getTotalPages(), - page.getNumber(), - page.getSize(), - page.getContent() - ); - } -} diff --git a/src/main/java/com/prgrms/board/global/common/SuccessMessage.java b/src/main/java/com/prgrms/board/global/common/SuccessMessage.java index 829340287..60f3af569 100644 --- a/src/main/java/com/prgrms/board/global/common/SuccessMessage.java +++ b/src/main/java/com/prgrms/board/global/common/SuccessMessage.java @@ -7,6 +7,7 @@ @Getter @AllArgsConstructor(access = AccessLevel.PRIVATE) public enum SuccessMessage { + GET_POSTS_SUCCESS("게시물 전체 조회 성공"), GET_POST_SUCCESS("게시물 조회 성공"), CREATE_POST_SUCCESS("게시물 생성 성공"), diff --git a/src/main/java/com/prgrms/board/global/common/BaseResponse.java b/src/main/java/com/prgrms/board/global/common/dto/BaseResponse.java similarity index 89% rename from src/main/java/com/prgrms/board/global/common/BaseResponse.java rename to src/main/java/com/prgrms/board/global/common/dto/BaseResponse.java index 812ab0c3f..8b6324cce 100644 --- a/src/main/java/com/prgrms/board/global/common/BaseResponse.java +++ b/src/main/java/com/prgrms/board/global/common/dto/BaseResponse.java @@ -1,4 +1,4 @@ -package com.prgrms.board.global.common; +package com.prgrms.board.global.common.dto; import static com.fasterxml.jackson.annotation.JsonInclude.Include.*; import static org.springframework.http.HttpStatus.*; @@ -6,6 +6,8 @@ import org.springframework.http.HttpStatus; import com.fasterxml.jackson.annotation.JsonInclude; +import com.prgrms.board.global.common.ErrorCode; +import com.prgrms.board.global.common.SuccessMessage; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/src/main/java/com/prgrms/board/global/common/dto/PageResponse.java b/src/main/java/com/prgrms/board/global/common/dto/PageResponse.java new file mode 100644 index 000000000..a4c06427b --- /dev/null +++ b/src/main/java/com/prgrms/board/global/common/dto/PageResponse.java @@ -0,0 +1,26 @@ +package com.prgrms.board.global.common.dto; + +import java.util.List; + +import org.springframework.data.domain.Page; + +import lombok.Builder; + +@Builder +public record PageResponse( + long totalCount, + int totalPage, + int page, + int size, + List items +) { + public static PageResponse from(Page page) { + return PageResponse.builder() + .totalCount(page.getTotalElements()) + .totalPage(page.getTotalPages()) + .page(page.getNumber()) + .size(page.getSize()) + .items(page.getContent()) + .build(); + } +} diff --git a/src/main/java/com/prgrms/board/global/exception/ExceptionControllerAdvice.java b/src/main/java/com/prgrms/board/global/exception/ExceptionControllerAdvice.java index 22a03031d..2bae0bf3d 100644 --- a/src/main/java/com/prgrms/board/global/exception/ExceptionControllerAdvice.java +++ b/src/main/java/com/prgrms/board/global/exception/ExceptionControllerAdvice.java @@ -12,7 +12,7 @@ import com.prgrms.board.domain.post.exception.PostNotFoundException; import com.prgrms.board.domain.user.exception.UserNotFoundException; -import com.prgrms.board.global.common.BaseResponse; +import com.prgrms.board.global.common.dto.BaseResponse; import lombok.extern.slf4j.Slf4j; @@ -20,24 +20,24 @@ @RestControllerAdvice public class ExceptionControllerAdvice { - @ResponseStatus(NOT_FOUND) - @ExceptionHandler({ - UserNotFoundException.class, - PostNotFoundException.class, - }) - public BaseResponse handleNotFound(CustomException exception) { - log.error("[NotFound] => ", exception); - return BaseResponse.error(exception.getError()); - } - - @ResponseStatus(BAD_REQUEST) - @ExceptionHandler(MethodArgumentNotValidException.class) - public BaseResponse handleBadRequestException(MethodArgumentNotValidException exception) { - log.error("[BadRequest] => ", exception); - - String errorMessage = Optional.ofNullable(exception.getBindingResult().getFieldError()) - .map(DefaultMessageSourceResolvable::getDefaultMessage) - .orElse("입력 값이 올바르지 않습니다."); - return BaseResponse.error(BAD_REQUEST, errorMessage); - } + @ResponseStatus(NOT_FOUND) + @ExceptionHandler({ + UserNotFoundException.class, + PostNotFoundException.class, + }) + public BaseResponse handleNotFound(CustomException exception) { + log.error("[NotFound] => ", exception); + return BaseResponse.error(exception.getError()); + } + + @ResponseStatus(BAD_REQUEST) + @ExceptionHandler(MethodArgumentNotValidException.class) + public BaseResponse handleBadRequestException(MethodArgumentNotValidException exception) { + log.error("[BadRequest] => ", exception); + + String errorMessage = Optional.ofNullable(exception.getBindingResult().getFieldError()) + .map(DefaultMessageSourceResolvable::getDefaultMessage) + .orElse("입력 값이 올바르지 않습니다."); + return BaseResponse.error(BAD_REQUEST, errorMessage); + } } diff --git a/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java b/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java index 86fb4eac6..e393e2da2 100644 --- a/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java +++ b/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java @@ -28,7 +28,7 @@ import com.prgrms.board.domain.post.repository.PostRepository; import com.prgrms.board.domain.user.entity.User; import com.prgrms.board.domain.user.service.UserService; -import com.prgrms.board.global.common.PageResponse; +import com.prgrms.board.global.common.dto.PageResponse; import com.prgrms.board.support.PostFixture; import com.prgrms.board.support.UserFixture; From c880a934ef4476d188fc9f15185d719283b5bbb1 Mon Sep 17 00:00:00 2001 From: ymkim97 Date: Thu, 3 Aug 2023 15:56:06 +0900 Subject: [PATCH 19/23] =?UTF-8?q?docs:=20gitignore=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + BOOT-INF/classes/static/docs/index.html | 523 ------------------------ 2 files changed, 1 insertion(+), 523 deletions(-) delete mode 100644 BOOT-INF/classes/static/docs/index.html diff --git a/.gitignore b/.gitignore index cbca2e05f..fcfa360f2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ build/ gradlew gradlew.bat gradle +BOOT-INF ### STS ### .apt_generated diff --git a/BOOT-INF/classes/static/docs/index.html b/BOOT-INF/classes/static/docs/index.html deleted file mode 100644 index 7da70086b..000000000 --- a/BOOT-INF/classes/static/docs/index.html +++ /dev/null @@ -1,523 +0,0 @@ - - - - - - - -Board REST API - - - - - -
-
-

게시물 생성

-
-
-

REQUEST

-
-

Unresolved directive in index.adoc - include::{snippets}/posts/createPost/http-request.adoc[]

-
-
-
-

RESPONSE

-
-

Unresolved directive in index.adoc - include::{snippets}/posts/createPost/http-response.adoc[]

-
-
-
-
-
-

게시물 전체 조회

-
-
-

REQUEST

-
-

Unresolved directive in index.adoc - include::{snippets}/posts/getPosts/http-request.adoc[]

-
-
-
-

RESPONSE

-
-

Unresolved directive in index.adoc - include::{snippets}/posts/getPosts/http-response.adoc[]

-
-
-
-
-
-

게시물 조회

-
-
-

REQUEST

-
-

Unresolved directive in index.adoc - include::{snippets}/posts/getPost/http-request.adoc[]

-
-
-
-

RESPONSE

-
-

Unresolved directive in index.adoc - include::{snippets}/posts/getPost/http-response.adoc[]

-
-
-
-
-
-

게시물 수정

-
-
-

REQUEST

-
-

Unresolved directive in index.adoc - include::{snippets}/posts/updatePost/http-request.adoc[]

-
-
-
-

RESPONSE

-
-

Unresolved directive in index.adoc - include::{snippets}/posts/updatePost/http-response.adoc[]

-
-
-
-
-
- - - \ No newline at end of file From 2c15cdac45d5e4e3207d3d56ec9c132ad89bb4c8 Mon Sep 17 00:00:00 2001 From: kmebin Date: Thu, 3 Aug 2023 16:10:10 +0900 Subject: [PATCH 20/23] =?UTF-8?q?feat:=20PostResponse=20=EB=B9=8C=EB=8D=94?= =?UTF-8?q?=20=ED=8C=A8=ED=84=B4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../board/domain/post/dto/response/PostResponse.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/prgrms/board/domain/post/dto/response/PostResponse.java b/src/main/java/com/prgrms/board/domain/post/dto/response/PostResponse.java index 0218149fb..455090ea3 100644 --- a/src/main/java/com/prgrms/board/domain/post/dto/response/PostResponse.java +++ b/src/main/java/com/prgrms/board/domain/post/dto/response/PostResponse.java @@ -2,12 +2,19 @@ import com.prgrms.board.domain.post.entity.Post; +import lombok.Builder; + +@Builder public record PostResponse( Long postId, String title, String content ) { public static PostResponse from(Post post) { - return new PostResponse(post.getId(), post.getTitle(), post.getContent()); + return PostResponse.builder() + .postId(post.getId()) + .title(post.getTitle()) + .content(post.getContent()) + .build(); } } From 3e20a9671cb80e34df682b6ff6b7ace7226b7a4b Mon Sep 17 00:00:00 2001 From: kmebin Date: Thu, 3 Aug 2023 16:45:52 +0900 Subject: [PATCH 21/23] =?UTF-8?q?fix:=20url=20=EB=B2=84=EC=A0=80=EB=8B=9D?= =?UTF-8?q?=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../board/domain/post/controller/ApiPostController.java | 2 +- .../domain/post/controller/ApiPostControllerTest.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java b/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java index 510be7575..2b5942b8f 100644 --- a/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java +++ b/src/main/java/com/prgrms/board/domain/post/controller/ApiPostController.java @@ -29,7 +29,7 @@ @RestController @RequiredArgsConstructor -@RequestMapping("/api/v1/posts") +@RequestMapping("/posts") public class ApiPostController { private final PostService postService; diff --git a/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java b/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java index 2d11a898f..fc24c5c32 100644 --- a/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java +++ b/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java @@ -62,7 +62,7 @@ void create_post_success() throws Exception { PostCreateRequest request = new PostCreateRequest(user.getId(), "제목", "내용"); // when & then - mockMvc.perform(post("/api/v1/posts") + mockMvc.perform(post("/posts") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andDo(print()) @@ -93,7 +93,7 @@ void get_posts_success() throws Exception { int totalPage = (int)Math.ceil((double)posts.size() / size); // when & then - mockMvc.perform(get("/api/v1/posts") + mockMvc.perform(get("/posts") .param("page", String.valueOf(page)) .param("size", String.valueOf(size)) ) @@ -120,7 +120,7 @@ void get_post_success() throws Exception { postRepository.save(post); // when & then - mockMvc.perform(get("/api/v1/posts/" + post.getId())) + mockMvc.perform(get("/posts/" + post.getId())) .andDo(print()) .andDo(document("posts/getPost", preprocessRequest(prettyPrint()), @@ -146,7 +146,7 @@ void update_post_success() throws Exception { PostUpdateRequest request = new PostUpdateRequest("수정한 제목", "수정한 내용"); // when & then - mockMvc.perform(patch("/api/v1/posts/" + post.getId()) + mockMvc.perform(patch("/posts/" + post.getId()) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request)) ) From 46b8c3eb7f551278a4069437f9c4a56fdd5d00a9 Mon Sep 17 00:00:00 2001 From: kmebin Date: Thu, 3 Aug 2023 17:55:46 +0900 Subject: [PATCH 22/23] =?UTF-8?q?feat:=20Fixture=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ApiPostControllerTest.java | 12 ++--- .../domain/post/service/PostServiceTest.java | 44 ++++++++++--------- .../com/prgrms/board/support/PostFixture.java | 36 +++++++++++++-- .../com/prgrms/board/support/UserFixture.java | 20 ++++++--- 4 files changed, 75 insertions(+), 37 deletions(-) diff --git a/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java b/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java index fc24c5c32..ca9dff3ef 100644 --- a/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java +++ b/src/test/java/com/prgrms/board/domain/post/controller/ApiPostControllerTest.java @@ -51,7 +51,7 @@ class ApiPostControllerTest { @BeforeEach void init() { - user = UserFixture.create(); + user = UserFixture.user().build(); userRepository.save(user); } @@ -81,9 +81,9 @@ void create_post_success() throws Exception { @DisplayName("게시물 전체 조회에 성공한다.") void get_posts_success() throws Exception { // given - Post post1 = PostFixture.create(user, "제목1", "내용1"); - Post post2 = PostFixture.create(user, "제목2", "내용2"); - Post post3 = PostFixture.create(user, "제목3", "내용3"); + Post post1 = PostFixture.post().user(user).title("제목1").content("내용1").build(); + Post post2 = PostFixture.post().user(user).title("제목2").content("내용2").build(); + Post post3 = PostFixture.post().user(user).title("제목3").content("내용3").build(); List posts = List.of(post1, post2, post3); postRepository.saveAll(posts); @@ -116,7 +116,7 @@ void get_posts_success() throws Exception { @DisplayName("게시물 조회에 성공한다.") void get_post_success() throws Exception { // given - Post post = PostFixture.create(user, "제목", "내용"); + Post post = PostFixture.post().user(user).build(); postRepository.save(post); // when & then @@ -141,7 +141,7 @@ void get_post_success() throws Exception { @DisplayName("게시물 수정에 성공한다.") void update_post_success() throws Exception { // given - Post post = PostFixture.create(user, "제목", "내용"); + Post post = PostFixture.post().user(user).build(); postRepository.save(post); PostUpdateRequest request = new PostUpdateRequest("수정한 제목", "수정한 내용"); diff --git a/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java b/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java index e393e2da2..4b7034b0d 100644 --- a/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java +++ b/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java @@ -48,17 +48,18 @@ class PostServiceTest { @BeforeEach void init() { - user = UserFixture.createByBuilder(); + user = UserFixture.user().build(); } @Test @DisplayName("게시물 생성에 성공한다.") void create_post_success() { // given - PostCreateRequest request = new PostCreateRequest(user.getId(), "제목", "내용"); - Post post = PostFixture.createByBuilder(user, "제목", "내용"); + Long userId = 1L; + Post post = PostFixture.post().build(); + PostCreateRequest request = new PostCreateRequest(userId, "제목", "내용"); - given(userService.findUserOrThrow(any(Long.class))).willReturn(user); + given(userService.findUserOrThrow(userId)).willReturn(user); given(postRepository.save(any(Post.class))).willReturn(post); // when @@ -73,13 +74,14 @@ void create_post_success() { @DisplayName("전체 게시물 조회에 성공한다.") void get_posts_success() { // given - Post post1 = PostFixture.create(user, "제목1", "내용1"); - Post post2 = PostFixture.create(user, "제목2", "내용2"); - Post post3 = PostFixture.create(user, "제목3", "내용3"); - List posts = List.of(post1, post2, post3); + Post post1 = PostFixture.post().title("제목1").content("내용1").build(); + Post post2 = PostFixture.post().title("제목2").content("내용2").build(); + Post post3 = PostFixture.post().title("제목3").content("내용3").build(); + List posts = List.of(post1, post2, post3); Pageable pageable = PageRequest.of(0, 2); Page page = new PageImpl<>(posts.subList(0, 2), pageable, posts.size()); + given(postRepository.findAll(any(Pageable.class))).willReturn(page); // when @@ -95,28 +97,30 @@ void get_posts_success() { @DisplayName("특정 게시물 조회에 성공한다.") void get_post_success() { // given - Post post = PostFixture.createByBuilder(user, "제목1", "내용1"); - given(postRepository.findById(any(Long.class))).willReturn(Optional.of(post)); + Long postId = 1L; + Post post = PostFixture.post().id(postId).build(); + given(postRepository.findById(postId)).willReturn(Optional.of(post)); // when - PostDetailResponse postDetailResponse = postService.getPost(post.getId()); + PostDetailResponse postDetailResponse = postService.getPost(postId); // then - assertThat(postDetailResponse.title()).isEqualTo("제목1"); - assertThat(postDetailResponse.content()).isEqualTo("내용1"); + assertThat(postDetailResponse.title()).isEqualTo(post.getTitle()); + assertThat(postDetailResponse.content()).isEqualTo(post.getContent()); } @Test @DisplayName("게시물 수정에 성공한다.") void update_post_success() { // given + Long postId = 1L; + Post post = PostFixture.post().id(postId).build(); PostUpdateRequest request = new PostUpdateRequest("수정한 제목", "수정한 내용"); - Post post = PostFixture.createByBuilder(user, "제목", "내용"); - given(postRepository.findById(any(Long.class))).willReturn(Optional.of(post)); + given(postRepository.findById(postId)).willReturn(Optional.of(post)); // when - PostResponse result = postService.updatePost(post.getId(), request); + PostResponse result = postService.updatePost(postId, request); // then assertThat(result.title()).isEqualTo("수정한 제목"); @@ -127,11 +131,11 @@ void update_post_success() { @DisplayName("존재하는 게시물이 없는 경우 예외가 발생한다.") void get_post_not_found() { // given - Post post = PostFixture.createByBuilder(user, "제목1", "내용1"); - given(postRepository.findById(any(Long.class))).willReturn(Optional.empty()); + Long postId = 1L; + given(postRepository.findById(postId)).willReturn(Optional.empty()); - // when, then - assertThatThrownBy(() -> postService.getPost(post.getId())) + // when & then + assertThatThrownBy(() -> postService.getPost(postId)) .isInstanceOf(PostNotFoundException.class) .hasMessage("존재하지 않는 게시물입니다."); } diff --git a/src/test/java/com/prgrms/board/support/PostFixture.java b/src/test/java/com/prgrms/board/support/PostFixture.java index 870c5ec53..fd818c8c0 100644 --- a/src/test/java/com/prgrms/board/support/PostFixture.java +++ b/src/test/java/com/prgrms/board/support/PostFixture.java @@ -5,13 +5,41 @@ public class PostFixture { - public static Post create(User user, String title, String content) { - return Post.create(user, title, content); + private Long id; + private String title = "제목"; + private String content = "내용"; + private User user = UserFixture.user().build(); + + private PostFixture() { + } + + public static PostFixture post() { + return new PostFixture(); + } + + public PostFixture id(Long id) { + this.id = id; + return this; + } + + public PostFixture title(String title) { + this.title = title; + return this; + } + + public PostFixture content(String content) { + this.content = content; + return this; + } + + public PostFixture user(User user) { + this.user = user; + return this; } - public static Post createByBuilder(User user, String title, String content) { + public Post build() { return Post.builder() - .id(1L) + .id(id) .user(user) .title(title) .content(content) diff --git a/src/test/java/com/prgrms/board/support/UserFixture.java b/src/test/java/com/prgrms/board/support/UserFixture.java index fc8d7cf35..be63990f8 100644 --- a/src/test/java/com/prgrms/board/support/UserFixture.java +++ b/src/test/java/com/prgrms/board/support/UserFixture.java @@ -4,16 +4,22 @@ public class UserFixture { - public static User create() { - return User.create("이름", 10, "취미"); + private Long id; + private String name = "이름"; + private int age = 10; + + private UserFixture() { } - public static User createByBuilder() { + public static UserFixture user() { + return new UserFixture(); + } + + public User build() { return User.builder() - .id(1L) - .name("이름") - .age(10) - .hobby("취미") + .id(id) + .name(name) + .age(age) .build(); } } From 2e6eed6845c72867b82327c29b49a2c74483276c Mon Sep 17 00:00:00 2001 From: kmebin Date: Thu, 3 Aug 2023 18:25:06 +0900 Subject: [PATCH 23/23] =?UTF-8?q?chore:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/post/service/PostServiceTest.java | 30 +++++++------------ .../com/prgrms/board/support/UserFixture.java | 7 ++++- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java b/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java index 4b7034b0d..d7d00bdcd 100644 --- a/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java +++ b/src/test/java/com/prgrms/board/domain/post/service/PostServiceTest.java @@ -7,7 +7,6 @@ import java.util.List; import java.util.Optional; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -44,22 +43,15 @@ class PostServiceTest { @Mock private UserService userService; - private User user; - - @BeforeEach - void init() { - user = UserFixture.user().build(); - } - @Test @DisplayName("게시물 생성에 성공한다.") void create_post_success() { // given - Long userId = 1L; + User user = UserFixture.user().id(1L).build(); Post post = PostFixture.post().build(); - PostCreateRequest request = new PostCreateRequest(userId, "제목", "내용"); + PostCreateRequest request = new PostCreateRequest(user.getId(), "제목", "내용"); - given(userService.findUserOrThrow(userId)).willReturn(user); + given(userService.findUserOrThrow(user.getId())).willReturn(user); given(postRepository.save(any(Post.class))).willReturn(post); // when @@ -77,8 +69,8 @@ void get_posts_success() { Post post1 = PostFixture.post().title("제목1").content("내용1").build(); Post post2 = PostFixture.post().title("제목2").content("내용2").build(); Post post3 = PostFixture.post().title("제목3").content("내용3").build(); - List posts = List.of(post1, post2, post3); + Pageable pageable = PageRequest.of(0, 2); Page page = new PageImpl<>(posts.subList(0, 2), pageable, posts.size()); @@ -97,12 +89,11 @@ void get_posts_success() { @DisplayName("특정 게시물 조회에 성공한다.") void get_post_success() { // given - Long postId = 1L; - Post post = PostFixture.post().id(postId).build(); - given(postRepository.findById(postId)).willReturn(Optional.of(post)); + Post post = PostFixture.post().id(1L).build(); + given(postRepository.findById(post.getId())).willReturn(Optional.of(post)); // when - PostDetailResponse postDetailResponse = postService.getPost(postId); + PostDetailResponse postDetailResponse = postService.getPost(post.getId()); // then assertThat(postDetailResponse.title()).isEqualTo(post.getTitle()); @@ -113,14 +104,13 @@ void get_post_success() { @DisplayName("게시물 수정에 성공한다.") void update_post_success() { // given - Long postId = 1L; - Post post = PostFixture.post().id(postId).build(); + Post post = PostFixture.post().id(1L).build(); PostUpdateRequest request = new PostUpdateRequest("수정한 제목", "수정한 내용"); - given(postRepository.findById(postId)).willReturn(Optional.of(post)); + given(postRepository.findById(post.getId())).willReturn(Optional.of(post)); // when - PostResponse result = postService.updatePost(postId, request); + PostResponse result = postService.updatePost(post.getId(), request); // then assertThat(result.title()).isEqualTo("수정한 제목"); diff --git a/src/test/java/com/prgrms/board/support/UserFixture.java b/src/test/java/com/prgrms/board/support/UserFixture.java index be63990f8..f1ca4054f 100644 --- a/src/test/java/com/prgrms/board/support/UserFixture.java +++ b/src/test/java/com/prgrms/board/support/UserFixture.java @@ -14,7 +14,12 @@ private UserFixture() { public static UserFixture user() { return new UserFixture(); } - + + public UserFixture id(Long id) { + this.id = id; + return this; + } + public User build() { return User.builder() .id(id)