From 20355ef7f02e6bd40fe71f6d87e5ba81af1dd82c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9A=A9=EC=A4=80?= <59381113+jjuny0310@users.noreply.github.com> Date: Fri, 3 Nov 2023 10:57:27 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=A0=84=EC=B2=B4=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EA=B8=80=20=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0?= =?UTF-8?q?=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 * feat: 전체 게시글 목록 조회 기능 구현 * test: 전체 게시글 목록 조회 컨트롤러 테스트 구현 * test: HOT_POST_LIKES_THRESHOLD 5로 수정 및 테스트 코드 수정 * docs: API 문서 최신화 * chore: 안쓰는 의존성 제거 * fix: 사용하지 않는 파일 관련 어노테이션 삭제 --- build.gradle | 7 - src/docs/asciidoc/post.adoc | 3 + .../post/controller/PostController.java | 7 + .../post/repository/PostRepository.java | 6 +- .../domain/post/service/PostService.java | 9 + .../global/validator/CheckFileCount.java | 19 - .../global/validator/CheckFileSize.java | 19 - .../global/validator/CheckImage.java | 17 - .../global/validator/FileCountValidator.java | 26 - .../global/validator/FileSizeValidator.java | 31 - .../global/validator/ImageValidator.java | 44 -- src/main/resources/static/docs/index.html | 601 ++++++++++++------ .../post/controller/PostControllerTest.java | 38 ++ .../domain/post/service/PostServiceTest.java | 12 +- .../global/util/fixture/PostFixture.java | 11 +- 15 files changed, 483 insertions(+), 367 deletions(-) delete mode 100644 src/main/java/com/ssafy/ssafsound/global/validator/CheckFileCount.java delete mode 100644 src/main/java/com/ssafy/ssafsound/global/validator/CheckFileSize.java delete mode 100644 src/main/java/com/ssafy/ssafsound/global/validator/CheckImage.java delete mode 100644 src/main/java/com/ssafy/ssafsound/global/validator/FileCountValidator.java delete mode 100644 src/main/java/com/ssafy/ssafsound/global/validator/FileSizeValidator.java delete mode 100644 src/main/java/com/ssafy/ssafsound/global/validator/ImageValidator.java diff --git a/build.gradle b/build.gradle index c4f9d427e..314edb13b 100644 --- a/build.gradle +++ b/build.gradle @@ -126,13 +126,6 @@ dependencies { // Spring Cloud AWS implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' -// Spring Boot Batch - implementation 'org.springframework.boot:spring-boot-starter-batch' - implementation 'org.springframework.boot:spring-boot-starter-quartz' - -// apache tika(파일 분석 라이브러리) - implementation 'org.apache.tika:tika-parsers:1.28' - runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5' runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5' compileOnly 'org.projectlombok:lombok' diff --git a/src/docs/asciidoc/post.adoc b/src/docs/asciidoc/post.adoc index 3efb87638..5feb0d4ec 100644 --- a/src/docs/asciidoc/post.adoc +++ b/src/docs/asciidoc/post.adoc @@ -1,5 +1,8 @@ == 익명 게시판 +=== 전체 게시글 목록 조회(Offset) +operation::post/find-all-posts-by-offset[snippets='http-request,http-response,cookie,request-parameters,response-fields'] + === 게시글 목록 조회(Cursor) operation::post/find-posts-by-cursor[snippets='http-request,http-response,cookie,request-parameters,response-fields'] diff --git a/src/main/java/com/ssafy/ssafsound/domain/post/controller/PostController.java b/src/main/java/com/ssafy/ssafsound/domain/post/controller/PostController.java index 089ba2321..d57dc29de 100644 --- a/src/main/java/com/ssafy/ssafsound/domain/post/controller/PostController.java +++ b/src/main/java/com/ssafy/ssafsound/domain/post/controller/PostController.java @@ -19,6 +19,13 @@ public class PostController { private final PostService postService; + @GetMapping("/all/offset") + public EnvelopeResponse findAllPostsByOffset(@Valid @ModelAttribute BasePageRequest basePageRequest) { + return EnvelopeResponse.builder() + .data(postService.findAllPostsByOffset(basePageRequest)) + .build(); + } + @GetMapping("/cursor") public EnvelopeResponse findPostsByCursor(@Valid @ModelAttribute GetPostCursorReqDto getPostCursorReqDto) { return EnvelopeResponse.builder() diff --git a/src/main/java/com/ssafy/ssafsound/domain/post/repository/PostRepository.java b/src/main/java/com/ssafy/ssafsound/domain/post/repository/PostRepository.java index 2bb52214f..bc3585b24 100644 --- a/src/main/java/com/ssafy/ssafsound/domain/post/repository/PostRepository.java +++ b/src/main/java/com/ssafy/ssafsound/domain/post/repository/PostRepository.java @@ -12,12 +12,10 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.List; import java.util.Optional; @Repository public interface PostRepository extends JpaRepository, PostCustomRepository { - boolean existsByIdAndMemberId(Long id, Long memberId); @Query("SELECT p FROM post p JOIN FETCH p.member WHERE p.id = :id") Optional findByIdWithMember(@Param("id") Long id); @@ -48,4 +46,8 @@ public interface PostRepository extends JpaRepository, PostCustomRep @Query("select p from post p " + "where p.member = :member ") Page findMyPostsByMemberAndPageable(@Param("member") Member member, PageRequest pageRequest); + + @EntityGraph(attributePaths = {"board", "member", "likes"}) + @Query(value = "select p from post p ") + Page findAllWithPageable(Pageable pageable); } diff --git a/src/main/java/com/ssafy/ssafsound/domain/post/service/PostService.java b/src/main/java/com/ssafy/ssafsound/domain/post/service/PostService.java index bdc49dca2..0aa6ca49a 100644 --- a/src/main/java/com/ssafy/ssafsound/domain/post/service/PostService.java +++ b/src/main/java/com/ssafy/ssafsound/domain/post/service/PostService.java @@ -362,4 +362,13 @@ public GetPostOffsetResDto searchHotPostsByOffset(GetPostHotSearchOffsetReqDto g Page hotPosts = hotPostRepository.searchHotPostsByKeywordAndPageable(keyword, pageRequest); return GetPostOffsetResDto.ofHotPosts(hotPosts); } + + @Transactional(readOnly = true) + public GetPostOffsetResDto findAllPostsByOffset(BasePageRequest basePageRequest) { + PageRequest pageRequest = basePageRequest.toPageRequest(); + + Page posts = postRepository.findAllWithPageable(pageRequest); + return GetPostOffsetResDto.ofPosts(posts); + + } } diff --git a/src/main/java/com/ssafy/ssafsound/global/validator/CheckFileCount.java b/src/main/java/com/ssafy/ssafsound/global/validator/CheckFileCount.java deleted file mode 100644 index 7f4320676..000000000 --- a/src/main/java/com/ssafy/ssafsound/global/validator/CheckFileCount.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.ssafy.ssafsound.global.validator; - -import javax.validation.Constraint; -import javax.validation.Payload; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.FIELD}) -@Retention(RetentionPolicy.RUNTIME) -@Constraint(validatedBy = FileCountValidator.class) -public @interface CheckFileCount { - String message() default "파일 개수를 초과했습니다."; - Class[] groups() default {}; - Class[] payload() default {}; - - int maxFileCount(); -} diff --git a/src/main/java/com/ssafy/ssafsound/global/validator/CheckFileSize.java b/src/main/java/com/ssafy/ssafsound/global/validator/CheckFileSize.java deleted file mode 100644 index 8a78ccf67..000000000 --- a/src/main/java/com/ssafy/ssafsound/global/validator/CheckFileSize.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.ssafy.ssafsound.global.validator; - -import javax.validation.Constraint; -import javax.validation.Payload; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.FIELD}) -@Retention(RetentionPolicy.RUNTIME) -@Constraint(validatedBy = FileSizeValidator.class) -public @interface CheckFileSize { - String message() default "파일이 제한된 용량을 초과했습니다."; - Class[] groups() default {}; - Class[] payload() default {}; - - long maxFileSize(); // 최대 파일 용량 -} diff --git a/src/main/java/com/ssafy/ssafsound/global/validator/CheckImage.java b/src/main/java/com/ssafy/ssafsound/global/validator/CheckImage.java deleted file mode 100644 index 342bf67c8..000000000 --- a/src/main/java/com/ssafy/ssafsound/global/validator/CheckImage.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.ssafy.ssafsound.global.validator; - -import javax.validation.Constraint; -import javax.validation.Payload; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.FIELD}) -@Retention(RetentionPolicy.RUNTIME) -@Constraint(validatedBy = ImageValidator.class) -public @interface CheckImage { - String message() default "이미지 파일이 아닙니다."; - Class[] groups() default {}; - Class[] payload() default {}; -} diff --git a/src/main/java/com/ssafy/ssafsound/global/validator/FileCountValidator.java b/src/main/java/com/ssafy/ssafsound/global/validator/FileCountValidator.java deleted file mode 100644 index 1a3a9d928..000000000 --- a/src/main/java/com/ssafy/ssafsound/global/validator/FileCountValidator.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.ssafy.ssafsound.global.validator; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.multipart.MultipartFile; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import java.util.List; - -@Slf4j -public class FileCountValidator implements ConstraintValidator> { - private int maxFileCount; - - @Override - public void initialize(CheckFileCount constraintAnnotation) { - this.maxFileCount = constraintAnnotation.maxFileCount(); - } - - @Override - public boolean isValid(List files, ConstraintValidatorContext context) { - if (files.get(0).isEmpty()) { - return true; - } - return files.size() <= maxFileCount; - } -} diff --git a/src/main/java/com/ssafy/ssafsound/global/validator/FileSizeValidator.java b/src/main/java/com/ssafy/ssafsound/global/validator/FileSizeValidator.java deleted file mode 100644 index b7a648c1e..000000000 --- a/src/main/java/com/ssafy/ssafsound/global/validator/FileSizeValidator.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.ssafy.ssafsound.global.validator; - -import org.springframework.web.multipart.MultipartFile; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import java.util.List; - -public class FileSizeValidator implements ConstraintValidator> { - - private Long maxFileSize; - - @Override - public void initialize(CheckFileSize constraintAnnotation) { - this.maxFileSize = constraintAnnotation.maxFileSize(); - } - - @Override - public boolean isValid(List files, ConstraintValidatorContext context) { - if (files.get(0).isEmpty()) { - return true; - } - - for (MultipartFile file : files) { - if (file.getSize() > maxFileSize) - return false; - } - - return true; - } -} diff --git a/src/main/java/com/ssafy/ssafsound/global/validator/ImageValidator.java b/src/main/java/com/ssafy/ssafsound/global/validator/ImageValidator.java deleted file mode 100644 index 04e958622..000000000 --- a/src/main/java/com/ssafy/ssafsound/global/validator/ImageValidator.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.ssafy.ssafsound.global.validator; - -import org.apache.tika.Tika; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.web.multipart.MultipartFile; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import java.io.IOException; -import java.util.List; -import java.util.Objects; - -public class ImageValidator implements ConstraintValidator> { - @Value("${spring.constant.global.validator.IMAGE_EXTENSIONS}") - private List IMAGE_EXTENSIONS; - - @Override - public boolean isValid(List files, ConstraintValidatorContext context) { - if (files.get(0).isEmpty()) { - return true; - } - - - for (MultipartFile file : files) { - // 확장자 검증 - String fileName = file.getOriginalFilename(); - String extension = Objects.requireNonNull(fileName).substring(fileName.lastIndexOf(".") + 1); - if (!IMAGE_EXTENSIONS.contains(extension.toLowerCase())) - return false; - - try { - // 파일 타입 검증 - Tika tika = new Tika(); - String mimeType = tika.detect(file.getBytes()); - if (!mimeType.startsWith("image/")) - return false; - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - return true; - } -} diff --git a/src/main/resources/static/docs/index.html b/src/main/resources/static/docs/index.html index 171c78727..58082d128 100644 --- a/src/main/resources/static/docs/index.html +++ b/src/main/resources/static/docs/index.html @@ -457,25 +457,26 @@

SSAF-SOUND API Documentation

  • 4. 익명 게시판
  • 5. 게시판 댓글 @@ -824,9 +825,219 @@

    4. 익명 게시판

    -

    4.1. 게시글 목록 조회(Cursor)

    +

    4.1. 전체 게시글 목록 조회(Offset)

    -

    4.1.1. HTTP request

    +

    4.1.1. HTTP request

    +
    +
    +
    GET /posts/all/offset?page=1&size=10 HTTP/1.1
    +Host: api.ssafsound.com
    +Cookie: accessToken=accessTokenValue
    +
    +
    +
    +
    +

    4.1.2. HTTP response

    +
    +
    +
    HTTP/1.1 200 OK
    +Vary: Origin
    +Vary: Access-Control-Request-Method
    +Vary: Access-Control-Request-Headers
    +Content-Type: application/json
    +Content-Length: 970
    +
    +{
    +  "code" : "200",
    +  "message" : "success",
    +  "data" : {
    +    "posts" : [ {
    +      "boardId" : 1,
    +      "boardTitle" : "자유 게시판",
    +      "postId" : 4,
    +      "title" : "싸피 어떤가요??",
    +      "content" : "저도 싸피에서 교육들으면 개발실력 엄청 오르겠죠?",
    +      "likeCount" : 11,
    +      "commentCount" : 29,
    +      "createdAt" : "2023-11-02T19:22:10.819607",
    +      "nickname" : "이용준",
    +      "anonymity" : false,
    +      "thumbnail" : "썸네일 URL"
    +    }, {
    +      "boardId" : 1,
    +      "boardTitle" : "취업 게시판",
    +      "postId" : 6,
    +      "title" : "안녕하세요 반갑습니다.",
    +      "content" : "SSAFY 9기 합격했습니다!!",
    +      "likeCount" : 3,
    +      "commentCount" : 2,
    +      "createdAt" : "2023-11-02T19:22:10.819607",
    +      "nickname" : "이용준",
    +      "anonymity" : false,
    +      "thumbnail" : "썸네일 URL"
    +    } ],
    +    "currentPage" : 1,
    +    "totalPageCount" : 1
    +  }
    +}
    +
    +
    +
    +
    + + ++++ + + + + + + + + + + + + +
    CookieDescription

    accessToken

    액세스 토큰 불필요

    +
    +
    +

    4.1.4. Request parameters

    + ++++ + + + + + + + + + + + + + + + + +
    ParameterDescription

    page

    page값은 불러올 현재 페이지의 값을 의미함, 초기 page는 1(또는 첫 페이지는 1)

    size

    현재 페이지의 게시글 개수를 의미함, 최소 size는 10

    +
    +
    +

    4.1.5. Response fields

    + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    PathTypeDescription

    code

    String

    응답 코드

    message

    String

    응답 메시지

    data

    Object

    응답 데이터

    data.posts

    Array

    게시글 목록

    data.currentPage

    Number

    현재 페이지 번호

    data.totalPageCount

    Number

    전체 페이지 수

    data.posts[].boardId

    Number

    게시글이 작성된 게시판 종류의 ID

    data.posts[].boardTitle

    String

    게시글이 작성된 게시판의 종류, 자유 게시판 | 취업 게시판 | 맛집 게시판 | 질문 게시판 | 싸피 예비생 게시판

    data.posts[].postId

    Number

    게시글의 고유 ID

    data.posts[].title

    String

    게시글의 제목

    data.posts[].content

    String

    게시글의 내용

    data.posts[].likeCount

    Number

    게시글의 좋아요 개수

    data.posts[].commentCount

    Number

    게시글의 댓글 개수

    data.posts[].createdAt

    String

    게시글의 작성일

    data.posts[].nickname

    String

    게시글 작성자의 닉네임

    data.posts[].anonymity

    Boolean

    게시글 작성자의 익명 여부인지 나타내는 필드

    data.posts[].thumbnail

    String

    게시판의 썸네일, 게시글의 사진이 여러개가 있을 때 첫 번째 사진이 해당 게시글의 썸네일이 됨.

    +
    +
    +
    +

    4.2. 게시글 목록 조회(Cursor)

    +
    +

    4.2.1. HTTP request

    GET /posts/cursor?boardId=1&cursor=-1&size=10 HTTP/1.1
    @@ -836,7 +1047,7 @@ 

    -

    4.1.2. HTTP response

    +

    4.2.2. HTTP response

    HTTP/1.1 200 OK
    @@ -844,7 +1055,7 @@ 

    - +

    @@ -903,7 +1114,7 @@

    4.2.4. Request parameters

    @@ -932,7 +1143,7 @@

    @@ -1032,9 +1243,9 @@

    -

    4.2. 게시글 목록 조회(Offset)

    +

    4.3. 게시글 목록 조회(Offset)

    -

    4.2.1. HTTP request

    +

    4.3.1. HTTP request

    GET /posts/offset?boardId=1&page=1&size=10 HTTP/1.1
    @@ -1044,7 +1255,7 @@ 

    -

    4.2.2. HTTP response

    +

    4.3.2. HTTP response

    HTTP/1.1 200 OK
    @@ -1052,7 +1263,7 @@ 

    - +

    @@ -1112,7 +1323,7 @@

    4.3.4. Request parameters

    @@ -1141,7 +1352,7 @@

    @@ -1246,9 +1457,9 @@

    -

    4.3. 게시글 상세 보기(실명)

    +

    4.4. 게시글 상세 보기(실명)

    -

    4.3.1. HTTP request

    +

    4.4.1. HTTP request

    GET /posts/1 HTTP/1.1
    @@ -1258,7 +1469,7 @@ 

    -

    4.3.2. HTTP response

    +

    4.4.2. HTTP response

    HTTP/1.1 200 OK
    @@ -1308,7 +1519,7 @@ 

    - +

    @@ -1329,7 +1540,7 @@

    4.4.4. Path parameters

    @@ -1351,7 +1562,7 @@

    -

    4.3.5. Response fields

    +

    4.4.5. Response fields

    Table 1. /posts/{postId}
    @@ -1526,9 +1737,9 @@

    -

    4.4. 게시글 상세 보기(익명)

    +

    4.5. 게시글 상세 보기(익명)

    -

    4.4.1. HTTP request

    +

    4.5.1. HTTP request

    GET /posts/2 HTTP/1.1
    @@ -1538,7 +1749,7 @@ 

    -

    4.4.2. HTTP response

    +

    4.5.2. HTTP response

    HTTP/1.1 200 OK
    @@ -1583,7 +1794,7 @@ 

    - +

    @@ -1604,7 +1815,7 @@

    4.5.4. Path parameters

    @@ -1626,7 +1837,7 @@

    -

    4.4.5. Response fields

    +

    4.5.5. Response fields

    Table 1. /posts/{postId}
    @@ -1801,9 +2012,9 @@

    -

    4.5. 게시글 검색(Cursor)

    +

    4.6. 게시글 검색(Cursor)

    -

    4.5.1. HTTP request

    +

    4.6.1. HTTP request

    GET /posts/search/cursor?boardId=1&keyword=%EC%95%88%EB%85%95%ED%95%98%EC%84%B8%EC%9A%94&cursor=-1&size=10 HTTP/1.1
    @@ -1813,7 +2024,7 @@ 

    -

    4.5.2. HTTP response

    +

    4.6.2. HTTP response

    HTTP/1.1 200 OK
    @@ -1821,7 +2032,7 @@ 

    - +

    @@ -1868,7 +2079,7 @@

    4.6.4. Request parameters

    @@ -1901,7 +2112,7 @@

    -

    4.5.5. Response fields

    +

    4.6.5. Response fields

    @@ -2001,9 +2212,9 @@

    -

    4.6. 게시글 검색(Offset)

    +

    4.7. 게시글 검색(Offset)

    -

    4.6.1. HTTP request

    +

    4.7.1. HTTP request

    GET /posts/search/offset?boardId=1&keyword=%EC%95%88%EB%85%95%ED%95%98%EC%84%B8%EC%9A%94&page=1&size=10 HTTP/1.1
    @@ -2013,7 +2224,7 @@ 

    -

    4.6.2. HTTP response

    +

    4.7.2. HTTP response

    HTTP/1.1 200 OK
    @@ -2021,7 +2232,7 @@ 

    - +

    @@ -2069,7 +2280,7 @@

    4.7.4. Request parameters

    @@ -2102,7 +2313,7 @@

    -

    4.6.5. Response fields

    +

    4.7.5. Response fields

    @@ -2207,9 +2418,9 @@

    -

    4.7. 게시글 작성

    +

    4.8. 게시글 작성

    -

    4.7.1. HTTP request

    +

    4.8.1. HTTP request

    POST /posts?boardId=1 HTTP/1.1
    @@ -2229,7 +2440,7 @@ 

    -

    4.7.2. HTTP response

    +

    4.8.2. HTTP response

    HTTP/1.1 200 OK
    @@ -2250,7 +2461,7 @@ 

    - +

    @@ -2271,7 +2482,7 @@

    4.8.4. Request parameters

    @@ -2292,7 +2503,7 @@

    -

    4.7.5. Request fields

    +

    4.8.5. Request fields

    @@ -2341,7 +2552,7 @@

    -

    4.7.6. Response fields

    +

    4.8.6. Response fields

    @@ -2381,9 +2592,9 @@

    -

    4.8. 게시글 수정

    +

    4.9. 게시글 수정

    -

    4.8.1. HTTP request

    +

    4.9.1. HTTP request

    PATCH /posts/1 HTTP/1.1
    @@ -2403,7 +2614,7 @@ 

    -

    4.8.2. HTTP response

    +

    4.9.2. HTTP response

    HTTP/1.1 200 OK
    @@ -2424,7 +2635,7 @@ 

    - +

    @@ -2445,7 +2656,7 @@

    4.9.4. Path parameters

    @@ -2467,7 +2678,7 @@

    -

    4.8.5. Request fields

    +

    4.9.5. Request fields

    Table 1. /posts/{postId}
    @@ -2516,7 +2727,7 @@

    -

    4.8.6. Response fields

    +

    4.9.6. Response fields

    @@ -2556,9 +2767,9 @@

    -

    4.9. 게시글 삭제

    +

    4.10. 게시글 삭제

    -

    4.9.1. HTTP request

    +

    4.10.1. HTTP request

    DELETE /posts/1 HTTP/1.1
    @@ -2568,7 +2779,7 @@ 

    -

    4.9.2. HTTP response

    +

    4.10.2. HTTP response

    HTTP/1.1 200 OK
    @@ -2589,7 +2800,7 @@ 

    - +

    @@ -2610,7 +2821,7 @@

    4.10.4. Path parameters

    @@ -2632,7 +2843,7 @@

    -

    4.9.5. Response fields

    +

    4.10.5. Response fields

    Table 1. /posts/{postId}
    @@ -2672,9 +2883,9 @@

    -

    4.10. 게시글 좋아요

    +

    4.11. 게시글 좋아요

    -

    4.10.1. HTTP request

    +

    4.11.1. HTTP request

    POST /posts/1/like HTTP/1.1
    @@ -2684,7 +2895,7 @@ 

    -

    4.10.2. HTTP response

    +

    4.11.2. HTTP response

    HTTP/1.1 200 OK
    @@ -2706,7 +2917,7 @@ 

    - +

    @@ -2727,7 +2938,7 @@

    4.11.4. Path parameters

    @@ -2749,7 +2960,7 @@

    -

    4.10.5. Response fields

    +

    4.11.5. Response fields

    Table 1. /posts/{postId}/like
    @@ -2794,9 +3005,9 @@

    -

    4.11. 게시글 스크랩

    +

    4.12. 게시글 스크랩

    -

    4.11.1. HTTP request

    +

    4.12.1. HTTP request

    POST /posts/1/scrap HTTP/1.1
    @@ -2806,7 +3017,7 @@ 

    -

    4.11.2. HTTP response

    +

    4.12.2. HTTP response

    HTTP/1.1 200 OK
    @@ -2828,7 +3039,7 @@ 

    - +

    @@ -2849,7 +3060,7 @@

    4.12.4. Path parameters

    @@ -2871,7 +3082,7 @@

    -

    4.11.5. Response fields

    +

    4.12.5. Response fields

    Table 1. /posts/{postId}/scrap
    @@ -2916,9 +3127,9 @@

    -

    4.12. Hot 게시글 목록 조회(Cursor)

    +

    4.13. Hot 게시글 목록 조회(Cursor)

    -

    4.12.1. HTTP request

    +

    4.13.1. HTTP request

    GET /posts/hot/cursor?cursor=-1&size=10 HTTP/1.1
    @@ -2928,7 +3139,7 @@ 

    -

    4.12.2. HTTP response

    +

    4.13.2. HTTP response

    HTTP/1.1 200 OK
    @@ -2936,7 +3147,7 @@ 

    - +

    @@ -2995,7 +3206,7 @@

    4.13.4. Request parameters

    @@ -3020,7 +3231,7 @@

    @@ -3120,9 +3331,9 @@

    @@ -3200,7 +3411,7 @@

    4.14.4. Request parameters

    @@ -3225,7 +3436,7 @@

    @@ -3330,9 +3541,9 @@

    -

    4.14. Hot 게시글 검색(Cursor)

    +

    4.15. Hot 게시글 검색(Cursor)

    -

    4.14.1. HTTP request

    +

    4.15.1. HTTP request

    GET /posts/hot/search/cursor?keyword=%EC%B7%A8%EC%97%85&cursor=-1&size=10 HTTP/1.1
    @@ -3342,7 +3553,7 @@ 

    -

    4.14.2. HTTP response

    +

    4.15.2. HTTP response

    HTTP/1.1 200 OK
    @@ -3350,7 +3561,7 @@ 

    - +

    @@ -3397,7 +3608,7 @@

    4.15.4. Request parameters

    @@ -3426,7 +3637,7 @@

    -

    4.14.5. Response fields

    +

    4.15.5. Response fields

    @@ -3526,9 +3737,9 @@

    -

    4.15. Hot 게시글 검색(Offset)

    +

    4.16. Hot 게시글 검색(Offset)

    -

    4.15.1. HTTP request

    +

    4.16.1. HTTP request

    GET /posts/hot/search/offset?keyword=%EC%B7%A8%EC%97%85&page=1&size=10 HTTP/1.1
    @@ -3538,7 +3749,7 @@ 

    -

    4.15.2. HTTP response

    +

    4.16.2. HTTP response

    HTTP/1.1 200 OK
    @@ -3546,7 +3757,7 @@ 

    - +

    @@ -3594,7 +3805,7 @@

    4.16.4. Request parameters

    @@ -3623,7 +3834,7 @@

    -

    4.15.5. Response fields

    +

    4.16.5. Response fields

    @@ -3728,9 +3939,9 @@

    -

    4.16. 나의 게시글 목록 조회(Cursor)

    +

    4.17. 나의 게시글 목록 조회(Cursor)

    -

    4.16.1. HTTP request

    +

    4.17.1. HTTP request

    GET /posts/my/cursor?cursor=-1&size=10 HTTP/1.1
    @@ -3740,7 +3951,7 @@ 

    @@ -3807,7 +4018,7 @@

    4.17.4. Request parameters

    @@ -3832,7 +4043,7 @@

    -

    4.16.5. Response fields

    +

    4.17.5. Response fields

    @@ -3932,9 +4143,9 @@

    @@ -4012,7 +4223,7 @@

    4.18.4. Request parameters

    @@ -4037,7 +4248,7 @@

    -

    4.17.5. Response fields

    +

    4.18.5. Response fields

    @@ -4142,9 +4353,9 @@

    @@ -4221,7 +4432,7 @@
    @@ -4246,7 +4457,7 @@

    @@ -4346,9 +4557,9 @@

    @@ -4426,7 +4637,7 @@
    @@ -4451,7 +4662,7 @@

    @@ -4591,7 +4802,7 @@

    @@ -13632,7 +13843,7 @@

    @@ -13848,7 +14059,7 @@

    @@ -14581,7 +14792,7 @@

    diff --git a/src/test/java/com/ssafy/ssafsound/domain/post/controller/PostControllerTest.java b/src/test/java/com/ssafy/ssafsound/domain/post/controller/PostControllerTest.java index d6bb3904f..24d6c01e7 100644 --- a/src/test/java/com/ssafy/ssafsound/domain/post/controller/PostControllerTest.java +++ b/src/test/java/com/ssafy/ssafsound/domain/post/controller/PostControllerTest.java @@ -18,6 +18,44 @@ class PostControllerTest extends ControllerTest { + @Test + @DisplayName("전체 게시글 목록 조회(Offset), page와 size를 기준으로 오프셋 기반 페이지네이션이 수행됨.") + void findAllPostsByOffset() { + doReturn(GET_POST_OFFSET_RES_DTO3) + .when(postService) + .findAllPostsByOffset(any()); + + restDocs.cookie(ACCESS_TOKEN) + .when().get("/posts/all/offset?page={page}&size={pageSize}", 1, 10) + .then().log().all() + .statusCode(HttpStatus.OK.value()) + .apply(document("post/find-all-posts-by-offset", + requestCookieAccessTokenNeedless(), + requestParameters( + parameterWithName("page").description("page값은 불러올 현재 페이지의 값을 의미함, 초기 page는 1(또는 첫 페이지는 1)"), + parameterWithName("size").description("현재 페이지의 게시글 개수를 의미함, 최소 size는 10") + ), + getEnvelopPatternWithData().andWithPrefix("data.", + fieldWithPath("posts").type(JsonFieldType.ARRAY).description("게시글 목록"), + fieldWithPath("currentPage").type(JsonFieldType.NUMBER).description("현재 페이지 번호"), + fieldWithPath("totalPageCount").type(JsonFieldType.NUMBER).description("전체 페이지 수") + ).andWithPrefix("data.posts[].", + fieldWithPath("boardId").type(JsonFieldType.NUMBER).description("게시글이 작성된 게시판 종류의 ID"), + fieldWithPath("boardTitle").type(JsonFieldType.STRING).description("게시글이 작성된 게시판의 종류, 자유 게시판 | 취업 게시판 | 맛집 게시판 | 질문 게시판 | 싸피 예비생 게시판"), + fieldWithPath("postId").type(JsonFieldType.NUMBER).description("게시글의 고유 ID"), + fieldWithPath("title").type(JsonFieldType.STRING).description("게시글의 제목"), + fieldWithPath("content").type(JsonFieldType.STRING).description("게시글의 내용"), + fieldWithPath("likeCount").type(JsonFieldType.NUMBER).description("게시글의 좋아요 개수"), + fieldWithPath("commentCount").type(JsonFieldType.NUMBER).description("게시글의 댓글 개수"), + fieldWithPath("createdAt").type(JsonFieldType.STRING).description("게시글의 작성일").optional(), + fieldWithPath("nickname").type(JsonFieldType.STRING).description("게시글 작성자의 닉네임"), + fieldWithPath("anonymity").type(JsonFieldType.BOOLEAN).description("게시글 작성자의 익명 여부인지 나타내는 필드"), + fieldWithPath("thumbnail").type(JsonFieldType.STRING).description("게시판의 썸네일, 게시글의 사진이 여러개가 있을 때 첫 번째 사진이 해당 게시글의 썸네일이 됨.").optional() + ) + ) + ); + } + @Test @DisplayName("게시글 목록 조회(Cursor), cursor와 size를 기준으로 커서 기반 페이지네이션이 수행됨.") void findPostsByCursor() { diff --git a/src/test/java/com/ssafy/ssafsound/domain/post/service/PostServiceTest.java b/src/test/java/com/ssafy/ssafsound/domain/post/service/PostServiceTest.java index da7620fb1..e896e8031 100644 --- a/src/test/java/com/ssafy/ssafsound/domain/post/service/PostServiceTest.java +++ b/src/test/java/com/ssafy/ssafsound/domain/post/service/PostServiceTest.java @@ -205,13 +205,13 @@ void Given_PostIdAndLoginMemberId_When_SaveLikePost_Then_Success() { // given Post post = POST_FIXTURE1; Member member = memberFixture.createGeneralMember(); - int likeCount = 4; + int likeCount = 2; given(postRepository.findById(post.getId())).willReturn(Optional.of(post)); given(memberRepository.findById(member.getId())).willReturn(Optional.of(member)); given(postLikeRepository.findByPostIdAndMemberId(post.getId(), member.getId())).willReturn(Optional.empty()); given(postLikeRepository.countByPostId(post.getId())).willReturn(likeCount); - given(postConstantProvider.getHOT_POST_LIKES_THRESHOLD()).willReturn(10L); + given(postConstantProvider.getHOT_POST_LIKES_THRESHOLD()).willReturn(HOT_POST_LIKES_THRESHOLD); // when PostCommonLikeResDto response = postService.likePost(post.getId(), member.getId()); @@ -265,13 +265,13 @@ void Given_PostIdAndLoginMemberId_When_likePost_Then_SaveHotPost() { // given Post post = POST_FIXTURE1; Member member = memberFixture.createGeneralMember(); - int likeCount = 9; + int likeCount = 4; given(postRepository.findById(post.getId())).willReturn(Optional.of(post)); given(memberRepository.findById(member.getId())).willReturn(Optional.of(member)); given(postLikeRepository.findByPostIdAndMemberId(post.getId(), member.getId())).willReturn(Optional.empty()); given(postLikeRepository.countByPostId(post.getId())).willReturn(likeCount); - given(postConstantProvider.getHOT_POST_LIKES_THRESHOLD()).willReturn(10L); + given(postConstantProvider.getHOT_POST_LIKES_THRESHOLD()).willReturn(HOT_POST_LIKES_THRESHOLD); given(hotPostRepository.existsByPostId(post.getId())).willReturn(false); // when @@ -296,13 +296,13 @@ void Given_PostIdAndLoginMemberId_When_likePost_Then_NotSaveHotPost() { // given Post post = POST_FIXTURE1; Member member = memberFixture.createGeneralMember(); - int likeCount = 9; + int likeCount = 4; given(postRepository.findById(post.getId())).willReturn(Optional.of(post)); given(memberRepository.findById(member.getId())).willReturn(Optional.of(member)); given(postLikeRepository.findByPostIdAndMemberId(post.getId(), member.getId())).willReturn(Optional.empty()); given(postLikeRepository.countByPostId(post.getId())).willReturn(likeCount); - given(postConstantProvider.getHOT_POST_LIKES_THRESHOLD()).willReturn(10L); + given(postConstantProvider.getHOT_POST_LIKES_THRESHOLD()).willReturn(HOT_POST_LIKES_THRESHOLD); given(hotPostRepository.existsByPostId(post.getId())).willReturn(true); // when diff --git a/src/test/java/com/ssafy/ssafsound/global/util/fixture/PostFixture.java b/src/test/java/com/ssafy/ssafsound/global/util/fixture/PostFixture.java index 6c1fc39f8..4b127a5ec 100644 --- a/src/test/java/com/ssafy/ssafsound/global/util/fixture/PostFixture.java +++ b/src/test/java/com/ssafy/ssafsound/global/util/fixture/PostFixture.java @@ -12,6 +12,8 @@ public class PostFixture { private static final MemberFixture memberFixture = new MemberFixture(); private static final BoardFixture boardFixture = new BoardFixture(); + public static final Long HOT_POST_LIKES_THRESHOLD = 5L; + public static final Post POST_FIXTURE1 = Post.builder() .id(1L) .title("싸탈하고 싶다.") @@ -69,7 +71,7 @@ public class PostFixture { public static final GetPostElement GET_POST_ELEMENT3 = GetPostElement.builder() .boardId(1L) - .boardTitle("자유 게시판") + .boardTitle("취업 게시판") .postId(6L) .title("안녕하세요 반갑습니다.") .content("SSAFY 9기 합격했습니다!!") @@ -161,6 +163,13 @@ public class PostFixture { .totalPageCount(1) .build(); + public static final GetPostOffsetResDto GET_POST_OFFSET_RES_DTO3 = GetPostOffsetResDto.builder() + .posts(List.of(GET_POST_ELEMENT1, + GET_POST_ELEMENT3)) + .currentPage(1) + .totalPageCount(1) + .build(); + public static final GetPostCursorResDto GET_POST_HOT_CURSOR_RES_DTO1 = GetPostCursorResDto.builder() .posts(List.of(GET_POST_HOT_ELEMENT1, GET_POST_HOT_ELEMENT2))