TIL

TIL - 2024/07/27

기석김 2024. 7. 31. 00:53

최종프로젝트가 시작한지 약2주가 지나고 우리팀은 설계를 하고 개발을 시작한지 약 1주일 넘게 지났다

나는 처음 1차 스코프 맡은 스페이드쪽 CRUD를 맡았다. 내가 맡은건 비교적 다른팀원이 했던거보다 엄청 쉬워서

금방 끝낼 수 있었다. 다른팀원분들이 맡은건 웹소켓을 이용한 음성, 채팅 , 프론트 등 다 어려운거를 맡으셔서

나는 쉬운걸 빨리 끝냈으니, 스코프에서 나온 기능들을 빠르게 api를 뚫으려고 한다.

 

일단 저번 블로그에서 한 CRUD는 됐긴했는데 , 예외처리부분이 안돼 있었다. 예외처리 부분을 공통으로 구현하고

다른사람이 기능을 개발할때 파일을 @@ErrorCode , @@SuccessCode 등 이렇게 파일을 만든 후 간단하게

예외를 찍게 하려고 한다. 아래 코드는 공통 예외처리 부분이다.

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    @ExceptionHandler(CustomException.class)
    protected ResponseEntity<Mono<CommonReason>> handleCustomException(ServerWebExchange exchange, CustomException e) {
        return ResponseEntity.status(e.getBaseCode().getCommonReason().getStatus())
                        .body(Mono.just(e.getBaseCode().getCommonReason()));
    }
}
public interface BaseCode {
    public String getRemark();
    public CommonReason getCommonReason();
}
@Getter
public class CommonReason {
    private final HttpStatus status;
    private final int code;
    private final String msg;

    @Builder
    public CommonReason(HttpStatus status, int code, String msg) {
        this.status = status;
        this.code = code;
        this.msg = msg;
    }
}
@Getter
@Slf4j
public class CustomException extends RuntimeException {
    private final BaseCode baseCode;

    public CustomException(BaseCode baseCode) {
        super(baseCode.getRemark());
        this.baseCode = baseCode;
        log.info("ExceptionMethod: {}", getExceptionMethod());
        log.info("ErrorCode: {}, ErrorMsg: {}", baseCode.getCommonReason().getCode(), baseCode.getCommonReason().getMsg());
    }

    public String getExceptionMethod() {
        String className = Thread.currentThread().getStackTrace()[3].getClassName();
        String methodName = Thread.currentThread().getStackTrace()[3].getMethodName();
        return className + "." + methodName;
    }
}
@Component
public class GlobalErrorAttributes extends DefaultErrorAttributes {
    @Override
    public Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
        Map<String, Object> originMap = super.getErrorAttributes(request, options);
        Map<String, Object> map = new HashMap<>();

        map.put("status", ErrorCode.FAIL.getStatus().value());

        Throwable throwable = getError(request);
        if (throwable instanceof CustomException) {
            CustomException ex = (CustomException) getError(request);
            map.put("message", ex.getBaseCode().getCommonReason().getMsg());
            map.put("status", ex.getBaseCode().getCommonReason().getStatus().value());
        }

        if (throwable instanceof SecurityException) {
            map.put("message", ErrorCode.UNAUTHORIZED.getMsg());
            map.put("status", ErrorCode.UNAUTHORIZED.getStatus().value());
        }

        map.put("path", originMap.get("path"));
        map.put("timestamp", originMap.get("timestamp"));

        return map;
    }
}

 

이렇게 공통 예외처리 코드를 만들어놓는다.

예외가 발생할때 custom exception 발생 해서  > global exception handler > CommonReason 객체 생성 > 반환

.flatMap(existingMember -> Mono.error(new CustomException(SpaceErrorCode.SPACE_ALREADY_JOINED)))

이렇게 처리를 한다 . 아래는 스페이스에러코드 모음이고 저렇게 계속 맡은 기능 사용자가 따로 파일을 만들어서

저렇게 생성을하고 던져주면 된다 . 매우 간편하다

@Getter
@AllArgsConstructor
public enum SpaceErrorCode implements BaseCode {

    SPACE_ENTRY_FAILURE(HttpStatus.BAD_REQUEST, 5000, "입장 실패: 코드가 유효하지 않습니다.", "유효하지 않은 입장 코드입니다."),
    SPACE_ALREADY_JOINED(HttpStatus.BAD_REQUEST, 409, "입장 실패: 이미 입장한 사용자입니다.", "이미 입장한 사용자입니다."),
    SPACE_NOT_FOUND(HttpStatus.NOT_FOUND, 404, "스페이스 데이터를 찾을 수 없습니다.", "스페이스 데이터가 존재하지 않습니다."),
    INVALID_SPACE_NAME(HttpStatus.BAD_REQUEST, 5001, "스페이스 이름은 20자 미만이어야 합니다.", "스페이스 이름이 유효하지 않습니다."),
    INVALID_IS_PUBLIC(HttpStatus.BAD_REQUEST, 5002, "공개 여부는 Y 또는 N이어야 합니다.", "공개 여부 값이 유효하지 않습니다."),
    
    ;

    private final HttpStatus status;
    private final int code;
    private final String msg;
    private final String remark;

    @Override
    public CommonReason getCommonReason() {
        return CommonReason.builder()
            .status(status)
            .code(code)
            .msg(msg)
            .build();
    }
}