Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.dodo.backend.board.controller;

import com.dodo.backend.board.dto.request.BoardRequest.BoardCreateRequest;
import com.dodo.backend.board.dto.response.BoardResponse;
import com.dodo.backend.board.dto.response.BoardResponse.BoardCreateResponse;
import com.dodo.backend.board.dto.response.BoardResponse.BoardDetailResponse;
import com.dodo.backend.board.service.BoardService;
import com.dodo.backend.common.exception.ErrorResponse;
import io.swagger.v3.oas.annotations.Operation;
Expand All @@ -11,6 +12,7 @@
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
Expand All @@ -20,6 +22,9 @@

import java.util.UUID;

/**
* 게시글 관련 HTTP 요청을 처리하는 컨트롤러입니다.
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/boards")
Expand All @@ -29,10 +34,13 @@ public class BoardController {

private final BoardService boardService;

/**
* 게시글 작성
*/
@Operation(summary = "새로운 게시글 작성", description = "새로운 게시글을 작성합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "게시글이 성공적으로 작성되었습니다.",
content = @Content(schema = @Schema(implementation = BoardResponse.BoardCreateResponse.class))),
content = @Content(schema = @Schema(implementation = BoardCreateResponse.class))),
@ApiResponse(responseCode = "400", description = "잘못된 요청입니다.",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
Expand All @@ -48,6 +56,51 @@ public class BoardController {
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(name = "403 Forbidden",
value = "{\"status\": 403, \"message\": \"게시글을 생성할 권한이 없습니다.\"}"))),
@ApiResponse(responseCode = "500", description = "서버 내부 오류가 발생했습니다.",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(name = "500 Internal Server Error",
value = "{\"status\": 500, \"message\": \"서버 내부 오류가 발생했습니다.\"}")))
})
@PostMapping
public ResponseEntity<BoardCreateResponse> createBoard(
@Valid @RequestBody BoardCreateRequest request,
@AuthenticationPrincipal UserDetails userDetails
) {

UUID userId = UUID.fromString(userDetails.getUsername());
log.info("게시글 작성 요청 수신 - User: {}, Title: {}", userId, request.getBoardTitle());

Long boardId = boardService.createBoard(userId, request);

BoardCreateResponse response =
BoardCreateResponse.toDto(boardId, "게시글이 성공적으로 작성되었습니다.");

return ResponseEntity.ok(response);
}

