diff --git a/apps/user-service/src/main/java/site/icebang/common/dto/ApiResponse.java b/apps/user-service/src/main/java/site/icebang/common/dto/ApiResponse.java index 0f99e59b..8a986b4d 100644 --- a/apps/user-service/src/main/java/site/icebang/common/dto/ApiResponse.java +++ b/apps/user-service/src/main/java/site/icebang/common/dto/ApiResponse.java @@ -4,15 +4,72 @@ import lombok.Data; +/** + * 공통 APi 응답 DTO 클래스입니다. + * + *
REST API의 응답 형식을 표준화하기 위해 사용됩니다. 모든 응답은 성공 여부({@link #success}), 응답 데이터({@link #data}), 응답 + * 메시지({@link #message}), 그리고 HTTP 상태 코드({@link #status})를 포함합니다. + * + *
사용 예시: + * + *
{@code
+ * // 성공 응답 생성
+ * ApiResponse response = ApiResponse.success(userDto);
+ *
+ * // 메시지를 포함한 성공 응답
+ * ApiResponse response = ApiResponse.success(userDto, "회원 조회 성공");
+ *
+ * // 오류 응답 생성
+ * ApiResponse errorResponse = ApiResponse.error("잘못된 요청입니다.", HttpStatus.BAD_REQUEST);
+ * }
+ *
+ * @param true: 요청이 정상적으로 처리됨 false: 요청 처리 중 오류 발생 + */ private boolean success; + + /** + * 실제 응답 데이터(payload). + * + *
요청이 성공적으로 처리되었을 경우 반환되는 데이터이며, 실패 시에는 {@code null}일 수 있습니다. + */ private T data; + + /** + * 응답 메세지. + * + *
성공 또는 오류 상황을 설명하는 메시지를 담습니다. 클라이언트에서 사용자에게 직접 표시할 수도 있습니다. + */ private String message; + + /** + * HTTP 상태 코드. + * + *
Spring의 {@link HttpStatus} 열거형을 사용합니다.
+ */
private HttpStatus status; // HttpStatus로 변경
+ /** 기본 생성자입니다. 모든 필드가 기본값으로 초기화됩니다. */
public ApiResponse() {}
+ /**
+ * 모든 필드를 초기화하는 생성자.
+ *
+ * @param success 요청 성공 여부
+ * @param data 응답 데이터
+ * @param message 응답 메시지
+ * @param status HTTP 상태 코드
+ */
public ApiResponse(boolean success, T data, String message, HttpStatus status) {
this.success = success;
this.data = data;
@@ -20,18 +77,50 @@ public ApiResponse(boolean success, T data, String message, HttpStatus status) {
this.status = status;
}
+ /**
+ * 성공 응답을 생성합니다. (기본 메시지: "OK", 상태: 200 OK)
+ *
+ * @param data 응답 데이터
+ * @param 목록 조회 API에서 공통적으로 사용되는 요청 파라미터를 정의합니다. 현재 페이지 번호({@link #current}), 페이지 크기({@link #pageSize}),
+ * 검색어({@link #search}), 정렬 조건({@link #sorters}), 필터 조건({@link #filters})를 포함합니다.
+ *
+ * 사용 예시:
+ *
+ * 1부터 시작하며, 기본값은 1입니다. 0 이하의 값은 유효하지 않습니다.
+ */
private int current = 1;
+
+ /**
+ * 한 펭지에 표시할 데이터 개수.
+ *
+ * 한 페이지에 표시할 항목의 개수를 지정합니다. 기본값은 10개이며, 일반적으로 10, 20, 50, 100 등의 값을 사용합니다.
+ */
private int pageSize = 10;
+
+ /**
+ * 검색어.
+ *
+ * 목록에서 특정 조건으로 검색할 때 사용되는 키워드입니다. {@code null}이거나 빈 문자열인 경우 검색 조건이 적용되지 않습니다.
+ */
private String search;
+
+ /**
+ * 정렬 조건 배열.
+ *
+ * 예: {@code ["name:asc", "createdAt:desc"]} API 설계에 따라 "필드명:정렬방향" 형식을 권장합니다. {@code null}이거나 빈
+ * 배열인 경우 기본 정렬이 적용됩니다.
+ */
private String[] sorters;
+
+ /**
+ * 필터링 조건 배열.
+ *
+ * 예: {@code ["status:active", "role:admin"]} 각 요소는 특정 필드에 대한 필터링 조건을 나타냅니다. 형태는 구현에 따라 다를 수
+ * 있습니다.
+ */
private String[] filters;
- // 계산된 offset
+ /**
+ * 페이징 처리를 위한 offset(시작 위치)을 계산합니다.
+ *
+ * @return (current - 1) * pageSize
+ */
public int getOffset() {
return (current - 1) * pageSize;
}
+ /**
+ * 검색어가 유효하게 존재하는지 확인합니다.
+ *
+ * @return 검색어가 null이 아니고 공백이 아닌 경우 true
+ */
public boolean hasSearch() {
return search != null && !search.trim().isEmpty();
}
+ /**
+ * 정렬 조건이 존재하는지 확인합니다.
+ *
+ * @return 정렬 조건 배열이 null이 아니고, 1개 이상 있는 경우 true
+ */
public boolean hasSorters() {
return sorters != null && sorters.length > 0;
}
diff --git a/apps/user-service/src/main/java/site/icebang/common/dto/PageResult.java b/apps/user-service/src/main/java/site/icebang/common/dto/PageResult.java
index 4a2a8bfa..0982be0a 100644
--- a/apps/user-service/src/main/java/site/icebang/common/dto/PageResult.java
+++ b/apps/user-service/src/main/java/site/icebang/common/dto/PageResult.java
@@ -6,17 +6,67 @@
import lombok.Data;
import lombok.NoArgsConstructor;
+/**
+ * 페이징 처리된 결과 DTO 클래스.
+ *
+ * 목록 조회 API에서 페이징된 데이터를 반환할 때 사용됩니다. 실제 데이터 목록({@link #data}), 전체 개수({@link #total}), 현재 페이지
+ * 번호({@link #current}), 페이지 크기({@link #pageSize}), 전체 페이지 수({@link #totalPages}), 다음/이전 페이지 여부를
+ * 포함합니다.
+ *
+ * 사용 예시:
+ *
+ * totalPages, hasNext, hasPrevious 값을 설정합니다.
+ */
private void calculatePagination() {
this.totalPages = total > 0 ? (int) Math.ceil((double) total / pageSize) : 0;
this.hasNext = current < totalPages;
this.hasPrevious = current > 1;
}
- // 기존 of 메서드
+ /**
+ * PageResult 객체를 생성합니다.
+ *
+ * @param data 현재 페이지 데이터
+ * @param total 전체 데이터 개수
+ * @param current 현재 페이지 번호
+ * @param pageSize 페이지 크기
+ * @param 데이터 조회와 카운트 조회를 별도의 Supplier로 받아 트랜잭션 내에서 실행할 수 있습니다.
+ *
+ * @param pageParams 요청 파라미터 ({@link PageParams})
+ * @param dataSupplier 데이터 조회 함수
+ * @param countSupplier 전체 개수 조회 함수
+ * @param 엔티티나 DTO 목록을 페이징 처리하여 반환해야 하는 서비스에서 구현합니다. 공통적으로 {@link PageParams} 요청 파라미터를 받아 {@link
+ * PageResult} 응답을 제공합니다.
+ *
+ * 사용 예시:
+ *
+ * 이 클래스는 애플리케이션 전역에서 발생하는 예외를 {@link ApiResponse} 형태로 변환하여 클라이언트에게 반환합니다. 예외 유형에 따라 적절한 {@link
+ * HttpStatus} 코드를 설정하며, 공통적인 예외 처리 로직을 중앙화합니다.
+ *
+ * 처리되는 주요 예외는 다음과 같습니다:
+ *
+ * 모든 응답은 {@code ApiResponse.error(...)} 메서드를 통해 생성되며, 에러 메시지와 HTTP 상태 코드가 포함됩니다.
+ */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
+
+ /**
+ * 요청 데이터 유효성 검증 실패 시 발생하는 예외를 처리합니다.
+ *
+ * @param ex 발생한 {@link MethodArgumentNotValidException}
+ * @return {@link ApiResponse} - 검증 실패 메시지와 {@link HttpStatus#BAD_REQUEST}
+ */
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResponse Spring Security에서 인가(Authorization) 실패 시 호출됩니다. 사용자가 필요한 권한 없이 보호된 리소스에 접근하려고 하면 이 핸들러가 실행되어
+ * JSON 형식의 에러 응답을 반환합니다.
+ *
+ * 주요 특징:
+ *
+ * 이 핸들러는 기본 HTML 오류 페이지 대신, REST API 클라이언트에 JSON 기반의 표준 에러 응답을 제공하기 위해 사용됩니다.
+ */
@Component
@RequiredArgsConstructor
public class RestAccessDeniedHandler implements AccessDeniedHandler {
+
+ /** JSON 직렬화를 위한 ObjectMapper */
private final ObjectMapper objectMapper;
+ /**
+ * 인가되지 않은 요청이 들어왔을 때 실행됩니다.
+ *
+ * @param request 현재 요청
+ * @param response 응답 객체
+ * @param ex 발생한 {@link AccessDeniedException}
+ * @throws IOException 응답 스트림 처리 중 오류 발생 시
+ */
@Override
public void handle(
HttpServletRequest request, HttpServletResponse response, AccessDeniedException ex)
diff --git a/apps/user-service/src/main/java/site/icebang/global/handler/exception/RestAuthenticationEntryPoint.java b/apps/user-service/src/main/java/site/icebang/global/handler/exception/RestAuthenticationEntryPoint.java
index b7c50d76..9d3ec7b5 100644
--- a/apps/user-service/src/main/java/site/icebang/global/handler/exception/RestAuthenticationEntryPoint.java
+++ b/apps/user-service/src/main/java/site/icebang/global/handler/exception/RestAuthenticationEntryPoint.java
@@ -15,11 +15,37 @@
import site.icebang.common.dto.ApiResponse;
+/**
+ * 인증 진입점 처리기 (REST 전용 AuthenticationEntryPoint).
+ *
+ * Spring Security에서 인증(Authentication) 실패 시 호출됩니다. 인증되지 않은 사용자가 보호된 리소스에 접근하려고 하면 이 핸들러가 실행되어
+ * JSON 형식의 에러 응답을 반환합니다.
+ *
+ * 주요 특징:
+ *
+ * 이 핸들러는 기본 로그인 페이지 리다이렉트 대신, REST API 클라이언트에 JSON 기반의 표준 에러 응답을 제공하기 위해 사용됩니다.
+ */
@Component
@RequiredArgsConstructor
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
+
+ /** JSON 직렬화를 위한 ObjectMapper */
private final ObjectMapper objectMapper;
+ /**
+ * 인증되지 않은 요청이 들어왔을 때 실행됩니다.
+ *
+ * @param request 현재 요청
+ * @param response 응답 객체
+ * @param ex 발생한 {@link AuthenticationException}
+ * @throws IOException 응답 스트림 처리 중 오류 발생 시
+ */
@Override
public void commence(
HttpServletRequest request, HttpServletResponse response, AuthenticationException ex)
{@code
+ * PageParams params = new PageParams();
+ * params.setCurrent(2);
+ * params.setPageSize(20);
+ * params.setSearch("회원");
+ *
+ * int offset = params.getOffset(); // 20
+ * boolean searchable = params.hasSearch(); // true
+ * }
+ *
+ * @author jys01012@gmail.com
+ * @since v0.0.1-alpha
+ * @see lombok.Data
+ */
@Data
public class PageParams {
+ /**
+ * 현재 페이지 번호 (1부터 시작).
+ *
+ * {@code
+ * PageParams params = new PageParams();
+ * params.setCurrent(2);
+ * params.setPageSize(10);
+ *
+ * // Repository나 Mapper에서 데이터를 가져와 PageResult 생성
+ * PageResult
+ *
+ * @param > dataSupplier, Supplier
{@code
+ * @Service
+ * public class UserService implements PageableService
+ *
+ * @param
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *