Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
68f60f6
[chore] Spring docs 의존성 주입 추가 (#108)
buzz0331 Jul 27, 2025
2146259
[chore] Swagger 설정 (#108)
buzz0331 Jul 27, 2025
fd94086
[docs] user 도메인 Swagger UI로 API 명세 (#108)
buzz0331 Jul 27, 2025
6585db2
[docs] user 도메인 Swagger UI로 API 명세 디테일 수정 (#108)
buzz0331 Jul 28, 2025
bcb7fe5
[fix] whilte list는 filter 거치지 않도록 수정 (#108)
buzz0331 Jul 28, 2025
22b2bb4
[docs] Room 도메인 관련 API 명세 (#108)
buzz0331 Jul 28, 2025
b176da0
[fix] merge (#108)
buzz0331 Jul 28, 2025
baae8ca
[refactor] 사용하지 않는 쿼리 삭제 (#108)
buzz0331 Jul 28, 2025
39012af
[fix] merge (#108)
buzz0331 Jul 28, 2025
f59b496
[docs] Vote 도메인 관련 API 명세 (#108)
buzz0331 Jul 28, 2025
8242dbb
[refactor] 안쓰는 파라미터 제거 (#108)
buzz0331 Jul 28, 2025
8ca4cd1
[docs] Record 도메인 관련 API 명세 (#108)
buzz0331 Jul 28, 2025
7d3d4ca
[docs] Feed 도메인 관련 API 명세 (#108)
buzz0331 Jul 28, 2025
1bc668d
[docs] Feed 도메인 관련 API 명세 (#108)
buzz0331 Jul 28, 2025
cf40d6c
[docs] Comment 도메인 관련 API 명세 (#108)
buzz0331 Jul 28, 2025
61d1895
[docs] Book 도메인 관련 API 명세 (#108)
buzz0331 Jul 28, 2025
b6d5b4f
[fix] 잘못된 HttpStatus 수정 (#108)
buzz0331 Jul 28, 2025
dc1271a
[fix] Request Dto에서 Boolean 래퍼 클래스 사용 (#108)
buzz0331 Jul 28, 2025
29008c4
[fix] merge (#108)
buzz0331 Jul 28, 2025
01ab7b2
[docs] 팔로잉 여부 조회 api 명세 (#108)
buzz0331 Jul 28, 2025
f8d2731
[docs] 내 모임방 리스트 조회 api 명세 (#108)
buzz0331 Jul 28, 2025
279ad57
[fix] 메서드명 오타 수정 (#107)
buzz0331 Jul 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ dependencies {

//Google Guava
implementation 'com.google.guava:guava:33.2.0-jre'

// Swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8'
}

def querydslDir = layout.buildDirectory.dir("generated/querydsl").get().asFile
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,45 @@
package konkuk.thip.book.adapter.in.web;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Pattern;
import konkuk.thip.book.adapter.in.web.request.PostBookIsSavedRequest;
import konkuk.thip.book.adapter.in.web.response.PostBookIsSavedResponse;
import konkuk.thip.book.application.port.in.BookSavedUseCase;
import konkuk.thip.common.dto.BaseResponse;
import konkuk.thip.common.security.annotation.UserId;
import konkuk.thip.common.swagger.annotation.ExceptionDescription;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
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.RestController;

import static konkuk.thip.common.swagger.SwaggerResponseDescription.CHANGE_BOOK_SAVED_STATE;

@Tag(name = "Book Command API", description = "책 상태변경 관련 API")
@Validated
@RestController
@RequiredArgsConstructor
public class BookCommandController {

private final BookSavedUseCase bookSavedUseCase;

//책 저장 상태 변경
@Operation(
summary = "책 저장 상태 변경",
description = "사용자가 책의 저장 상태를 변경합니다. (true -> 저장, false -> 저장 취소)"
)
@ExceptionDescription(CHANGE_BOOK_SAVED_STATE)
@PostMapping("/books/{isbn}/saved")
public BaseResponse<PostBookIsSavedResponse> changeSavedBook(@PathVariable("isbn")
@Pattern(regexp = "\\d{13}") final String isbn,
@RequestBody final PostBookIsSavedRequest postBookIsSavedRequest,
@UserId final Long userId) {
public BaseResponse<PostBookIsSavedResponse> changeSavedBook(
@Parameter(description = "책의 ISBN 번호 (13자리 숫자)", example = "9781234567890")
@PathVariable("isbn") @Pattern(regexp = "\\d{13}") final String isbn,
@RequestBody @Valid final PostBookIsSavedRequest postBookIsSavedRequest,
@Parameter(hidden = true) @UserId final Long userId
) {
return BaseResponse.ok(PostBookIsSavedResponse.of(bookSavedUseCase.changeSavedBook(isbn,postBookIsSavedRequest.type(),userId)));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
package konkuk.thip.book.adapter.in.web;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.Pattern;
import konkuk.thip.book.adapter.in.web.response.GetBookDetailSearchResponse;
import konkuk.thip.book.adapter.in.web.response.GetBookMostSearchResponse;
import konkuk.thip.book.adapter.in.web.response.GetBookSearchListResponse;
import konkuk.thip.book.application.port.in.BookSearchUseCase;
import konkuk.thip.book.application.port.in.BookMostSearchUseCase;
import konkuk.thip.book.application.port.in.BookSearchUseCase;
import konkuk.thip.common.dto.BaseResponse;
import konkuk.thip.common.security.annotation.UserId;
import konkuk.thip.common.swagger.annotation.ExceptionDescription;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import static konkuk.thip.common.swagger.SwaggerResponseDescription.*;

@Tag(name = "Book Query API", description = "책 조회 관련 API")
@Validated
@RestController
@RequiredArgsConstructor
Expand All @@ -20,30 +30,43 @@ public class BookQueryController {
private final BookSearchUseCase bookSearchUseCase;
private final BookMostSearchUseCase bookMostSearchUseCase;


//책 검색결과 조회
@Operation(
summary = "책 검색결과 조회",
description = "사용자가 입력한 키워드로 책을 검색합니다."
)
@ExceptionDescription(BOOK_SEARCH)
@GetMapping("/books")
public BaseResponse<GetBookSearchListResponse> getBookSearchList(@RequestParam final String keyword,
@RequestParam final int page,
@UserId final Long userId) {
public BaseResponse<GetBookSearchListResponse> getBookSearchList(
@Parameter(description = "검색 키워드", example = "해리포터") @RequestParam final String keyword,
@Parameter(description = "페이지 번호 (1부터 시작)", example = "1") @RequestParam final int page,
@Parameter(hidden = true) @UserId final Long userId) {
return BaseResponse.ok(GetBookSearchListResponse.of(bookSearchUseCase.searchBooks(keyword, page,userId), page));
}

//책 상세검색 결과 조회
@Operation(
summary = "책 상세검색 결과 조회",
description = "ISBN을 통해 책의 상세 정보를 조회합니다."
)
@ExceptionDescription(BOOK_DETAIL_SEARCH)
@GetMapping("/books/{isbn}")
public BaseResponse<GetBookDetailSearchResponse> getBookDetailSearch(@PathVariable("isbn")
@Pattern(regexp = "\\d{13}") final String isbn,
@UserId final Long userId) {



public BaseResponse<GetBookDetailSearchResponse> getBookDetailSearch(
@Parameter(description = "책의 ISBN 번호 (13자리 숫자)", example = "9781234567890")
@PathVariable("isbn") @Pattern(regexp = "\\d{13}") final String isbn,
@Parameter(hidden = true) @UserId final Long userId
) {
return BaseResponse.ok(GetBookDetailSearchResponse.of(bookSearchUseCase.searchDetailBooks(isbn,userId)));
}

//가장 많이 검색된 책 조회
@Operation(
summary = "가장 많이 검색된 책 조회",
description = "사용자가 가장 많이 검색한 책들을 조회합니다."
)
@ExceptionDescription(POPULAR_BOOK_SEARCH)
@GetMapping("/books/most-searched")
public BaseResponse<GetBookMostSearchResponse> getMostSearchedBooks(@UserId final Long userId) {

public BaseResponse<GetBookMostSearchResponse> getMostSearchedBooks(
@Parameter(hidden = true) @UserId final Long userId) {
return BaseResponse.ok(GetBookMostSearchResponse.of(bookMostSearchUseCase.getMostSearchedBooks(userId)));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package konkuk.thip.book.adapter.in.web.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;


@Schema(description = "책 저장 상태 변경 요청 DTO")
public record PostBookIsSavedRequest(
@Schema(description = "저장 여부 type (true -> 저장, false -> 저장 취소)", example = "true")
@NotNull(message = "type은 필수입니다.")
boolean type
Boolean type
) {
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package konkuk.thip.comment.adapter.in.web;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import konkuk.thip.comment.adapter.in.web.request.CommentCreateRequest;
import konkuk.thip.comment.adapter.in.web.request.CommentIsLikeRequest;
Expand All @@ -9,9 +12,17 @@
import konkuk.thip.comment.application.port.in.CommentLikeUseCase;
import konkuk.thip.common.dto.BaseResponse;
import konkuk.thip.common.security.annotation.UserId;
import konkuk.thip.common.swagger.annotation.ExceptionDescription;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
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.RestController;

import static konkuk.thip.common.swagger.SwaggerResponseDescription.CHANGE_COMMENT_LIKE_STATE;
import static konkuk.thip.common.swagger.SwaggerResponseDescription.COMMENT_CREATE;

@Tag(name = "Comment Command API", description = "댓글 상태변경 관련 API")
@RestController
@RequiredArgsConstructor
public class CommentCommandController {
Expand All @@ -24,18 +35,31 @@ public class CommentCommandController {
* parentId:{Long},isReplyRequest:true 답글
* parentId:null,isReplyRequest:false 댓글
*/
@Operation(
summary = "댓글 작성",
description = "사용자가 댓글을 작성합니다.\n" +
"답글 작성 시 parentId를 지정하고 isReplyRequest를 true로 설정합니다. " +
"댓글 작성 시 parentId는 null로 설정하고 isReplyRequest를 false로 설정합니다."
)
@ExceptionDescription(COMMENT_CREATE)
@PostMapping("/comments/{postId}")
public BaseResponse<CommentIdResponse> createComment(@RequestBody @Valid final CommentCreateRequest request,
@PathVariable("postId") final Long postId,
@UserId final Long userId) {
public BaseResponse<CommentIdResponse> createComment(
@RequestBody @Valid final CommentCreateRequest request,
@Parameter(description = "댓글을 작성하려는 게시물 ID", example = "1") @PathVariable("postId") final Long postId,
@Parameter(hidden = true) @UserId final Long userId) {
return BaseResponse.ok(CommentIdResponse.of(commentCreateUseCase.createComment(request.toCommand(userId,postId))));
}

//댓글 좋아요 상태 변경: true -> 좋아요, false -> 좋아요 취소
@Operation(
summary = "댓글 좋아요 상태 변경",
description = "사용자가 댓글의 좋아요 상태를 변경합니다. (true -> 좋아요, false -> 좋아요 취소)"
)
@ExceptionDescription(CHANGE_COMMENT_LIKE_STATE)
@PostMapping("/comments/{commentId}/likes")
public BaseResponse<CommentIsLikeResponse> likeComment(@RequestBody @Valid final CommentIsLikeRequest request,
@PathVariable("commentId") final Long commentId,
@UserId final Long userId) {
public BaseResponse<CommentIsLikeResponse> likeComment(
@RequestBody @Valid final CommentIsLikeRequest request,
@Parameter(description = "좋아요 상태를 변경하려는 댓글 ID", example = "1") @PathVariable("commentId") final Long commentId,
@Parameter(hidden = true) @UserId final Long userId) {
return BaseResponse.ok(CommentIsLikeResponse.of(commentLikeUseCase.changeLikeStatusComment(request.toCommand(userId, commentId))));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
package konkuk.thip.comment.adapter.in.web.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import konkuk.thip.comment.application.port.in.dto.CommentCreateCommand;

@Schema(description = "댓글 작성 요청 DTO")
public record CommentCreateRequest(

@Schema(description = "댓글 내용", example = "이 게시물 정말 좋아요!")
@NotBlank(message = "댓글 내용은 필수입니다.")
String content,

@Schema(description = "답글 여부", example = "true")
@NotNull(message = "답글 여부는 필수입니다.")
Boolean isReplyRequest,

@Schema(description = "답글의 부모 댓글 ID (답글이 아닐 경우 null)", example = "1")
Long parentId,

@Schema(description = "게시물 타입 (RECORD, VOTE, FEED)", example = "RECORD")
@NotBlank(message = "게시물 타입은 필수입니다.")
String postType

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package konkuk.thip.comment.adapter.in.web.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import konkuk.thip.comment.application.port.in.dto.CommentIsLikeCommand;

@Schema(description = "댓글 좋아요 상태 변경 요청 DTO")
public record CommentIsLikeRequest(
@Schema(description = "좋아요 여부 type (true -> 좋아요, false -> 좋아요 취소)", example = "true")
@NotNull(message = "좋아요 여부는 필수입니다.")
Boolean type
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ public enum ErrorCode implements ResponseCode {
/**
* 80000 : book error
*/
BOOK_KEYWORD_ENCODING_FAILED(HttpStatus.BAD_REQUEST, 80000, "검색어 인코딩에 실패했습니다."),
BOOK_NAVER_API_REQUEST_ERROR(HttpStatus.BAD_REQUEST, 80001,"네이버 API 요청에 실패하였습니다."),
BOOK_KEYWORD_ENCODING_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, 80000, "검색어 인코딩에 실패했습니다."),
BOOK_NAVER_API_REQUEST_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, 80001,"네이버 API 요청에 실패하였습니다."),
BOOK_NAVER_API_PARSING_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, 80002,"네이버 API 응답 파싱에 실패하였습니다."),
BOOK_NAVER_API_URL_ERROR(HttpStatus.BAD_REQUEST, 80003,"네이버 API URL이 잘못되었습니다."),
BOOK_NAVER_API_URL_HTTP_CONNECT_FAILED(HttpStatus.BAD_REQUEST, 80004,"네이버 API 요청 중, HTTP 연결에 실패하였습니다."),
BOOK_NAVER_API_URL_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, 80003,"네이버 API URL이 잘못되었습니다."),
BOOK_NAVER_API_URL_HTTP_CONNECT_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, 80004,"네이버 API 요청 중, HTTP 연결에 실패하였습니다."),
BOOK_NAVER_API_RESPONSE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, 80005,"네이버 API 응답에 실패하였습니다."),
BOOK_SEARCH_PAGE_OUT_OF_RANGE(HttpStatus.BAD_REQUEST, 80006,"검색어 페이지가 범위를 벗어났습니다."),
BOOK_KEYWORD_REQUIRED(HttpStatus.BAD_REQUEST, 80007, "검색어는 필수 입력값입니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,16 @@ private String extractToken(HttpServletRequest request) {
return null;
}

@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
String path = request.getRequestURI();

// 화이트리스트 경로에 대해서는 JWT 필터 제외
return path.startsWith("/swagger-ui")
|| path.startsWith("/v3/api-docs")
|| path.startsWith("/api-docs")
|| path.startsWith("/oauth2/authorization")
|| path.startsWith("/login/oauth2/code");
}

}
14 changes: 14 additions & 0 deletions src/main/java/konkuk/thip/common/swagger/ExampleHolder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package konkuk.thip.common.swagger;

import io.swagger.v3.oas.models.examples.Example;
import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class ExampleHolder {

private Example holder;
private String name;
private int code;
}
Loading