From 548f67b538644d3c8de3dfb0ffcd5f57329240b6 Mon Sep 17 00:00:00 2001 From: 3un0ia Date: Mon, 25 Mar 2024 21:45:08 +0900 Subject: [PATCH] =?UTF-8?q?post=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=20=EB=B0=8F=20=EA=B8=B0=EB=B3=B8=20=EC=98=88=EC=99=B8=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../JWT/common/exception/CommonException.java | 15 +++ .../JWT/common/exception/ExceptionAdvice.java | 32 +++++ .../JWT/common/exception/ExceptionMapper.java | 42 ++++++ .../common/exception/ExceptionResponse.java | 11 ++ .../common/exception/ExceptionSituation.java | 17 +++ .../JWT/post/controller/PostController.java | 10 +- .../post/exception/IsNotNoticeException.java | 6 + .../post/exception/PostNotFoundException.java | 9 ++ .../JWT/post/service/PostService.java | 122 +++++++++--------- .../exception/HasNoAuthorityException.java | 6 + .../user/exception/UserNotFoundException.java | 6 + 11 files changed, 210 insertions(+), 66 deletions(-) create mode 100644 JWT/src/main/java/JWTLogIn/JWT/common/exception/CommonException.java create mode 100644 JWT/src/main/java/JWTLogIn/JWT/common/exception/ExceptionAdvice.java create mode 100644 JWT/src/main/java/JWTLogIn/JWT/common/exception/ExceptionMapper.java create mode 100644 JWT/src/main/java/JWTLogIn/JWT/common/exception/ExceptionResponse.java create mode 100644 JWT/src/main/java/JWTLogIn/JWT/common/exception/ExceptionSituation.java create mode 100644 JWT/src/main/java/JWTLogIn/JWT/post/exception/IsNotNoticeException.java create mode 100644 JWT/src/main/java/JWTLogIn/JWT/post/exception/PostNotFoundException.java create mode 100644 JWT/src/main/java/JWTLogIn/JWT/user/exception/HasNoAuthorityException.java create mode 100644 JWT/src/main/java/JWTLogIn/JWT/user/exception/UserNotFoundException.java diff --git a/JWT/src/main/java/JWTLogIn/JWT/common/exception/CommonException.java b/JWT/src/main/java/JWTLogIn/JWT/common/exception/CommonException.java new file mode 100644 index 0000000..164495d --- /dev/null +++ b/JWT/src/main/java/JWTLogIn/JWT/common/exception/CommonException.java @@ -0,0 +1,15 @@ +package JWTLogIn.JWT.common.exception; + +public abstract class CommonException extends RuntimeException { + + protected CommonException () { + } + + protected CommonException(Exception e) { + super(e); + } + + protected CommonException(String message) { + super(message); + } +} diff --git a/JWT/src/main/java/JWTLogIn/JWT/common/exception/ExceptionAdvice.java b/JWT/src/main/java/JWTLogIn/JWT/common/exception/ExceptionAdvice.java new file mode 100644 index 0000000..7f34ad6 --- /dev/null +++ b/JWT/src/main/java/JWTLogIn/JWT/common/exception/ExceptionAdvice.java @@ -0,0 +1,32 @@ +package JWTLogIn.JWT.common.exception; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class ExceptionAdvice { // Exception Handler + Logger defaultLog = LoggerFactory.getLogger(ExceptionAdvice.class); + Logger exceptionLog = LoggerFactory.getLogger("ExceptionLogger"); + + @ExceptionHandler(CommonException.class) + public ResponseEntity handleCommonException(CommonException e) { + ExceptionSituation exceptionSituation = ExceptionMapper.getSituationOf(e); + + defaultLog.warn(exceptionSituation.getMessage()); + exceptionLog.warn(exceptionSituation.getMessage(), e); + + return ResponseEntity.status(exceptionSituation.getStatusCode()) + .body(ExceptionResponse.from(exceptionSituation)); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity handleException(Exception e) { + defaultLog.error(e.getMessage()); + exceptionLog.error(e.getMessage(), e); + + return ResponseEntity.internalServerError().build(); + } +} diff --git a/JWT/src/main/java/JWTLogIn/JWT/common/exception/ExceptionMapper.java b/JWT/src/main/java/JWTLogIn/JWT/common/exception/ExceptionMapper.java new file mode 100644 index 0000000..03eb376 --- /dev/null +++ b/JWT/src/main/java/JWTLogIn/JWT/common/exception/ExceptionMapper.java @@ -0,0 +1,42 @@ +package JWTLogIn.JWT.common.exception; + +import JWTLogIn.JWT.post.exception.IsNotNoticeException; +import JWTLogIn.JWT.post.exception.PostNotFoundException; +import JWTLogIn.JWT.user.exception.HasNoAuthorityException; +import JWTLogIn.JWT.user.exception.UserNotFoundException; +import org.springframework.http.HttpStatus; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class ExceptionMapper { // 예외 객체 -> 예외 상태로 바꿔주는 mapper + + private static final Map, ExceptionSituation> mapper = new LinkedHashMap<>(); + + static { + setUpUserException(); + setUpPostException(); +// setUpReplyException(); + } + + private static void setUpUserException() { + mapper.put(UserNotFoundException.class, + ExceptionSituation.of("해당 유저를 찾을 수 없습니다", HttpStatus.NOT_FOUND, 404)); + mapper.put(HasNoAuthorityException.class, + ExceptionSituation.of("유저에 대한 접근 권한이 부족합니다", HttpStatus.FORBIDDEN, 403)); + } + + private static void setUpPostException() { + mapper.put(PostNotFoundException.class, + ExceptionSituation.of("해당 공지를 찾을 수 없습니다", HttpStatus.NOT_FOUND, 404)); + mapper.put(IsNotNoticeException.class, + ExceptionSituation.of("요청된 게시글은 공지가 아닙니다", HttpStatus.BAD_REQUEST, 400)); + } + + + public static ExceptionSituation getSituationOf(Exception exception) { + return mapper.get(exception.getClass()); + } + + +} diff --git a/JWT/src/main/java/JWTLogIn/JWT/common/exception/ExceptionResponse.java b/JWT/src/main/java/JWTLogIn/JWT/common/exception/ExceptionResponse.java new file mode 100644 index 0000000..3a4c0a0 --- /dev/null +++ b/JWT/src/main/java/JWTLogIn/JWT/common/exception/ExceptionResponse.java @@ -0,0 +1,11 @@ +package JWTLogIn.JWT.common.exception; + +import com.fasterxml.jackson.annotation.JsonInclude; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public record ExceptionResponse(int code, String message) { + + public static ExceptionResponse from(ExceptionSituation exceptionSituation) { + return new ExceptionResponse(exceptionSituation.getErrorCode(), exceptionSituation.getMessage()); + } +} diff --git a/JWT/src/main/java/JWTLogIn/JWT/common/exception/ExceptionSituation.java b/JWT/src/main/java/JWTLogIn/JWT/common/exception/ExceptionSituation.java new file mode 100644 index 0000000..9185a6c --- /dev/null +++ b/JWT/src/main/java/JWTLogIn/JWT/common/exception/ExceptionSituation.java @@ -0,0 +1,17 @@ +package JWTLogIn.JWT.common.exception; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@AllArgsConstructor +@Getter +public class ExceptionSituation { + private final String message; + private final HttpStatus statusCode; + private final int errorCode; + + public static ExceptionSituation of(String message, HttpStatus statusCode, int errorCode) { + return new ExceptionSituation(message, statusCode, errorCode); + } +} diff --git a/JWT/src/main/java/JWTLogIn/JWT/post/controller/PostController.java b/JWT/src/main/java/JWTLogIn/JWT/post/controller/PostController.java index f9b1484..f19ca00 100644 --- a/JWT/src/main/java/JWTLogIn/JWT/post/controller/PostController.java +++ b/JWT/src/main/java/JWTLogIn/JWT/post/controller/PostController.java @@ -79,14 +79,12 @@ public ResponseEntity> searchPost(@RequestParam String text) return ResponseEntity.ok(postDtos); } - @PostMapping("/notice/post/{userId}") // 공지 작성 - POST, /tgwing.kr/notice/post - public ResponseEntity post(@RequestBody PostDto requestDto, - @PathVariable("userId") Long userId) + @PostMapping("/notice/post") // 공지 작성 - POST, /tgwing.kr/notice/post + public ResponseEntity post(@RequestBody PostDto requestDto) { System.out.println("-- Post new post --"); System.out.println("Request Dto = " + requestDto); - // RequestDTO : title, content, thumbnail(선택) - // userId : 해당 URL을 요청한 유저의 Id + // RequestDTO : writer, title, content, thumbnail(선택) // dto 가져온 값을 엔티티로 바꾸고 DB에 save // 다시 꺼내와서 완성된 객체의 구성요소(id, title, description, writtenDate ...) @@ -94,7 +92,7 @@ public ResponseEntity post(@RequestBody PostDto requestDto, // 유저의 level 확인 필요 - level = MANAGER인 경우에만 작성가능 // 로그인 되어있지 않은 경우 NORMAL, 로그인 된 경우 MEMBER, 관리자인 경우 MANAGER - PostDto responseDto = postService.createPost(requestDto, userId); + PostDto responseDto = postService.createPost(requestDto); return ResponseEntity.ok(responseDto); } // @CrossOrigin diff --git a/JWT/src/main/java/JWTLogIn/JWT/post/exception/IsNotNoticeException.java b/JWT/src/main/java/JWTLogIn/JWT/post/exception/IsNotNoticeException.java new file mode 100644 index 0000000..71b1f5c --- /dev/null +++ b/JWT/src/main/java/JWTLogIn/JWT/post/exception/IsNotNoticeException.java @@ -0,0 +1,6 @@ +package JWTLogIn.JWT.post.exception; + +import JWTLogIn.JWT.common.exception.CommonException; + +public class IsNotNoticeException extends CommonException { +} diff --git a/JWT/src/main/java/JWTLogIn/JWT/post/exception/PostNotFoundException.java b/JWT/src/main/java/JWTLogIn/JWT/post/exception/PostNotFoundException.java new file mode 100644 index 0000000..fe56599 --- /dev/null +++ b/JWT/src/main/java/JWTLogIn/JWT/post/exception/PostNotFoundException.java @@ -0,0 +1,9 @@ +package JWTLogIn.JWT.post.exception; + +import JWTLogIn.JWT.common.exception.CommonException; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(HttpStatus.NOT_FOUND) +public class PostNotFoundException extends CommonException { +} diff --git a/JWT/src/main/java/JWTLogIn/JWT/post/service/PostService.java b/JWT/src/main/java/JWTLogIn/JWT/post/service/PostService.java index 596f56f..40536fb 100644 --- a/JWT/src/main/java/JWTLogIn/JWT/post/service/PostService.java +++ b/JWT/src/main/java/JWTLogIn/JWT/post/service/PostService.java @@ -3,10 +3,14 @@ import JWTLogIn.JWT.post.dto.PostDto; import JWTLogIn.JWT.post.entity.PostEntity; import JWTLogIn.JWT.post.entity.Type; +import JWTLogIn.JWT.post.exception.IsNotNoticeException; +import JWTLogIn.JWT.post.exception.PostNotFoundException; import JWTLogIn.JWT.post.repository.PostRepository; import JWTLogIn.JWT.user.entity.UserEntity; import JWTLogIn.JWT.user.entity.Enum.Level; import JWTLogIn.JWT.user.entity.Enum.Status; +import JWTLogIn.JWT.user.exception.HasNoAuthorityException; +import JWTLogIn.JWT.user.exception.UserNotFoundException; import JWTLogIn.JWT.user.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; @@ -37,45 +41,35 @@ public class PostService { @Autowired private final UserRepository userRepository; - public List getAllPosts() { - -// List dtos = new ArrayList<>(); - -// List entities = postRepository.findAll(); + public List getAllPosts() { // 모든 공지 가져오기 + // findAllNotice() : type=NOT인 post를 모두 가져옴 List allPosts = postRepository.findAllNotice(); - // DB에서 가져온 모든 POST 중에서 type = NOT인 게시글을 모두 가져옴 - - if (allPosts.isEmpty()) {throw new ResponseStatusException(HttpStatus.NOT_FOUND);} + // 가져온 List가 비어있는 경우 == 공지 없음 + if (allPosts.isEmpty()) throw new PostNotFoundException(); List dtos = allPosts.stream().map(postEntity -> toDto(postEntity)).collect(Collectors.toList()); - - for (PostDto dto : dtos) { - System.out.println("dto = " + dto); - } - return dtos; } - public PostEntity getPostInfo(Long id) // 특정 게시글 가져오기 + public PostEntity getPostInfo(Long id) // 특정 게시글 정보 모두 보내기 (엔티티로 바로 응답) { // 입력된 id에 해당하는 글 찾기 Optional postEntityInOp = postRepository.findById(id); - PostEntity postEntity = postEntityInOp.orElseThrow(); - // 관리자 여부 확인 - if (postEntity.getType() == Type.NOT) { return postEntity; } - else return null; + PostEntity postEntity = postEntityInOp.orElseThrow(PostNotFoundException::new); + // 공지인지 확인 + if (postEntity.getType() == Type.NOT) { return postEntity; } // 엔티티 바로 보내기 + else throw new IsNotNoticeException(); } public PostDto getPost(Long id) // 특정 게시글 가져오기 { // 입력된 id에 해당하는 글 찾기 Optional postEntityInOp = postRepository.findById(id); - PostEntity postEntity = postEntityInOp.orElseThrow(); - // 관리자 여부 확인 - if (postEntity.getType() == Type.NOT) { - return toDto(postEntity); - } - else return null; + PostEntity postEntity = postEntityInOp.orElseThrow(PostNotFoundException::new); + + // 공지인지 확인 + if (postEntity.getType() == Type.NOT) return toDto(postEntity); // dto로 변환해서 보내기 + else throw new IsNotNoticeException(); } // @Transactional @@ -102,59 +96,67 @@ public PostDto getPost(Long id) // 특정 게시글 가져오기 // } - public List searchPosts(String search) + public List searchPosts(String search) // 공지 내용으로 검색하기 { - List postDtos = new ArrayList<>(); + // findByContentContains() : 검색한 text를 포함하고 있는 공지를 모두 가져옴 + List searchedEntity = postRepository.findByContentContains(search); + // 가져온 List가 비어있는 경우 == 공지 없음 + if (searchedEntity.isEmpty()) throw new PostNotFoundException(); + + // 공지인지 확인 후 dto list에 담고, 공지가 아닌 경우 null로 변환 + List postDtos = searchedEntity.stream().map(postEntity -> { + if(postEntity.getType() == Type.NOT) return toDto(postEntity); + else return null; + }).collect(Collectors.toList()); + + // null 제거 + while(postDtos.remove(null)){} - List SearchedEntity = postRepository.findByContentContains(search); - for (PostEntity postEntity : SearchedEntity) { -// System.out.println("postEntity = " + postEntity); - postDtos.add(toDto(postEntity)); - } return postDtos; } - public PostDto createPost(PostDto requestDto, Long userId) // 게시글 생성하기 + public PostDto createPost(PostDto requestDto) // 공지 생성하기 { // 글을 작성할 user 조회 - Optional userById = userRepository.findById(userId); + Optional userById = userRepository.findById(requestDto.getWriter()); + // userEntity를 받아오지 못한 경우 - 회원을 찾을 수 없음 (Exception) + UserEntity userEntity = userById.orElseThrow(UserNotFoundException::new); -// else { // user 조회되면, user name을 author로 설정 -// UserEntity userEntity = byId.get(); -// dto.setAuthor(userEntity.getName()); -// } - if(userById.isPresent()) { - UserEntity userEntity = userById.orElseThrow(); -// if (userEntity.getLevel() == Level.MANAGER) { - - if(true) { - PostEntity postEntity = toEntity(requestDto); // DTO 기반으로 엔티티 생성 - writer는 요청된 user의 ID - System.out.println("postEntity = " + postEntity); // 생성된 엔티티 확인 - - PostEntity savedEntity = postRepository.save(postEntity); - PostDto responseDto = toDto(savedEntity); - return responseDto; - - } else { - // 공지 생성 불가능 (level이 NORMAL, MEMBER인 경우) - throw new ResponseStatusException(HttpStatus.FORBIDDEN); - } - } - else { - // 공지 생성 불가능 (등록되지 않은 회원인 경우) - throw new ResponseStatusException(HttpStatus.UNAUTHORIZED); + /** + * requestDTO에 받아올 정보 : title, content, thumbnail + writer(userId)를 함께 받아와야 함 + */ + +// authService.extractStudentId(jwt); --> userEntity.getStudentId()와 같은지 확인 필요 (URL 요청자와 요청 JSON 정보가 같은지) + +// if (userEntity.getLevel() == Level.MANAGER) { // user가 관리자 level인 경우에만 동작 + if(true) { // level 해결까지는 무조건 if 통과 + PostEntity postEntity = toEntity(requestDto); // DTO 기반으로 엔티티 생성 - writer는 요청된 user의 ID + + System.out.println("postEntity = " + postEntity); // request 엔티티 확인 + + PostEntity savedEntity = postRepository.save(postEntity); // response 엔티티 확인 + + System.out.println("savedEntity = " + savedEntity); // response 엔티티 확인 + PostDto responseDto = toDto(savedEntity); // 저장된 엔티티 를 DTO로 변환해서 return + return responseDto; + + } else { // user가 관리자가 아닌 경우 + // 공지 생성 불가능 - 접근 권한 없음 (Exception) + throw new HasNoAuthorityException(); } } public PostDto updatePost(PostDto postDto, Long userId, Long postId) // 게시글 수정하기 { Optional postById = postRepository.findById(postId); - PostEntity postEntity = postById.orElseThrow(); + PostEntity postEntity = postById.orElseThrow(PostNotFoundException::new); - // 해당 URL을 요청한 사람이 공지 작성자인 경우에만 수정 가능 + // 해당 URL을 요청자 == 공지 작성자 일 때에만 수정 가능 // 수정 목록 : title, content, thumbnail + + // DB 내 게시글 작성자 - 요청된 유저 ID 동일 & DB 내 게시글 작성자 - 요청된 게시글 작성자 동일 if(postEntity.getWriter() == userId && postEntity.getWriter() == postDto.getWriter()) { - System.out.println("유저 정보가 일치"); + System.out.println("유저 정보 일치"); postEntity.updateContent(postDto); PostEntity savedEntity = postRepository.save(postEntity); diff --git a/JWT/src/main/java/JWTLogIn/JWT/user/exception/HasNoAuthorityException.java b/JWT/src/main/java/JWTLogIn/JWT/user/exception/HasNoAuthorityException.java new file mode 100644 index 0000000..5543658 --- /dev/null +++ b/JWT/src/main/java/JWTLogIn/JWT/user/exception/HasNoAuthorityException.java @@ -0,0 +1,6 @@ +package JWTLogIn.JWT.user.exception; + +import JWTLogIn.JWT.common.exception.CommonException; + +public class HasNoAuthorityException extends CommonException { +} diff --git a/JWT/src/main/java/JWTLogIn/JWT/user/exception/UserNotFoundException.java b/JWT/src/main/java/JWTLogIn/JWT/user/exception/UserNotFoundException.java new file mode 100644 index 0000000..2e5c28e --- /dev/null +++ b/JWT/src/main/java/JWTLogIn/JWT/user/exception/UserNotFoundException.java @@ -0,0 +1,6 @@ +package JWTLogIn.JWT.user.exception; + +import JWTLogIn.JWT.common.exception.CommonException; + +public class UserNotFoundException extends CommonException { +}