Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package org.sejongisc.backend.board.controller;

import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.sejongisc.backend.board.entity.BoardType;
import org.sejongisc.backend.board.entity.PostType;
import org.sejongisc.backend.board.dto.*;
import org.sejongisc.backend.board.service.PostService;
import org.sejongisc.backend.common.auth.springsecurity.CustomUserDetails;
import org.springframework.data.domain.Page;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.UUID;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/post")
@Tag(
name = "게시글 및 댓글 API",
description = "게시글 및 댓글 작성, 수정, 삭제 관련 API 제공"
)
public class PostController {

private final PostService postService;

// 게시글 작성
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Void> createPost(
@Valid @ModelAttribute PostRequest request,
@AuthenticationPrincipal CustomUserDetails customUserDetails) {
UUID userId = customUserDetails.getUserId();
postService.savePost(request, userId);
return ResponseEntity.ok().build();
}

// 게시글 수정
@PutMapping(value = "/{postId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Void> updatePost(
@Valid @ModelAttribute PostRequest request,
@PathVariable UUID postId,
@AuthenticationPrincipal CustomUserDetails customUserDetails) {
UUID userId = customUserDetails.getUserId();
postService.updatePost(request, postId, userId);
return ResponseEntity.ok().build();
}

// 게시글 삭제
@DeleteMapping("/{postId}")
public void deletePost(
@PathVariable UUID postId,
@AuthenticationPrincipal CustomUserDetails customUserDetails) {
UUID userId = customUserDetails.getUserId();
postService.deletePost(postId, userId);
}

// 게시글 조회 (공지/일반)
@GetMapping
public ResponseEntity<Page<PostResponse>> getPosts(
@RequestParam BoardType boardType,
@RequestParam(defaultValue = "0") int pageNumber,
@RequestParam(defaultValue = "20") int pageSize) {
return ResponseEntity.ok(postService.getPosts(boardType, pageNumber, pageSize));
}

// 게시글 검색
@GetMapping("/search")
public ResponseEntity<Page<PostResponse>> searchPosts(
@RequestParam String keyword,
@RequestParam(defaultValue = "0") int pageNumber,
@RequestParam(defaultValue = "20") int pageSize) {
return ResponseEntity.ok(postService.searchPosts(keyword, pageNumber, pageSize));
}

// 게시물 상세 조회
@GetMapping("/{postId}")
public ResponseEntity<PostResponse> getPostDetail(
@PathVariable UUID postId,
@RequestParam(defaultValue = "0") int commentPageNumber,
@RequestParam(defaultValue = "20") int commentPageSize) {
PostResponse response = postService.getPostDetail(postId, commentPageNumber, commentPageSize);
return ResponseEntity.ok(response);
}

// 좋아요 토글
@PostMapping("/{postId}/like")
public ResponseEntity<Void> toggleLike(
@PathVariable UUID postId,
@AuthenticationPrincipal CustomUserDetails customUserDetails) {
UUID userId = customUserDetails.getUserId();
postService.toggleLike(postId, userId);
return ResponseEntity.ok().build();
}

// 북마크 토글
@PostMapping("/{postId}/bookmark")
public ResponseEntity<Void> toggleBookmark(
@PathVariable UUID postId,
@AuthenticationPrincipal CustomUserDetails customUserDetails) {
UUID userId = customUserDetails.getUserId();
postService.toggleBookmark(postId, userId);
return ResponseEntity.ok().build();
}

// 댓글 작성
@PostMapping("/{postId}/comment")
public ResponseEntity<Void> createComment(
@RequestBody CommentRequest request,
@AuthenticationPrincipal CustomUserDetails customUserDetails) {
UUID userId = customUserDetails.getUserId();
postService.createComment(request, userId);
return ResponseEntity.ok().build();
}

// 댓글 수정
@PutMapping("/comment/{commentId}")
public void updateComment(
@PathVariable UUID commentId,
@RequestBody CommentRequest request,
@AuthenticationPrincipal CustomUserDetails customUserDetails) {
UUID userId = customUserDetails.getUserId();
postService.updateComment(request, commentId, userId);
}

// 댓글 삭제
@DeleteMapping("/comment/{commentId}")
public void deleteComment(
@PathVariable UUID commentId,
@AuthenticationPrincipal CustomUserDetails customUserDetails) {
UUID userId = customUserDetails.getUserId();
postService.deleteComment(commentId, userId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.sejongisc.backend.board.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@ToString
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Builder
public class CommentRequest {

@NotNull
private UUID postId;

@NotBlank(message = "댓글 내용은 필수 항목입니다.")
private String content;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.sejongisc.backend.board.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

import java.time.LocalDateTime;
import java.util.UUID;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.sejongisc.backend.board.entity.Comment;

@ToString
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Builder
public class CommentResponse {
private UUID commentId;
private UUID postId;
private String content;
private LocalDateTime createdDate;
private LocalDateTime updatedDate;

public static CommentResponse of(Comment comment) {
return CommentResponse.builder()
.commentId(comment.getCommentId())
.postId(comment.getPost().getPostId())
.content(comment.getContent())
.createdDate(comment.getCreatedDate())
.updatedDate(comment.getUpdatedDate())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.sejongisc.backend.board.dto;

import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.sejongisc.backend.board.entity.PostAttachment;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PostAttachmentResponse {
private UUID postAttachmentId;
private String originalFilename;
private String filePath;

public static PostAttachmentResponse of(PostAttachment attachment) {
return PostAttachmentResponse.builder()
.postAttachmentId(attachment.getPostAttachmentId())
.originalFilename(attachment.getOriginalFilename())
.filePath(attachment.getFilePath())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.sejongisc.backend.board.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.sejongisc.backend.board.entity.BoardType;
import org.sejongisc.backend.board.entity.PostType;
import org.springframework.web.multipart.MultipartFile;

@ToString
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Builder
public class PostRequest {

@NotNull(message = "게시판 타입을 선택해주세요.")
private BoardType boardType;

@NotBlank(message = "제목은 필수 항목입니다.")
private String title;

@NotBlank(message = "내용은 필수 항목입니다.")
private String content;

@NotNull(message = "게시글 타입을 선택해주세요.")
private PostType postType;

private List<MultipartFile> files;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.sejongisc.backend.board.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.sejongisc.backend.board.entity.BoardType;
import org.sejongisc.backend.board.entity.Post;
import org.sejongisc.backend.board.entity.PostType;

import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import org.sejongisc.backend.user.entity.User;
import org.springframework.data.domain.Page;

@ToString
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Builder
public class PostResponse {

private UUID postId;
private BoardType boardType;
private User user;
private String title;
private String content;
private PostType postType;
private Integer bookmarkCount;
private Integer likeCount;
private Integer commentCount;
private LocalDateTime createdDate;
private LocalDateTime updatedDate;
private Page<CommentResponse> comments;
private List<PostAttachmentResponse> attachments;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.sejongisc.backend.board.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;

import java.time.LocalDateTime;
import java.util.UUID;

@Getter
@AllArgsConstructor
public class PostSummaryResponse {
private UUID id;
private String title;
private int likeCount;
private int commentCount;
private LocalDateTime createdAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.sejongisc.backend.board.entity;

public enum BoardType {
GENERAL, // 전체 게시판
FINANCE_IT, // 금융 IT 게시판
ASSET_MANAGEMENT // 자산 운용 게시판
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.sejongisc.backend.board.entity;

import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.CreationTimestamp;
import java.time.LocalDateTime;
import java.util.UUID;
import org.sejongisc.backend.common.entity.postgres.BasePostgresEntity;
import org.sejongisc.backend.user.entity.User;

@Entity
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Comment extends BasePostgresEntity {

@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID commentId;

@ManyToOne(fetch = FetchType.LAZY)
private Post post;

@ManyToOne(fetch = FetchType.LAZY)
private User user;

@Column(columnDefinition = "TEXT", nullable = false)
private String content;
}
Loading