Merge pull request 'feat/remodel_code_log_251117' (#8) from feat/remodel_code_log_251117 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/8
This commit is contained in:
@@ -33,6 +33,7 @@ dependencies {
|
||||
annotationProcessor 'org.projectlombok:lombok'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-validation'
|
||||
|
||||
//geometry
|
||||
implementation 'com.fasterxml.jackson.core:jackson-databind'
|
||||
|
||||
4
http/CommonCode.http
Normal file
4
http/CommonCode.http
Normal file
@@ -0,0 +1,4 @@
|
||||
### GET getByCodeId
|
||||
GET http://localhost:8080/api/code/1
|
||||
Content-Type: application/json
|
||||
###
|
||||
@@ -0,0 +1,188 @@
|
||||
package com.kamco.cd.kamcoback.code;
|
||||
|
||||
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto;
|
||||
import com.kamco.cd.kamcoback.code.service.CommonCodeService;
|
||||
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Tag(name = "공통코드 관리", description = "공통코드 관리 API")
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/code")
|
||||
public class CommonCodeApiController {
|
||||
|
||||
private final CommonCodeService commonCodeService;
|
||||
|
||||
@Operation(summary = "목록 조회", description = "모든 공통코드 조회")
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "조회 성공",
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = CommonCodeDto.Basic.class))),
|
||||
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
|
||||
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
|
||||
})
|
||||
@GetMapping
|
||||
public ApiResponseDto<List<CommonCodeDto.Basic>> getFindAll() {
|
||||
return ApiResponseDto.createOK(commonCodeService.getFindAll());
|
||||
}
|
||||
|
||||
@Operation(summary = "단건 조회", description = "단건 조회")
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "조회 성공",
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = CommonCodeDto.Basic.class))),
|
||||
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
|
||||
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
|
||||
})
|
||||
@GetMapping("/{id}")
|
||||
public ApiResponseDto<CommonCodeDto.Basic> getOneById(
|
||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
description = "단건 조회",
|
||||
required = true)
|
||||
@PathVariable Long id) {
|
||||
return ApiResponseDto.ok(commonCodeService.getOneById(id));
|
||||
}
|
||||
|
||||
@Operation(summary = "저장", description = "공통코드를 저장 합니다.")
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(responseCode = "201", description = "공통코드 저장 성공", content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = Long.class))),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
|
||||
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
|
||||
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
|
||||
})
|
||||
@PostMapping
|
||||
public ApiResponseDto<Long> save(
|
||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
description = "공통코드 생성 요청 정보",
|
||||
required = true,
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = CommonCodeDto.AddReq.class)))
|
||||
@RequestBody
|
||||
@Valid CommonCodeDto.AddReq req) {
|
||||
return ApiResponseDto.createOK(commonCodeService.save(req));
|
||||
}
|
||||
|
||||
@Operation(summary = "수정", description = "공통코드를 수정 합니다.")
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(responseCode = "204", description = "공통코드 수정 성공", content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = Long.class))),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
|
||||
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
|
||||
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
|
||||
})
|
||||
@PutMapping("/{id}")
|
||||
public ApiResponseDto<Void> update(
|
||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
description = "공통코드 수정 요청 정보",
|
||||
required = true,
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = CommonCodeDto.ModifyReq.class)))
|
||||
@PathVariable Long id, @RequestBody @Valid CommonCodeDto.ModifyReq req) {
|
||||
commonCodeService.update(id, req);
|
||||
return ApiResponseDto.deleteOk(null);
|
||||
}
|
||||
|
||||
@Operation(summary = "삭제", description = "공통코드를 삭제 합니다.")
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(responseCode = "204", description = "공통코드 삭제 성공", content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = Long.class))),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
|
||||
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
|
||||
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
|
||||
})
|
||||
@DeleteMapping("/{id}")
|
||||
public ApiResponseDto<Long> remove(
|
||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
description = "공통코드 삭제 요청 정보",
|
||||
required = true)
|
||||
@PathVariable Long id) {
|
||||
commonCodeService.remove(id);
|
||||
return ApiResponseDto.deleteOk(id);
|
||||
}
|
||||
|
||||
@Operation(summary = "순서 변경", description = "공통코드 순서를 변경 합니다.")
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(responseCode = "204", description = "공통코드 순서 변경 성공", content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = Long.class))),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
|
||||
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
|
||||
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
|
||||
})
|
||||
@PutMapping("/order")
|
||||
public ApiResponseDto<Void> updateOrder(
|
||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
description = "공통코드 순서변경 요청 정보",
|
||||
required = true,
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = CommonCodeDto.OrderReq.class)))
|
||||
@RequestBody @Valid CommonCodeDto.OrderReq req) {
|
||||
commonCodeService.updateOrder(req);
|
||||
return ApiResponseDto.deleteOk(null);
|
||||
}
|
||||
|
||||
@Operation(summary = "code 기반 조회", description = "code 기반 조회")
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(responseCode = "200", description = "공통코드 순서 변경 성공", content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = Long.class))),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
|
||||
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
|
||||
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
|
||||
})
|
||||
@GetMapping("/used")
|
||||
public ApiResponseDto<List<CommonCodeDto.Basic>> getByCode(
|
||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
description = "공통코드 순서변경 요청 정보",
|
||||
required = true)
|
||||
@RequestParam String code) {
|
||||
return ApiResponseDto.ok(commonCodeService.findByCode(code));
|
||||
}
|
||||
}
|
||||
115
src/main/java/com/kamco/cd/kamcoback/code/dto/CommonCodeDto.java
Normal file
115
src/main/java/com/kamco/cd/kamcoback/code/dto/CommonCodeDto.java
Normal file
@@ -0,0 +1,115 @@
|
||||
package com.kamco.cd.kamcoback.code.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
|
||||
import com.kamco.cd.kamcoback.postgres.entity.CommonCodeEntity;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.PositiveOrZero;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
|
||||
public class CommonCodeDto {
|
||||
|
||||
@Schema(name = "CodeAddReq", description = "공통코드 저장 정보")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class AddReq {
|
||||
|
||||
@NotEmpty
|
||||
private String code;
|
||||
@NotEmpty
|
||||
private String name;
|
||||
private String description;
|
||||
private int order;
|
||||
private boolean used;
|
||||
private Long parentId;
|
||||
}
|
||||
|
||||
@Schema(name = "CodeModifyReq", description = "공통코드 수정 정보")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class ModifyReq {
|
||||
@NotEmpty
|
||||
private String name;
|
||||
private String description;
|
||||
private int order;
|
||||
private boolean used;
|
||||
}
|
||||
|
||||
@Schema(name = "CodeOrderReq", description = "공통코드 순서 변경 정보")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class OrderReq {
|
||||
@Valid
|
||||
List<OrderReqDetail> orders;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class OrderReqDetail {
|
||||
@NotNull
|
||||
private Long id;
|
||||
|
||||
@NotNull
|
||||
private Integer order;
|
||||
}
|
||||
|
||||
@Schema(name = "CommonCode Basic", description = "공통코드 기본 정보")
|
||||
@Getter
|
||||
public static class Basic {
|
||||
|
||||
private Long id;
|
||||
private String code;
|
||||
private String description;
|
||||
private String name;
|
||||
private Integer order;
|
||||
private Boolean used;
|
||||
private Boolean deleted;
|
||||
private List<CommonCodeDto.Basic> children;
|
||||
|
||||
@JsonFormatDttm
|
||||
private ZonedDateTime createdDttm;
|
||||
|
||||
@JsonFormatDttm
|
||||
private ZonedDateTime updatedDttm;
|
||||
|
||||
public Basic(
|
||||
Long id,
|
||||
String code,
|
||||
String description,
|
||||
String name,
|
||||
Integer order,
|
||||
Boolean used,
|
||||
Boolean deleted,
|
||||
List<CommonCodeDto.Basic> children,
|
||||
ZonedDateTime createdDttm,
|
||||
ZonedDateTime updatedDttm) {
|
||||
this.id = id;
|
||||
this.code = code;
|
||||
this.description = description;
|
||||
this.name = name;
|
||||
this.order = order;
|
||||
this.used = used;
|
||||
this.deleted = deleted;
|
||||
this.children = children;
|
||||
this.createdDttm = createdDttm;
|
||||
this.updatedDttm = updatedDttm;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.kamco.cd.kamcoback.code.service;
|
||||
|
||||
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto.AddReq;
|
||||
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto.Basic;
|
||||
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto.ModifyReq;
|
||||
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto.OrderReq;
|
||||
import com.kamco.cd.kamcoback.postgres.core.CommonCodeCoreService;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(readOnly = true)
|
||||
public class CommonCodeService {
|
||||
|
||||
private final CommonCodeCoreService commonCodeCoreService;
|
||||
|
||||
|
||||
/**
|
||||
* 공통코드 목록 조회
|
||||
* @return 모튼 코드 정보
|
||||
*/
|
||||
public List<Basic> getFindAll() {
|
||||
return commonCodeCoreService.findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 공통코드 단건 조회
|
||||
* @param id
|
||||
* @return 코드 아이디로 조회한 코드 정보
|
||||
*/
|
||||
public Basic getOneById(Long id) {
|
||||
return commonCodeCoreService.getOneById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 공통코드 생성 요청
|
||||
* @param req 생성요청 정보
|
||||
* @return 생성된 코드 id
|
||||
*/
|
||||
@Transactional
|
||||
public Long save(AddReq req) {
|
||||
return commonCodeCoreService.save(req).getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 공통코드 수정 요청
|
||||
* @param id 코드 아이디
|
||||
* @param req 수정요청 정보
|
||||
*/
|
||||
@Transactional
|
||||
public void update(Long id, ModifyReq req) {
|
||||
commonCodeCoreService.update(id, req);
|
||||
}
|
||||
|
||||
/**
|
||||
* 공통코드 삭제 처리
|
||||
* @param id 코드 아이디
|
||||
*/
|
||||
@Transactional
|
||||
public void remove(Long id) {
|
||||
commonCodeCoreService.remove(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 공통코드 순서 변경
|
||||
* @param req id, order 정보를 가진 List
|
||||
*/
|
||||
@Transactional
|
||||
public void updateOrder(OrderReq req) {
|
||||
commonCodeCoreService.updateOrder(req);
|
||||
}
|
||||
|
||||
/**
|
||||
* 코드기반 조회
|
||||
* @param code 코드
|
||||
* @return 코드로 조회한 공통코드 정보
|
||||
*/
|
||||
public List<Basic> findByCode(String code) {
|
||||
return commonCodeCoreService.findByCode(code);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.kamco.cd.kamcoback.common.utils.interfaces;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@JacksonAnnotationsInside
|
||||
@JsonFormat(
|
||||
shape = JsonFormat.Shape.STRING,
|
||||
pattern = "yyyy-MM-dd'T'HH:mm:ssXXX",
|
||||
timezone = "Asia/Seoul"
|
||||
)
|
||||
public @interface JsonFormatDttm {
|
||||
|
||||
}
|
||||
@@ -1,24 +1,177 @@
|
||||
package com.kamco.cd.kamcoback.config;
|
||||
|
||||
import com.kamco.cd.kamcoback.config.api.ApiLogFunction;
|
||||
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
|
||||
import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ApiResponseCode;
|
||||
import com.kamco.cd.kamcoback.log.dto.ErrorLogDto;
|
||||
import com.kamco.cd.kamcoback.postgres.entity.ErrorLogEntity;
|
||||
import com.kamco.cd.kamcoback.postgres.repository.log.ErrorLogRepository;
|
||||
import jakarta.persistence.EntityNotFoundException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.client.HttpServerErrorException;
|
||||
|
||||
import java.nio.file.AccessDeniedException;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Order(value = 1)
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
// 로그인 정보가 잘못됐습니다 권한 없음
|
||||
@org.springframework.web.bind.annotation.ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
private final ErrorLogRepository errorLogRepository;
|
||||
|
||||
public GlobalExceptionHandler(ErrorLogRepository errorLogRepository) {
|
||||
this.errorLogRepository = errorLogRepository;
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
@ExceptionHandler(EntityNotFoundException.class)
|
||||
public ApiResponseDto<String> handlerEntityNotFoundException(EntityNotFoundException e) {
|
||||
public ApiResponseDto<String> handlerEntityNotFoundException(EntityNotFoundException e, HttpServletRequest request) {
|
||||
log.warn("[EntityNotFoundException] resource :{} ", e.getMessage());
|
||||
String message = String.format("%s [%s]", e.getMessage(), e.getCause());
|
||||
return ApiResponseDto.createException(ApiResponseDto.ApiResponseCode.NOT_FOUND, message);
|
||||
String codeName = "NOT_FOUND";
|
||||
ErrorLogEntity errorLog = saveErrerLogData(request, ApiResponseCode.getCode(codeName),
|
||||
HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.ERROR, e.getStackTrace());
|
||||
|
||||
return ApiResponseDto.createException(ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf(codeName), errorLog.getId());
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
@ExceptionHandler(HttpMessageNotReadableException.class)
|
||||
public ApiResponseDto<String> handleUnreadable(HttpMessageNotReadableException e, HttpServletRequest request) {
|
||||
log.warn("[HttpMessageNotReadableException] resource :{} ", e.getMessage());
|
||||
String codeName = "BAD_REQUEST";
|
||||
ErrorLogEntity errorLog = saveErrerLogData(request, ApiResponseCode.getCode(codeName),
|
||||
HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.WARNING, e.getStackTrace());
|
||||
|
||||
return ApiResponseDto.createException(ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf(codeName), errorLog.getId());
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
@ExceptionHandler(NoSuchElementException.class)
|
||||
public ApiResponseDto<String> handlerNoSuchElementException(NoSuchElementException e, HttpServletRequest request) {
|
||||
log.warn("[NoSuchElementException] resource :{} ", e.getMessage());
|
||||
String codeName = "NOT_FOUND_DATA";
|
||||
ErrorLogEntity errorLog = saveErrerLogData(request, ApiResponseCode.getCode(codeName),
|
||||
HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.WARNING, e.getStackTrace());
|
||||
|
||||
return ApiResponseDto.createException(ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf("NOT_FOUND"), errorLog.getId());
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
@ExceptionHandler(IllegalArgumentException.class)
|
||||
public ApiResponseDto<String> handlerIllegalArgumentException(IllegalArgumentException e, HttpServletRequest request) {
|
||||
log.warn("[handlerIllegalArgumentException] resource :{} ", e.getMessage());
|
||||
String codeName = "BAD_REQUEST";
|
||||
ErrorLogEntity errorLog = saveErrerLogData(request, ApiResponseCode.getCode(codeName),
|
||||
HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.WARNING, e.getStackTrace());
|
||||
|
||||
return ApiResponseDto.createException(ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf(codeName), errorLog.getId());
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
|
||||
@ExceptionHandler(DataIntegrityViolationException.class)
|
||||
public ApiResponseDto<String> handlerDataIntegrityViolationException(DataIntegrityViolationException e, HttpServletRequest request) {
|
||||
log.warn("[DataIntegrityViolationException] resource :{} ", e.getMessage());
|
||||
String codeName = "DATA_INTEGRITY_ERROR";
|
||||
ErrorLogEntity errorLog = saveErrerLogData(request, ApiResponseCode.getCode(codeName),
|
||||
HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.CRITICAL, e.getStackTrace());
|
||||
|
||||
return ApiResponseDto.createException(ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf("UNPROCESSABLE_ENTITY"), errorLog.getId());
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public ApiResponseDto<String> handlerMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
|
||||
log.warn("[MethodArgumentNotValidException] resource :{} ", e.getMessage());
|
||||
String codeName = "BAD_REQUEST";
|
||||
ErrorLogEntity errorLog = saveErrerLogData(request, ApiResponseCode.getCode(codeName),
|
||||
HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.WARNING, e.getStackTrace());
|
||||
|
||||
return ApiResponseDto.createException(ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf(codeName), errorLog.getId());
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.UNAUTHORIZED)
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
public ApiResponseDto<String> handlerAccessDeniedException(AccessDeniedException e, HttpServletRequest request) {
|
||||
log.warn("[AccessDeniedException] resource :{} ", e.getMessage());
|
||||
String codeName = "UNAUTHORIZED";
|
||||
ErrorLogEntity errorLog = saveErrerLogData(request, ApiResponseCode.getCode(codeName),
|
||||
HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.ERROR, e.getStackTrace());
|
||||
|
||||
return ApiResponseDto.createException(ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf(codeName), errorLog.getId());
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.BAD_GATEWAY)
|
||||
@ExceptionHandler(HttpServerErrorException.BadGateway.class)
|
||||
public ApiResponseDto<String> handlerHttpServerErrorException(HttpServerErrorException e, HttpServletRequest request) {
|
||||
log.warn("[HttpServerErrorException] resource :{} ", e.getMessage());
|
||||
String codeName = "BAD_GATEWAY";
|
||||
ErrorLogEntity errorLog = saveErrerLogData(request, ApiResponseCode.getCode(codeName),
|
||||
HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.CRITICAL, e.getStackTrace());
|
||||
|
||||
return ApiResponseDto.createException(ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf(codeName), errorLog.getId());
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
@ExceptionHandler(RuntimeException.class)
|
||||
public ApiResponseDto<String> handlerRuntimeException(RuntimeException e, HttpServletRequest request) {
|
||||
log.warn("[RuntimeException] resource :{} ", e.getMessage());
|
||||
|
||||
String codeName = "INTERNAL_SERVER_ERROR";
|
||||
ErrorLogEntity errorLog = saveErrerLogData(request, ApiResponseCode.getCode(codeName),
|
||||
HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.CRITICAL, e.getStackTrace());
|
||||
|
||||
return ApiResponseDto.createException(ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf(codeName), errorLog.getId());
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ApiResponseDto<String> handlerException(Exception e, HttpServletRequest request) {
|
||||
log.warn("[Exception] resource :{} ", e.getMessage());
|
||||
|
||||
String codeName = "INTERNAL_SERVER_ERROR";
|
||||
ErrorLogEntity errorLog = saveErrerLogData(request, ApiResponseCode.getCode(codeName),
|
||||
HttpStatus.valueOf(codeName), ErrorLogDto.LogErrorLevel.CRITICAL, e.getStackTrace());
|
||||
|
||||
return ApiResponseDto.createException(ApiResponseCode.getCode(codeName), ApiResponseCode.getMessage(codeName), HttpStatus.valueOf(codeName), errorLog.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 에러 로그 테이블 저장 로직
|
||||
* @param request : request
|
||||
* @param errorCode : 정의된 enum errorCode
|
||||
* @param httpStatus : HttpStatus 값
|
||||
* @param logErrorLevel : WARNING, ERROR, CRITICAL
|
||||
* @param stackTrace : 에러 내용
|
||||
* @return : insert하고 결과로 받은 Entity
|
||||
*/
|
||||
private ErrorLogEntity saveErrerLogData(HttpServletRequest request, ApiResponseCode errorCode,
|
||||
HttpStatus httpStatus, ErrorLogDto.LogErrorLevel logErrorLevel, StackTraceElement[] stackTrace) {
|
||||
//TODO : 로그인 개발되면 이것도 연결해야 함
|
||||
Long userid = Long.valueOf(Optional.ofNullable(ApiLogFunction.getUserId(request)).orElse("1"));
|
||||
|
||||
//TODO : stackTrace limit 10줄? 확인 필요
|
||||
String stackTraceStr = Arrays.stream(stackTrace)
|
||||
.limit(10)
|
||||
.map(StackTraceElement::toString)
|
||||
.collect(Collectors.joining("\n"));
|
||||
|
||||
ErrorLogEntity errorLogEntity = new ErrorLogEntity(request.getRequestURI(), ApiLogFunction.getEventType(request), logErrorLevel,
|
||||
String.valueOf(httpStatus.value()), errorCode.getText(), stackTraceStr, userid, ZonedDateTime.now());
|
||||
|
||||
return errorLogRepository.save(errorLogEntity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.kamco.cd.kamcoback.config.api;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
import org.springframework.web.util.ContentCachingRequestWrapper;
|
||||
import org.springframework.web.util.ContentCachingResponseWrapper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
public class ApiLogFilter extends OncePerRequestFilter {
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
ContentCachingRequestWrapper wrappedRequest =
|
||||
new ContentCachingRequestWrapper(request);
|
||||
|
||||
ContentCachingResponseWrapper wrappedResponse =
|
||||
new ContentCachingResponseWrapper(response);
|
||||
|
||||
filterChain.doFilter(wrappedRequest, wrappedResponse);
|
||||
|
||||
// 반드시 response body copy
|
||||
wrappedResponse.copyBodyToResponse();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package com.kamco.cd.kamcoback.config.api;
|
||||
|
||||
import com.kamco.cd.kamcoback.log.dto.EventStatus;
|
||||
import com.kamco.cd.kamcoback.log.dto.EventType;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.web.util.ContentCachingRequestWrapper;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ApiLogFunction {
|
||||
// 클라이언트 IP 추출
|
||||
public static String getClientIp(HttpServletRequest request) {
|
||||
String[] headers = {
|
||||
"X-Forwarded-For",
|
||||
"Proxy-Client-IP",
|
||||
"WL-Proxy-Client-IP",
|
||||
"HTTP_CLIENT_IP",
|
||||
"HTTP_X_FORWARDED_FOR"
|
||||
};
|
||||
for (String header : headers) {
|
||||
String ip = request.getHeader(header);
|
||||
if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
|
||||
return ip.split(",")[0];
|
||||
}
|
||||
}
|
||||
String ip = request.getRemoteAddr();
|
||||
if ("0:0:0:0:0:0:0:1".equals(ip)) { //local 일 때
|
||||
ip = "127.0.0.1";
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
// 사용자 ID 추출 예시 (Spring Security 기준)
|
||||
public static String getUserId(HttpServletRequest request) {
|
||||
try {
|
||||
return request.getUserPrincipal() != null ? request.getUserPrincipal().getName() : null;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static EventType getEventType(HttpServletRequest request) {
|
||||
String method = request.getMethod().toUpperCase();
|
||||
String uri = request.getRequestURI().toLowerCase();
|
||||
|
||||
//URL 기반 DOWNLOAD/PRINT 분류
|
||||
if(uri.contains("/download") || uri.contains("/export")) return EventType.DOWNLOAD;
|
||||
if(uri.contains("/print")) return EventType.PRINT;
|
||||
|
||||
// 일반 CRUD
|
||||
return switch (method) {
|
||||
case "POST" -> EventType.CREATE;
|
||||
case "GET" -> EventType.READ;
|
||||
case "DELETE" -> EventType.DELETE;
|
||||
case "PUT", "PATCH" -> EventType.UPDATE;
|
||||
default -> EventType.OTHER;
|
||||
};
|
||||
}
|
||||
|
||||
public static String getRequestBody(HttpServletRequest servletRequest, ContentCachingRequestWrapper contentWrapper) {
|
||||
StringBuilder resultBody = new StringBuilder();
|
||||
// GET, form-urlencoded POST 파라미터
|
||||
Map<String, String[]> paramMap = servletRequest.getParameterMap();
|
||||
|
||||
String queryParams = paramMap.entrySet().stream()
|
||||
.map(e -> e.getKey() + "=" + String.join(",", e.getValue()))
|
||||
.collect(Collectors.joining("&"));
|
||||
|
||||
resultBody.append(queryParams.isEmpty() ? "" : queryParams);
|
||||
|
||||
// JSON Body
|
||||
if ("POST".equalsIgnoreCase(servletRequest.getMethod())
|
||||
&& servletRequest.getContentType() != null
|
||||
&& servletRequest.getContentType().contains("application/json")) {
|
||||
try {
|
||||
//json인 경우는 Wrapper를 통해 가져오기
|
||||
resultBody.append(getBodyData(contentWrapper));
|
||||
|
||||
} catch (Exception e) {
|
||||
resultBody.append("cannot read JSON body ").append(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// Multipart form-data
|
||||
if ("POST".equalsIgnoreCase(servletRequest.getMethod())
|
||||
&& servletRequest.getContentType() != null
|
||||
&& servletRequest.getContentType().startsWith("multipart/form-data")) {
|
||||
resultBody.append("multipart/form-data request");
|
||||
}
|
||||
|
||||
return resultBody.toString();
|
||||
}
|
||||
|
||||
// JSON Body 읽기
|
||||
public static String getBodyData(ContentCachingRequestWrapper request) {
|
||||
byte[] buf = request.getContentAsByteArray();
|
||||
if (buf.length == 0) return null;
|
||||
try {
|
||||
return new String(buf, request.getCharacterEncoding());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return new String(buf);
|
||||
}
|
||||
}
|
||||
|
||||
//ApiResponse 의 Status가 2xx 범위이면 SUCCESS, 아니면 FAILED
|
||||
public static EventStatus isSuccessFail(ApiResponseDto<?> apiResponse){
|
||||
return apiResponse.getHttpStatus().is2xxSuccessful() ? EventStatus.SUCCESS : EventStatus.FAILED;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,19 @@
|
||||
package com.kamco.cd.kamcoback.config.api;
|
||||
|
||||
import com.kamco.cd.kamcoback.postgres.entity.AuditLogEntity;
|
||||
import com.kamco.cd.kamcoback.postgres.repository.log.AuditLogRepository;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
||||
import org.springframework.web.util.ContentCachingRequestWrapper;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* ApiResponseDto의 내장된 HTTP 상태 코드를 실제 HTTP 응답에 적용하는 Advice
|
||||
@@ -16,6 +23,12 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
||||
@RestControllerAdvice
|
||||
public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
|
||||
|
||||
private final AuditLogRepository auditLogRepository;
|
||||
|
||||
public ApiResponseAdvice(AuditLogRepository auditLogRepository) {
|
||||
this.auditLogRepository = auditLogRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(
|
||||
MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
|
||||
@@ -32,9 +45,25 @@ public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
|
||||
ServerHttpRequest request,
|
||||
ServerHttpResponse response) {
|
||||
|
||||
HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();
|
||||
ContentCachingRequestWrapper contentWrapper = (ContentCachingRequestWrapper) servletRequest;
|
||||
|
||||
if (body instanceof ApiResponseDto<?> apiResponse) {
|
||||
// ApiResponseDto에 설정된 httpStatus를 실제 HTTP 응답에 적용
|
||||
response.setStatusCode(apiResponse.getHttpStatus());
|
||||
|
||||
String ip = ApiLogFunction.getClientIp(servletRequest);
|
||||
//TODO : userid 가 계정명인지, uid 인지 확인 후 로직 수정 필요함
|
||||
Long userid = Long.valueOf(Optional.ofNullable(ApiLogFunction.getUserId(servletRequest)).orElse("1"));
|
||||
|
||||
//TODO: menuUid 를 동적으로 가져오게끔 해야함
|
||||
AuditLogEntity log = new AuditLogEntity(userid, ApiLogFunction.getEventType(servletRequest),
|
||||
ApiLogFunction.isSuccessFail(apiResponse), "MU_01_01", ip, servletRequest.getRequestURI(), ApiLogFunction.getRequestBody(servletRequest, contentWrapper),
|
||||
apiResponse.getErrorLogUid()
|
||||
);
|
||||
|
||||
//tb_audit_log 테이블 저장
|
||||
auditLogRepository.save(log);
|
||||
}
|
||||
|
||||
return body;
|
||||
|
||||
@@ -20,7 +20,9 @@ public class ApiResponseDto<T> {
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private T errorData;
|
||||
|
||||
@JsonIgnore private HttpStatus httpStatus = HttpStatus.OK;
|
||||
@JsonIgnore private HttpStatus httpStatus;
|
||||
|
||||
@JsonIgnore private Long errorLogUid;
|
||||
|
||||
public ApiResponseDto(T data) {
|
||||
this.data = data;
|
||||
@@ -38,6 +40,15 @@ public class ApiResponseDto<T> {
|
||||
public ApiResponseDto(ApiResponseCode code, String message) {
|
||||
this.error = new Error(code.getId(), message);
|
||||
}
|
||||
public ApiResponseDto(ApiResponseCode code, String message, HttpStatus httpStatus) {
|
||||
this.error = new Error(code.getId(), message);
|
||||
this.httpStatus = httpStatus;
|
||||
}
|
||||
public ApiResponseDto(ApiResponseCode code, String message, HttpStatus httpStatus, Long errorLogUid) {
|
||||
this.error = new Error(code.getId(), message);
|
||||
this.httpStatus = httpStatus;
|
||||
this.errorLogUid = errorLogUid;
|
||||
}
|
||||
|
||||
public ApiResponseDto(ApiResponseCode code, String message, T errorData) {
|
||||
this.error = new Error(code.getId(), message);
|
||||
@@ -64,6 +75,12 @@ public class ApiResponseDto<T> {
|
||||
public static ApiResponseDto<String> createException(ApiResponseCode code, String message) {
|
||||
return new ApiResponseDto<>(code, message);
|
||||
}
|
||||
public static ApiResponseDto<String> createException(ApiResponseCode code, String message, HttpStatus httpStatus) {
|
||||
return new ApiResponseDto<>(code, message, httpStatus);
|
||||
}
|
||||
public static ApiResponseDto<String> createException(ApiResponseCode code, String message, HttpStatus httpStatus, Long errorLogUid) {
|
||||
return new ApiResponseDto<>(code, message, httpStatus, errorLogUid);
|
||||
}
|
||||
|
||||
public static <T> ApiResponseDto<T> createException(
|
||||
ApiResponseCode code, String message, T data) {
|
||||
@@ -89,6 +106,7 @@ public class ApiResponseDto<T> {
|
||||
// @formatter:off
|
||||
OK("요청이 성공하였습니다."),
|
||||
BAD_REQUEST("요청 파라미터가 잘못되었습니다."),
|
||||
BAD_GATEWAY("네트워크 상태가 불안정합니다."),
|
||||
ALREADY_EXIST_MALL("이미 등록된 쇼핑센터입니다."),
|
||||
NOT_FOUND_MAP("지도를 찾을 수 없습니다."),
|
||||
UNAUTHORIZED("권한이 없습니다."),
|
||||
@@ -111,8 +129,8 @@ public class ApiResponseDto<T> {
|
||||
REQUIRED_EMAIL("이메일은 필수 항목입니다."),
|
||||
WRONG_PASSWORD("잘못된 패스워드입니다.."),
|
||||
DUPLICATE_EMAIL("이미 가입된 이메일입니다."),
|
||||
DUPLICATE_DATA("이미 등록되여 있습니다."),
|
||||
DATA_INTEGRITY_ERROR("요청을 처리할수 없습니다."),
|
||||
DUPLICATE_DATA("이미 등록되어 있습니다."),
|
||||
DATA_INTEGRITY_ERROR("데이터 무결성이 위반되어 요청을 처리할수 없습니다."),
|
||||
FOREIGN_KEY_ERROR("참조 중인 데이터가 있어 삭제할 수 없습니다."),
|
||||
DUPLICATE_EMPLOYEEID("이미 가입된 사번입니다."),
|
||||
NOT_FOUND_USER_FOR_EMAIL("이메일로 유저를 찾을 수 없습니다."),
|
||||
@@ -134,5 +152,13 @@ public class ApiResponseDto<T> {
|
||||
public String getText() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public static ApiResponseCode getCode(String name) {
|
||||
return ApiResponseCode.valueOf(name.toUpperCase());
|
||||
}
|
||||
|
||||
public static String getMessage(String name) {
|
||||
return ApiResponseCode.valueOf(name.toUpperCase()).getText();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
package com.kamco.cd.kamcoback.log;
|
||||
|
||||
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
|
||||
import com.kamco.cd.kamcoback.log.dto.AuditLogDto;
|
||||
import com.kamco.cd.kamcoback.postgres.core.AuditLogCoreService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Tag(name = "감사 로그", description = "감사 로그 관리 API")
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping({"/api/log/audit", "/v1/api/log/audit"})
|
||||
public class AuditLogApiController {
|
||||
|
||||
private final AuditLogCoreService auditLogCoreService;
|
||||
|
||||
@Operation(summary = "일자별 로그 조회")
|
||||
@GetMapping("/daily")
|
||||
public ApiResponseDto<Page<AuditLogDto.AuditList>> getDailyLogs(
|
||||
@RequestParam(required = false) LocalDate startDate,
|
||||
@RequestParam(required = false) LocalDate endDate,
|
||||
@RequestParam int page,
|
||||
@RequestParam(defaultValue = "20") int size
|
||||
) {
|
||||
AuditLogDto.DailySearchReq searchReq = new AuditLogDto.DailySearchReq(startDate, endDate, null, page, size, "created_dttm,desc");
|
||||
|
||||
Page<AuditLogDto.AuditList> result = auditLogCoreService.getLogByDaily(
|
||||
searchReq,
|
||||
startDate,
|
||||
endDate
|
||||
);
|
||||
|
||||
return ApiResponseDto.ok(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "일자별 로그 상세")
|
||||
@GetMapping("/daily/result")
|
||||
public ApiResponseDto<Page<AuditLogDto.AuditDetail>> getDailyResultLogs(
|
||||
@RequestParam LocalDate logDate,
|
||||
@RequestParam int page,
|
||||
@RequestParam(defaultValue = "20") int size
|
||||
) {
|
||||
AuditLogDto.DailySearchReq searchReq = new AuditLogDto.DailySearchReq(null, null, logDate, page, size, "created_dttm,desc");
|
||||
Page<AuditLogDto.AuditDetail> result = auditLogCoreService.getLogByDailyResult(
|
||||
searchReq,
|
||||
logDate
|
||||
);
|
||||
|
||||
return ApiResponseDto.ok(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "메뉴별 로그 조회")
|
||||
|
||||
@GetMapping("/menu")
|
||||
public ApiResponseDto<Page<AuditLogDto.AuditList>> getMenuLogs(
|
||||
@RequestParam(required = false) String searchValue,
|
||||
@RequestParam int page,
|
||||
@RequestParam(defaultValue = "20") int size
|
||||
) {
|
||||
AuditLogDto.MenuUserSearchReq searchReq = new AuditLogDto.MenuUserSearchReq(searchValue, null, null, page, size, "created_dttm,desc");
|
||||
Page<AuditLogDto.AuditList> result = auditLogCoreService.getLogByMenu(
|
||||
searchReq, searchValue
|
||||
);
|
||||
|
||||
return ApiResponseDto.ok(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "메뉴별 로그 상세")
|
||||
|
||||
@GetMapping("/menu/result")
|
||||
public ApiResponseDto<Page<AuditLogDto.AuditDetail>> getMenuResultLogs(
|
||||
@RequestParam String menuId,
|
||||
@RequestParam int page,
|
||||
@RequestParam(defaultValue = "20") int size
|
||||
) {
|
||||
AuditLogDto.MenuUserSearchReq searchReq = new AuditLogDto.MenuUserSearchReq(null, menuId, null, page, size, "created_dttm,desc");
|
||||
Page<AuditLogDto.AuditDetail> result = auditLogCoreService.getLogByMenuResult(
|
||||
searchReq,
|
||||
menuId
|
||||
);
|
||||
|
||||
return ApiResponseDto.ok(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "사용자별 로그 조회")
|
||||
|
||||
@GetMapping("/account")
|
||||
public ApiResponseDto<Page<AuditLogDto.AuditList>> getAccountLogs(
|
||||
@RequestParam(required = false) String searchValue,
|
||||
@RequestParam int page,
|
||||
@RequestParam(defaultValue = "20") int size
|
||||
) {
|
||||
AuditLogDto.MenuUserSearchReq searchReq = new AuditLogDto.MenuUserSearchReq(searchValue, null, null, page, size, "created_dttm,desc");
|
||||
Page<AuditLogDto.AuditList> result = auditLogCoreService.getLogByAccount(
|
||||
searchReq, searchValue
|
||||
);
|
||||
|
||||
return ApiResponseDto.ok(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "사용자별 로그 상세")
|
||||
|
||||
@GetMapping("/account/result")
|
||||
public ApiResponseDto<Page<AuditLogDto.AuditDetail>> getAccountResultLogs(
|
||||
@RequestParam Long userUid,
|
||||
@RequestParam int page,
|
||||
@RequestParam(defaultValue = "20") int size
|
||||
) {
|
||||
AuditLogDto.MenuUserSearchReq searchReq = new AuditLogDto.MenuUserSearchReq(null, null, userUid, page, size, "created_dttm,desc");
|
||||
Page<AuditLogDto.AuditDetail> result = auditLogCoreService.getLogByAccountResult(
|
||||
searchReq,
|
||||
userUid
|
||||
);
|
||||
|
||||
return ApiResponseDto.ok(result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.kamco.cd.kamcoback.log;
|
||||
|
||||
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
|
||||
import com.kamco.cd.kamcoback.log.dto.AuditLogDto;
|
||||
import com.kamco.cd.kamcoback.log.dto.ErrorLogDto;
|
||||
import com.kamco.cd.kamcoback.log.dto.EventType;
|
||||
import com.kamco.cd.kamcoback.postgres.core.AuditLogCoreService;
|
||||
import com.kamco.cd.kamcoback.postgres.core.ErrorLogCoreService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Tag(name = "에러 로그", description = "에러 로그 관리 API")
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping({"/api/log/error", "/v1/api/log/error"})
|
||||
public class ErrorLogApiController {
|
||||
|
||||
private final ErrorLogCoreService errorLogCoreService;
|
||||
|
||||
@Operation(summary = "에러로그 조회")
|
||||
|
||||
@GetMapping("/error")
|
||||
public ApiResponseDto<Page<ErrorLogDto.Basic>> getErrorLogs(
|
||||
@RequestParam(required = false) ErrorLogDto.LogErrorLevel logErrorLevel,
|
||||
@RequestParam(required = false) EventType eventType,
|
||||
@RequestParam(required = false) LocalDate startDate,
|
||||
@RequestParam(required = false) LocalDate endDate,
|
||||
@RequestParam int page,
|
||||
@RequestParam(defaultValue = "20") int size
|
||||
) {
|
||||
ErrorLogDto.ErrorSearchReq searchReq = new ErrorLogDto.ErrorSearchReq(logErrorLevel, eventType, startDate, endDate, page, size, "created_dttm,desc");
|
||||
Page<ErrorLogDto.Basic> result = errorLogCoreService.findLogByError(searchReq);
|
||||
|
||||
return ApiResponseDto.ok(result);
|
||||
}
|
||||
}
|
||||
181
src/main/java/com/kamco/cd/kamcoback/log/dto/AuditLogDto.java
Normal file
181
src/main/java/com/kamco/cd/kamcoback/log/dto/AuditLogDto.java
Normal file
@@ -0,0 +1,181 @@
|
||||
package com.kamco.cd.kamcoback.log.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
public class AuditLogDto {
|
||||
|
||||
@Schema(name = "AuditLogBasic", description = "감사로그 기본 정보")
|
||||
@Getter
|
||||
public static class Basic {
|
||||
|
||||
@JsonIgnore
|
||||
private final Long id;
|
||||
private final Long userUid;
|
||||
private final EventType eventType;
|
||||
private final EventStatus eventStatus;
|
||||
private final String menuUid;
|
||||
private final String ipAddress;
|
||||
private final String requestUri;
|
||||
private final String requestBody;
|
||||
private final Long errorLogUid;
|
||||
|
||||
@JsonFormatDttm
|
||||
private final ZonedDateTime createdDttm;
|
||||
|
||||
public Basic(
|
||||
Long id,
|
||||
Long userUid,
|
||||
EventType eventType,
|
||||
EventStatus eventStatus,
|
||||
String menuUid,
|
||||
String ipAddress,
|
||||
String requestUri,
|
||||
String requestBody,
|
||||
Long errorLogUid,
|
||||
ZonedDateTime createdDttm) {
|
||||
this.id = id;
|
||||
this.userUid = userUid;
|
||||
this.eventType = eventType;
|
||||
this.eventStatus = eventStatus;
|
||||
this.menuUid = menuUid;
|
||||
this.ipAddress = ipAddress;
|
||||
this.requestUri = requestUri;
|
||||
this.requestBody = requestBody;
|
||||
this.errorLogUid = errorLogUid;
|
||||
this.createdDttm = createdDttm;
|
||||
}
|
||||
}
|
||||
|
||||
@Schema(name = "AuditList", description = "감사 로그 목록")
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public static class AuditList {
|
||||
private int readCount;
|
||||
private int cudCount;
|
||||
private int printCount;
|
||||
private int downloadCount;
|
||||
private Long totalCount;
|
||||
|
||||
private Long accountId;
|
||||
private String loginId;
|
||||
private String username;
|
||||
private LocalDateTime baseDate;
|
||||
private Long menuId;
|
||||
private String menuName;
|
||||
|
||||
public AuditList(LocalDateTime baseDate, int readCount, int cudCount, int printCount, int downloadCount, Long totalCount){
|
||||
this.baseDate = baseDate;
|
||||
this.readCount = readCount;
|
||||
this.cudCount = cudCount;
|
||||
this.printCount = printCount;
|
||||
this.downloadCount = downloadCount;
|
||||
this.totalCount = totalCount;
|
||||
}
|
||||
}
|
||||
|
||||
@Schema(name = "AuditDetail", description = "감사 로그 상세")
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public static class AuditDetail {
|
||||
private Long logId;
|
||||
private LocalDateTime logDateTime;
|
||||
private EventType eventType;
|
||||
private LogDetail detail;
|
||||
|
||||
private String userName;
|
||||
private String loginId;
|
||||
private String menuName;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
public static class LogDetail{
|
||||
String serviceName;
|
||||
String parentMenuName;
|
||||
String menuName;
|
||||
String menuUrl;
|
||||
String menuDescription;
|
||||
int sortOrder;
|
||||
boolean used;
|
||||
}
|
||||
|
||||
@Schema(name = "LogDailySearchReq", description = "일자별 로그 검색 요청")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class DailySearchReq {
|
||||
|
||||
private LocalDate startDate;
|
||||
private LocalDate endDate;
|
||||
|
||||
// 일자별 로그 검색 조건
|
||||
private LocalDate logDate;
|
||||
|
||||
// 페이징 파라미터
|
||||
private int page = 0;
|
||||
private int size = 20;
|
||||
private String sort;
|
||||
|
||||
public Pageable toPageable() {
|
||||
if (sort != null && !sort.isEmpty()) {
|
||||
String[] sortParams = sort.split(",");
|
||||
String property = sortParams[0];
|
||||
Sort.Direction direction =
|
||||
sortParams.length > 1 ? Sort.Direction.fromString(sortParams[1]) : Sort.Direction.ASC;
|
||||
return PageRequest.of(page, size, Sort.by(direction, property));
|
||||
}
|
||||
return PageRequest.of(page, size);
|
||||
}
|
||||
}
|
||||
|
||||
@Schema(name = "MenuUserSearchReq", description = "메뉴별,사용자별 로그 검색 요청")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public static class MenuUserSearchReq {
|
||||
|
||||
// 메뉴별, 사용자별 로그 검색 조건
|
||||
private String searchValue;
|
||||
private String menuUid;
|
||||
private Long userUid; //menuId, userUid 조회
|
||||
|
||||
// 페이징 파라미터
|
||||
private int page = 0;
|
||||
private int size = 20;
|
||||
private String sort;
|
||||
|
||||
public MenuUserSearchReq(String searchValue, String menuUid, Long userUid, int page, int size, String sort) {
|
||||
this.searchValue = searchValue;
|
||||
this.menuUid = menuUid;
|
||||
this.page = page;
|
||||
this.size = size;
|
||||
this.sort = sort;
|
||||
}
|
||||
|
||||
public Pageable toPageable() {
|
||||
if (sort != null && !sort.isEmpty()) {
|
||||
String[] sortParams = sort.split(",");
|
||||
String property = sortParams[0];
|
||||
Sort.Direction direction =
|
||||
sortParams.length > 1 ? Sort.Direction.fromString(sortParams[1]) : Sort.Direction.ASC;
|
||||
return PageRequest.of(page, size, Sort.by(direction, property));
|
||||
}
|
||||
return PageRequest.of(page, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
121
src/main/java/com/kamco/cd/kamcoback/log/dto/ErrorLogDto.java
Normal file
121
src/main/java/com/kamco/cd/kamcoback/log/dto/ErrorLogDto.java
Normal file
@@ -0,0 +1,121 @@
|
||||
package com.kamco.cd.kamcoback.log.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
|
||||
import com.kamco.cd.kamcoback.config.enums.EnumType;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
public class ErrorLogDto {
|
||||
|
||||
@Schema(name = "ErrorLogBasic", description = "에러로그 기본 정보")
|
||||
@Getter
|
||||
public static class Basic {
|
||||
|
||||
@JsonIgnore
|
||||
private final Long id;
|
||||
private final String requestId;
|
||||
private final EventType errorType;
|
||||
private final LogErrorLevel errorLevel;
|
||||
private final String errorCode;
|
||||
private final String errorMessage;
|
||||
private final String stackTrace;
|
||||
private final Long handlerUid;
|
||||
|
||||
@JsonFormatDttm
|
||||
private final ZonedDateTime handledDttm;
|
||||
|
||||
@JsonFormatDttm
|
||||
private final ZonedDateTime createdDttm;
|
||||
|
||||
public Basic(
|
||||
Long id,
|
||||
String requestId,
|
||||
EventType errorType,
|
||||
LogErrorLevel errorLevel,
|
||||
String errorCode,
|
||||
String errorMessage,
|
||||
String stackTrace,
|
||||
Long handlerUid,
|
||||
ZonedDateTime handledDttm,
|
||||
ZonedDateTime createdDttm) {
|
||||
this.id = id;
|
||||
this.requestId = requestId;
|
||||
this.errorType = errorType;
|
||||
this.errorLevel = errorLevel;
|
||||
this.errorCode = errorCode;
|
||||
this.errorMessage = errorMessage;
|
||||
this.stackTrace = stackTrace;
|
||||
this.handlerUid = handlerUid;
|
||||
this.handledDttm = handledDttm;
|
||||
this.createdDttm = createdDttm;
|
||||
}
|
||||
}
|
||||
|
||||
@Schema(name = "ErrorSearchReq", description = "에러로그 검색 요청")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class ErrorSearchReq {
|
||||
|
||||
LogErrorLevel errorLevel;
|
||||
EventType eventType;
|
||||
LocalDate startDate;
|
||||
LocalDate endDate;
|
||||
|
||||
// 페이징 파라미터
|
||||
private int page = 0;
|
||||
private int size = 20;
|
||||
private String sort;
|
||||
|
||||
public ErrorSearchReq(LogErrorLevel errorLevel, EventType eventType, LocalDate startDate, LocalDate endDate, int page, int size) {
|
||||
this.errorLevel = errorLevel;
|
||||
this.eventType = eventType;
|
||||
this.startDate = startDate;
|
||||
this.endDate = endDate;
|
||||
this.page = page;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public Pageable toPageable() {
|
||||
if (sort != null && !sort.isEmpty()) {
|
||||
String[] sortParams = sort.split(",");
|
||||
String property = sortParams[0];
|
||||
Sort.Direction direction =
|
||||
sortParams.length > 1 ? Sort.Direction.fromString(sortParams[1]) : Sort.Direction.ASC;
|
||||
return PageRequest.of(page, size, Sort.by(direction, property));
|
||||
}
|
||||
return PageRequest.of(page, size);
|
||||
}
|
||||
}
|
||||
|
||||
public enum LogErrorLevel implements EnumType {
|
||||
WARNING("Warning"),
|
||||
ERROR("Error"),
|
||||
CRITICAL("Critical");
|
||||
|
||||
private final String desc;
|
||||
|
||||
LogErrorLevel(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() { return name(); }
|
||||
|
||||
@Override
|
||||
public String getText() { return desc; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.kamco.cd.kamcoback.log.dto;
|
||||
|
||||
import com.kamco.cd.kamcoback.config.enums.EnumType;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum EventStatus implements EnumType {
|
||||
SUCCESS("이벤트 결과 성공"),
|
||||
FAILED("이벤트 결과 실패");
|
||||
|
||||
private final String desc;
|
||||
|
||||
@Override
|
||||
public String getId() { return name(); }
|
||||
|
||||
@Override
|
||||
public String getText() { return desc; }
|
||||
}
|
||||
25
src/main/java/com/kamco/cd/kamcoback/log/dto/EventType.java
Normal file
25
src/main/java/com/kamco/cd/kamcoback/log/dto/EventType.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package com.kamco.cd.kamcoback.log.dto;
|
||||
|
||||
import com.kamco.cd.kamcoback.config.enums.EnumType;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum EventType implements EnumType {
|
||||
CREATE("생성"),
|
||||
READ("조회"),
|
||||
UPDATE("수정"),
|
||||
DELETE("삭제"),
|
||||
DOWNLOAD("다운로드"),
|
||||
PRINT("출력"),
|
||||
OTHER("기타");
|
||||
|
||||
private final String desc;
|
||||
|
||||
@Override
|
||||
public String getId() { return name(); }
|
||||
|
||||
@Override
|
||||
public String getText() { return desc; }
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.kamco.cd.kamcoback.postgres;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.MappedSuperclass;
|
||||
import jakarta.persistence.PrePersist;
|
||||
import lombok.Getter;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
@Getter
|
||||
@MappedSuperclass
|
||||
public class CommonCreateEntity {
|
||||
|
||||
@CreatedDate
|
||||
@Column(name = "created_dttm", updatable = false, nullable = false)
|
||||
private ZonedDateTime createdDate;
|
||||
|
||||
@PrePersist
|
||||
protected void onPersist() {
|
||||
this.createdDate = ZonedDateTime.now();
|
||||
}
|
||||
}
|
||||
@@ -14,11 +14,11 @@ import org.springframework.data.annotation.LastModifiedDate;
|
||||
public class CommonDateEntity {
|
||||
|
||||
@CreatedDate
|
||||
@Column(name = "created_date", updatable = false, nullable = false)
|
||||
@Column(name = "created_dttm", updatable = false, nullable = false)
|
||||
private ZonedDateTime createdDate;
|
||||
|
||||
@LastModifiedDate
|
||||
@Column(name = "modified_date", nullable = false)
|
||||
@Column(name = "updated_dttm", nullable = false)
|
||||
private ZonedDateTime modifiedDate;
|
||||
|
||||
@PrePersist
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.kamco.cd.kamcoback.postgres.core;
|
||||
|
||||
import com.kamco.cd.kamcoback.common.service.BaseCoreService;
|
||||
import com.kamco.cd.kamcoback.log.dto.AuditLogDto;
|
||||
import com.kamco.cd.kamcoback.postgres.repository.log.AuditLogRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(readOnly = true)
|
||||
public class AuditLogCoreService implements BaseCoreService<AuditLogDto.AuditList, Long, AuditLogDto.DailySearchReq> {
|
||||
|
||||
private final AuditLogRepository auditLogRepository;
|
||||
|
||||
@Override
|
||||
public void remove(Long aLong) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuditLogDto.AuditList getOneById(Long aLong) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<AuditLogDto.AuditList> search(AuditLogDto.DailySearchReq searchReq) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Page<AuditLogDto.AuditList> getLogByDaily(AuditLogDto.DailySearchReq searchRange, LocalDate startDate, LocalDate endDate) {
|
||||
return auditLogRepository.findLogByDaily(searchRange, startDate, endDate);
|
||||
}
|
||||
|
||||
public Page<AuditLogDto.AuditList> getLogByMenu(AuditLogDto.MenuUserSearchReq searchRange, String searchValue) {
|
||||
return auditLogRepository.findLogByMenu(searchRange, searchValue);
|
||||
}
|
||||
|
||||
public Page<AuditLogDto.AuditList> getLogByAccount(AuditLogDto.MenuUserSearchReq searchRange, String searchValue) {
|
||||
return auditLogRepository.findLogByAccount(searchRange, searchValue);
|
||||
}
|
||||
|
||||
public Page<AuditLogDto.AuditDetail> getLogByDailyResult(AuditLogDto.DailySearchReq searchRange, LocalDate logDate) {
|
||||
return auditLogRepository.findLogByDailyResult(searchRange, logDate);
|
||||
}
|
||||
|
||||
public Page<AuditLogDto.AuditDetail> getLogByMenuResult(AuditLogDto.MenuUserSearchReq searchRange, String menuId) {
|
||||
return auditLogRepository.findLogByMenuResult(searchRange, menuId);
|
||||
}
|
||||
|
||||
public Page<AuditLogDto.AuditDetail> getLogByAccountResult(AuditLogDto.MenuUserSearchReq searchRange, Long accountId) {
|
||||
return auditLogRepository.findLogByAccountResult(searchRange, accountId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.kamco.cd.kamcoback.postgres.core;
|
||||
|
||||
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto;
|
||||
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto.Basic;
|
||||
import com.kamco.cd.kamcoback.common.service.BaseCoreService;
|
||||
import com.kamco.cd.kamcoback.postgres.entity.CommonCodeEntity;
|
||||
import com.kamco.cd.kamcoback.postgres.repository.CommonCodeRepository;
|
||||
import com.kamco.cd.kamcoback.zoo.dto.AnimalDto.SearchReq;
|
||||
import jakarta.persistence.EntityNotFoundException;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class CommonCodeCoreService implements BaseCoreService<CommonCodeDto.Basic, Long, SearchReq> {
|
||||
|
||||
private final CommonCodeRepository commonCodeRepository;
|
||||
|
||||
|
||||
public List<CommonCodeDto.Basic> findAll() {
|
||||
return commonCodeRepository.findByAll().stream().map(CommonCodeEntity::toDto).toList();
|
||||
}
|
||||
|
||||
public CommonCodeDto.Basic save(CommonCodeDto.AddReq req) {
|
||||
if(req.getParentId() != null){
|
||||
CommonCodeEntity parentCommonCodeEntity = commonCodeRepository.findById(req.getParentId())
|
||||
.orElseThrow(() -> new EntityNotFoundException("parent id 를 찾을 수 없습니다. id : " + req.getParentId()));
|
||||
|
||||
CommonCodeEntity entity = new CommonCodeEntity(req.getCode(), req.getName(), req.getDescription(), req.getOrder(), req.isUsed());
|
||||
entity.addParent(parentCommonCodeEntity);
|
||||
return commonCodeRepository.save(entity).toDto();
|
||||
}
|
||||
|
||||
CommonCodeEntity entity = new CommonCodeEntity(req.getCode(), req.getName(), req.getDescription(), req.getOrder(), req.isUsed());
|
||||
return commonCodeRepository.save(entity).toDto();
|
||||
}
|
||||
|
||||
public CommonCodeDto.Basic update(Long id, CommonCodeDto.ModifyReq req) {
|
||||
CommonCodeEntity found = commonCodeRepository.findByCodeId(id)
|
||||
.orElseThrow(()->new EntityNotFoundException("common code 를 찾을 수 없습니다. id : " + id));
|
||||
|
||||
CommonCodeEntity entity = new CommonCodeEntity( id, req.getName(), req.getDescription(), req.getOrder(), req.isUsed(), found.getDeleted());
|
||||
|
||||
return commonCodeRepository.save(entity).toDto();
|
||||
}
|
||||
|
||||
public void updateOrder(CommonCodeDto.OrderReq req) {
|
||||
commonCodeRepository.updateOrder(req);
|
||||
}
|
||||
|
||||
public List<CommonCodeDto.Basic> findByCode(String code) {
|
||||
return commonCodeRepository.findByCode(code).stream().map(CommonCodeEntity::toDto).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Long id) {
|
||||
CommonCodeEntity entity = commonCodeRepository.findByCodeId(id)
|
||||
.orElseThrow(()->new EntityNotFoundException("code를 찾을 수 없습니다. id " + id));
|
||||
|
||||
// 하위 코드 deleted = false 업데이트
|
||||
entity.getChildren().forEach(CommonCodeEntity::deleted);
|
||||
// id 코드 deleted = false 업데이트
|
||||
entity.deleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Basic getOneById(Long id) {
|
||||
CommonCodeEntity entity = commonCodeRepository.findByCodeId(id)
|
||||
.orElseThrow(()->new EntityNotFoundException("code를 찾을 수 없습니다. id " + id));
|
||||
return entity.toDto();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Basic> search(SearchReq searchReq) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.kamco.cd.kamcoback.postgres.core;
|
||||
|
||||
import com.kamco.cd.kamcoback.common.service.BaseCoreService;
|
||||
import com.kamco.cd.kamcoback.log.dto.AuditLogDto;
|
||||
import com.kamco.cd.kamcoback.log.dto.ErrorLogDto;
|
||||
import com.kamco.cd.kamcoback.postgres.repository.log.AuditLogRepository;
|
||||
import com.kamco.cd.kamcoback.postgres.repository.log.ErrorLogRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(readOnly = true)
|
||||
public class ErrorLogCoreService implements BaseCoreService<ErrorLogDto.Basic, Long, ErrorLogDto.ErrorSearchReq> {
|
||||
|
||||
private final ErrorLogRepository errorLogRepository;
|
||||
|
||||
public Page<ErrorLogDto.Basic> findLogByError(ErrorLogDto.ErrorSearchReq searchReq) {
|
||||
return errorLogRepository.findLogByError(searchReq);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Long aLong) {}
|
||||
|
||||
@Override
|
||||
public ErrorLogDto.Basic getOneById(Long aLong) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<ErrorLogDto.Basic> search(ErrorLogDto.ErrorSearchReq searchReq) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.kamco.cd.kamcoback.postgres.entity;
|
||||
|
||||
import com.kamco.cd.kamcoback.log.dto.AuditLogDto;
|
||||
import com.kamco.cd.kamcoback.log.dto.EventStatus;
|
||||
import com.kamco.cd.kamcoback.log.dto.EventType;
|
||||
import com.kamco.cd.kamcoback.postgres.CommonCreateEntity;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
@Table(name = "tb_audit_log")
|
||||
public class AuditLogEntity extends CommonCreateEntity {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "audit_log_uid")
|
||||
private Long id;
|
||||
|
||||
@Column(name = "user_uid")
|
||||
private Long userUid;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private EventType eventType;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private EventStatus eventStatus;
|
||||
|
||||
@Column(name = "menu_uid")
|
||||
private String menuUid;
|
||||
|
||||
@Column(name = "ip_address")
|
||||
private String ipAddress;
|
||||
|
||||
@Column(name = "request_uri")
|
||||
private String requestUri;
|
||||
|
||||
@Column(name = "request_body")
|
||||
private String requestBody;
|
||||
|
||||
@Column(name = "error_log_uid")
|
||||
private Long errorLogUid;
|
||||
|
||||
public AuditLogEntity(Long userUid, EventType eventType, EventStatus eventStatus, String menuUid, String ipAddress, String requestUri, String requestBody, Long errorLogUid) {
|
||||
this.userUid = userUid;
|
||||
this.eventType = eventType;
|
||||
this.eventStatus = eventStatus;
|
||||
this.menuUid = menuUid;
|
||||
this.ipAddress = ipAddress;
|
||||
this.requestUri = requestUri;
|
||||
this.requestBody = requestBody;
|
||||
this.errorLogUid = errorLogUid;
|
||||
}
|
||||
|
||||
public AuditLogDto.Basic toDto() {
|
||||
return new AuditLogDto.Basic(
|
||||
this.id,
|
||||
this.userUid,
|
||||
this.eventType,
|
||||
this.eventStatus,
|
||||
this.menuUid,
|
||||
this.ipAddress,
|
||||
this.requestUri,
|
||||
this.requestBody,
|
||||
this.errorLogUid,
|
||||
super.getCreatedDate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(this.id).append("\n")
|
||||
.append(this.userUid).append("\n")
|
||||
.append(this.eventType).append("\n")
|
||||
.append(this.eventStatus).append("\n")
|
||||
.append(this.menuUid).append("\n")
|
||||
.append(this.ipAddress).append("\n")
|
||||
.append(this.requestUri).append("\n")
|
||||
.append(this.requestBody).append("\n")
|
||||
.append(this.errorLogUid);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package com.kamco.cd.kamcoback.postgres.entity;
|
||||
|
||||
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto;
|
||||
import com.kamco.cd.kamcoback.postgres.CommonDateEntity;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
@Table(name = "tb_cm_cd")
|
||||
public class CommonCodeEntity extends CommonDateEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "code_id", nullable = false, updatable = false)
|
||||
private Long id;
|
||||
|
||||
@Size(max = 255)
|
||||
@Column(name = "code_cd", updatable = false)
|
||||
private String code;
|
||||
|
||||
@Size(max = 255)
|
||||
@Column(name = "cd_ct")
|
||||
private String description;
|
||||
|
||||
@Size(max = 255)
|
||||
@Column(name = "cd_nm")
|
||||
private String name;
|
||||
|
||||
@Column(name = "cd_odr")
|
||||
private Integer order;
|
||||
|
||||
@Column(name = "used")
|
||||
private Boolean used;
|
||||
|
||||
@NotNull
|
||||
@Column(name = "deleted", nullable = false)
|
||||
private Boolean deleted = false;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "parent_id", updatable = false)
|
||||
private CommonCodeEntity parent;
|
||||
|
||||
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
private List<CommonCodeEntity> children = new ArrayList<>();
|
||||
|
||||
public CommonCodeEntity(String code, String name, String description, Integer order, Boolean used) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.order = order;
|
||||
this.used = used;
|
||||
}
|
||||
|
||||
public CommonCodeEntity(Long id, String name, String description, Integer order, Boolean used, Boolean deleted) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.order = order;
|
||||
this.used = used;
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
public CommonCodeDto.Basic toDto() {
|
||||
return new CommonCodeDto.Basic(
|
||||
this.id,
|
||||
this.code,
|
||||
this.description,
|
||||
this.name,
|
||||
this.order,
|
||||
this.used,
|
||||
this.deleted,
|
||||
this.children.stream().map(CommonCodeEntity::toDto).toList(),
|
||||
super.getCreatedDate(),
|
||||
super.getModifiedDate());
|
||||
}
|
||||
|
||||
|
||||
public void addParent(CommonCodeEntity parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void deleted() {
|
||||
this.deleted = true;
|
||||
}
|
||||
|
||||
public void updateOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.kamco.cd.kamcoback.postgres.entity;
|
||||
|
||||
import com.kamco.cd.kamcoback.log.dto.ErrorLogDto;
|
||||
import com.kamco.cd.kamcoback.log.dto.EventType;
|
||||
import com.kamco.cd.kamcoback.postgres.CommonCreateEntity;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
@Table(name = "tb_error_log")
|
||||
public class ErrorLogEntity extends CommonCreateEntity {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "error_log_uid")
|
||||
private Long id;
|
||||
|
||||
@Column(name = "request_id")
|
||||
private String requestId;
|
||||
|
||||
@Column(name = "error_type")
|
||||
@Enumerated(EnumType.STRING)
|
||||
private EventType errorType;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private ErrorLogDto.LogErrorLevel errorLevel;
|
||||
private String errorCode;
|
||||
private String errorMessage;
|
||||
private String stackTrace;
|
||||
private Long handlerUid;
|
||||
private ZonedDateTime handledDttm;
|
||||
|
||||
public ErrorLogEntity(String requestId, EventType errorType, ErrorLogDto.LogErrorLevel errorLevel, String errorCode, String errorMessage, String stackTrace
|
||||
, Long handlerUid, ZonedDateTime handledDttm) {
|
||||
this.requestId = requestId;
|
||||
this.errorType = errorType;
|
||||
this.errorLevel = errorLevel;
|
||||
this.errorCode = errorCode;
|
||||
this.errorMessage = errorMessage;
|
||||
this.stackTrace = stackTrace;
|
||||
this.handlerUid = handlerUid;
|
||||
this.handledDttm = handledDttm;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.kamco.cd.kamcoback.postgres.entity;
|
||||
|
||||
import com.kamco.cd.kamcoback.log.dto.EventStatus;
|
||||
import com.kamco.cd.kamcoback.log.dto.EventType;
|
||||
import com.kamco.cd.kamcoback.postgres.CommonDateEntity;
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
@Table(name = "tb_menu")
|
||||
public class MenuEntity extends CommonDateEntity {
|
||||
@Id
|
||||
@Column(name = "menu_uid")
|
||||
private String menuUid;
|
||||
|
||||
@Column(name = "menu_nm")
|
||||
private String menuNm;
|
||||
|
||||
@Column(name = "menu_url")
|
||||
private String menuUrl;
|
||||
|
||||
@Column(name = "description")
|
||||
private String description;
|
||||
|
||||
@Column(name = "menu_order")
|
||||
private Long menuOrder;
|
||||
|
||||
@NotNull
|
||||
@Column(name = "is_use", nullable = true)
|
||||
private Boolean isUse = true;
|
||||
|
||||
@NotNull
|
||||
@Column(name = "deleted", nullable = false)
|
||||
private Boolean deleted = false;
|
||||
|
||||
private Long createdUid;
|
||||
private Long updatedUid;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "parent_menu_uid")
|
||||
private MenuEntity parent;
|
||||
|
||||
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
private List<MenuEntity> children = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.kamco.cd.kamcoback.postgres.entity;
|
||||
|
||||
import com.kamco.cd.kamcoback.log.dto.ErrorLogDto;
|
||||
import com.kamco.cd.kamcoback.log.dto.EventType;
|
||||
import com.kamco.cd.kamcoback.postgres.CommonDateEntity;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
@Table(name = "tb_user")
|
||||
public class UserEntity extends CommonDateEntity {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "user_uid")
|
||||
private Long id;
|
||||
|
||||
@Column(name = "user_nm")
|
||||
private String userNm;
|
||||
|
||||
@Column(name = "user_id")
|
||||
private String userId;
|
||||
|
||||
@Column(name = "pswd")
|
||||
private String pswd; //TODO: 암호화
|
||||
|
||||
//@Enumerated(EnumType.STRING)
|
||||
private String state; //TODO: 추후 enum -> ACTIVE : 정상, LOCKED : 잠김, EXPIRED : 만료, WITHDRAWAL : 탈퇴
|
||||
|
||||
private ZonedDateTime dateWithdrawal;
|
||||
|
||||
private String userEmail;
|
||||
private Long createdUid;
|
||||
private Long updatedUid;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.kamco.cd.kamcoback.postgres.repository;
|
||||
|
||||
import com.kamco.cd.kamcoback.postgres.entity.CommonCodeEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface CommonCodeRepository extends JpaRepository<CommonCodeEntity, Long>, CommonCodeRepositoryCustom {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.kamco.cd.kamcoback.postgres.repository;
|
||||
|
||||
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto;
|
||||
import com.kamco.cd.kamcoback.postgres.entity.CommonCodeEntity;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface CommonCodeRepositoryCustom {
|
||||
Optional<CommonCodeEntity> findByCodeId(Long id);
|
||||
Optional<CommonCodeEntity> findByCode(String code);
|
||||
List<CommonCodeEntity> findByAll();
|
||||
void updateOrder(CommonCodeDto.OrderReq req);
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.kamco.cd.kamcoback.postgres.repository;
|
||||
|
||||
import static com.kamco.cd.kamcoback.postgres.entity.QCommonCodeEntity.commonCodeEntity;
|
||||
|
||||
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto;
|
||||
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto.OrderReqDetail;
|
||||
import com.kamco.cd.kamcoback.postgres.entity.CommonCodeEntity;
|
||||
import com.kamco.cd.kamcoback.postgres.entity.QCommonCodeEntity;
|
||||
import com.querydsl.core.types.dsl.Expressions;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
|
||||
|
||||
public class CommonCodeRepositoryImpl extends QuerydslRepositorySupport implements CommonCodeRepositoryCustom {
|
||||
|
||||
private final JPAQueryFactory queryFactory;
|
||||
|
||||
public CommonCodeRepositoryImpl(JPAQueryFactory queryFactory) {
|
||||
super(CommonCodeEntity.class);
|
||||
this.queryFactory = queryFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<CommonCodeEntity> findByCodeId(Long id) {
|
||||
QCommonCodeEntity child = new QCommonCodeEntity("child");
|
||||
return Optional.ofNullable(
|
||||
queryFactory
|
||||
.selectFrom(commonCodeEntity)
|
||||
.leftJoin(commonCodeEntity.children, child)
|
||||
.fetchJoin()
|
||||
.where(
|
||||
commonCodeEntity.id.eq(id),
|
||||
commonCodeEntity.deleted.isFalse()
|
||||
)
|
||||
.orderBy(commonCodeEntity.order.asc(), child.order.asc())
|
||||
.fetchOne()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<CommonCodeEntity> findByCode(String code) {
|
||||
QCommonCodeEntity child = new QCommonCodeEntity("child");
|
||||
return Optional.ofNullable(
|
||||
queryFactory
|
||||
.selectFrom(commonCodeEntity)
|
||||
.leftJoin(commonCodeEntity.children, child)
|
||||
.fetchJoin()
|
||||
.where(
|
||||
commonCodeEntity.parent.isNull(),
|
||||
commonCodeEntity.code.eq(code),
|
||||
commonCodeEntity.used.isTrue(),
|
||||
commonCodeEntity.deleted.isFalse()
|
||||
)
|
||||
.orderBy(child.order.asc())
|
||||
.fetchOne()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommonCodeEntity> findByAll() {
|
||||
QCommonCodeEntity child = new QCommonCodeEntity("child");
|
||||
return queryFactory
|
||||
.selectFrom(commonCodeEntity)
|
||||
.leftJoin(commonCodeEntity.children, child)
|
||||
.fetchJoin()
|
||||
.where(
|
||||
commonCodeEntity.parent.isNull(),
|
||||
commonCodeEntity.deleted.isFalse()
|
||||
)
|
||||
.orderBy(commonCodeEntity.order.asc(), child.order.asc())
|
||||
.fetch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateOrder(CommonCodeDto.OrderReq req) {
|
||||
Map<Long, Integer> orderMap = req.getOrders().stream().
|
||||
collect(Collectors.toMap(OrderReqDetail::getId, OrderReqDetail::getOrder));
|
||||
|
||||
List<CommonCodeEntity> entity = findAllByIds(orderMap.keySet());
|
||||
|
||||
entity.forEach(commonCodeEntity -> {
|
||||
Integer order = orderMap.get(commonCodeEntity.getId());
|
||||
if(order != null) {
|
||||
commonCodeEntity.updateOrder(order);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private List<CommonCodeEntity> findAllByIds(Set<Long> ids) {
|
||||
return queryFactory
|
||||
.selectFrom(commonCodeEntity)
|
||||
.where(
|
||||
commonCodeEntity.id.in(ids),
|
||||
commonCodeEntity.deleted.isFalse()
|
||||
)
|
||||
.fetch();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.kamco.cd.kamcoback.postgres.repository.log;
|
||||
|
||||
import com.kamco.cd.kamcoback.postgres.entity.AuditLogEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface AuditLogRepository extends JpaRepository<AuditLogEntity, Long>, AuditLogRepositoryCustom {}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.kamco.cd.kamcoback.postgres.repository.log;
|
||||
|
||||
import com.kamco.cd.kamcoback.log.dto.AuditLogDto;
|
||||
import org.springframework.data.domain.Page;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public interface AuditLogRepositoryCustom {
|
||||
|
||||
Page<AuditLogDto.AuditList> findLogByDaily(AuditLogDto.DailySearchReq searchReq, LocalDate startDate, LocalDate endDate);
|
||||
|
||||
Page<AuditLogDto.AuditList> findLogByMenu(AuditLogDto.MenuUserSearchReq searchReq, String searchValue);
|
||||
|
||||
Page<AuditLogDto.AuditList> findLogByAccount(AuditLogDto.MenuUserSearchReq searchReq, String searchValue);
|
||||
|
||||
Page<AuditLogDto.AuditDetail> findLogByDailyResult(AuditLogDto.DailySearchReq searchReq, LocalDate logDate);
|
||||
|
||||
Page<AuditLogDto.AuditDetail> findLogByMenuResult(AuditLogDto.MenuUserSearchReq searchReq, String menuId);
|
||||
|
||||
Page<AuditLogDto.AuditDetail> findLogByAccountResult(AuditLogDto.MenuUserSearchReq searchReq, Long accountId);
|
||||
}
|
||||
@@ -0,0 +1,427 @@
|
||||
package com.kamco.cd.kamcoback.postgres.repository.log;
|
||||
|
||||
import com.kamco.cd.kamcoback.log.dto.AuditLogDto;
|
||||
import com.kamco.cd.kamcoback.log.dto.ErrorLogDto;
|
||||
import com.kamco.cd.kamcoback.log.dto.EventStatus;
|
||||
import com.kamco.cd.kamcoback.log.dto.EventType;
|
||||
import com.kamco.cd.kamcoback.postgres.entity.AuditLogEntity;
|
||||
import com.querydsl.core.types.Projections;
|
||||
import com.querydsl.core.types.dsl.*;
|
||||
import com.querydsl.jpa.impl.JPAQuery;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
import io.micrometer.common.util.StringUtils;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.kamco.cd.kamcoback.postgres.entity.QUserEntity.userEntity;
|
||||
import static com.kamco.cd.kamcoback.postgres.entity.QAuditLogEntity.auditLogEntity;
|
||||
import static com.kamco.cd.kamcoback.postgres.entity.QErrorLogEntity.errorLogEntity;
|
||||
import static com.kamco.cd.kamcoback.postgres.entity.QMenuEntity.menuEntity;
|
||||
import com.kamco.cd.kamcoback.postgres.entity.QMenuEntity;
|
||||
|
||||
public class AuditLogRepositoryImpl extends QuerydslRepositorySupport implements AuditLogRepositoryCustom {
|
||||
private final JPAQueryFactory queryFactory;
|
||||
private final StringExpression NULL_STRING = Expressions.stringTemplate("cast(null as text)");
|
||||
|
||||
public AuditLogRepositoryImpl(JPAQueryFactory queryFactory) {
|
||||
super(AuditLogEntity.class);
|
||||
this.queryFactory = queryFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<AuditLogDto.AuditList> findLogByDaily(AuditLogDto.DailySearchReq searchReq, LocalDate startDate, LocalDate endDate) {
|
||||
DateTimeExpression<LocalDateTime> groupDateTime =
|
||||
Expressions.dateTimeTemplate(LocalDateTime.class, "date_trunc('day', {0})", auditLogEntity.createdDate);
|
||||
|
||||
Pageable pageable = searchReq.toPageable();
|
||||
List<AuditLogDto.AuditList> foundContent = queryFactory
|
||||
.select(
|
||||
Projections.constructor(
|
||||
AuditLogDto.AuditList.class,
|
||||
groupDateTime.as("baseDate"),
|
||||
readCount().as("readCount"),
|
||||
cudCount().as("cudCount"),
|
||||
printCount().as("printCount"),
|
||||
downloadCount().as("downloadCount"),
|
||||
auditLogEntity.count().as("totalCount")
|
||||
)
|
||||
)
|
||||
.from(auditLogEntity)
|
||||
.where(
|
||||
eventEndedAtBetween(startDate, endDate)
|
||||
)
|
||||
.groupBy(groupDateTime)
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize())
|
||||
.orderBy(groupDateTime.desc())
|
||||
.fetch();
|
||||
|
||||
Long countQuery = queryFactory
|
||||
.select(groupDateTime.countDistinct())
|
||||
.from(auditLogEntity)
|
||||
.where(
|
||||
eventEndedAtBetween(startDate, endDate)
|
||||
)
|
||||
.fetchOne();
|
||||
|
||||
return new PageImpl<>(foundContent, pageable, countQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<AuditLogDto.AuditList> findLogByMenu(AuditLogDto.MenuUserSearchReq searchReq, String searchValue) {
|
||||
Pageable pageable = searchReq.toPageable();
|
||||
List<AuditLogDto.AuditList> foundContent = queryFactory
|
||||
.select(
|
||||
Projections.constructor(
|
||||
AuditLogDto.AuditList.class,
|
||||
auditLogEntity.menuUid.as("menuId"),
|
||||
menuEntity.menuNm.max().as("menuName"),
|
||||
readCount().as("readCount"),
|
||||
cudCount().as("cudCount"),
|
||||
printCount().as("printCount"),
|
||||
downloadCount().as("downloadCount"),
|
||||
auditLogEntity.count().as("totalCount")
|
||||
)
|
||||
)
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(menuEntity).on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
|
||||
.where(
|
||||
menuNameEquals(searchValue)
|
||||
)
|
||||
.groupBy(auditLogEntity.menuUid)
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize())
|
||||
.orderBy(auditLogEntity.createdDate.max().desc())
|
||||
.fetch();
|
||||
|
||||
// count query group by 를 지정하면 하나의 row 가 아니라 그룹핑된 여러 row 가 나올 수 있다.
|
||||
// select query 의 group by 대상의 컬럼을 count query 에선 select distinct 로 처리 한다.
|
||||
Long countQuery = queryFactory
|
||||
.select(auditLogEntity.menuUid.countDistinct())
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(menuEntity).on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
|
||||
.where(menuNameEquals(searchValue))
|
||||
.fetchOne();
|
||||
|
||||
return new PageImpl<>(foundContent, pageable, countQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<AuditLogDto.AuditList> findLogByAccount(AuditLogDto.MenuUserSearchReq searchReq, String searchValue) {
|
||||
Pageable pageable = searchReq.toPageable();
|
||||
List<AuditLogDto.AuditList> foundContent = queryFactory
|
||||
.select(
|
||||
Projections.constructor(
|
||||
AuditLogDto.AuditList.class,
|
||||
auditLogEntity.userUid.as("accountId"),
|
||||
userEntity.userId.as("loginId"),
|
||||
userEntity.userNm.as("username"),
|
||||
readCount().as("readCount"),
|
||||
cudCount().as("cudCount"),
|
||||
printCount().as("printCount"),
|
||||
downloadCount().as("downloadCount"),
|
||||
auditLogEntity.count().as("totalCount")
|
||||
)
|
||||
)
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(userEntity).on(auditLogEntity.userUid.eq(userEntity.id))
|
||||
.where(
|
||||
loginIdOrUsernameContains(searchValue)
|
||||
)
|
||||
.groupBy(auditLogEntity.userUid, userEntity.userId, userEntity.userNm)
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize())
|
||||
// .orderBy(auditLogEntity.eventEndedAt.max().desc())
|
||||
.fetch();
|
||||
|
||||
Long countQuery = queryFactory
|
||||
.select(auditLogEntity.userUid.countDistinct())
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(userEntity).on(auditLogEntity.userUid.eq(userEntity.id))
|
||||
.where(loginIdOrUsernameContains(searchValue))
|
||||
.fetchOne();
|
||||
|
||||
return new PageImpl<>(foundContent, pageable, countQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<AuditLogDto.AuditDetail> findLogByDailyResult(AuditLogDto.DailySearchReq searchReq, LocalDate logDate) {
|
||||
Pageable pageable = searchReq.toPageable();
|
||||
QMenuEntity parent = new QMenuEntity("parent");
|
||||
// 1depth menu name
|
||||
StringExpression parentMenuName =
|
||||
new CaseBuilder()
|
||||
.when(parent.menuUid.isNull()).then(menuEntity.menuNm)
|
||||
.otherwise(parent.menuNm);
|
||||
|
||||
// 2depth menu name
|
||||
StringExpression menuName =
|
||||
new CaseBuilder()
|
||||
.when(parent.menuUid.isNull()).then(NULL_STRING)
|
||||
.otherwise(menuEntity.menuNm);
|
||||
|
||||
List<AuditLogDto.AuditDetail> foundContent = queryFactory
|
||||
.select(
|
||||
Projections.constructor(
|
||||
AuditLogDto.AuditDetail.class,
|
||||
auditLogEntity.id.as("logId"),
|
||||
userEntity.userNm.as("userName"),
|
||||
userEntity.userId.as("loginId"),
|
||||
menuEntity.menuNm.as("menuName"),
|
||||
auditLogEntity.eventType.as("eventType"),
|
||||
Projections.constructor(
|
||||
AuditLogDto.LogDetail.class,
|
||||
Expressions.constant("한국자산관리공사"), //serviceName
|
||||
parentMenuName.as("parentMenuName"),
|
||||
menuName,
|
||||
menuEntity.menuUrl.as("menuUrl"),
|
||||
menuEntity.description.as("menuDescription"),
|
||||
menuEntity.menuOrder.as("sortOrder"),
|
||||
menuEntity.isUse.as("used")
|
||||
)
|
||||
)
|
||||
)
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(menuEntity).on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
|
||||
.leftJoin(menuEntity.parent, parent)
|
||||
.leftJoin(userEntity).on(auditLogEntity.userUid.eq(userEntity.id))
|
||||
.where(
|
||||
eventEndedAtEqDate(logDate)
|
||||
)
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize())
|
||||
.orderBy(auditLogEntity.createdDate.desc())
|
||||
.fetch();
|
||||
|
||||
Long countQuery = queryFactory
|
||||
.select(auditLogEntity.id.countDistinct())
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(menuEntity).on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
|
||||
.leftJoin(menuEntity.parent, parent)
|
||||
.leftJoin(userEntity).on(auditLogEntity.userUid.eq(userEntity.id))
|
||||
.where(
|
||||
eventEndedAtEqDate(logDate)
|
||||
)
|
||||
.fetchOne();
|
||||
|
||||
return new PageImpl<>(foundContent, pageable, countQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<AuditLogDto.AuditDetail> findLogByMenuResult(AuditLogDto.MenuUserSearchReq searchReq, String menuUid) {
|
||||
Pageable pageable = searchReq.toPageable();
|
||||
QMenuEntity parent = new QMenuEntity("parent");
|
||||
// 1depth menu name
|
||||
StringExpression parentMenuName =
|
||||
new CaseBuilder()
|
||||
.when(parent.menuUid.isNull()).then(menuEntity.menuNm)
|
||||
.otherwise(parent.menuNm);
|
||||
|
||||
// 2depth menu name
|
||||
StringExpression menuName =
|
||||
new CaseBuilder()
|
||||
.when(parent.menuUid.isNull()).then(NULL_STRING)
|
||||
.otherwise(menuEntity.menuNm);
|
||||
|
||||
List<AuditLogDto.AuditDetail> foundContent = queryFactory
|
||||
.select(
|
||||
Projections.constructor(
|
||||
AuditLogDto.AuditDetail.class,
|
||||
auditLogEntity.id.as("logId"),
|
||||
auditLogEntity.createdDate.as("logDateTime"),
|
||||
userEntity.userNm.as("userName"),
|
||||
userEntity.userId.as("loginId"),
|
||||
auditLogEntity.eventType.as("eventType"),
|
||||
Projections.constructor(
|
||||
AuditLogDto.LogDetail.class,
|
||||
Expressions.constant("한국자산관리공사"), //serviceName
|
||||
parentMenuName.as("parentMenuName"),
|
||||
menuName,
|
||||
menuEntity.menuUrl.as("menuUrl"),
|
||||
menuEntity.description.as("menuDescription"),
|
||||
menuEntity.menuOrder.as("sortOrder"),
|
||||
menuEntity.isUse.as("used")
|
||||
)
|
||||
)
|
||||
)
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(menuEntity).on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
|
||||
.leftJoin(menuEntity.parent, parent)
|
||||
.leftJoin(userEntity).on(auditLogEntity.userUid.eq(userEntity.id))
|
||||
.where(
|
||||
menuUidEq(menuUid)
|
||||
)
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize())
|
||||
.orderBy(auditLogEntity.createdDate.desc())
|
||||
.fetch();
|
||||
|
||||
Long countQuery = queryFactory
|
||||
.select(auditLogEntity.id.countDistinct())
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(menuEntity).on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
|
||||
.leftJoin(menuEntity.parent, parent)
|
||||
.leftJoin(userEntity).on(auditLogEntity.userUid.eq(userEntity.id))
|
||||
.where(
|
||||
menuUidEq(menuUid)
|
||||
).fetchOne();
|
||||
|
||||
return new PageImpl<>(foundContent, pageable, countQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<AuditLogDto.AuditDetail> findLogByAccountResult(AuditLogDto.MenuUserSearchReq searchReq, Long userUid) {
|
||||
Pageable pageable = searchReq.toPageable();
|
||||
QMenuEntity parent = new QMenuEntity("parent");
|
||||
// 1depth menu name
|
||||
StringExpression parentMenuName =
|
||||
new CaseBuilder()
|
||||
.when(parent.menuUid.isNull()).then(menuEntity.menuNm)
|
||||
.otherwise(parent.menuNm);
|
||||
|
||||
// 2depth menu name
|
||||
StringExpression menuName =
|
||||
new CaseBuilder()
|
||||
.when(parent.menuUid.isNull()).then(NULL_STRING)
|
||||
.otherwise(menuEntity.menuNm);
|
||||
|
||||
List<AuditLogDto.AuditDetail> foundContent = queryFactory
|
||||
.select(
|
||||
Projections.constructor(
|
||||
AuditLogDto.AuditDetail.class,
|
||||
auditLogEntity.id.as("logId"),
|
||||
auditLogEntity.createdDate.as("logDateTime"),
|
||||
menuEntity.menuNm.as("menuName"),
|
||||
auditLogEntity.eventType.as("eventType"),
|
||||
Projections.constructor(
|
||||
AuditLogDto.LogDetail.class,
|
||||
Expressions.constant("한국자산관리공사"), //serviceName
|
||||
parentMenuName.as("parentMenuName"),
|
||||
menuName,
|
||||
menuEntity.menuUrl.as("menuUrl"),
|
||||
menuEntity.description.as("menuDescription"),
|
||||
menuEntity.menuOrder.as("sortOrder"),
|
||||
menuEntity.isUse.as("used")
|
||||
)
|
||||
)
|
||||
)
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(menuEntity).on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
|
||||
.leftJoin(menuEntity.parent, parent)
|
||||
.leftJoin(userEntity).on(auditLogEntity.userUid.eq(userEntity.id))
|
||||
.where(
|
||||
userUidEq(userUid)
|
||||
)
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize())
|
||||
.orderBy(auditLogEntity.createdDate.desc())
|
||||
.fetch();
|
||||
|
||||
Long countQuery = queryFactory
|
||||
.select(auditLogEntity.id.countDistinct())
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(menuEntity).on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
|
||||
.leftJoin(menuEntity.parent, parent)
|
||||
.leftJoin(userEntity).on(auditLogEntity.userUid.eq(userEntity.id))
|
||||
.where(
|
||||
userUidEq(userUid)
|
||||
)
|
||||
.fetchOne();
|
||||
|
||||
return new PageImpl<>(foundContent, pageable, countQuery);
|
||||
}
|
||||
|
||||
private BooleanExpression eventEndedAtBetween(LocalDate startDate, LocalDate endDate) {
|
||||
if (Objects.isNull(startDate) || Objects.isNull(endDate)) {
|
||||
return null;
|
||||
}
|
||||
LocalDateTime startDateTime = startDate.atStartOfDay();
|
||||
LocalDateTime endDateTime = endDate.plusDays(1).atStartOfDay();
|
||||
return auditLogEntity.createdDate.goe(ZonedDateTime.from(startDateTime))
|
||||
.and(auditLogEntity.createdDate.lt(ZonedDateTime.from(endDateTime)));
|
||||
}
|
||||
|
||||
private BooleanExpression menuNameEquals(String searchValue) {
|
||||
if (StringUtils.isBlank(searchValue)) {
|
||||
return null;
|
||||
}
|
||||
return menuEntity.menuNm.contains(searchValue);
|
||||
}
|
||||
|
||||
private BooleanExpression loginIdOrUsernameContains(String searchValue) {
|
||||
if (StringUtils.isBlank(searchValue)) {
|
||||
return null;
|
||||
}
|
||||
return userEntity.userId.contains(searchValue).or(userEntity.userNm.contains(searchValue));
|
||||
}
|
||||
|
||||
private BooleanExpression eventStatusEqFailed() {
|
||||
return auditLogEntity.eventStatus.eq(EventStatus.FAILED);
|
||||
}
|
||||
|
||||
private BooleanExpression eventTypeEq(EventType eventType) {
|
||||
if (Objects.isNull(eventType)) {
|
||||
return null;
|
||||
}
|
||||
return auditLogEntity.eventType.eq(eventType);
|
||||
}
|
||||
|
||||
private BooleanExpression errorLevelEq(ErrorLogDto.LogErrorLevel level) {
|
||||
if (Objects.isNull(level)) {
|
||||
return null;
|
||||
}
|
||||
return errorLogEntity.errorLevel.eq(ErrorLogDto.LogErrorLevel.valueOf(level.name()));
|
||||
}
|
||||
|
||||
private BooleanExpression eventEndedAtEqDate(LocalDate logDate) {
|
||||
DateTimeExpression<LocalDateTime> eventEndedDate =
|
||||
Expressions.dateTimeTemplate(LocalDateTime.class, "date_trunc('day', {0})", auditLogEntity.createdDate);
|
||||
LocalDateTime comparisonDate = logDate.atStartOfDay();
|
||||
|
||||
return eventEndedDate.eq(comparisonDate);
|
||||
}
|
||||
|
||||
private BooleanExpression menuUidEq(String menuUid) {
|
||||
return auditLogEntity.menuUid.eq(menuUid);
|
||||
}
|
||||
|
||||
private BooleanExpression userUidEq(Long userUid) {
|
||||
return auditLogEntity.userUid.eq(userUid);
|
||||
}
|
||||
|
||||
private NumberExpression<Integer> readCount() {
|
||||
return new CaseBuilder()
|
||||
.when(auditLogEntity.eventType.eq(EventType.READ)).then(1)
|
||||
.otherwise(0)
|
||||
.sum();
|
||||
}
|
||||
|
||||
private NumberExpression<Integer> cudCount() {
|
||||
return new CaseBuilder()
|
||||
.when(auditLogEntity.eventType.in(EventType.CREATE, EventType.UPDATE, EventType.DELETE)).then(1)
|
||||
.otherwise(0)
|
||||
.sum();
|
||||
}
|
||||
|
||||
private NumberExpression<Integer> printCount() {
|
||||
return new CaseBuilder()
|
||||
.when(auditLogEntity.eventType.eq(EventType.PRINT)).then(1)
|
||||
.otherwise(0)
|
||||
.sum();
|
||||
}
|
||||
|
||||
private NumberExpression<Integer> downloadCount() {
|
||||
return new CaseBuilder()
|
||||
.when(auditLogEntity.eventType.eq(EventType.DOWNLOAD)).then(1)
|
||||
.otherwise(0)
|
||||
.sum();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.kamco.cd.kamcoback.postgres.repository.log;
|
||||
|
||||
import com.kamco.cd.kamcoback.postgres.entity.ErrorLogEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface ErrorLogRepository extends JpaRepository<ErrorLogEntity, Long>, ErrorLogRepositoryCustom {}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.kamco.cd.kamcoback.postgres.repository.log;
|
||||
|
||||
import com.kamco.cd.kamcoback.log.dto.AuditLogDto;
|
||||
import com.kamco.cd.kamcoback.log.dto.ErrorLogDto;
|
||||
import com.kamco.cd.kamcoback.postgres.entity.AuditLogEntity;
|
||||
import org.springframework.data.domain.Page;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public interface ErrorLogRepositoryCustom {
|
||||
public Page<ErrorLogDto.Basic> findLogByError(ErrorLogDto.ErrorSearchReq searchReq);
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package com.kamco.cd.kamcoback.postgres.repository.log;
|
||||
|
||||
import com.kamco.cd.kamcoback.log.dto.ErrorLogDto;
|
||||
import com.kamco.cd.kamcoback.log.dto.EventStatus;
|
||||
import com.kamco.cd.kamcoback.log.dto.EventType;
|
||||
import com.kamco.cd.kamcoback.postgres.entity.AuditLogEntity;
|
||||
import com.querydsl.core.types.Projections;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import com.querydsl.core.types.dsl.Expressions;
|
||||
import com.querydsl.core.types.dsl.StringExpression;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.kamco.cd.kamcoback.postgres.entity.QAuditLogEntity.auditLogEntity;
|
||||
import static com.kamco.cd.kamcoback.postgres.entity.QErrorLogEntity.errorLogEntity;
|
||||
import static com.kamco.cd.kamcoback.postgres.entity.QMenuEntity.menuEntity;
|
||||
import static com.kamco.cd.kamcoback.postgres.entity.QUserEntity.userEntity;
|
||||
|
||||
public class ErrorLogRepositoryImpl extends QuerydslRepositorySupport implements ErrorLogRepositoryCustom {
|
||||
private final JPAQueryFactory queryFactory;
|
||||
private final StringExpression NULL_STRING = Expressions.stringTemplate("cast(null as text)");
|
||||
|
||||
public ErrorLogRepositoryImpl(JPAQueryFactory queryFactory) {
|
||||
super(AuditLogEntity.class);
|
||||
this.queryFactory = queryFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<ErrorLogDto.Basic> findLogByError(ErrorLogDto.ErrorSearchReq searchReq) {
|
||||
Pageable pageable = searchReq.toPageable();
|
||||
List<ErrorLogDto.Basic> foundContent = queryFactory
|
||||
.select(
|
||||
Projections.constructor(
|
||||
ErrorLogDto.Basic.class,
|
||||
errorLogEntity.id.as("logId"),
|
||||
Expressions.constant("한국자산관리공사"), //serviceName
|
||||
menuEntity.menuNm.as("menuName"),
|
||||
userEntity.userId.as("loginId"),
|
||||
userEntity.userNm.as("userName"),
|
||||
errorLogEntity.errorType.as("eventType"),
|
||||
errorLogEntity.errorMessage.as("errorName"), // 기존에는 errorName 값이 있었는데 신규 테이블에는 없음. 에러 메세지와 동일
|
||||
errorLogEntity.errorLevel.as("errorLevel"),
|
||||
errorLogEntity.errorCode.as("errorCode"),
|
||||
errorLogEntity.errorMessage.as("errorMessage"),
|
||||
errorLogEntity.stackTrace.as("errorDetail"),
|
||||
errorLogEntity.createdDate
|
||||
)
|
||||
)
|
||||
.from(errorLogEntity)
|
||||
.leftJoin(auditLogEntity).on(errorLogEntity.id.eq(auditLogEntity.errorLogUid))
|
||||
.leftJoin(menuEntity).on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
|
||||
.leftJoin(userEntity).on(errorLogEntity.handlerUid.eq(userEntity.id))
|
||||
.where(
|
||||
eventStatusEqFailed(),
|
||||
eventEndedAtBetween(searchReq.getStartDate(), searchReq.getEndDate()),
|
||||
eventTypeEq(searchReq.getEventType()),
|
||||
errorLevelEq(searchReq.getErrorLevel())
|
||||
)
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize())
|
||||
.orderBy(errorLogEntity.createdDate.desc())
|
||||
.fetch();
|
||||
|
||||
Long countQuery = queryFactory
|
||||
.select(errorLogEntity.id.countDistinct())
|
||||
.from(errorLogEntity)
|
||||
.leftJoin(auditLogEntity).on(errorLogEntity.id.eq(auditLogEntity.errorLogUid))
|
||||
.leftJoin(menuEntity).on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
|
||||
.leftJoin(userEntity).on(errorLogEntity.handlerUid.eq(userEntity.id))
|
||||
.where(
|
||||
eventStatusEqFailed(),
|
||||
eventEndedAtBetween(searchReq.getStartDate(), searchReq.getEndDate()),
|
||||
eventTypeEq(searchReq.getEventType()),
|
||||
errorLevelEq(searchReq.getErrorLevel())
|
||||
)
|
||||
.fetchOne();
|
||||
|
||||
return new PageImpl<>(foundContent, pageable, countQuery);
|
||||
}
|
||||
|
||||
private BooleanExpression eventEndedAtBetween(LocalDate startDate, LocalDate endDate) {
|
||||
if (Objects.isNull(startDate) || Objects.isNull(endDate)) {
|
||||
return null;
|
||||
}
|
||||
LocalDateTime startDateTime = startDate.atStartOfDay();
|
||||
LocalDateTime endDateTime = endDate.plusDays(1).atStartOfDay();
|
||||
return auditLogEntity.createdDate.goe(ZonedDateTime.from(startDateTime))
|
||||
.and(auditLogEntity.createdDate.lt(ZonedDateTime.from(endDateTime)));
|
||||
}
|
||||
|
||||
private BooleanExpression eventStatusEqFailed() {
|
||||
return auditLogEntity.eventStatus.eq(EventStatus.FAILED);
|
||||
}
|
||||
|
||||
private BooleanExpression eventTypeEq(EventType eventType) {
|
||||
if (Objects.isNull(eventType)) {
|
||||
return null;
|
||||
}
|
||||
return auditLogEntity.eventType.eq(eventType);
|
||||
}
|
||||
|
||||
private BooleanExpression errorLevelEq(ErrorLogDto.LogErrorLevel level) {
|
||||
if (Objects.isNull(level)) {
|
||||
return null;
|
||||
}
|
||||
return errorLogEntity.errorLevel.eq(ErrorLogDto.LogErrorLevel.valueOf(level.name()));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user