diff --git a/ontime-back/src/main/java/devkor/ontime_back/LoggingAspect.java b/ontime-back/src/main/java/devkor/ontime_back/LoggingAspect.java index fbd248b..a3873b7 100644 --- a/ontime-back/src/main/java/devkor/ontime_back/LoggingAspect.java +++ b/ontime-back/src/main/java/devkor/ontime_back/LoggingAspect.java @@ -1,9 +1,12 @@ package devkor.ontime_back; +import devkor.ontime_back.dto.RequestInfoDto; import devkor.ontime_back.entity.ApiLog; import devkor.ontime_back.repository.ApiLogRepository; import devkor.ontime_back.response.GeneralException; +import devkor.ontime_back.service.ApiLogService; import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; @@ -13,48 +16,36 @@ import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.AccessDeniedException; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; +import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import java.lang.annotation.Annotation; +import java.util.Map; @Slf4j @Aspect @Component +@RequiredArgsConstructor public class LoggingAspect { - private final ApiLogRepository apiLogRepository; - - public LoggingAspect(ApiLogRepository apiLogRepository) { - this.apiLogRepository = apiLogRepository; - } - + private final ApiLogService apiLogService; + private static final String NO_PARAMS = "No Params"; + private static final String NO_BODY = "No Body"; @Pointcut("bean(*Controller)") private void allRequest() {} @Around("allRequest()") public Object logRequest(ProceedingJoinPoint joinPoint) throws Throwable { - - HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); - - // requestUrl - String requestUrl = request.getRequestURI(); - // requestMethod - String requestMethod = request.getMethod(); - // userId - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - String userId = (authentication != null && authentication.isAuthenticated()) - ? authentication.getName() // 인증된 사용자의 이름 (주로 ID로 사용됨) - : "Anonymous"; - // clientIp - String clientIp = request.getRemoteAddr(); + RequestInfoDto requestInfoDto = extractRequestInfo(); // requestTime long beforeRequest = System.currentTimeMillis(); @@ -91,21 +82,14 @@ public Object logRequest(ProceedingJoinPoint joinPoint) throws Throwable { // 정상 요청 로그 저장 long timeTaken = System.currentTimeMillis() - beforeRequest; - ApiLog apiLog = ApiLog.builder(). - requestUrl(requestUrl). - requestMethod(requestMethod). - userId(userId). - clientIp(clientIp). - responseStatus(responseStatus). - takenTime(timeTaken). - build(); - apiLogRepository.save(apiLog); + ApiLog apiLog = buildApiLog(requestInfoDto, responseStatus, timeTaken); + apiLogService.saveLog(apiLog); log.info("[Request Log] requestUrl: {}, requestMethod: {}, userId: {}, clientIp: {}, pathVariable: {}, requestBody: {}, responseStatus: {}, timeTaken: {}", - requestUrl, requestMethod, userId, clientIp, - pathVariable != null ? pathVariable : "No Params", - requestBody != null ? requestBody : "No Body", + requestInfoDto.getRequestUrl(), requestInfoDto.getRequestMethod(), requestInfoDto.getUserId(), requestInfoDto.getClientIp(), + pathVariable != null ? pathVariable : NO_PARAMS, + requestBody != null ? requestBody : NO_BODY, responseStatus, timeTaken); return result; @@ -117,19 +101,7 @@ public Object logRequest(ProceedingJoinPoint joinPoint) throws Throwable { @AfterThrowing(pointcut = "allRequest()", throwing = "ex") public void logException(JoinPoint joinPoint, Exception ex) { - HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); - - // requestUrl - String requestUrl = request.getRequestURI(); - // requestMethod - String requestMethod = request.getMethod(); - // userId - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - String userId = (authentication != null && authentication.isAuthenticated()) - ? authentication.getName() // 인증된 사용자의 이름 (주로 ID로 사용됨) - : "Anonymous"; - // clientIp - String clientIp = request.getRemoteAddr(); + RequestInfoDto requestInfoDto = extractRequestInfo(); // exceptionName String exceptionName; @@ -144,32 +116,44 @@ public void logException(JoinPoint joinPoint, Exception ex) { int responseStatus = mapExceptionToStatusCode(ex); log.error("[Error Log] requestUrl: {}, requestMethod: {}, userId: {}, clientIp: {}, exception: {}, message: {}, responseStatus: {}", - requestUrl, requestMethod, userId, clientIp, exceptionName, exceptionMessage, responseStatus); - - // DB에 에러 로그 저장 - ApiLog errorLog = ApiLog.builder(). - requestUrl(requestUrl). - requestMethod(requestMethod). - userId(userId). - clientIp(clientIp). - responseStatus(responseStatus). - takenTime(0). - build(); - // 상태 코드와 시간은 예제로 설정 - apiLogRepository.save(errorLog); + requestInfoDto.getRequestUrl(), requestInfoDto.getRequestMethod(), requestInfoDto.getUserId(), requestInfoDto.getClientIp(), exceptionName, exceptionMessage, responseStatus); + + ApiLog errorLog = buildApiLog(requestInfoDto, responseStatus, 0); + apiLogService.saveLog(errorLog); + } + + // requestinfo 추출 + private RequestInfoDto extractRequestInfo() { + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); + + String requestUrl = request.getRequestURI(); + String requestMethod = request.getMethod(); + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + String userId = (authentication != null && authentication.isAuthenticated()) + ? authentication.getName() + : "Anonymous"; + String clientIp = request.getRemoteAddr(); + + return new RequestInfoDto(requestUrl, requestMethod, userId, clientIp); + } + + // apilog 생성 + private ApiLog buildApiLog(RequestInfoDto info, int responseStatus, long timeTaken) { + return ApiLog.builder() + .requestUrl(info.getRequestUrl()) + .requestMethod(info.getRequestMethod()) + .userId(info.getUserId()) + .clientIp(info.getClientIp()) + .responseStatus(responseStatus) + .takenTime(timeTaken) + .build(); } private int mapExceptionToStatusCode(Exception e) { - if (e instanceof IllegalArgumentException) { - return 400; // Bad Request - } else if (e instanceof org.springframework.security.access.AccessDeniedException) { - return 403; // Forbidden - } else if (e instanceof org.springframework.web.bind.MethodArgumentNotValidException) { - return 422; // Unprocessable Entity - } else { - return 500; // Internal Server Error + if (e instanceof GeneralException ge) { + return ge.getErrorCode().getCode(); } + return 500; } - } diff --git a/ontime-back/src/main/java/devkor/ontime_back/OntimeBackApplication.java b/ontime-back/src/main/java/devkor/ontime_back/OntimeBackApplication.java index 958f674..783c631 100644 --- a/ontime-back/src/main/java/devkor/ontime_back/OntimeBackApplication.java +++ b/ontime-back/src/main/java/devkor/ontime_back/OntimeBackApplication.java @@ -2,8 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; +@EnableAsync @SpringBootApplication @EnableScheduling public class OntimeBackApplication { diff --git a/ontime-back/src/main/java/devkor/ontime_back/config/SwaggerConfig.java b/ontime-back/src/main/java/devkor/ontime_back/config/SwaggerConfig.java index 54f58a8..bd562a7 100644 --- a/ontime-back/src/main/java/devkor/ontime_back/config/SwaggerConfig.java +++ b/ontime-back/src/main/java/devkor/ontime_back/config/SwaggerConfig.java @@ -15,7 +15,7 @@ @Configuration @OpenAPIDefinition( servers = { - @Server(url = "https://ontime.devkor.club", description = "Production Server"), + @Server(url = "https://api.ontime.devkor.club", description = "Production Server"), @Server(url = "http://localhost:8080", description = "Local Serever") } ) diff --git a/ontime-back/src/main/java/devkor/ontime_back/dto/RequestInfoDto.java b/ontime-back/src/main/java/devkor/ontime_back/dto/RequestInfoDto.java new file mode 100644 index 0000000..6d03ccb --- /dev/null +++ b/ontime-back/src/main/java/devkor/ontime_back/dto/RequestInfoDto.java @@ -0,0 +1,14 @@ +package devkor.ontime_back.dto; + + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class RequestInfoDto { + private String requestUrl; + private String requestMethod; + private String userId; + private String clientIp; +} diff --git a/ontime-back/src/main/java/devkor/ontime_back/dto/ScheduleAddDto.java b/ontime-back/src/main/java/devkor/ontime_back/dto/ScheduleAddDto.java index 0f3597e..fe2af23 100644 --- a/ontime-back/src/main/java/devkor/ontime_back/dto/ScheduleAddDto.java +++ b/ontime-back/src/main/java/devkor/ontime_back/dto/ScheduleAddDto.java @@ -1,5 +1,8 @@ package devkor.ontime_back.dto; +import devkor.ontime_back.entity.Place; +import devkor.ontime_back.entity.Schedule; +import devkor.ontime_back.entity.User; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -14,22 +17,29 @@ @AllArgsConstructor public class ScheduleAddDto { private UUID scheduleId; - private UUID placeId; - private String placeName; - private String scheduleName; - private Integer moveTime; // 이동시간 - private LocalDateTime scheduleTime; // 약속시각 - private Boolean isChange; // 변경여부 - private Boolean isStarted; // 버튼누름여부 - private Integer scheduleSpareTime; // 스케줄 별 여유시간 - private String scheduleNote; // 스케줄 별 주의사항 + + public Schedule toEntity(User user, Place place) { + return Schedule.builder() + .user(user) + .scheduleId(this.scheduleId) + .place(place) + .scheduleName(this.scheduleName) + .moveTime(this.moveTime) + .scheduleTime(this.scheduleTime) + .isChange(false) + .isStarted(false) + .scheduleSpareTime(this.scheduleSpareTime) + .latenessTime(-1) + .scheduleNote(this.scheduleNote) + .build(); + } } diff --git a/ontime-back/src/main/java/devkor/ontime_back/entity/Schedule.java b/ontime-back/src/main/java/devkor/ontime_back/entity/Schedule.java index 1ed53dc..b175e9d 100644 --- a/ontime-back/src/main/java/devkor/ontime_back/entity/Schedule.java +++ b/ontime-back/src/main/java/devkor/ontime_back/entity/Schedule.java @@ -1,5 +1,6 @@ package devkor.ontime_back.entity; +import devkor.ontime_back.dto.ScheduleModDto; import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.OnDelete; @@ -54,14 +55,14 @@ public class Schedule { @Column(columnDefinition = "TEXT") // 명시적으로 TEXT 타입으로 정의 private String scheduleNote; // 스케줄 별 주의사항 - public void updateSchedule(Place place, String scheduleName, Integer moveTime, LocalDateTime scheduleTime, Integer scheduleSpareTime, Integer latenessTime, String scheduleNote) { + public void updateSchedule(Place place, ScheduleModDto scheduleModDto) { this.place = place; - this.scheduleName = scheduleName; - this.moveTime = moveTime; - this.scheduleTime = scheduleTime; - this.scheduleSpareTime = scheduleSpareTime; - this.latenessTime = latenessTime; - this.scheduleNote = scheduleNote; + this.scheduleName = scheduleModDto.getScheduleName(); + this.moveTime = scheduleModDto.getMoveTime(); + this.scheduleTime = scheduleModDto.getScheduleTime(); + this.scheduleSpareTime = scheduleModDto.getScheduleSpareTime(); + this.latenessTime = scheduleModDto.getLatenessTime(); + this.scheduleNote = scheduleModDto.getScheduleNote(); } public void startSchedule() { diff --git a/ontime-back/src/main/java/devkor/ontime_back/response/ApiResponseForm.java b/ontime-back/src/main/java/devkor/ontime_back/response/ApiResponseForm.java index fda4b6d..3274ef9 100644 --- a/ontime-back/src/main/java/devkor/ontime_back/response/ApiResponseForm.java +++ b/ontime-back/src/main/java/devkor/ontime_back/response/ApiResponseForm.java @@ -8,10 +8,10 @@ public class ApiResponseForm { // 제네릭 api 응답 객체 private String status; - private String code; + private int code; private String message; private final T data; - public ApiResponseForm(String status, String code, String message, T data) { + public ApiResponseForm(String status, int code, String message, T data) { this.status = status; // HttpResponse의 생성자 호출 (부모 클래스의 생성자 또는 메서드를 호출, 자식 클래스는 부모 클래스의 private 필드에 직접 접근 X) this.code = code; this.message = message; @@ -20,33 +20,33 @@ public ApiResponseForm(String status, String code, String message, T data) { // 성공 응답을 위한 메서드 (message를 받는 경우) public static ApiResponseForm success(T data, String message) { - return new ApiResponseForm<>("success", "200", message, data); + return new ApiResponseForm<>("success", 200, message, data); } // 성공 응답을 위한 메서드 (message를 받지 않는 경우) public static ApiResponseForm success(T data) { - return new ApiResponseForm<>("success", "200", "OK", data); + return new ApiResponseForm<>("success", 200, "OK", data); } // 실패 응답을 위한 메서드 - public static ApiResponseForm fail(String code, String message) { + public static ApiResponseForm fail(int code, String message) { return new ApiResponseForm<>("fail", code, message, null); // 실패의 경우 data는 null로 처리 } - public static ApiResponseForm accessTokenEmpty(String code, String message) { + public static ApiResponseForm accessTokenEmpty(int code, String message) { return new ApiResponseForm<>("accessTokenEmpty", code, message, null); // 실패의 경우 data는 null로 처리 } - public static ApiResponseForm accessTokenInvalid(String code, String message) { + public static ApiResponseForm accessTokenInvalid(int code, String message) { return new ApiResponseForm<>("accessTokenInvalid", code, message, null); // 실패의 경우 data는 null로 처리 } - public static ApiResponseForm refreshTokenInvalid(String code, String message) { + public static ApiResponseForm refreshTokenInvalid(int code, String message) { return new ApiResponseForm<>("refreshTokenInvalid", code, message, null); // 실패의 경우 data는 null로 처리 } // 오류 응답을 위한 메서드 - public static ApiResponseForm error(String code, String message) { + public static ApiResponseForm error(int code, String message) { return new ApiResponseForm<>("error", code, message, null); // 오류의 경우 data는 null로 처리 } diff --git a/ontime-back/src/main/java/devkor/ontime_back/response/ErrorCode.java b/ontime-back/src/main/java/devkor/ontime_back/response/ErrorCode.java index fbd8a5c..7cbb665 100644 --- a/ontime-back/src/main/java/devkor/ontime_back/response/ErrorCode.java +++ b/ontime-back/src/main/java/devkor/ontime_back/response/ErrorCode.java @@ -5,47 +5,47 @@ public enum ErrorCode { // HTTP 상태 코드 (4xx) - BAD_REQUEST("400", "Bad Request: Invalid input or malformed request.", HttpStatus.BAD_REQUEST), - UNAUTHORIZED("401", "Unauthorized: You must authenticate to access this resource.", HttpStatus.UNAUTHORIZED), - FORBIDDEN("403", "Forbidden: You do not have permission to access this resource.", HttpStatus.FORBIDDEN), - NOT_FOUND("404", "Not Found: The requested resource could not be found.", HttpStatus.NOT_FOUND), + BAD_REQUEST(400, "Bad Request: Invalid input or malformed request.", HttpStatus.BAD_REQUEST), + UNAUTHORIZED(401, "Unauthorized: You must authenticate to access this resource.", HttpStatus.UNAUTHORIZED), + FORBIDDEN(403, "Forbidden: You do not have permission to access this resource.", HttpStatus.FORBIDDEN), + NOT_FOUND(404, "Not Found: The requested resource could not be found.", HttpStatus.NOT_FOUND), // HTTP 상태 코드 (5xx) - INTERNAL_SERVER_ERROR("500", "Internal Server Error: An unexpected error occurred on the server.", HttpStatus.INTERNAL_SERVER_ERROR), - BAD_GATEWAY("502", "Bad Gateway: The server received an invalid response from the upstream server.", HttpStatus.BAD_GATEWAY), - SERVICE_UNAVAILABLE("503", "Service Unavailable: The server is temporarily unable to handle the request.", HttpStatus.SERVICE_UNAVAILABLE), + INTERNAL_SERVER_ERROR(500, "Internal Server Error: An unexpected error occurred on the server.", HttpStatus.INTERNAL_SERVER_ERROR), + BAD_GATEWAY(502, "Bad Gateway: The server received an invalid response from the upstream server.", HttpStatus.BAD_GATEWAY), + SERVICE_UNAVAILABLE(503, "Service Unavailable: The server is temporarily unable to handle the request.", HttpStatus.SERVICE_UNAVAILABLE), // 비즈니스 로직 오류 코드 - USER_NOT_FOUND("1001", "해당 ID의 사용자를 찾을 수 없습니다.", HttpStatus.BAD_REQUEST), - INVALID_INPUT("1002", "유효하지 않은 입력값입니다.", HttpStatus.BAD_REQUEST), - RESOURCE_ALREADY_EXISTS("1003", "생성하려는 리소스가 이미 존재합니다.", HttpStatus.BAD_REQUEST), - UNAUTHORIZED_ACCESS("1004", "해당 작업에 대한 권한이 없습니다.", HttpStatus.UNAUTHORIZED), - EMAIL_ALREADY_EXIST("1005", "이미 존재하는 이메일입니다.", HttpStatus.BAD_REQUEST), - NAME_ALREADY_EXIST("1006", "이미 존재하는 이름입니다.", HttpStatus.BAD_REQUEST), - USER_SETTING_ALREADY_EXIST("1007", "이미 존재하는 userSettingId 입니다.", HttpStatus.BAD_REQUEST), - PASSWORD_INCORRECT("1008", "기존 비밀번호가 틀렸습니다.", HttpStatus.BAD_REQUEST), - SAME_PASSWORD("1009", "새 비밀번호와 기존 비밀번호가 일치합니다.", HttpStatus.BAD_REQUEST), - SCHEDULE_NOT_FOUND("1010", "해당 약속이 존재하지 않습니다.", HttpStatus.BAD_REQUEST), - FIREBASE("1011", "FIREBASE로 메세지를 발송하였으나 오류가 발생했습니다.(유효하지 않은 토큰 등)", HttpStatus.BAD_REQUEST), - FIRST_PREPARATION_NOT_FOUND("1012", "해당 ID의 사용자의 준비과정을 찾을 수 없습니다.", HttpStatus.BAD_REQUEST), - NOTIFICATION_NOT_FOUND("1013", "알림을 찾을 수 없습니다.", HttpStatus.BAD_REQUEST ), + USER_NOT_FOUND(1001, "해당 ID의 사용자를 찾을 수 없습니다.", HttpStatus.BAD_REQUEST), + INVALID_INPUT(1002, "유효하지 않은 입력값입니다.", HttpStatus.BAD_REQUEST), + RESOURCE_ALREADY_EXISTS(1003, "생성하려는 리소스가 이미 존재합니다.", HttpStatus.BAD_REQUEST), + UNAUTHORIZED_ACCESS(1004, "해당 작업에 대한 권한이 없습니다.", HttpStatus.UNAUTHORIZED), + EMAIL_ALREADY_EXIST(1005, "이미 존재하는 이메일입니다.", HttpStatus.BAD_REQUEST), + NAME_ALREADY_EXIST(1006, "이미 존재하는 이름입니다.", HttpStatus.BAD_REQUEST), + USER_SETTING_ALREADY_EXIST(1007, "이미 존재하는 userSettingId 입니다.", HttpStatus.BAD_REQUEST), + PASSWORD_INCORRECT(1008, "기존 비밀번호가 틀렸습니다.", HttpStatus.BAD_REQUEST), + SAME_PASSWORD(1009, "새 비밀번호와 기존 비밀번호가 일치합니다.", HttpStatus.BAD_REQUEST), + SCHEDULE_NOT_FOUND(1010, "해당 약속이 존재하지 않습니다.", HttpStatus.BAD_REQUEST), + FIREBASE(1011, "FIREBASE로 메세지를 발송하였으나 오류가 발생했습니다.(유효하지 않은 토큰 등)", HttpStatus.BAD_REQUEST), + FIRST_PREPARATION_NOT_FOUND(1012, "해당 ID의 사용자의 준비과정을 찾을 수 없습니다.", HttpStatus.BAD_REQUEST), + NOTIFICATION_NOT_FOUND(1013, "알림을 찾을 수 없습니다.", HttpStatus.BAD_REQUEST ), // 공통 오류 메시지 - UNEXPECTED_ERROR("1000", "Unexpected Error: An unexpected error occurred.", HttpStatus.INTERNAL_SERVER_ERROR),; + UNEXPECTED_ERROR(1000, "Unexpected Error: An unexpected error occurred.", HttpStatus.INTERNAL_SERVER_ERROR),; - private final String code; + private final int code; private final String message; private final HttpStatus httpStatus; // 생성자 - ErrorCode(String code, String message, HttpStatus httpStatus) { + ErrorCode(int code, String message, HttpStatus httpStatus) { this.code = code; this.message = message; this.httpStatus = httpStatus; } // 코드와 메시지를 반환하는 메서드 - public String getCode() { + public int getCode() { return code; } diff --git a/ontime-back/src/main/java/devkor/ontime_back/response/GlobalExceptionHandler.java b/ontime-back/src/main/java/devkor/ontime_back/response/GlobalExceptionHandler.java index d31ba9f..d0d8f1b 100644 --- a/ontime-back/src/main/java/devkor/ontime_back/response/GlobalExceptionHandler.java +++ b/ontime-back/src/main/java/devkor/ontime_back/response/GlobalExceptionHandler.java @@ -25,7 +25,7 @@ public ResponseEntity> handleGeneralException(GeneralExcep public ResponseEntity> handleInvalidTokenException(InvalidTokenException ex, HttpServletRequest request) { return ResponseEntity .status(HttpStatus.UNAUTHORIZED) - .body(ApiResponseForm.error("401", ex.getMessage())); + .body(ApiResponseForm.error(401, ex.getMessage())); } @ExceptionHandler(HttpMessageNotReadableException.class) @@ -34,7 +34,7 @@ public ResponseEntity> handleHttpMessageNotReadableExcepti request.getRequestURI(), request.getMethod(), (request.getUserPrincipal() != null) ? request.getUserPrincipal().getName() : "Anonymous", request.getRemoteAddr(), "HttpMessageNotReadableException", "요청 형식이 올바르지 않습니다.", 400); return ResponseEntity .status(HttpStatus.BAD_REQUEST) - .body(ApiResponseForm.error("400", "요청 형식이 올바르지 않습니다.")); + .body(ApiResponseForm.error(400, "요청 형식이 올바르지 않습니다.")); } } \ No newline at end of file diff --git a/ontime-back/src/main/java/devkor/ontime_back/service/ApiLogService.java b/ontime-back/src/main/java/devkor/ontime_back/service/ApiLogService.java new file mode 100644 index 0000000..595b55e --- /dev/null +++ b/ontime-back/src/main/java/devkor/ontime_back/service/ApiLogService.java @@ -0,0 +1,26 @@ +package devkor.ontime_back.service; + +import devkor.ontime_back.entity.ApiLog; +import devkor.ontime_back.repository.ApiLogRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +@Slf4j +@RequiredArgsConstructor +@Service +public class ApiLogService { + private final ApiLogRepository apiLogRepository; + + @Async + public void saveLog(ApiLog apiLog) { + try { + log.info("[Async] saveLog started on thread: {}", Thread.currentThread().getName()); + apiLogRepository.save(apiLog); + log.info("[Async] saveLog finished on thread: {}", Thread.currentThread().getName()); + } catch (Exception e) { + log.error("API 로그 저장 실패", e); + } + } +} diff --git a/ontime-back/src/main/java/devkor/ontime_back/service/NotificationService.java b/ontime-back/src/main/java/devkor/ontime_back/service/NotificationService.java index db9a597..2b62d74 100644 --- a/ontime-back/src/main/java/devkor/ontime_back/service/NotificationService.java +++ b/ontime-back/src/main/java/devkor/ontime_back/service/NotificationService.java @@ -24,7 +24,6 @@ import java.util.concurrent.ScheduledFuture; @Slf4j -@EnableAsync @Service @RequiredArgsConstructor @Transactional(readOnly = true) diff --git a/ontime-back/src/main/java/devkor/ontime_back/service/ScheduleService.java b/ontime-back/src/main/java/devkor/ontime_back/service/ScheduleService.java index e93e8ea..8fd5132 100644 --- a/ontime-back/src/main/java/devkor/ontime_back/service/ScheduleService.java +++ b/ontime-back/src/main/java/devkor/ontime_back/service/ScheduleService.java @@ -1,10 +1,7 @@ package devkor.ontime_back.service; import devkor.ontime_back.dto.*; -import devkor.ontime_back.entity.NotificationSchedule; -import devkor.ontime_back.entity.Place; -import devkor.ontime_back.entity.Schedule; -import devkor.ontime_back.entity.User; +import devkor.ontime_back.entity.*; import devkor.ontime_back.repository.*; import devkor.ontime_back.response.GeneralException; import lombok.RequiredArgsConstructor; @@ -88,13 +85,12 @@ public void deleteSchedule(UUID scheduleId, Long userId) { NotificationSchedule notification = notificationScheduleRepository.findByScheduleScheduleId(scheduleId) .orElseThrow(() -> new GeneralException(NOTIFICATION_NOT_FOUND)); - cancleAndDeleteNotification(notification); + cancelAndDeleteNotification(notification); notificationScheduleRepository.flush(); - preparationScheduleRepository.deleteBySchedule(schedule); scheduleRepository.deleteByScheduleId(scheduleId); } - private void cancleAndDeleteNotification(NotificationSchedule notification) { + private void cancelAndDeleteNotification(NotificationSchedule notification) { log.info("{}에 대한 알림 취소 및 삭제 됨", notification.getSchedule().getScheduleName()); notification.disconnectSchedule(); notificationService.cancelScheduledNotification(notification.getId()); @@ -110,14 +106,8 @@ public void modifySchedule(Long userId, UUID scheduleId, ScheduleModDto schedule Place place = placeRepository.findByPlaceName(scheduleModDto.getPlaceName()) .orElseGet(() -> placeRepository.save(new Place(scheduleModDto.getPlaceId(), scheduleModDto.getPlaceName()))); - schedule.updateSchedule( - place, - scheduleModDto.getScheduleName(), - scheduleModDto.getMoveTime(), - scheduleModDto.getScheduleTime(), - scheduleModDto.getScheduleSpareTime(), - scheduleModDto.getLatenessTime(), - scheduleModDto.getScheduleNote()); + schedule.updateSchedule(place, scheduleModDto); + scheduleRepository.save(schedule); @@ -146,19 +136,7 @@ public void addSchedule(ScheduleAddDto scheduleAddDto, Long userId) { Place place = placeRepository.findByPlaceName(scheduleAddDto.getPlaceName()) .orElseGet(() -> placeRepository.save(new Place(scheduleAddDto.getPlaceId(), scheduleAddDto.getPlaceName()))); - Schedule schedule = Schedule.builder() - .scheduleId(scheduleAddDto.getScheduleId()) - .user(user) - .place(place) - .scheduleName(scheduleAddDto.getScheduleName()) - .moveTime(scheduleAddDto.getMoveTime()) - .scheduleTime(scheduleAddDto.getScheduleTime()) - .scheduleSpareTime(scheduleAddDto.getScheduleSpareTime()) - .scheduleNote(scheduleAddDto.getScheduleNote()) - .isChange(false) - .isStarted(false) - .latenessTime(-1) - .build(); + Schedule schedule = scheduleAddDto.toEntity(user, place); scheduleRepository.save(schedule); NotificationSchedule notification = NotificationSchedule.builder()