kmbin92_2025081302 #3
							
								
								
									
										21
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								README.md
									
									
									
									
									
								
							@@ -32,14 +32,14 @@ src/main/java/com/bio/bio_backend/
 | 
				
			|||||||
└── BioBackendApplication.java
 | 
					└── BioBackendApplication.java
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 2. API 응답 표준화 (CustomApiResponse)
 | 
					### 2. API 응답 표준화 (ApiResponseDto)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### 응답 구조
 | 
					#### 응답 구조
 | 
				
			||||||
 | 
					
 | 
				
			||||||
모든 API 응답은 `CustomApiResponse<T>` 형태로 표준화되어 있습니다.
 | 
					모든 API 응답은 `ApiResponseDto<T>` 형태로 표준화되어 있습니다.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```java
 | 
					```java
 | 
				
			||||||
public class CustomApiResponse<T> {
 | 
					public class ApiResponseDto<T> {
 | 
				
			||||||
    private int code;           // HTTP 상태 코드
 | 
					    private int code;           // HTTP 상태 코드
 | 
				
			||||||
    private String message;     // 응답 메시지 (ApiResponseCode enum 값)
 | 
					    private String message;     // 응답 메시지 (ApiResponseCode enum 값)
 | 
				
			||||||
    private String description; // 응답 설명
 | 
					    private String description; // 응답 설명
 | 
				
			||||||
@@ -81,12 +81,12 @@ public class CustomApiResponse<T> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```java
 | 
					```java
 | 
				
			||||||
@PostMapping("/members")
 | 
					@PostMapping("/members")
 | 
				
