Spring 숙련 과제(최종)

2022. 12. 21. 23:06스파르타 내일배움캠프/Spring 강의 정리

오늘은 미처 하지 못했던 예외 처리와 엔티티 맵핑을 완성하였습니다.

 

 

  1. 예외 처리
    • 토큰이 필요한 API 요청에서 토큰을 전달하지 않았거나 정상 토큰이 아닐 때는 "토큰이 유효하지 않습니다." 라는 에러메시지와 statusCode: 400을 Client에 반환하기
    • 토큰이 있고, 유효한 토큰이지만 해당 사용자가 작성한 게시글/댓글이 아닌 경우에는 “작성자만 삭제/수정할 수 있습니다.”라는 에러메시지와 statusCode: 400을 Client에 반환하기
    • DB에 이미 존재하는 username으로 회원가입을 요청한 경우 "중복된 username 입니다." 라는 에러메시지와 statusCode: 400을 Client에 반환하기
    • 로그인 시, 전달된 username과 password 중 맞지 않는 정보가 있다면 "회원을 찾을 수 없습니다."라는 에러메시지와 statusCode: 400을 Client에 반환하기

 

이 부분을 

Internal Server Error 메세지를 내보낸다...

 

이렇게 우아하지 못하게 단순한 형식으로 내보냈습니다.

Internal Server Error 가 아닌 내가 지정한 예외 메세지를 내보낼 방법을 찾아야 했습니다.

 

 

return new SignupLoginResponseDto("fail", "400");

실패할 때도 예외 메세지 대신에, 이런 식으로 직접 값을 지정해서 내보냈기 때문에 출력되는 값이 한정되었습니다.

 

이문제를 @RestControllerAdvice 로 해결하였습니다.

 

package com.nbcamp.myserver.exception;


import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import static com.nbcamp.myserver.exception.ErrorCode.DUPLICATE_RESOURCE;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(value = { ConstraintViolationException.class, DataIntegrityViolationException.class})
    protected ResponseEntity<ErrorResponse> handleDataException() {
        log.error("handleDataException throw Exception : {}", DUPLICATE_RESOURCE);
        return ErrorResponse.toResponseEntity(DUPLICATE_RESOURCE);
    }

    @ExceptionHandler(value = { CustomException.class })
    protected ResponseEntity<ErrorResponse> handleCustomException(CustomException e) {
        log.error("handleCustomException throw CustomException : {}", e.getErrorCode());
        return ErrorResponse.toResponseEntity(e.getErrorCode());
    }
}

 

 

에러 메시지는 enum 형식으로 지정해두었습니다.

package com.nbcamp.myserver.exception;

import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

import static org.springframework.http.HttpStatus.*;

@Getter
@AllArgsConstructor
public enum ErrorCode {
    /* 400 BAD_REQUEST : 잘못된 요청 */
    INVALID_TOKEN(BAD_REQUEST, "토큰이 유효하지 않습니다."),

    /* 401 UNAUTHORIZED : 인증되지 않은 사용자 */
    INVALID_AUTH_TOKEN(UNAUTHORIZED, "작성자만 삭제/수정할 수 있습니다."),

    /* 404 NOT_FOUND : 회원을 찾을 수 없음 || id 또는 password 오류 */
    MEMBER_NOT_FOUND(NOT_FOUND, "회원을 찾을 수 없습니다."),

    /* 409 CONFLICT : Resource 의 현재 상태와 충돌. 보통 중복된 데이터 존재 */
    DUPLICATE_RESOURCE(CONFLICT, "중복된 username 입니다."),
    ;

    private final HttpStatus httpStatus;
    private final String detail;
}

 

이렇게 4가지로 지정하였더니 요구사항을 모두 만족하면서 각기 다른 예외 메세지를 드디어 띄울 수 있었습니다.

 

엔티티 맵핑에서도 다음과 같은 오류 메세지가 발생하였습니다.

 

"org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [\"FKOH58Q92B96DBFV4TCUNRE9AVL: PUBLIC.BOARD_COMMENTS FOREIGN KEY(COMMENTS_ID) REFERENCES PUBLIC.COMMENT(ID) (CAST(1 AS BIGINT))\" ....

 

mappedby를 지정하지 않은 오류였습니다.

 

Board.java 중에서

@OneToMany(mappedBy = "board", cascade = CascadeType.REMOVE)
private List<Comment> comments = new ArrayList<>();

이렇게 mappedBy를 추가해주고, cascade로 연관있는 테이블 행들도 삭제해주어서 해당 오류를 해결하였습니다.

 

 

이번 과제도 정말 힘들었지만, 무사히 마무리 되어서 기쁩니다. 다만, Service 부분에서 관리자/유저 인증 부분이 함께 들어 있는 부분을 수정해야 할 것 같습니다.

Controller에서 HttpServlet 관련 부분을 모두 처리하여 좀 더 "객체 지향"적인 코드로 리펙토링 해볼 예정입니다.

'스파르타 내일배움캠프 > Spring 강의 정리' 카테고리의 다른 글

Spring 심화 pjt  (0) 2023.01.03
Spring Security  (0) 2022.12.26
Spring 숙련 과제(2)  (0) 2022.12.20
Spring 숙련 과제  (0) 2022.12.19
Spring project  (0) 2022.12.16