Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

30 feat global exception #37

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.alom.dorundorunbe.global.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http)
throws Exception {
http
.csrf(AbstractHttpConfigurer::disable) // CSRF 보호 비활성화
.authorizeHttpRequests(auth -> auth
.requestMatchers(
"/v3/api-docs/**",
"/swagger-ui/**",
"/swagger-ui.html",
"/swagger-resources/**",
"/webjars/**",
"/actuator/**",
"/doodle/**",
"/challenges/**"
).permitAll() // Swagger 및 관련 리소스 허용
.anyRequest().authenticated() // 나머지 요청은 인증 필요
);

return http.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.alom.dorundorunbe.global.config;

import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SwaggerConfig {

@Bean
public OpenAPI openAPI() {
return new OpenAPI()
.components(new Components())
.info(apiInfo());
}

private Info apiInfo() {
return new Info()
.title("두런두런 백엔드 API")
.description("두런두런과 함께 비대면 러닝을 시작해보세요")
.version("1.0.0");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.alom.dorundorunbe.global.exception;

import lombok.Getter;

@Getter
public class BusinessException extends RuntimeException{

private final ErrorCode errorCode;
private final String detail;

public BusinessException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.errorCode = errorCode;
this.detail = "";
}

public BusinessException(ErrorCode errorCode, String detail) {
super(errorCode.getMessage());
this.errorCode = errorCode;
this.detail = detail;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.alom.dorundorunbe.global.exception;

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

@Getter
@AllArgsConstructor
public enum ErrorCode {
// 챌린지
NO_SUCH_CHALLENGE(HttpStatus.NOT_FOUND, "존재하지 않는 챌린지입니다."),
// 알려지지 않은 문제
UNKNOWN(HttpStatus.INTERNAL_SERVER_ERROR, "알려지지 않은 문제가 발생하였습니다."),
// 입력 값 오류
BLANK_ARGUMENT(HttpStatus.BAD_REQUEST, "비어있는 값이 존재합니다."),
INVALID_EMAIL_FORMAT(HttpStatus.BAD_REQUEST, "이메일 형식이 올바르지 않습니다."),
PASSWORD_POLICY_VIOLATION(HttpStatus.BAD_REQUEST, "비밀번호 조건을 충족하지 않습니다."),
INVALID_SEARCH_CRITERIA(HttpStatus.BAD_REQUEST, "검색 조건을 잘못 설정하였습니다."),
PROFANITY_IN_NAME(HttpStatus.BAD_REQUEST, "이름에 비속어가 포함되어 있습니다."),
DUPLICATE_NAME(HttpStatus.CONFLICT, "중복된 이름입니다."),
// 계정 관련 오류
EMAIL_ALREADY_EXISTS(HttpStatus.CONFLICT, "이미 존재하는 이메일입니다."),
EMAIL_ALREADY_EXISTS_OTHER_AUTH(HttpStatus.CONFLICT, "이미 다른 방식으로 인증되어 있는 이메일입니다."),
INVALID_EMAIL_OR_PASSWORD(HttpStatus.UNAUTHORIZED, "이메일 또는 비밀번호가 틀립니다."),
MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 사용자입니다."),
// OAuth 및 토큰 오류
OAUTH_COMMUNICATION_FAILURE(HttpStatus.INTERNAL_SERVER_ERROR, "OAuth 통신에 실패하였습니다."),
INVALID_OAUTH_CODE(HttpStatus.BAD_REQUEST, "올바르지 않은 OAuth code입니다."),
INVALID_TOKEN(HttpStatus.UNAUTHORIZED, "올바르지 않은 토큰입니다."),
EXPIRED_ACCESS_TOKEN(HttpStatus.UNAUTHORIZED, "만료된 엑세스 토큰입니다."),
EXPIRED_REFRESH_TOKEN(HttpStatus.UNAUTHORIZED, "만료된 리프레시 토큰입니다."),
TAMPERED_TOKEN_SIGNATURE(HttpStatus.UNAUTHORIZED, "서명이 변형된 토큰입니다."),
EMPTY_TOKEN_PROVIDED(HttpStatus.BAD_REQUEST, "요청에 토큰이 비어있습니다."),
INSUFFICIENT_MEMBER_PERMISSION(HttpStatus.FORBIDDEN, "권한이 부족한 사용자입니다."),
// 메일 전송 오류
EMAIL_SENDING_FAILURE(HttpStatus.INTERNAL_SERVER_ERROR, "메일 전송에 실패하였습니다."),
EMAIL_VERIFIED_FAILURE(HttpStatus.INTERNAL_SERVER_ERROR, "메일 인증에 실패하였습니다."),
// 프로세스 오류
FAIL_PROCEED(HttpStatus.INTERNAL_SERVER_ERROR, "프로세스 실행중 문제가 발생하였습니다."),
// 정상
SUCCESS(HttpStatus.OK, "SUCCESS");

private final HttpStatus httpStatus;
private final String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.alom.dorundorunbe.global.exception;

import com.alom.dorundorunbe.global.util.BasicResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class RestExceptionHandler {
private final Logger LOGGER = LoggerFactory.getLogger(RestExceptionHandler.class);
@ExceptionHandler(BusinessException.class)
public ResponseEntity<BasicResponse> handleBusinessException(BusinessException exception) {
LOGGER.info("[ExceptionHandler] Message: {}, Detail: {}", exception.getMessage(), exception.getDetail());

return BasicResponse.to(exception);
}

@ExceptionHandler(RuntimeException.class)
public ResponseEntity<BasicResponse> handleRuntimeException(RuntimeException exception) {
LOGGER.error("[ExceptionHandler] Runtime exception occurred: ", exception);

ErrorCode errorCode = ErrorCode.FAIL_PROCEED;
HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;

BusinessException businessException = new BusinessException(errorCode, "서버 내부 오류가 발생했습니다.");
LOGGER.error("[ExceptionHandler] Message: {}, Detail: {}", businessException.getMessage(), exception.getMessage());

return ResponseEntity
.status(status)
.body(BasicResponse.of(businessException));
}
}
33 changes: 33 additions & 0 deletions src/main/java/com/alom/dorundorunbe/global/util/BasicResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.alom.dorundorunbe.global.util;

import com.alom.dorundorunbe.global.exception.BusinessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

public record BasicResponse(
HttpStatus status,
String message,
String detail
) {
public static BasicResponse of(BusinessException exception) {
return new BasicResponse(
exception.getErrorCode().getHttpStatus(),
exception.getErrorCode().getMessage(),
exception.getDetail()
);
}

public static BasicResponse of(String message) {
return new BasicResponse(
HttpStatus.OK,
message,
""
);
}

public static ResponseEntity<BasicResponse> to(BusinessException exception) {
return ResponseEntity
.status(exception.getErrorCode().getHttpStatus())
.body(BasicResponse.of(exception));
}
}