/**
* 게시글 상세 조회
*/
@Operation(summary = "특정 게시글 상세 조회", description = "게시글 ID를 기반으로 게시글 상세 정보를 조회합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "게시글 상세 조회에 성공했습니다.",
content = @Content(schema = @Schema(implementation = BoardDetailResponse.class))),
@ApiResponse(responseCode = "400", description = "잘못된 요청입니다.",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(name = "400 Bad Request",
value = "{\"status\": 400, \"message\": \"잘못된 요청입니다.\"}"))),
@ApiResponse(responseCode = "401", description = "로그인이 필요한 기능입니다.",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(name = "401 Unauthorized",
value = "{\"status\": 401, \"message\": \"로그인이 필요한 기능입니다.\"}"))),
@ApiResponse(responseCode = "403", description = "특정 게시글을 조회할 권한이 없습니다.",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(name = "403 Forbidden",
value = "{\"status\": 403, \"message\": \"특정 게시글을 조회할 권한이 없습니다.\"}"))),
@ApiResponse(responseCode = "404", description = "해당 ID의 게시글을 찾을 수 없습니다.",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
Expand All @@ -59,22 +112,16 @@ public class BoardController {
examples = @ExampleObject(name = "500 Internal Server Error",
value = "{\"status\": 500, \"message\": \"서버 내부 오류가 발생했습니다.\"}")))
})
/**
* 게시글 작성
*/
@PostMapping
public ResponseEntity<BoardResponse.BoardCreateResponse> createBoard(
@RequestBody BoardCreateRequest request,
@GetMapping("/{boardId}")
public ResponseEntity<BoardDetailResponse> getBoardDetail(
@PathVariable Long boardId,
@AuthenticationPrincipal UserDetails userDetails
) {

UUID userId = UUID.fromString(userDetails.getUsername());
log.info("게시글 작성 요청 수신 - User: {}, Title: {}", userId, request.getBoardTitle());

Long boardId = boardService.createBoard(userId, request);
log.info("게시글 상세 조회 요청 수신 - User: {}, BoardId: {}", userId, boardId);

BoardResponse.BoardCreateResponse response =
BoardResponse.BoardCreateResponse.toDto(boardId, "게시글이 성공적으로 작성되었습니다.");
BoardDetailResponse response = boardService.getBoardDetail(boardId);

return ResponseEntity.ok(response);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static class BoardCreateRequest {
@NotBlank(message = "내용은 필수입니다.")
private String boardContent;

@Schema(description = "게시글 이미지 URL 목록")
@Schema(description = "게시글 이미지 URL 목록", nullable = true)
private List<String> imageFileUrls;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

Expand Down Expand Up @@ -37,4 +36,55 @@ public static BoardCreateResponse toDto(Long boardId, String message) {
.build();
}
}

/**
* 게시글 상세 조회 응답 DTO
*/
@Getter
@Builder
@AllArgsConstructor
@Schema(description = "게시글 상세 조회 응답")
public static class BoardDetailResponse {

@Schema(description = "응답 메시지", example = "게시글 상세 조회에 성공했습니다.")
private String message;

@Schema(description = "게시글 ID", example = "123")
private Long boardId;

@Schema(description = "게시글 제목", example = "저희 강아지 자랑합니다!")
private String boardTitle;

@Schema(description = "게시글 내용", example = "오늘 산책하다 찍은 사진이에요. 너무 귀엽죠?")
private String boardContent;

@Schema(description = "게시글 이미지 URL", example = "https://example.com/images/bori.jpg")
private String imageFileUrl;

@Schema(description = "작성자 닉네임", example = "자유로운영혼")
private String nickname;

@Schema(description = "조회수", example = "51")
private Integer viewCount;

@Schema(description = "게시글 생성 시각", example = "2025-10-06T10:00:00")
private LocalDateTime boardCreatedAt;

@Schema(description = "게시글 수정 시각", example = "2025-10-06T11:00:00")
private LocalDateTime modifiedAt;

public static BoardDetailResponse toDto(Board board, String imageFileUrl, String message) {
return BoardDetailResponse.builder()
.message(message)
.boardId(board.getBoardId())
.boardTitle(board.getBoardTitle())
.boardContent(board.getBoardContent())
.imageFileUrl(imageFileUrl)
.nickname(board.getUser().getNickname())
.viewCount(board.getViewCount())
.boardCreatedAt(board.getBoardCreatedAt())
.modifiedAt(board.getModifiedAt())
.build();
}
}
}
15 changes: 13 additions & 2 deletions src/main/java/com/dodo/backend/board/service/BoardService.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.dodo.backend.board.service;

import com.dodo.backend.board.dto.response.BoardResponse;
import com.dodo.backend.board.dto.request.BoardRequest.BoardCreateRequest;
import com.dodo.backend.board.dto.response.BoardResponse.BoardDetailResponse;
import com.dodo.backend.board.entity.Board;
import com.dodo.backend.board.dto.request.BoardRequest;

import java.util.UUID;

/**
* 게시물(Board) 도메인의 비즈니스 로직을 처리하는 서비스 인터페이스입니다.
*/
Expand All @@ -21,7 +21,18 @@ public interface BoardService {

/**
* 게시글 생성
*
* @param userId 요청 사용자 ID
* @param request 게시글 생성 요청 DTO
* @return 생성된 게시글 ID
*/
Long createBoard(UUID userId, BoardCreateRequest request);

/**
* 게시글 상세 조회
*
* @param boardId 게시글 ID
* @return 게시글 상세 조회 응답 DTO
*/
BoardDetailResponse getBoardDetail(Long boardId);
}
Loading
Loading