			||||||
public ResponseEntity<CustomApiResponse<CreateMemberResponseDto>> createMember(@RequestBody CreateMemberRequestDto requestDto) {
 | 
					public ResponseEntity<ApiResponseDto<CreateMemberResponseDto>> createMember(@RequestBody CreateMemberRequestDto requestDto) {
 | 
				
			||||||
    // ... 비즈니스 로직 ...
 | 
					    // ... 비즈니스 로직 ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 성공 응답
 | 
					    // 성공 응답
 | 
				
			||||||
    CustomApiResponse<CreateMemberResponseDto> apiResponse =
 | 
					    ApiResponseDto<CreateMemberResponseDto> apiResponse =
 | 
				
			||||||
        CustomApiResponse.success(ApiResponseCode.COMMON_SUCCESS_CREATED, responseDto);
 | 
					        ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_CREATED, responseDto);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ResponseEntity.status(HttpStatus.CREATED).body(apiResponse);
 | 
					    return ResponseEntity.status(HttpStatus.CREATED).body(apiResponse);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -114,7 +114,7 @@ public enum ApiResponseCode {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#### 핵심 규칙
 | 
					#### 핵심 규칙
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- **모든 API 응답**: `CustomApiResponse<T>`로 감싸서 반환
 | 
					- **모든 API 응답**: `ApiResponseDto<T>`로 감싸서 반환
 | 
				
			||||||
- **공용 응답 코드**: `COMMON_` 접두사로 시작하는 범용 코드 사용
 | 
					- **공용 응답 코드**: `COMMON_` 접두사로 시작하는 범용 코드 사용
 | 
				
			||||||
- **일관된 구조**: `code`, `message`, `description`, `data` 필드로 표준화
 | 
					- **일관된 구조**: `code`, `message`, `description`, `data` 필드로 표준화
 | 
				
			||||||
- **제네릭 활용**: `<T>`를 통해 다양한 데이터 타입 지원
 | 
					- **제네릭 활용**: `<T>`를 통해 다양한 데이터 타입 지원
 | 
				
			||||||
@@ -132,12 +132,11 @@ public enum ApiResponseCode {
 | 
				
			|||||||
@Tag(name = "Member", description = "회원 관리 API")
 | 
					@Tag(name = "Member", description = "회원 관리 API")
 | 
				
			||||||
@Operation(summary = "회원 가입", description = "새로운 회원을 등록합니다.")
 | 
					@Operation(summary = "회원 가입", description = "새로운 회원을 등록합니다.")
 | 
				
			||||||
@ApiResponses(value = {
 | 
					@ApiResponses(value = {
 | 
				
			||||||
    @ApiResponse(responseCode = "201", description = "회원 가입 성공",
 | 
					    @ApiResponse(responseCode = "201", description = "회원 가입 성공"),
 | 
				
			||||||
                content = @Content(schema = @Schema(implementation = CustomApiResponse.class))),
 | 
					 | 
				
			||||||
    @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터",
 | 
					    @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터",
 | 
				
			||||||
                content = @Content(schema = @Schema(implementation = CustomApiResponse.class))),
 | 
					                content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
 | 
				
			||||||
    @ApiResponse(responseCode = "409", description = "중복된 사용자 정보",
 | 
					    @ApiResponse(responseCode = "409", description = "중복된 사용자 정보",
 | 
				
			||||||
                content = @Content(schema = @Schema(implementation = CustomApiResponse.class)))
 | 
					                content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +1,11 @@
 | 
				
			|||||||
package com.bio.bio_backend.domain.user.member.controller;
 | 
					package com.bio.bio_backend.domain.user.member.controller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.bio.bio_backend.global.dto.CustomApiResponse;
 | 
					import com.bio.bio_backend.global.dto.ApiResponseDto;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.tags.Tag;
 | 
					import io.swagger.v3.oas.annotations.tags.Tag;
 | 
				
			||||||
import org.springframework.http.HttpStatus;
 | 
					import org.springframework.http.HttpStatus;
 | 
				
			||||||
import org.springframework.http.ResponseEntity;
 | 
					import org.springframework.http.ResponseEntity;
 | 
				
			||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 | 
					import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 | 
				
			||||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
					import org.springframework.web.bind.annotation.*;
 | 
				
			||||||
import org.springframework.web.bind.annotation.PostMapping;
 | 
					 | 
				
			||||||
import org.springframework.web.bind.annotation.RequestBody;
 | 
					 | 
				
			||||||
import org.springframework.web.bind.annotation.RestController;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import jakarta.validation.Valid;
 | 
					import jakarta.validation.Valid;
 | 
				
			||||||
import com.bio.bio_backend.domain.user.member.dto.MemberDto;
 | 
					import com.bio.bio_backend.domain.user.member.dto.MemberDto;
 | 
				
			||||||
@@ -27,6 +24,7 @@ import com.bio.bio_backend.global.utils.ApiResponseCode;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@Tag(name = "Member", description = "회원 관련 API")
 | 
					@Tag(name = "Member", description = "회원 관련 API")
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
 | 
					@RequestMapping("/members")
 | 
				
			||||||
@RequiredArgsConstructor
 | 
					@RequiredArgsConstructor
 | 
				
			||||||
@Slf4j
 | 
					@Slf4j
 | 
				
			||||||
public class MemberController {
 | 
					public class MemberController {
 | 
				
			||||||
@@ -38,16 +36,15 @@ public class MemberController {
 | 
				
			|||||||
    @Operation(summary = "회원 가입", description = "새로운 회원을 등록합니다.")
 | 
					    @Operation(summary = "회원 가입", description = "새로운 회원을 등록합니다.")
 | 
				
			||||||
    @ApiResponses({
 | 
					    @ApiResponses({
 | 
				
			||||||
        @ApiResponse(responseCode = "201", description = "회원 가입 성공"),
 | 
					        @ApiResponse(responseCode = "201", description = "회원 가입 성공"),
 | 
				
			||||||
        @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터"),
 | 
					        @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
 | 
				
			||||||
        @ApiResponse(responseCode = "409", description = "중복된 사용자 정보")
 | 
					        @ApiResponse(responseCode = "409", description = "중복된 사용자 정보", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    @PostMapping("/members")
 | 
					    @PostMapping
 | 
				
			||||||
    public ResponseEntity<CustomApiResponse<CreateMemberResponseDto>> createMember(@RequestBody @Valid CreateMemberRequestDto requestDto) {
 | 
					    public ResponseEntity<ApiResponseDto<CreateMemberResponseDto>> createMember(@RequestBody @Valid CreateMemberRequestDto requestDto) {
 | 
				
			||||||
        MemberDto member = memberMapper.toMemberDto(requestDto);
 | 
					        MemberDto member = memberMapper.toMemberDto(requestDto);
 | 
				
			||||||
        MemberDto createdMember = memberService.createMember(member);
 | 
					        MemberDto createdMember = memberService.createMember(member);
 | 
				
			||||||
        CreateMemberResponseDto responseDto = memberMapper.toCreateMemberResponseDto(createdMember);
 | 
					        CreateMemberResponseDto responseDto = memberMapper.toCreateMemberResponseDto(createdMember);
 | 
				
			||||||
 | 
					        ApiResponseDto<CreateMemberResponseDto> apiResponse = ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_CREATED, responseDto);
 | 
				
			||||||
        CustomApiResponse<CreateMemberResponseDto> apiResponse = CustomApiResponse.success(ApiResponseCode.COMMON_SUCCESS_CREATED, responseDto);
 | 
					 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return ResponseEntity.status(HttpStatus.CREATED).body(apiResponse);
 | 
					        return ResponseEntity.status(HttpStatus.CREATED).body(apiResponse);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -81,7 +78,7 @@ public class MemberController {
 | 
				
			|||||||
    // }
 | 
					    // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // @PutMapping("/member")
 | 
					    // @PutMapping("/member")
 | 
				
			||||||
    // public CustomApiResponse<Void> updateMember(@RequestBody @Valid CreateMemberRequestDTO requestMember, @AuthenticationPrincipal MemberDTO registrant) {
 | 
					    // public ApiResponseDto<Void> updateMember(@RequestBody @Valid CreateMemberRequestDTO requestMember, @AuthenticationPrincipal MemberDTO registrant) {
 | 
				
			||||||
    //     // 현재 JWT는 사용자 id 값을 통하여 생성, 회원정보 변경 시 JWT 재발급 여부 검토
 | 
					    //     // 현재 JWT는 사용자 id 값을 통하여 생성, 회원정보 변경 시 JWT 재발급 여부 검토
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //     MemberDTO member = mapper.map(requestMember, MemberDTO.class);
 | 
					    //     MemberDTO member = mapper.map(requestMember, MemberDTO.class);
 | 
				
			||||||
@@ -93,31 +90,31 @@ public class MemberController {
 | 
				
			|||||||
    //     member.setRegSeq(registrant.getSeq());
 | 
					    //     member.setRegSeq(registrant.getSeq());
 | 
				
			||||||
    //     memberService.updateMember(member);
 | 
					    //     memberService.updateMember(member);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //     return CustomApiResponse.success(ApiResponseCode.USER_INFO_CHANGE, null);
 | 
					    //     return ApiResponseDto.success(ApiResponseCode.USER_INFO_CHANGE, null);
 | 
				
			||||||
    // }
 | 
					    // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // @DeleteMapping("/member")
 | 
					    // @DeleteMapping("/member")
 | 
				
			||||||
    // public CustomApiResponse<Void> deleteMember(@RequestBody @Valid CreateMemberRequestDTO requestMember){
 | 
					    // public ApiResponseDto<Void> deleteMember(@RequestBody @Valid CreateMemberRequestDTO requestMember){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //     MemberDTO member = mapper.map(requestMember, MemberDTO.class);
 | 
					    //     MemberDTO member = mapper.map(requestMember, MemberDTO.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //     memberService.deleteMember(member);
 | 
					    //     memberService.deleteMember(member);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //     return CustomApiResponse.success(ApiResponseCode.USER_DELETE_SUCCESSFUL, null);
 | 
					    //     return ApiResponseDto.success(ApiResponseCode.USER_DELETE_SUCCESSFUL, null);
 | 
				
			||||||
    // }
 | 
					    // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // @PostMapping("/logout")
 | 
					    // @PostMapping("/logout")
 | 
				
			||||||
    // public CustomApiResponse<Void> logout(@AuthenticationPrincipal MemberDTO member) {
 | 
					    // public ApiResponseDto<Void> logout(@AuthenticationPrincipal MemberDTO member) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //     String id = member.getId();
 | 
					    //     String id = member.getId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //     try {
 | 
					    //     try {
 | 
				
			||||||
    //         memberService.deleteRefreshToken(id);
 | 
					    //         memberService.deleteRefreshToken(id);
 | 
				
			||||||
    //     } catch (Exception e) {
 | 
					    //     } catch (Exception e) {
 | 
				
			||||||
    //         return CustomApiResponse.fail(ApiResponseCode.INTERNAL_SERVER_ERROR, null);
 | 
					    //         return ApiResponseDto.fail(ApiResponseCode.INTERNAL_SERVER_ERROR, null);
 | 
				
			||||||
    //     }
 | 
					    //     }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //     return CustomApiResponse.success(ApiResponseCode.LOGOUT_SUCCESSFUL, null);
 | 
					    //     return ApiResponseDto.success(ApiResponseCode.LOGOUT_SUCCESSFUL, null);
 | 
				
			||||||
    // }
 | 
					    // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,6 @@ package com.bio.bio_backend.global.config;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import io.swagger.v3.oas.models.OpenAPI;
 | 
					import io.swagger.v3.oas.models.OpenAPI;
 | 
				
			||||||
import io.swagger.v3.oas.models.info.Info;
 | 
					import io.swagger.v3.oas.models.info.Info;
 | 
				
			||||||
import io.swagger.v3.oas.models.info.Contact;
 | 
					 | 
				
			||||||
import io.swagger.v3.oas.models.info.License;
 | 
					import io.swagger.v3.oas.models.info.License;
 | 
				
			||||||
import io.swagger.v3.oas.models.servers.Server;
 | 
					import io.swagger.v3.oas.models.servers.Server;
 | 
				
			||||||
import org.springframework.context.annotation.Bean;
 | 
					import org.springframework.context.annotation.Bean;
 | 
				
			||||||
@@ -22,10 +21,6 @@ public class SwaggerConfig {
 | 
				
			|||||||
                        .version("v1.0.0")
 | 
					                        .version("v1.0.0")
 | 
				
			||||||
                        .license(new License()
 | 
					                        .license(new License()
 | 
				
			||||||
                                .name("STAM License")
 | 
					                                .name("STAM License")
 | 
				
			||||||
                                .url("https://stam.kr/")))
 | 
					                                .url("https://stam.kr/")));
 | 
				
			||||||
                .servers(List.of(
 | 
					 | 
				
			||||||
                        new Server().url("http://localhost:8080/service").description("Local Development Server"),
 | 
					 | 
				
			||||||
                        new Server().url("https://api.bio.com/service").description("Production Server")
 | 
					 | 
				
			||||||
                ));
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,11 +7,10 @@ import com.bio.bio_backend.global.utils.ApiResponseCode;
 | 
				
			|||||||
import lombok.Data;
 | 
					import lombok.Data;
 | 
				
			||||||
import lombok.RequiredArgsConstructor;
 | 
					import lombok.RequiredArgsConstructor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//공통 response Class
 | 
					 | 
				
			||||||
@Data
 | 
					@Data
 | 
				
			||||||
@RequiredArgsConstructor
 | 
					@RequiredArgsConstructor
 | 
				
			||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
 | 
					@JsonInclude(JsonInclude.Include.NON_NULL)
 | 
				
			||||||
public class CustomApiResponse<T> {
 | 
					public class ApiResponseDto<T> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private int code;
 | 
					    private int code;
 | 
				
			||||||
    private String message;
 | 
					    private String message;
 | 
				
			||||||
@@ -20,19 +19,19 @@ public class CustomApiResponse<T> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private static final int SUCCESS = 200;
 | 
					    private static final int SUCCESS = 200;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private CustomApiResponse(int code, String message, String description, T data){
 | 
					    private ApiResponseDto(int code, String message, String description, T data){
 | 
				
			||||||
        this.code = code;
 | 
					        this.code = code;
 | 
				
			||||||
        this.message = message;
 | 
					        this.message = message;
 | 
				
			||||||
        this.description = description;
 | 
					        this.description = description;
 | 
				
			||||||
        this.data = data;
 | 
					        this.data = data;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static <T> CustomApiResponse<T> success(ApiResponseCode responseCode, T data) {
 | 
					    public static <T> ApiResponseDto<T> success(ApiResponseCode responseCode, T data) {
 | 
				
			||||||
        return new CustomApiResponse<T>(SUCCESS, responseCode.name(), responseCode.getDescription(), data);
 | 
					        return new ApiResponseDto<T>(SUCCESS, responseCode.name(), responseCode.getDescription(), data);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static <T> CustomApiResponse<T> fail(ApiResponseCode responseCode, T data) {
 | 
					    public static <T> ApiResponseDto<T> fail(ApiResponseCode responseCode, T data) {
 | 
				
			||||||
        return new CustomApiResponse<T>(responseCode.getStatusCode(), responseCode.name(), responseCode.getDescription(), data);
 | 
					        return new ApiResponseDto<T>(responseCode.getStatusCode(), responseCode.name(), responseCode.getDescription(), data);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -14,7 +14,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 | 
				
			|||||||
import jakarta.servlet.ServletException;
 | 
					import jakarta.servlet.ServletException;
 | 
				
			||||||
import jakarta.servlet.http.HttpServletRequest;
 | 
					import jakarta.servlet.http.HttpServletRequest;
 | 
				
			||||||
import jakarta.servlet.http.HttpServletResponse;
 | 
					import jakarta.servlet.http.HttpServletResponse;
 | 
				
			||||||
import com.bio.bio_backend.global.dto.CustomApiResponse;
 | 
					import com.bio.bio_backend.global.dto.ApiResponseDto;
 | 
				
			||||||
import com.bio.bio_backend.global.utils.ApiResponseCode;
 | 
					import com.bio.bio_backend.global.utils.ApiResponseCode;
 | 
				
			||||||
import lombok.RequiredArgsConstructor;
 | 
					import lombok.RequiredArgsConstructor;
 | 
				
			||||||
import lombok.extern.slf4j.Slf4j;
 | 
					import lombok.extern.slf4j.Slf4j;
 | 
				
			||||||
@@ -36,14 +36,14 @@ public class CustomAuthenticationFailureHandler implements AuthenticationFailure
 | 
				
			|||||||
        response.setCharacterEncoding("UTF-8");
 | 
					        response.setCharacterEncoding("UTF-8");
 | 
				
			||||||
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
 | 
					        response.setStatus(HttpStatus.UNAUTHORIZED.value());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        CustomApiResponse<String> apiResponse;
 | 
					        ApiResponseDto<String> apiResponse;
 | 
				
			||||||
        if (exception instanceof UsernameNotFoundException) {
 | 
					        if (exception instanceof UsernameNotFoundException) {
 | 
				
			||||||
            apiResponse = CustomApiResponse.fail(ApiResponseCode.USER_NOT_FOUND, null);
 | 
					            apiResponse = ApiResponseDto.fail(ApiResponseCode.USER_NOT_FOUND, null);
 | 
				
			||||||
        } else if (exception instanceof BadCredentialsException) {
 | 
					        } else if (exception instanceof BadCredentialsException) {
 | 
				
			||||||
            apiResponse = CustomApiResponse.fail(ApiResponseCode.COMMON_UNAUTHORIZED, null);
 | 
					            apiResponse = ApiResponseDto.fail(ApiResponseCode.COMMON_UNAUTHORIZED, null);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
 | 
					            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
 | 
				
			||||||
            apiResponse = CustomApiResponse.fail(ApiResponseCode.COMMON_INTERNAL_SERVER_ERROR, null);
 | 
					            apiResponse = ApiResponseDto.fail(ApiResponseCode.COMMON_INTERNAL_SERVER_ERROR, null);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        String jsonResponse = objectMapper.writeValueAsString(apiResponse);
 | 
					        String jsonResponse = objectMapper.writeValueAsString(apiResponse);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,92 +1,32 @@
 | 
				
			|||||||
package com.bio.bio_backend.global.exception;
 | 
					package com.bio.bio_backend.global.exception;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Objects;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import lombok.Getter;
 | 
					 | 
				
			||||||
import org.springframework.http.converter.HttpMessageNotReadableException;
 | 
					 | 
				
			||||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
 | 
					 | 
				
			||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
 | 
					import org.springframework.web.bind.annotation.ExceptionHandler;
 | 
				
			||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
 | 
					import org.springframework.web.bind.annotation.RestControllerAdvice;
 | 
				
			||||||
import org.springframework.web.bind.MethodArgumentNotValidException;
 | 
					import org.springframework.web.bind.MethodArgumentNotValidException;
 | 
				
			||||||
import org.springframework.web.servlet.resource.NoResourceFoundException;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.fasterxml.jackson.core.JsonProcessingException;
 | 
					import com.bio.bio_backend.global.dto.ApiResponseDto;
 | 
				
			||||||
 | 
					 | 
				
			||||||
import io.jsonwebtoken.ExpiredJwtException;
 | 
					 | 
				
			||||||
import io.jsonwebtoken.JwtException;
 | 
					 | 
				
			||||||
import io.jsonwebtoken.MalformedJwtException;
 | 
					 | 
				
			||||||
import io.jsonwebtoken.security.SignatureException;
 | 
					 | 
				
			||||||
import com.bio.bio_backend.global.dto.CustomApiResponse;
 | 
					 | 
				
			||||||
import com.bio.bio_backend.global.utils.ApiResponseCode;
 | 
					import com.bio.bio_backend.global.utils.ApiResponseCode;
 | 
				
			||||||
 | 
					import org.springframework.http.HttpStatus;
 | 
				
			||||||
 | 
					import org.springframework.http.ResponseEntity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RestControllerAdvice
 | 
					@RestControllerAdvice
 | 
				
			||||||
public class GlobalExceptionHandler {
 | 
					public class GlobalExceptionHandler {
 | 
				
			||||||
    @ExceptionHandler(HttpMessageNotReadableException.class)
 | 
					 | 
				
			||||||
    public CustomApiResponse<Void> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
 | 
					 | 
				
			||||||
        if (Objects.requireNonNull(e.getMessage()).contains("JSON parse error")) {
 | 
					 | 
				
			||||||
            return CustomApiResponse.fail(ApiResponseCode.COMMON_FORMAT_WRONG, null);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return CustomApiResponse.fail(ApiResponseCode.COMMON_BAD_REQUEST, null);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
 | 
					 | 
				
			||||||
    public CustomApiResponse<Void> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
 | 
					 | 
				
			||||||
        return CustomApiResponse.fail(ApiResponseCode.COMMON_METHOD_NOT_ALLOWED, null);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @ExceptionHandler(NoResourceFoundException.class)
 | 
					 | 
				
			||||||
    public CustomApiResponse<Void> handleNoResourceFoundException(NoResourceFoundException e){
 | 
					 | 
				
			||||||
        return CustomApiResponse.fail(ApiResponseCode.COMMON_NOT_FOUND, null);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @ExceptionHandler(IllegalArgumentException.class)
 | 
					 | 
				
			||||||
    public CustomApiResponse<Void> handleIllegalArgumentException(IllegalArgumentException e){
 | 
					 | 
				
			||||||
        return CustomApiResponse.fail(ApiResponseCode.COMMON_ARGUMENT_NOT_VALID, null);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @ExceptionHandler(IndexOutOfBoundsException.class)
 | 
					 | 
				
			||||||
    public CustomApiResponse<Void> handleIndexOutOfBoundsException(IndexOutOfBoundsException e){
 | 
					 | 
				
			||||||
        return CustomApiResponse.fail(ApiResponseCode.COMMON_INDEX_OUT_OF_BOUND, null);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @ExceptionHandler(SignatureException.class)
 | 
					 | 
				
			||||||
    public CustomApiResponse<Void> handleSignatureException(SignatureException e) {
 | 
					 | 
				
			||||||
        return CustomApiResponse.fail(ApiResponseCode.JWT_SIGNATURE_MISMATCH, null);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @ExceptionHandler(MalformedJwtException.class)
 | 
					 | 
				
			||||||
    public CustomApiResponse<Void> handleMalformedJwtException(MalformedJwtException e) {
 | 
					 | 
				
			||||||
        return CustomApiResponse.fail(ApiResponseCode.JWT_SIGNATURE_MISMATCH, null);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @ExceptionHandler(JwtException.class)
 | 
					 | 
				
			||||||
    public CustomApiResponse<Void> handleJwtExceptionException(JwtException e) {
 | 
					 | 
				
			||||||
        return CustomApiResponse.fail(ApiResponseCode.JWT_TOKEN_NULL, null);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @ExceptionHandler(ExpiredJwtException.class)
 | 
					 | 
				
			||||||
    public CustomApiResponse<Void> handleExpiredJwtException(ExpiredJwtException e) {
 | 
					 | 
				
			||||||
        return CustomApiResponse.fail(ApiResponseCode.JWT_TOKEN_EXPIRED, null);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    @ExceptionHandler(JsonProcessingException.class)
 | 
					 | 
				
			||||||
    public CustomApiResponse<Void> handleExpiredJwtException(JsonProcessingException e) {
 | 
					 | 
				
			||||||
        return CustomApiResponse.fail(ApiResponseCode.COMMON_JSON_PROCESSING_EXCEPTION, null);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @ExceptionHandler(ApiException.class)
 | 
					    @ExceptionHandler(ApiException.class)
 | 
				
			||||||
    public CustomApiResponse<Void> handleApiException(ApiException e) {
 | 
					    public ResponseEntity<ApiResponseDto<Void>> handleApiException(ApiException e) {
 | 
				
			||||||
        return CustomApiResponse.fail(e.getResponseCode(), null);
 | 
					        ApiResponseDto<Void> response = ApiResponseDto.fail(e.getResponseCode(), null);
 | 
				
			||||||
 | 
					        return ResponseEntity.status(e.getResponseCode().getStatusCode()).body(response);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    @ExceptionHandler(MethodArgumentNotValidException.class)
 | 
					    @ExceptionHandler(MethodArgumentNotValidException.class)
 | 
				
			||||||
    public CustomApiResponse<Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
 | 
					    public ResponseEntity<ApiResponseDto<Object>> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
 | 
				
			||||||
        // 검증 실패한 필드들의 상세 오류 정보 추출
 | 
					        // 검증 실패한 필드들의 상세 오류 정보 추출
 | 
				
			||||||
        var errors = e.getBindingResult().getFieldErrors().stream()
 | 
					        var errors = e.getBindingResult().getFieldErrors().stream()
 | 
				
			||||||
            .map(error -> new ValidationError(error.getField(), error.getDefaultMessage()))
 | 
					            .map(error -> new ValidationError(error.getField(), error.getDefaultMessage()))
 | 
				
			||||||
            .toList();
 | 
					            .toList();
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return CustomApiResponse.fail(ApiResponseCode.COMMON_ARGUMENT_NOT_VALID, errors);
 | 
					        ApiResponseDto<Object> response = ApiResponseDto.fail(ApiResponseCode.COMMON_ARGUMENT_NOT_VALID, errors);
 | 
				
			||||||
 | 
					        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 검증 오류 상세 정보를 위한 내부 클래스
 | 
					    // 검증 오류 상세 정보를 위한 내부 클래스
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 | 
				
			|||||||
import jakarta.servlet.ServletException;
 | 
					import jakarta.servlet.ServletException;
 | 
				
			||||||
import jakarta.servlet.http.HttpServletRequest;
 | 
					import jakarta.servlet.http.HttpServletRequest;
 | 
				
			||||||
import jakarta.servlet.http.HttpServletResponse;
 | 
					import jakarta.servlet.http.HttpServletResponse;
 | 
				
			||||||
import com.bio.bio_backend.global.dto.CustomApiResponse;
 | 
					import com.bio.bio_backend.global.dto.ApiResponseDto;
 | 
				
			||||||
import com.bio.bio_backend.global.utils.ApiResponseCode;
 | 
					import com.bio.bio_backend.global.utils.ApiResponseCode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component
 | 
					@Component
 | 
				
			||||||
@@ -35,8 +35,7 @@ public class JwtAccessDeniedHandler implements AccessDeniedHandler {
 | 
				
			|||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
 | 
					            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
 | 
				
			||||||
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
 | 
					            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
 | 
				
			||||||
            new ObjectMapper().writeValue(response.getWriter(),
 | 
					            new ObjectMapper().writeValue(response.getWriter(), ApiResponseDto.fail(ApiResponseCode.COMMON_FORBIDDEN, null));
 | 
				
			||||||
                    CustomApiResponse.fail(ApiResponseCode.COMMON_FORBIDDEN, null));
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@ import jakarta.servlet.ServletException;
 | 
				
			|||||||
import jakarta.servlet.http.Cookie;
 | 
					import jakarta.servlet.http.Cookie;
 | 
				
			||||||
import jakarta.servlet.http.HttpServletRequest;
 | 
					import jakarta.servlet.http.HttpServletRequest;
 | 
				
			||||||
import jakarta.servlet.http.HttpServletResponse;
 | 
					import jakarta.servlet.http.HttpServletResponse;
 | 
				
			||||||
import com.bio.bio_backend.global.dto.CustomApiResponse;
 | 
					import com.bio.bio_backend.global.dto.ApiResponseDto;
 | 
				
			||||||
import com.bio.bio_backend.domain.user.member.dto.LoginRequestDto;
 | 
					import com.bio.bio_backend.domain.user.member.dto.LoginRequestDto;
 | 
				
			||||||
import com.bio.bio_backend.domain.user.member.dto.LoginResponseDto;
 | 
					import com.bio.bio_backend.domain.user.member.dto.LoginResponseDto;
 | 
				
			||||||
import com.bio.bio_backend.domain.user.member.dto.MemberDto;
 | 
					import com.bio.bio_backend.domain.user.member.dto.MemberDto;
 | 
				
			||||||
@@ -116,6 +116,6 @@ public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilte
 | 
				
			|||||||
        response.setStatus(HttpStatus.OK.value());
 | 
					        response.setStatus(HttpStatus.OK.value());
 | 
				
			||||||
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
 | 
					        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
 | 
				
			||||||
        new ObjectMapper().writeValue(response.getWriter(),
 | 
					        new ObjectMapper().writeValue(response.getWriter(),
 | 
				
			||||||
                CustomApiResponse.success(ApiResponseCode.LOGIN_SUCCESSFUL, memberData));
 | 
					                ApiResponseDto.success(ApiResponseCode.LOGIN_SUCCESSFUL, memberData));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,7 @@ import jakarta.servlet.FilterChain;
 | 
				
			|||||||
import jakarta.servlet.ServletException;
 | 
					import jakarta.servlet.ServletException;
 | 
				
			||||||
import jakarta.servlet.http.HttpServletRequest;
 | 
					import jakarta.servlet.http.HttpServletRequest;
 | 
				
			||||||
import jakarta.servlet.http.HttpServletResponse;
 | 
					import jakarta.servlet.http.HttpServletResponse;
 | 
				
			||||||
import com.bio.bio_backend.global.dto.CustomApiResponse;
 | 
					import com.bio.bio_backend.global.dto.ApiResponseDto;
 | 
				
			||||||
import com.bio.bio_backend.domain.user.member.service.MemberService;
 | 
					import com.bio.bio_backend.domain.user.member.service.MemberService;
 | 
				
			||||||
import com.bio.bio_backend.global.utils.ApiResponseCode;
 | 
					import com.bio.bio_backend.global.utils.ApiResponseCode;
 | 
				
			||||||
import com.bio.bio_backend.global.utils.JwtUtils;
 | 
					import com.bio.bio_backend.global.utils.JwtUtils;
 | 
				
			||||||
@@ -50,7 +50,7 @@ public class JwtTokenFilter extends OncePerRequestFilter {
 | 
				
			|||||||
        String refreshToken = jwtUtils.extractRefreshJwtFromCookie(request);
 | 
					        String refreshToken = jwtUtils.extractRefreshJwtFromCookie(request);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(accessToken == null){
 | 
					        if(accessToken == null){
 | 
				
			||||||
            sendJsonResponse(response, CustomApiResponse.fail(ApiResponseCode.JWT_TOKEN_NULL, null));
 | 
					            sendJsonResponse(response, ApiResponseDto.fail(ApiResponseCode.JWT_TOKEN_NULL, null));
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -83,7 +83,7 @@ public class JwtTokenFilter extends OncePerRequestFilter {
 | 
				
			|||||||
                response.setHeader("Authorization", "Bearer " + newAccessToken);
 | 
					                response.setHeader("Authorization", "Bearer " + newAccessToken);
 | 
				
			||||||
                filterChain.doFilter(request, response);
 | 
					                filterChain.doFilter(request, response);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                sendJsonResponse(response, CustomApiResponse.fail(ApiResponseCode.ALL_TOKEN_INVALID, null));
 | 
					                sendJsonResponse(response, ApiResponseDto.fail(ApiResponseCode.ALL_TOKEN_INVALID, null));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } catch (Exception e) {
 | 
					        } catch (Exception e) {
 | 
				
			||||||
            request.setAttribute("exception", e);
 | 
					            request.setAttribute("exception", e);
 | 
				
			||||||
@@ -92,7 +92,7 @@ public class JwtTokenFilter extends OncePerRequestFilter {
 | 
				
			|||||||
        filterChain.doFilter(request, response);
 | 
					        filterChain.doFilter(request, response);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void sendJsonResponse(HttpServletResponse response, CustomApiResponse<?> apiResponse) throws IOException {
 | 
					    private void sendJsonResponse(HttpServletResponse response, ApiResponseDto<?> apiResponse) throws IOException {
 | 
				
			||||||
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
 | 
					        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
 | 
				
			||||||
        response.setCharacterEncoding("UTF-8");
 | 
					        response.setCharacterEncoding("UTF-8");
 | 
				
			||||||
        response.setStatus(apiResponse.getCode());
 | 
					        response.setStatus(apiResponse.getCode());
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user