Fix : common
This commit is contained in:
parent
cb7c025405
commit
3d0ed4c268
@ -8,4 +8,8 @@ public class ActionPlanNotFoundException extends AnalyticsException {
|
||||
public ActionPlanNotFoundException(Long planId) {
|
||||
super("ACTION_PLAN_NOT_FOUND", "실행 계획을 찾을 수 없습니다: " + planId);
|
||||
}
|
||||
|
||||
public ActionPlanNotFoundException(String message) {
|
||||
super("ACTION_PLAN_NOT_FOUND", message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
package com.ktds.hi.analytics.infra.exception;
|
||||
|
||||
import com.ktds.hi.common.dto.ErrorResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import jakarta.validation.ConstraintViolationException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@ -11,14 +14,13 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
|
||||
|
||||
import jakarta.validation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 글로벌 예외 처리 핸들러
|
||||
* 글로벌 예외 처리 핸들러 (수정 완료)
|
||||
* 모든 컨트롤러에서 발생하는 예외를 중앙에서 처리
|
||||
* 새로운 ErrorResponse 필드 구조에 맞게 수정
|
||||
*/
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
@ -28,16 +30,15 @@ public class GlobalExceptionHandler {
|
||||
* 분석 서비스 커스텀 예외 처리
|
||||
*/
|
||||
@ExceptionHandler(AnalyticsException.class)
|
||||
public ResponseEntity<ErrorResponse> handleAnalyticsException(AnalyticsException ex) {
|
||||
public ResponseEntity<ErrorResponse<Void>> handleAnalyticsException(
|
||||
AnalyticsException ex, HttpServletRequest request) {
|
||||
log.error("Analytics Exception: {}", ex.getMessage(), ex);
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.BAD_REQUEST.value())
|
||||
.error("Analytics Error")
|
||||
.message(ex.getMessage())
|
||||
.path("/api/analytics")
|
||||
.build();
|
||||
ErrorResponse<Void> errorResponse = ErrorResponse.of(
|
||||
ex.getErrorCode(),
|
||||
ex.getMessage(),
|
||||
request.getRequestURI()
|
||||
);
|
||||
|
||||
return ResponseEntity.badRequest().body(errorResponse);
|
||||
}
|
||||
@ -46,16 +47,15 @@ public class GlobalExceptionHandler {
|
||||
* 매장 정보 없음 예외 처리
|
||||
*/
|
||||
@ExceptionHandler(StoreNotFoundException.class)
|
||||
public ResponseEntity<ErrorResponse> handleStoreNotFoundException(StoreNotFoundException ex) {
|
||||
public ResponseEntity<ErrorResponse<Void>> handleStoreNotFoundException(
|
||||
StoreNotFoundException ex, HttpServletRequest request) {
|
||||
log.error("Store Not Found: {}", ex.getMessage());
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.NOT_FOUND.value())
|
||||
.error("Store Not Found")
|
||||
.message(ex.getMessage())
|
||||
.path("/api/analytics")
|
||||
.build();
|
||||
ErrorResponse<Void> errorResponse = ErrorResponse.of(
|
||||
"STORE_NOT_FOUND",
|
||||
ex.getMessage(),
|
||||
request.getRequestURI()
|
||||
);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse);
|
||||
}
|
||||
@ -64,16 +64,15 @@ public class GlobalExceptionHandler {
|
||||
* 실행 계획 없음 예외 처리
|
||||
*/
|
||||
@ExceptionHandler(ActionPlanNotFoundException.class)
|
||||
public ResponseEntity<ErrorResponse> handleActionPlanNotFoundException(ActionPlanNotFoundException ex) {
|
||||
public ResponseEntity<ErrorResponse<Void>> handleActionPlanNotFoundException(
|
||||
ActionPlanNotFoundException ex, HttpServletRequest request) {
|
||||
log.error("Action Plan Not Found: {}", ex.getMessage());
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.NOT_FOUND.value())
|
||||
.error("Action Plan Not Found")
|
||||
.message(ex.getMessage())
|
||||
.path("/api/action-plans")
|
||||
.build();
|
||||
ErrorResponse<Void> errorResponse = ErrorResponse.of(
|
||||
"ACTION_PLAN_NOT_FOUND",
|
||||
ex.getMessage(),
|
||||
request.getRequestURI()
|
||||
);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse);
|
||||
}
|
||||
@ -82,16 +81,15 @@ public class GlobalExceptionHandler {
|
||||
* AI 서비스 예외 처리
|
||||
*/
|
||||
@ExceptionHandler(AIServiceException.class)
|
||||
public ResponseEntity<ErrorResponse> handleAIServiceException(AIServiceException ex) {
|
||||
public ResponseEntity<ErrorResponse<Void>> handleAIServiceException(
|
||||
AIServiceException ex, HttpServletRequest request) {
|
||||
log.error("AI Service Exception: {}", ex.getMessage(), ex);
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.SERVICE_UNAVAILABLE.value())
|
||||
.error("AI Service Error")
|
||||
.message("AI 서비스 연동 중 오류가 발생했습니다.")
|
||||
.path("/api/analytics")
|
||||
.build();
|
||||
ErrorResponse<Void> errorResponse = ErrorResponse.of(
|
||||
"AI_SERVICE_ERROR",
|
||||
"AI 서비스 연동 중 오류가 발생했습니다.",
|
||||
request.getRequestURI()
|
||||
);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(errorResponse);
|
||||
}
|
||||
@ -100,16 +98,15 @@ public class GlobalExceptionHandler {
|
||||
* 외부 서비스 예외 처리
|
||||
*/
|
||||
@ExceptionHandler(ExternalServiceException.class)
|
||||
public ResponseEntity<ErrorResponse> handleExternalServiceException(ExternalServiceException ex) {
|
||||
public ResponseEntity<ErrorResponse<Void>> handleExternalServiceException(
|
||||
ExternalServiceException ex, HttpServletRequest request) {
|
||||
log.error("External Service Exception: {}", ex.getMessage(), ex);
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.SERVICE_UNAVAILABLE.value())
|
||||
.error("External Service Error")
|
||||
.message("외부 서비스 연동 중 오류가 발생했습니다.")
|
||||
.path("/api/analytics")
|
||||
.build();
|
||||
ErrorResponse<Void> errorResponse = ErrorResponse.of(
|
||||
ex.getErrorCode(),
|
||||
"외부 서비스 연동 중 오류가 발생했습니다.",
|
||||
request.getRequestURI()
|
||||
);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(errorResponse);
|
||||
}
|
||||
@ -118,20 +115,25 @@ public class GlobalExceptionHandler {
|
||||
* 입력 값 검증 예외 처리
|
||||
*/
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException ex) {
|
||||
public ResponseEntity<ErrorResponse<Void>> handleValidationException(
|
||||
MethodArgumentNotValidException ex, HttpServletRequest request) {
|
||||
log.error("Validation Exception: {}", ex.getMessage());
|
||||
|
||||
String errorMessage = ex.getBindingResult().getFieldErrors().stream()
|
||||
.map(FieldError::getDefaultMessage)
|
||||
.collect(Collectors.joining(", "));
|
||||
List<ErrorResponse.ValidationError> validationErrors = ex.getBindingResult()
|
||||
.getFieldErrors()
|
||||
.stream()
|
||||
.map(error -> ErrorResponse.ValidationError.builder()
|
||||
.field(error.getField())
|
||||
.rejectedValue(error.getRejectedValue())
|
||||
.message(error.getDefaultMessage())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.BAD_REQUEST.value())
|
||||
.error("Validation Error")
|
||||
.message(errorMessage)
|
||||
.path("/api/analytics")
|
||||
.build();
|
||||
ErrorResponse<Void> errorResponse = ErrorResponse.ofValidation(
|
||||
"입력값 검증 실패",
|
||||
request.getRequestURI(),
|
||||
validationErrors
|
||||
);
|
||||
|
||||
return ResponseEntity.badRequest().body(errorResponse);
|
||||
}
|
||||
@ -140,20 +142,24 @@ public class GlobalExceptionHandler {
|
||||
* 바인딩 예외 처리
|
||||
*/
|
||||
@ExceptionHandler(BindException.class)
|
||||
public ResponseEntity<ErrorResponse> handleBindException(BindException ex) {
|
||||
public ResponseEntity<ErrorResponse<Void>> handleBindException(
|
||||
BindException ex, HttpServletRequest request) {
|
||||
log.error("Bind Exception: {}", ex.getMessage());
|
||||
|
||||
String errorMessage = ex.getFieldErrors().stream()
|
||||
.map(FieldError::getDefaultMessage)
|
||||
.collect(Collectors.joining(", "));
|
||||
List<ErrorResponse.ValidationError> validationErrors = ex.getFieldErrors()
|
||||
.stream()
|
||||
.map(error -> ErrorResponse.ValidationError.builder()
|
||||
.field(error.getField())
|
||||
.rejectedValue(error.getRejectedValue())
|
||||
.message(error.getDefaultMessage())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.BAD_REQUEST.value())
|
||||
.error("Binding Error")
|
||||
.message(errorMessage)
|
||||
.path("/api/analytics")
|
||||
.build();
|
||||
ErrorResponse<Void> errorResponse = ErrorResponse.ofValidation(
|
||||
"바인딩 실패",
|
||||
request.getRequestURI(),
|
||||
validationErrors
|
||||
);
|
||||
|
||||
return ResponseEntity.badRequest().body(errorResponse);
|
||||
}
|
||||
@ -162,20 +168,19 @@ public class GlobalExceptionHandler {
|
||||
* 제약 조건 위반 예외 처리
|
||||
*/
|
||||
@ExceptionHandler(ConstraintViolationException.class)
|
||||
public ResponseEntity<ErrorResponse> handleConstraintViolationException(ConstraintViolationException ex) {
|
||||
public ResponseEntity<ErrorResponse<Void>> handleConstraintViolationException(
|
||||
ConstraintViolationException ex, HttpServletRequest request) {
|
||||
log.error("Constraint Violation Exception: {}", ex.getMessage());
|
||||
|
||||
String errorMessage = ex.getConstraintViolations().stream()
|
||||
.map(ConstraintViolation::getMessage)
|
||||
.collect(Collectors.joining(", "));
|
||||
.map(ConstraintViolation::getMessage)
|
||||
.collect(Collectors.joining(", "));
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.BAD_REQUEST.value())
|
||||
.error("Constraint Violation")
|
||||
.message(errorMessage)
|
||||
.path("/api/analytics")
|
||||
.build();
|
||||
ErrorResponse<Void> errorResponse = ErrorResponse.of(
|
||||
"CONSTRAINT_VIOLATION",
|
||||
errorMessage,
|
||||
request.getRequestURI()
|
||||
);
|
||||
|
||||
return ResponseEntity.badRequest().body(errorResponse);
|
||||
}
|
||||
@ -184,16 +189,15 @@ public class GlobalExceptionHandler {
|
||||
* 타입 불일치 예외 처리
|
||||
*/
|
||||
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
|
||||
public ResponseEntity<ErrorResponse> handleTypeMismatchException(MethodArgumentTypeMismatchException ex) {
|
||||
public ResponseEntity<ErrorResponse<Void>> handleTypeMismatchException(
|
||||
MethodArgumentTypeMismatchException ex, HttpServletRequest request) {
|
||||
log.error("Type Mismatch Exception: {}", ex.getMessage());
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.BAD_REQUEST.value())
|
||||
.error("Type Mismatch")
|
||||
.message("잘못된 파라미터 타입입니다: " + ex.getName())
|
||||
.path("/api/analytics")
|
||||
.build();
|
||||
ErrorResponse<Void> errorResponse = ErrorResponse.of(
|
||||
"TYPE_MISMATCH",
|
||||
"잘못된 파라미터 타입입니다: " + ex.getName(),
|
||||
request.getRequestURI()
|
||||
);
|
||||
|
||||
return ResponseEntity.badRequest().body(errorResponse);
|
||||
}
|
||||
@ -202,16 +206,15 @@ public class GlobalExceptionHandler {
|
||||
* 일반적인 RuntimeException 처리
|
||||
*/
|
||||
@ExceptionHandler(RuntimeException.class)
|
||||
public ResponseEntity<ErrorResponse> handleRuntimeException(RuntimeException ex) {
|
||||
public ResponseEntity<ErrorResponse<Void>> handleRuntimeException(
|
||||
RuntimeException ex, HttpServletRequest request) {
|
||||
log.error("Runtime Exception: {}", ex.getMessage(), ex);
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.INTERNAL_SERVER_ERROR.value())
|
||||
.error("Internal Server Error")
|
||||
.message("내부 서버 오류가 발생했습니다.")
|
||||
.path("/api/analytics")
|
||||
.build();
|
||||
ErrorResponse<Void> errorResponse = ErrorResponse.of(
|
||||
"RUNTIME_ERROR",
|
||||
"내부 서버 오류가 발생했습니다.",
|
||||
request.getRequestURI()
|
||||
);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
||||
}
|
||||
@ -220,16 +223,13 @@ public class GlobalExceptionHandler {
|
||||
* 모든 예외의 최종 처리
|
||||
*/
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {
|
||||
public ResponseEntity<ErrorResponse<Void>> handleAllExceptions(
|
||||
Exception ex, HttpServletRequest request) {
|
||||
log.error("Unexpected Exception: {}", ex.getMessage(), ex);
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.INTERNAL_SERVER_ERROR.value())
|
||||
.error("Unexpected Error")
|
||||
.message("예상치 못한 오류가 발생했습니다.")
|
||||
.path("/api/analytics")
|
||||
.build();
|
||||
ErrorResponse<Void> errorResponse = ErrorResponse.ofInternalError(
|
||||
"예상치 못한 오류가 발생했습니다."
|
||||
);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
||||
}
|
||||
|
||||
@ -8,4 +8,8 @@ public class StoreNotFoundException extends AnalyticsException {
|
||||
public StoreNotFoundException(Long storeId) {
|
||||
super("STORE_NOT_FOUND", "매장을 찾을 수 없습니다: " + storeId);
|
||||
}
|
||||
|
||||
public StoreNotFoundException(String message) {
|
||||
super("STORE_NOT_FOUND", message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
package com.ktds.hi.analytics.infra.gateway;
|
||||
|
||||
import static com.azure.ai.textanalytics.models.TextSentiment.*;
|
||||
|
||||
import com.azure.ai.textanalytics.TextAnalyticsClient;
|
||||
import com.azure.ai.textanalytics.TextAnalyticsClientBuilder;
|
||||
import com.azure.ai.textanalytics.models.AnalyzeSentimentResult;
|
||||
import com.azure.ai.textanalytics.models.DocumentSentiment;
|
||||
import com.azure.ai.textanalytics.models.TextSentiment;
|
||||
import com.azure.core.credential.AzureKeyCredential;
|
||||
import com.ktds.hi.analytics.biz.domain.AiFeedback;
|
||||
import com.ktds.hi.analytics.biz.domain.SentimentType;
|
||||
@ -97,16 +100,19 @@ public class AIServiceAdapter implements AIServicePort {
|
||||
@Override
|
||||
public SentimentType analyzeSentiment(String content) {
|
||||
try {
|
||||
AnalyzeSentimentResult result = textAnalyticsClient.analyzeSentiment(content);
|
||||
DocumentSentiment sentiment = result.getDocumentSentiment();
|
||||
DocumentSentiment documentSentiment = textAnalyticsClient.analyzeSentiment(content);
|
||||
TextSentiment sentiment = documentSentiment.getSentiment();
|
||||
|
||||
switch (sentiment) {
|
||||
case POSITIVE:
|
||||
return SentimentType.POSITIVE;
|
||||
case NEGATIVE:
|
||||
return SentimentType.NEGATIVE;
|
||||
default:
|
||||
return SentimentType.NEUTRAL;
|
||||
if (sentiment == TextSentiment.POSITIVE) {
|
||||
return SentimentType.POSITIVE;
|
||||
} else if (sentiment == TextSentiment.NEGATIVE) {
|
||||
return SentimentType.NEGATIVE;
|
||||
} else if (sentiment == TextSentiment.NEUTRAL) {
|
||||
return SentimentType.NEUTRAL;
|
||||
} else if (sentiment == TextSentiment.MIXED) {
|
||||
return SentimentType.NEUTRAL; // MIXED는 NEUTRAL로 처리
|
||||
} else {
|
||||
return SentimentType.NEUTRAL;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
@ -31,7 +31,7 @@ import java.util.concurrent.Executors;
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class EventHubAdapter implements EventPort {
|
||||
public class EventHubAdapter {
|
||||
|
||||
@Qualifier("reviewEventConsumer")
|
||||
private final EventHubConsumerClient reviewEventConsumer;
|
||||
@ -61,7 +61,6 @@ public class EventHubAdapter implements EventPort {
|
||||
aiAnalysisEventProducer.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishAnalysisCompletedEvent(Long storeId, AnalysisType analysisType) {
|
||||
try {
|
||||
Map<String, Object> eventData = new HashMap<>();
|
||||
@ -84,7 +83,7 @@ public class EventHubAdapter implements EventPort {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public void publishActionPlanCreatedEvent(ActionPlan actionPlan) {
|
||||
try {
|
||||
Map<String, Object> eventData = new HashMap<>();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user