Skip to content

chore: Global 전역, 공통 설정 클래스 구성 및 세팅(#3)#4

Merged
hisonghy merged 1 commit intodevelopfrom
chore/3
Jun 19, 2025
Merged

chore: Global 전역, 공통 설정 클래스 구성 및 세팅(#3)#4
hisonghy merged 1 commit intodevelopfrom
chore/3

Conversation

@hisonghy
Copy link
Contributor

@hisonghy hisonghy commented Jun 18, 2025

📌 작업 내용 및 특이사항

✅ 공통 응답 및 예외 처리

  • StandardResponse 클래스를 추가해 API 응답을 통일된 포맷으로 제공할 수 있도록 구성했습니다.
  • 공통 에러코드를 ErrorCode 인터페이스로 추상화하고, 도메인별로 CommonErrorCode, AuthErrorCode 등을 정의해 에러 코드를 관리할 수 있도록 구성했습니다.
  • 최상위 에러코드를 설계하면서 공통적으로 사용될 CommonErrorCode 와, 인증/인가 부분에서 사용될 AuthErrorCode 일부분 세팅했습니다.
  • ErrorResponse 클래스를 추가하여 에러 응답을 전용 구조로 분리하였고, MethodArgumentNotValidException과 같이 바인딩 오류가 발생했을 경우에는 에러 메시지와 함께 유효성 검증에 실패한 필드 정보들을 포함해 응답할 수 있도록 설계했습니다.
  • 전역 예외를 처리하는 핸들러와 유효성 검증 관련 예외를 처리하는 핸들러를 별도로 구성해 책임을 분리했습니다.(GlobalExceptionHandler, ValidationExceptionHandler)

✅ 전역 상수 관리

  • global.common.constants 패키지를 만들고, 전역에서 사용할 수 있는 상수들을 클래스로 관리할 수 있도록 구성했습니다.
  • SwaggerUrlConstants 클래스를 구성해 WebSecurity 설정에 필요한 swagger 관련 경로를 관리하고, 향후 JWT 필터에서 재사용할 수 있을 것 같습니다.
  • UrlConstants 클래스를 구성해 로컬/개발/운영 서버의 URL과 클라이언트 도메인 URL 등을 통합적으로 관리할 수 있도록 설정했습니다.

✅ 설정 파일 구성

  • swagger, web security, redis, query dsl, scheduler 초기 설정 파일을 추가했습니다.
  • application.yml 파일에 swagger.version 정보를 추가해, swagger 버전 정보를 유연하게 관리할 수 있도록 설정했습니다.
  • 운영환경(prod) 에서는 swagger 비활성화 처리해주었습니다.

✅ 스프링 시큐리티

  • 인증 실패 시 발생하는 예외를 처리하기 위해 CustomAuthenticationEntryPoint 클래스를, 접근 권한이 없을 때 발생하는 예외를 처리하기 위해 CustomAccessDeniedHandler 클래스를 구성했습니다.
  • Security 필터에서 발생하는 예외 응답을 일관된 형태로 내려주기 위해 SecurityResponseHandler 클래스를 추가했습니다. HttpServletResponse를 통해 JSON 형태로 표준 응답을 내려줍니다.

🌱 관련 이슈


🔍 참고사항(선택)


📚 기타(선택)

[swagger local test]
스크린샷 2025-06-18 오후 10 54 37

[스프링 시큐리티 인증 예외처리]
스크린샷 2025-06-18 오후 8 40 11

@hisonghy hisonghy requested a review from chaiminwoo0223 June 18, 2025 14:32
@hisonghy hisonghy added ⚙️chore 세팅 관련 ✨feature 구현, 개선 사항 관련 부분 labels Jun 18, 2025
@hisonghy hisonghy self-assigned this Jun 18, 2025
@chaiminwoo0223
Copy link
Contributor

@songhyeonpk 고생하셨습니다. Global 전역, 공통 설정 클래스들이 세부적으로 잘 구성되어 있네요~^^

@hisonghy
Copy link
Contributor Author

hisonghy commented Jun 19, 2025

@chaiminwoo0223

[추가 작업]

  • MethodArgumentNotValidExceptionConstraintViolationException 발생 시, 기존에는 Map<String, String> 형식(field: message)으로 응답하던 오류 정보를 FieldErrorResponse 객체 리스트 형태로 변경하였습니다. (가독성 향상 및 구조화)
  • 요청 방식별 샘플용 API(GET, POST 등)를 만들고, Swagger 문서에 등록했습니다.
  • 샘플 API로 테스트 중, 유효성 검증 실패 시 ValidationExceptionHandler 보다 GlobalExceptionHandlerException.class 핸들러가 먼저 처리되는 문제를 확인해 ValidationExceptionHandler@Order(Ordered.HIGHEST_PRECEDENCE) 어노테이션으로 순서를 지정해주었습니다.
스크린샷 2025-06-19 오후 5 19 04

private static final String DEV_SERVER_DESCRIPTION = "개발 서버 API 문서입니다.";
private static final String GITHUB_URL = "https://github.com/JECT-Study/JECT-4-server";

@Value("${swagger.version}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Value를 사용한 $ 방식으로 환경변수를 주입받는 것도 가능하지만, 프로젝트의 확장성과 유지보수성을 고려할 때 SwaggerProperties 클래스를 별도로 구현하여 설정 값을 주입받는 방식이 더 좋을 것 같아요.

예를 들어, 추후에 개발 서버 도메인이나 운영 서버 전용 설명 등의 항목이 추가될 경우, 프로퍼티 클래스를 통해 구조화된 방식으로 관리하는 것이 훨씬 안전하고 직관적입니다.

또한, Swagger 관련 설정이 분리되어 있으면, Swagger 설정만 명확하게 관리할 수 있어 코드의 명확성과 가독성 측면에서도 좋을 것 같아요.

Copy link
Contributor Author

@hisonghy hisonghy Jun 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@value를 사용한 $ 방식으로 환경변수를 주입받는 것도 가능하지만, 프로젝트의 확장성과 유지보수성을 고려할 때 SwaggerProperties 클래스를 별도로 구현하여 설정 값을 주입받는 방식이 더 좋을 것 같아요.

: 현재는 version 정보만 환경변수로 설정해서 @value 어노테이션으로 적용했었습니다. 만약 환경별 swagger 정보를 따로 관리한다면 민우님 말씀처럼 properties 클래스를 따로 구성하는게 더 좋을 것 같습니다.


예를 들어, 추후에 개발 서버 도메인이나 운영 서버 전용 설명 등의 항목이 추가될 경우, 프로퍼티 클래스를 통해 구조화된 방식으로 관리하는 것이 훨씬 안전하고 직관적입니다.

: 지금은 로컬, 개발 서버 URL을 모두 Server 객체로 만들어 함께 문서화하고 있는데, 현재 실행중인 환경에 따라 동적으로 Server URL을 구성하도록 하는 방법이 더 나을까요?


또한, Swagger 관련 설정이 분리되어 있으면, Swagger 설정만 명확하게 관리할 수 있어 코드의 명확성과 가독성 측면에서도 좋을 것 같아요.

: application-swagger.yml 파일로 swagger 설정을 따로 관리하는 방법을 말씀하시는 건가요?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

: application-swagger.yml 파일로 swagger 설정을 따로 관리하는 방법을 말씀하시는 건가요?

아니요. SwaggerProperties를 말씀드린거예요!

Copy link
Contributor Author

@hisonghy hisonghy Jun 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아니요. SwaggerProperties를 말씀드린거예요!

SwaggerProperties 에서 version 말고 또 관리할 수 있는 정보가 더 있을까요? 설명(description), 서버 URL 등이 있을까요?

Copy link
Contributor

@chaiminwoo0223 chaiminwoo0223 Jun 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SwaggerProperties 에서 version 말고 또 관리할 수 있는 정보가 더 있을까요? 설명(description), 서버 URL 등이 있을까요?

설명(description)은 민감하지 않은 정보라서 추가해서 관리할 필요는 없을 것 같아요. 버전과 서버 URL만 관리하면 될 것 같아요.


@RequestMapping("/api/sample")
@RestController
public class SampleController implements SampleApiSpec {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SampleApiSpec 인터페이스와 SampleController 클래스로 분리하셨는데, 앞으로도 Controller 부분은 이렇게 2개로 나누어서 구현해야 하는걸까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아니요, 이건 참고용으로만 생각해주시면 좋을 것 같습니다.
다만, 컨트롤러에서 swagger 관련 어노테이션을 함께 사용하면 가독성면에서 조금 불편한 부분이 있더라구요.
혹시, 저렇게 컨트롤러와 swagger 관련 설정을 분리하는 부분은 어떻게 생각하시나요?

Copy link
Contributor

@chaiminwoo0223 chaiminwoo0223 Jun 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

간단한 API까지 모두 분리하면 오히려 관리 포인트만 늘어나고 번거로울 수 있을 것 같아요. 기능이 많고 문서화가 중요하다면, 클래스와 인터페이스를 분리하는 것이 맞지만, 앞으로 저희가 구현해야 할 기능들을 생각하면 분리하지 않는 것이 더 좋을 것 같아요.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

간단한 API까지 모두 분리하면 오히려 관리 포인트만 늘어나고 번거로울 수 있을 것 같아요. 기능이 많고 문서화가 중요하다면, 클래스와 인터페이스를 분리하는 것이 맞지만, 앞으로 저희가 구현해야 할 기능들을 생각하면 분리하지 않는 것이 더 좋을 것 같아요.

넵. 추후 기능이 많아지고 복잡해지면 리팩토링하는 방향으로 가면 좋을 것 같습니다. 이 부분 수정해서 반영해놓겠습니다.

* feat: 공통 응답 포맷 클래스 추가
* feat: 공통 에러 코드 및 예외 처리 클래스 추가 (CustomException, ErrorCode, ErrorResponse, FieldErrorResponse)
* feat: global 예외 핸들러, validation 예외 핸들러 추가 및 구성
* feat: 전역으로 쓰이는 constants 추가 (SwaggerUrlConstants, UrlConstants)
* feat: swagger, web security, redis, querydsl, scheduler 설정 파일 구성
* feat: security 예외 핸들링, 응답 클래스 추가 및 구성
* chore: application.yml 파일에 swagger:version, server-url 설정 세팅
* feat: 샘플 API 추가
@hisonghy
Copy link
Contributor Author

hisonghy commented Jun 19, 2025

@chaiminwoo0223

[수정사항 반영]

  • 샘플 ApiSpec 인터페이스를 삭제했습니다.
  • SwaggerConfig 클래스에서 @Value 어노테이션을 삭제하고 SwaggerProperties 클래스를 구성해 설정을 관리하도록 변경했습니다.
  • application.ymlswagger.server-url 옵션을 추가하고, 환경변수를 통해 각 환경에 맞는 Swagger 서버 URL이 등록되도록 설정하였습니다.

Copy link
Contributor

@chaiminwoo0223 chaiminwoo0223 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@songhyeonpk 수정사항 모두 확인했습니다. 머지 부탁드립니다.

@hisonghy
Copy link
Contributor Author

@songhyeonpk 수정사항 모두 확인했습니다. 머지 부탁드립니다.

아 그리고 코드 리뷰 후 바로 rebase로 수정 사항을 반영하니까 변경된 내용을 확인하기가 어렵네요..
앞으로는 리뷰 후 수정 내용은 새로운 커밋으로 추가하고, 최종 머지 전에 rebase -i로 커밋을 squash 해서 하나로 정리한 뒤에 머지하도록 하겠습니다!

@hisonghy hisonghy merged commit 45bd503 into develop Jun 19, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚙️chore 세팅 관련 ✨feature 구현, 개선 사항 관련 부분

Projects

None yet

Development

Successfully merging this pull request may close these issues.

⚙️[CHORE]: Global 공통 설정 클래스 초기 구성

2 participants