localhost-back/src/main/java/io/company/localhost/controller/api/BoardController.java

304 lines
10 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.util.List;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
import com.github.pagehelper.PageInfo;
import io.company.localhost.common.annotation.Member;
import io.company.localhost.common.annotation.ParameterCheck;
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.common.exception.InvalidPasswordException;
import io.company.localhost.common.exception.NotFoundHandler;
import io.company.localhost.service.commoncodService;
import io.company.localhost.service.localbordService;
import io.company.localhost.utils.AuthUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@RestController
@RequestMapping("/api/board")
@RequiredArgsConstructor
@Slf4j
public class BoardController {
private final localbordService boardService;
private final commoncodService commoncodService;
private final PasswordEncoder passwordEncoder;
/**
* 공지사항 목록 조회
* @ReqMap map 요청 파라미터 (searchKeyword)
* @return 전체 공지사항 목록
*/
@Member
@ParameterCheck
@GetMapping("/notices")
public ApiResponse<List<MapDto>> getNotices(@ReqMap MapDto map) {
return ApiResponse.ok(boardService.selectNotices(map));
}
/**
* 자유/익명 게시판 목록 조회
* @ReqMap map 요청 파라미터 (page, searchKeyword, orderBy, size)
* @return 페이징된 자유/익명 게시판 목록
*/
@Member
@ParameterCheck
@GetMapping("/general")
public ApiResponse<PageInfo<MapDto>> getGeneralPosts(@ReqMap MapDto map) {
return ApiResponse.ok(boardService.selectGeneralPosts(map));
}
/**
* 게시물 작성
* @ReqMap map 요청 파라미터 (LOCBRDTTL, LOCBRDCON, MEMBERSEQ, LOCBRDTYP,
* LOCBRDPWD(익명일 때만), LOCBRDCAT(지식커뮤니티만))
* @return 작성된 게시물의 ID
*/
@Member
@ParameterCheck
@PostMapping
public ApiResponse<BigInteger> createBoard(@ReqMap MapDto map) {
Long userId = AuthUtil.getUser().getId();
map.put("MEMBERSEQ", userId);
if (map.containsKey("LOCBRDPWD") && !map.getString("LOCBRDPWD").trim().isEmpty()) { // 빈 값 체크
String rawPassword = map.getString("LOCBRDPWD");
String hashedPassword = passwordEncoder.encode(rawPassword);
map.put("LOCBRDPWD", hashedPassword);
}
return ApiResponse.ok(boardService.insertBoard(map));
}
/**
* 게시물 상세보기
* @param boardId 게시물 ID
* @return 게시물 상세정보
*/
@Member
@ParameterCheck
@GetMapping("/{boardId}")
public ApiResponse<MapDto> getBoardDetail(@PathVariable("boardId") Long boardId) {
MapDto board = boardService.selectBoardDetail(boardId);
if (board == null) {
throw new NotFoundHandler("게시물 ID " + boardId + "을(를) 찾을 수 없습니다.");
}
return ApiResponse.ok(board);
}
/**
* 게시물 삭제
* @ReqMap map 수정 데이터 (LOCBRDSEQ)
* @return 삭제 결과 메시지
*/
@Member
@ParameterCheck
@DeleteMapping("/{boardId}")
public ApiResponse<String> deleteBoard(@ReqMap MapDto map) {
boardService.deleteBoard(map);
return ApiResponse.ok("게시물이 삭제되었습니다.");
}
/**
* 게시물 수정
* @ReqMap map 수정 데이터 (LOCBRDTTL, LOCBRDCON, LOCBRDSEQ)
* @return 수정 결과 메시지
*/
@Member
@ParameterCheck
@PutMapping("/{boardId}")
public ApiResponse<String> updateBoard(@ReqMap MapDto map) {
boardService.updateBoard(map);
return ApiResponse.ok("게시물이 수정되었습니다.");
}
/**
* 첨부파일 추가
* @ReqMap map 요청 파라미터 (CMNFLEREG, CMNFLESIZ, CMNFLEEXT, CMNFLEORG, CMNFLENAM, CMNFLEPAT, CMNBRDSEQ)
* @return 첨부파일 저장 결과 메시지
*/
@Member
@ParameterCheck
@PostMapping("/{CMNBRDSEQ}/attachments")
public ApiResponse<String> uploadAttachment(@ReqMap MapDto map) {
Long userId = AuthUtil.getUser().getId();
map.put("CMNFLEREG", userId);
boardService.insertAttachment(map);
return ApiResponse.ok("첨부파일이 저장되었습니다.");
}
/**
* 게시물, 댓글 좋아요/싫어요 추가
* @ReqMap map 데이터 (LOCCMTSEQ, MEMBERSEQ, LOCGOBGOD, LOCGOBBAD, LOCBRDSEQ)
* @return 반응 추가 결과 메시지
*/
@Member
@ParameterCheck
@PostMapping("/{LOCBRDSEQ}/{LOCCMTSEQ}/reaction")
public ApiResponse<String> reactToBoard(@ReqMap MapDto map) {
Long userId = AuthUtil.getUser().getId();
map.put("MEMBERSEQ", userId);
boardService.procReactToBoard(map);
return ApiResponse.ok("반응이 성공적으로 처리되었습니다.");
}
/**
* 댓글/대댓글 조회
* @ReqMap map 수정 데이터 (LOCBRDSEQ)
* @return 댓글과 대댓글의 계층 구조 데이터
*/
@Member
@ParameterCheck
@GetMapping("/{boardId}/comments")
public ApiResponse<PageInfo<MapDto>> getComments(@ReqMap MapDto map) {
return ApiResponse.ok(boardService.selectComments(map));
}
/**
* 댓글/대댓글 작성
* @param boardId 게시물 ID
* @ReqMap map 댓글 데이터 (LOCBRDSEQ, LOCCMTRPY, LOCCMTPNT, LOCCMTPWD, MEMBERSEQ )
* @return 작성 결과 메시지
*/
@Member
@ParameterCheck
@PostMapping("/{LOCBRDSEQ}/comment")
public ApiResponse<String> addCommentOrReply(@ReqMap MapDto map) {
Long userId = AuthUtil.getUser().getId();
map.put("MEMBERSEQ", userId);
if (map.containsKey("LOCCMTPWD") && !map.getString("LOCCMTPWD").trim().isEmpty()) { // 빈 값 체크
String rawPassword = map.getString("LOCCMTPWD");
String hashedPassword = passwordEncoder.encode(rawPassword);
map.put("LOCCMTPWD", hashedPassword);
}
boardService.insertCommentOrReply(map);
return ApiResponse.ok("댓글 또는 대댓글이 작성되었습니다.");
}
/**
* 댓글/대댓글 수정
* @param commentId 댓글 ID
* @ReqMap map 수정 데이터 (LOCCMTSEQ, LOCCMTRPY)
* @return 수정 결과 메시지
*/
@Member
@ParameterCheck
@PutMapping("/comment/{commentId}")
public ApiResponse<String> updateComment(@ReqMap MapDto map) {
boardService.updateComment(map);
return ApiResponse.ok("댓글이 수정되었습니다.");
}
/**
* 댓글/대댓글 삭제
* @ReqMap map 수정 데이터 (LOCCMTSEQ)
* @return 삭제 결과 메시지
*/
@Member
@ParameterCheck
@DeleteMapping("/comment/{commentId}")
public ApiResponse<String> deleteComment(@ReqMap MapDto map) {
boardService.deleteComment(map);
return ApiResponse.ok("댓글이 삭제되었습니다.");
}
/**
* 게시물 비밀번호 확인 (해싱된 비밀번호 비교 적용)
* @ReqMap map 수정 데이터 (LOCBRDSEQ, LOCBRDPWD)
* @return 비밀번호 확인 결과
*/
@Member
@ParameterCheck
@PostMapping("/{boardId}/password")
public ApiResponse<Boolean> checkBoardPassword(@ReqMap MapDto map) {
// boardId 데이터 타입 변환
Object boardIdObj = map.get("LOCBRDSEQ");
int boardId = 0;
if (boardIdObj instanceof Integer) {
boardId = (Integer) boardIdObj;
} else if (boardIdObj instanceof String) {
boardId = Integer.parseInt((String) boardIdObj);
}
String rawPassword = map.getString("LOCBRDPWD");
String storedHashedPassword = boardService.selectBoardPassword(boardId);
if (storedHashedPassword == null) {
throw new NotFoundHandler("해당 게시물이 존재하지 않습니다.");
}
boolean isMatch = passwordEncoder.matches(rawPassword, storedHashedPassword);
if (!isMatch) {
throw new InvalidPasswordException("비밀번호가 일치하지 않습니다.");
}
return ApiResponse.ok(true);
}
/**
* 댓글 비밀번호 확인 (해싱된 비밀번호 비교 적용)
* @ReqMap map 수정 데이터 (LOCCMTSEQ, LOCCMTPWD)
* @return 비밀번호 확인 결과
*/
@Member
@ParameterCheck
@PostMapping("/comment/{commentId}/password")
public ApiResponse<Boolean> checkCommentPassword(@ReqMap MapDto map) {
// commentId 데이터 타입 변환
Object commentIdObj = map.get("LOCCMTSEQ");
int commentId = 0;
if (commentIdObj instanceof Integer) {
commentId = (Integer) commentIdObj;
} else if (commentIdObj instanceof String) {
commentId = Integer.parseInt((String) commentIdObj);
}
String rawPassword = map.getString("LOCCMTPWD");
String storedHashedPassword = boardService.selectCommentPassword(commentId);
if (storedHashedPassword == null) {
throw new NotFoundHandler("해당 댓글이 존재하지 않습니다.");
}
boolean isMatch = passwordEncoder.matches(rawPassword, storedHashedPassword);
if (!isMatch) {
throw new InvalidPasswordException("비밀번호가 일치하지 않습니다.");
}
return ApiResponse.ok(true);
}
/**
* 카테고리 목록 조회
* @return 카테고리 리스트
*/
@GetMapping("/categories")
public ApiResponse<List<MapDto>> getCategories() {
List<MapDto> categories = commoncodService.selectCategoryList();
return ApiResponse.ok(categories);
}
}