localhost-back/src/main/java/io/company/localhost/controller/api/BoardController.java
2025-01-16 11:06:38 +09:00

402 lines
15 KiB
Java

/************************************************************
*
* @packageName : io.company.localhost.controller.api
* @fileName : BoardController.java
* @author : 서지희
* @date : 25.01.07
* @description : 게시판
*
* ===========================================================
* DATE AUTHOR NOTE
* -----------------------------------------------------------
* 24.01.02 서지희 최초 생성
*
*************************************************************/
package io.company.localhost.controller.api;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.sql.Blob;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.PageSerializable;
import io.company.localhost.common.annotation.ReqMap;
import io.company.localhost.common.dto.ApiResponse;
import io.company.localhost.common.dto.MapDto;
import io.company.localhost.service.LocalBordService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@RestController
@RequestMapping("/api/board")
@RequiredArgsConstructor
@Slf4j
public class BoardController {
private final LocalBordService boardService;
/**
* 공지사항 목록 조회
* @ReqMap map 요청 파라미터 (searchKeyword)
* @return 페이징된 공지사항 목록
*/
@GetMapping("/notices")
public ApiResponse<List<MapDto>> getNotices(@ReqMap MapDto map) {
List<MapDto> posts = boardService.getNotices(map);
// Blob 데이터를 처리 (문자열로 변환)
for (MapDto post : posts) {
Object content = post.get("content");
if (content instanceof Blob) {
Blob blob = (Blob) content;
post.put("content", safeBlobToString(blob));
}
}
return ApiResponse.ok(posts);
}
/**
* 자유/익명 게시판 목록 조회
* @ReqMap map 요청 파라미터 (page, size, searchKeyword 포함)
* @return 페이징된 자유/익명 게시판 목록
*/
@GetMapping("/general")
public ApiResponse<PageInfo<MapDto>> getGeneralPosts(@ReqMap MapDto map) {
PageInfo<MapDto> posts = boardService.getGeneralPosts(map);
// Blob 데이터를 처리 (문자열로 변환)
for (MapDto post : posts.getList()) {
Object content = post.get("content");
if (content instanceof Blob) {
Blob blob = (Blob) content;
post.put("content", safeBlobToString(blob));
}
}
return ApiResponse.ok(posts);
}
/**
* 안전하게 Blob 데이터를 문자열로 변환하는 메서드
* @ReqMap
* @return 변환된 문자열 또는 null
*/
private String safeBlobToString(Blob blob) {
if (blob == null) {
return null; // Blob이 null이면 null 반환
}
try {
long blobLength = blob.length();
if (blobLength > Integer.MAX_VALUE) {
throw new IllegalArgumentException("Blob is too large to process.");
}
return new String(blob.getBytes(1, (int) blobLength), StandardCharsets.UTF_8);
} catch (Exception e) {
System.err.println("Failed to convert Blob to String: " + e.getMessage());
e.printStackTrace();
return null; // 변환 실패 시 null 반환
}
}
/**
* 게시물 작성
* @ReqMap map 요청 파라미터 (page, size, searchKeyword 포함)
* @return 작성된 게시물의 ID
*/
@PostMapping
public ApiResponse<?> createBoard(@ReqMap MapDto map) {
BigInteger createdIdx = boardService.createBoard(map); // 작성된 게시물의 idx를 반환
Map<String, Object> responseData = new HashMap<>();
responseData.put("boardId", createdIdx);
responseData.put("message", "게시물이 작성되었습니다.");
return ApiResponse.ok(responseData);
}
/**
* 첨부파일 추가
* @param boardId 게시물 ID
* @param file 업로드된 파일
* @param filePath 파일 저장 경로
* @param originalFileName 원본 파일명
* @param fileExtension 파일 확장자
* @param fileSize 파일 크기
* @param registrantId 등록자 ID
* @param fileName 저장될 파일명
* @return 첨부파일 저장 결과 메시지
*/
@PostMapping("/{boardId}/attachments")
public ApiResponse<String> uploadAttachment(
@PathVariable("boardId") Long boardId,
@RequestParam("file") MultipartFile file,
@RequestParam("CMNFLEPAT") String filePath,
@RequestParam("CMNFLEORG") String originalFileName,
@RequestParam("CMNFLEEXT") String fileExtension,
@RequestParam("CMNFLESIZ") Long fileSize,
@RequestParam("CMNFLEREG") Long registrantId,
@RequestParam("CMNFLENAM") String fileName
) {
// 데이터 준비
MapDto fileData = new MapDto();
fileData.put("CMNBRDSEQ", boardId);
fileData.put("CMNFLENAM", fileName); // 업로드된 파일 이름
fileData.put("CMNFLEORG", originalFileName);
fileData.put("CMNFLEPAT", filePath);
fileData.put("CMNFLEEXT", fileExtension);
fileData.put("CMNFLESIZ", fileSize);
fileData.put("CMNFLEREG", registrantId);
fileData.put("CMNFLERDT", new Date()); // 등록일 현재 시간
log.info("Uploading attachment for board ID: {}", boardId);
// 파일 데이터 저장
boardService.addAttachment(fileData);
return ApiResponse.ok("첨부파일이 저장되었습니다.");
}
/**
* 게시물 상세보기
* @param boardId 게시물 ID
* @return 게시물 상세정보, 첨부파일 목록, 댓글 목록
*/
@GetMapping("/{boardId}")
public ApiResponse<MapDto> getBoardDetail(@PathVariable("boardId") Long boardId) {
log.info("Fetching details for board ID: {}", boardId);
// 게시물 상세정보 조회
MapDto boardDetail = boardService.getBoardDetail(boardId);
if (boardDetail == null) {
throw new IllegalArgumentException("Board not found for ID: " + boardId);
}
// Blob 데이터를 문자열로 변환
if (boardDetail.get("content") instanceof Blob) {
try {
Blob blob = (Blob) boardDetail.get("content");
String contentString = new String(blob.getBytes(1, (int) blob.length()), StandardCharsets.UTF_8);
boardDetail.put("content", contentString);
} catch (Exception e) {
throw new RuntimeException("Failed to process Blob content", e);
}
}
// 첨부파일 및 댓글 조회
List<MapDto> attachments = boardService.getAttachments(boardId);
List<MapDto> comments = boardService.getComments(boardId.intValue());
// 결과 조합
MapDto result = new MapDto();
result.put("boardDetail", boardDetail);
result.put("attachments", attachments);
result.put("comments", comments);
return ApiResponse.ok(result);
}
/**
* 게시물 삭제
* @param boardId 게시물 ID
* @return 삭제 결과 메시지
*/
@DeleteMapping("/{boardId}")
public ApiResponse<String> deleteBoard(@PathVariable("boardId") Long boardId, @ReqMap MapDto map) {
map.put("LOCBRDSEQ", boardId);
log.info("Deleting board with ID: {}", boardId);
boardService.deleteBoard(map);
return ApiResponse.ok("게시물이 삭제되었습니다.");
}
/**
* 게시물 수정
* @param boardId 게시물 ID
* @ReqMap map 수정 데이터 (제목, 내용 등)
* @return 수정 결과 메시지
*/
@PutMapping("/{boardId}")
public ApiResponse<String> updateBoard(@PathVariable("boardId") Long boardId,@ReqMap MapDto map) {
map.put("LOCBRDSEQ", boardId);
boardService.updateBoard(map);
return ApiResponse.ok("게시물이 수정되었습니다.");
}
/**
* 게시물 좋아요/싫어요 추가
* @param boardId 게시물 ID
* @ReqMap map 좋아요/싫어요 데이터
* @return 반응 추가 결과 메시지
*/
@PostMapping("/{boardId}/reaction")
public ApiResponse<String> reactToBoard(@PathVariable("boardId") Long boardId, @ReqMap MapDto map) {
map.put("LOCBRDSEQ", boardId);
boardService.reactToBoard(map);
return ApiResponse.ok("반응이 추가되었습니다.");
}
/**
* 댓글/대댓글 조회
* @param boardId 게시물 ID
* @return 댓글과 대댓글의 계층 구조 데이터
*/
@GetMapping("/{boardId}/comments")
public ApiResponse<List<Map<String, Object>>> getComments(@PathVariable("boardId") int boardId) {
// 모든 댓글과 대댓글 조회
List<MapDto> comments = boardService.getComments(boardId);
// 댓글과 대댓글을 계층 구조로 정렬
Map<Integer, Map<String, Object>> commentMap = new HashMap<>();
for (MapDto comment : comments) {
int commentId = (int) comment.get("LOCCMTSEQ");
Integer parentId = (Integer) comment.get("LOCCMTRPY");
Map<String, Object> commentData = new HashMap<>(comment);
commentData.put("replies", new ArrayList<>()); // 대댓글 리스트 초기화
if (parentId == null) {
// 댓글인 경우
commentMap.put(commentId, commentData);
} else {
// 대댓글인 경우, 부모 댓글의 "replies"에 추가
Map<String, Object> parentComment = commentMap.get(parentId);
if (parentComment != null) {
List<Map<String, Object>> replies = (List<Map<String, Object>>) parentComment.get("replies");
replies.add(commentData);
}
}
}
// 최상위 댓글 리스트 반환
List<Map<String, Object>> result = new ArrayList<>(commentMap.values());
return ApiResponse.ok(result);
}
/**
* 댓글/대댓글 작성
* @param boardId 게시물 ID
* @ReqMap map 댓글 데이터 (내용, 부모 ID 등)
* @return 작성 결과 메시지
*/
@PostMapping("/{boardId}/comment")
public ApiResponse<String> addCommentOrReply(@PathVariable("boardId") int boardId, @ReqMap MapDto map) {
map.put("LOCBRDSEQ", boardId);
// 부모 댓글 확인
Integer parentCommentId = (Integer) map.get("LOCCMTRPY");
if (parentCommentId != null) {
MapDto parentComment = boardService.getCommentById(parentCommentId);
if (parentComment == null) {
throw new IllegalArgumentException("Invalid parent comment ID: " + parentCommentId);
}
}
boardService.addCommentOrReply(map);
return ApiResponse.ok("댓글 또는 대댓글이 작성되었습니다.");
}
/**
* 댓글/대댓글 수정
* @param commentId 댓글 ID
* @ReqMap map 수정 데이터 (내용, 비밀번호 등)
* @return 수정 결과 메시지
*/
@PutMapping("/comment/{commentId}")
public ApiResponse<String> updateComment(@PathVariable("commentId") int commentId, @ReqMap MapDto map) {
// 기존 댓글 조회
MapDto existingComment = boardService.getCommentById(commentId);
if (existingComment == null) {
throw new IllegalArgumentException("Comment not found for ID: " + commentId);
}
// 부모 댓글 ID는 수정 불가
map.remove("LOCCMTRPY");
map.put("LOCCMTSEQ", commentId);
boardService.updateComment(map);
return ApiResponse.ok("댓글이 수정되었습니다.");
}
/**
* 댓글/대댓글 삭제
* @param commentId 댓글 ID
* @ReqMap map 요청 데이터 (비밀번호 등)
* @return 삭제 결과 메시지
*/
@DeleteMapping("/comment/{commentId}")
public ApiResponse<String> deleteComment(@PathVariable("commentId") int commentId, @ReqMap MapDto map) {
map.put("LOCCMTSEQ", commentId);
boardService.deleteComment(map);
return ApiResponse.ok("댓글이 삭제되었습니다.");
}
/**
* 댓글 비밀번호 확인
* @param commentId 댓글 ID
* @ReqMap map 비밀번호 데이터
* @return 비밀번호 확인 결과
*/
@PostMapping("/comment/{commentId}/password")
public ApiResponse<Boolean> checkCommentPassword(@PathVariable("commentId") int commentId, @ReqMap MapDto map) {
map.put("LOCCMTSEQ", commentId);
return ApiResponse.ok(boardService.checkCommentPassword(map));
}
/**
* 게시물 비밀번호 확인
* @param boardId 게시물 ID
* @ReqMap map 비밀번호 데이터
* @return 비밀번호 확인 결과
*/
@PostMapping("/{boardId}/password")
public ApiResponse<Boolean> checkBoardPassword(@PathVariable("boardId") int boardId, @ReqMap MapDto map) {
map.put("LOCBRDSEQ", boardId);
return ApiResponse.ok(boardService.checkBoardPassword(map));
}
/**
* 비밀게시판 여부 확인
* @param boardId 게시물 ID
* @return 비밀게시판 여부
*/
@GetMapping("/{boardId}/isSecret")
public ApiResponse<Boolean> isSecretBoard(@PathVariable("boardId") Long boardId) {
log.info("Checking if board ID {} is secret", boardId);
return ApiResponse.ok(boardService.isSecretBoard(boardId));
}
/**
* 댓글 좋아요/싫어요 추가
* @param commentId 댓글 ID
* @ReqMap map 좋아요/싫어요 데이터
* @return 반응 추가 결과 메시지
*/
@PostMapping("/comment/{commentId}/reaction")
public ApiResponse<String> reactToComment(@PathVariable("commentId") int commentId, @ReqMap MapDto map) {
map.put("LOCCMTSEQ", commentId);
boardService.reactToComment(map);
return ApiResponse.ok("Comment reaction added.");
}
}