diff --git a/build.gradle b/build.gradle index d6193233..836a952d 100644 --- a/build.gradle +++ b/build.gradle @@ -79,6 +79,7 @@ dependencies { runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5' runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.5' // JSON (Jackson) + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' } configurations.configureEach { diff --git a/src/main/java/com/kamco/cd/kamcoback/config/RedisConfig.java b/src/main/java/com/kamco/cd/kamcoback/config/RedisConfig.java index 306c8637..c67ed10d 100644 --- a/src/main/java/com/kamco/cd/kamcoback/config/RedisConfig.java +++ b/src/main/java/com/kamco/cd/kamcoback/config/RedisConfig.java @@ -5,11 +5,13 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import java.time.Duration; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; @@ -43,7 +45,8 @@ public class RedisConfig { } /** Redis에서 사용할 공통 ObjectMapper */ - @Bean + @Bean(name = "redisObjectMapper") + @Primary public ObjectMapper redisObjectMapper() { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new JavaTimeModule()); @@ -56,7 +59,8 @@ public class RedisConfig { /** 공통 Serializer (Template + Cache 둘 다 이거 사용) */ @Bean - public GenericJackson2JsonRedisSerializer redisSerializer(ObjectMapper redisObjectMapper) { + public GenericJackson2JsonRedisSerializer redisSerializer( + @Qualifier("redisObjectMapper") ObjectMapper redisObjectMapper) { return new GenericJackson2JsonRedisSerializer(redisObjectMapper); } diff --git a/src/main/java/com/kamco/cd/kamcoback/config/api/ApiLogFunction.java b/src/main/java/com/kamco/cd/kamcoback/config/api/ApiLogFunction.java index e4d6ae41..43a78ac7 100644 --- a/src/main/java/com/kamco/cd/kamcoback/config/api/ApiLogFunction.java +++ b/src/main/java/com/kamco/cd/kamcoback/config/api/ApiLogFunction.java @@ -2,8 +2,10 @@ package com.kamco.cd.kamcoback.config.api; import com.kamco.cd.kamcoback.log.dto.EventStatus; import com.kamco.cd.kamcoback.log.dto.EventType; +import com.kamco.cd.kamcoback.menu.dto.MenuDto; import jakarta.servlet.http.HttpServletRequest; import java.io.UnsupportedEncodingException; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.springframework.web.util.ContentCachingRequestWrapper; @@ -116,4 +118,15 @@ public class ApiLogFunction { public static EventStatus isSuccessFail(ApiResponseDto apiResponse) { return apiResponse.getHttpStatus().is2xxSuccessful() ? EventStatus.SUCCESS : EventStatus.FAILED; } + + public static String getUriMenuInfo(List menuList, String uri) { + + MenuDto.Basic m = + menuList.stream() + .filter(menu -> menu.getMenuApiUrl() != null && uri.contains(menu.getMenuApiUrl())) + .findFirst() + .orElse(null); + + return m != null ? m.getMenuUid() : "SYSTEM"; + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/config/api/ApiResponseAdvice.java b/src/main/java/com/kamco/cd/kamcoback/config/api/ApiResponseAdvice.java index 70d48e3d..e6d1f12f 100644 --- a/src/main/java/com/kamco/cd/kamcoback/config/api/ApiResponseAdvice.java +++ b/src/main/java/com/kamco/cd/kamcoback/config/api/ApiResponseAdvice.java @@ -1,9 +1,15 @@ package com.kamco.cd.kamcoback.config.api; +import com.fasterxml.jackson.databind.ObjectMapper; import com.kamco.cd.kamcoback.auth.CustomUserDetails; +import com.kamco.cd.kamcoback.menu.dto.MenuDto; +import com.kamco.cd.kamcoback.menu.service.MenuService; import com.kamco.cd.kamcoback.postgres.entity.AuditLogEntity; import com.kamco.cd.kamcoback.postgres.repository.log.AuditLogRepository; import jakarta.servlet.http.HttpServletRequest; +import java.util.LinkedHashMap; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; @@ -24,9 +30,13 @@ import org.springframework.web.util.ContentCachingRequestWrapper; public class ApiResponseAdvice implements ResponseBodyAdvice { private final AuditLogRepository auditLogRepository; + private final MenuService menuService; - public ApiResponseAdvice(AuditLogRepository auditLogRepository) { + @Autowired private ObjectMapper objectMapper; + + public ApiResponseAdvice(AuditLogRepository auditLogRepository, MenuService menuService) { this.auditLogRepository = auditLogRepository; + this.menuService = menuService; } @Override @@ -75,13 +85,28 @@ public class ApiResponseAdvice implements ResponseBodyAdvice { String requestBody = ApiLogFunction.getRequestBody(servletRequest, contentWrapper); requestBody = maskSensitiveFields(requestBody); // 로그 저장전에 중요정보 마스킹 - // TODO: menuUid 를 동적으로 가져오게끔 해야함 + List list = menuService.getFindAll(); + + List result = + list.stream() + .map( + item -> { + if (item instanceof LinkedHashMap map) { + return objectMapper.convertValue(map, MenuDto.Basic.class); + } else if (item instanceof MenuDto.Basic dto) { + return dto; + } else { + throw new IllegalStateException("Unsupported cache type: " + item.getClass()); + } + }) + .toList(); + AuditLogEntity log = new AuditLogEntity( userid, ApiLogFunction.getEventType(servletRequest), ApiLogFunction.isSuccessFail(apiResponse), - "MU_01_01", + ApiLogFunction.getUriMenuInfo(result, servletRequest.getRequestURI()), ip, servletRequest.getRequestURI(), requestBody, diff --git a/src/main/java/com/kamco/cd/kamcoback/menu/MenuApiController.java b/src/main/java/com/kamco/cd/kamcoback/menu/MenuApiController.java index f1efef44..6af3435b 100644 --- a/src/main/java/com/kamco/cd/kamcoback/menu/MenuApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/menu/MenuApiController.java @@ -1,5 +1,7 @@ package com.kamco.cd.kamcoback.menu; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.kamco.cd.kamcoback.config.api.ApiLogFunction; import com.kamco.cd.kamcoback.config.api.ApiResponseDto; import com.kamco.cd.kamcoback.menu.dto.MenuDto; import com.kamco.cd.kamcoback.menu.service.MenuService; @@ -9,13 +11,15 @@ 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 java.util.LinkedHashMap; +import java.util.List; import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; 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.util.List; - @Tag(name = "메뉴 관리", description = "메뉴 관리 API") @RestController @RequiredArgsConstructor @@ -24,21 +28,44 @@ public class MenuApiController { private final MenuService menuService; + @Autowired private ObjectMapper objectMapper; + @Operation(summary = "목록 조회", description = "모든 메뉴 조회") @ApiResponses( - value = { - @ApiResponse( - responseCode = "200", - description = "조회 성공", - content = - @Content( - mediaType = "application/json", - schema = @Schema(implementation = MenuDto.Basic.class))), - @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), - @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - }) + value = { + @ApiResponse( + responseCode = "200", + description = "조회 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = MenuDto.Basic.class))), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) @GetMapping public ApiResponseDto> getFindAll() { return ApiResponseDto.ok(menuService.getFindAll()); } + + @GetMapping("/find-uri") + public ApiResponseDto getFindAllByUid(@RequestParam String apiUri) { + List list = menuService.getFindAll(); + + List result = + list.stream() + .map( + item -> { + if (item instanceof LinkedHashMap map) { + return objectMapper.convertValue(map, MenuDto.Basic.class); + } else if (item instanceof MenuDto.Basic dto) { + return dto; + } else { + throw new IllegalStateException("Unsupported cache type: " + item.getClass()); + } + }) + .toList(); + + return ApiResponseDto.ok(ApiLogFunction.getUriMenuInfo(result, apiUri)); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/menu/dto/MenuDto.java b/src/main/java/com/kamco/cd/kamcoback/menu/dto/MenuDto.java index 4657cecf..445a1684 100644 --- a/src/main/java/com/kamco/cd/kamcoback/menu/dto/MenuDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/menu/dto/MenuDto.java @@ -2,11 +2,10 @@ package com.kamco.cd.kamcoback.menu.dto; import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Getter; -import lombok.NoArgsConstructor; - import java.time.ZonedDateTime; import java.util.List; +import lombok.Getter; +import lombok.NoArgsConstructor; public class MenuDto { @@ -27,28 +26,26 @@ public class MenuDto { private List children; - @JsonFormatDttm - private ZonedDateTime createdDttm; + @JsonFormatDttm private ZonedDateTime createdDttm; - @JsonFormatDttm - private ZonedDateTime updatedDttm; + @JsonFormatDttm private ZonedDateTime updatedDttm; private String menuApiUrl; public Basic( - String menuUid, - String menuNm, - String menuUrl, - String description, - Long menuOrder, - Boolean isUse, - Boolean deleted, - Long createdUid, - Long updatedUid, - List children, - ZonedDateTime createdDttm, - ZonedDateTime updatedDttm, - String menuApiUrl) { + String menuUid, + String menuNm, + String menuUrl, + String description, + Long menuOrder, + Boolean isUse, + Boolean deleted, + Long createdUid, + Long updatedUid, + List children, + ZonedDateTime createdDttm, + ZonedDateTime updatedDttm, + String menuApiUrl) { this.menuUid = menuUid; this.menuNm = menuNm; this.menuUrl = menuUrl; diff --git a/src/main/java/com/kamco/cd/kamcoback/menu/service/MenuService.java b/src/main/java/com/kamco/cd/kamcoback/menu/service/MenuService.java index 6eb05aae..1e05390c 100644 --- a/src/main/java/com/kamco/cd/kamcoback/menu/service/MenuService.java +++ b/src/main/java/com/kamco/cd/kamcoback/menu/service/MenuService.java @@ -2,19 +2,18 @@ package com.kamco.cd.kamcoback.menu.service; import com.kamco.cd.kamcoback.menu.dto.MenuDto; import com.kamco.cd.kamcoback.postgres.core.MenuCoreService; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; -import java.util.List; - @Service @RequiredArgsConstructor public class MenuService { private final MenuCoreService menuCoreService; @Cacheable(value = "menuFindAll") - public List getFindAll(){ + public List getFindAll() { return menuCoreService.getFindAll(); } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/CommonCodeCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/CommonCodeCoreService.java index c9b81605..b3541ed9 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/CommonCodeCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/CommonCodeCoreService.java @@ -9,15 +9,14 @@ import com.kamco.cd.kamcoback.postgres.entity.CommonCodeEntity; import com.kamco.cd.kamcoback.postgres.repository.code.CommonCodeRepository; import com.kamco.cd.kamcoback.zoo.dto.AnimalDto.SearchReq; import jakarta.persistence.EntityNotFoundException; +import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Optional; - @Service @RequiredArgsConstructor public class CommonCodeCoreService @@ -47,15 +46,13 @@ public class CommonCodeCoreService String regex = "^([A-Z]+|[0-9]+|[A-Z0-9]+(_[A-Z0-9]+)+)$"; boolean isValid = req.getCode().matches(regex); if (!isValid) { - return new ResponseObj( - ApiResponseCode.CONFLICT, "공통코드에 영문 대문자, 숫자, 언더바(_)만 입력 가능합니다."); + return new ResponseObj(ApiResponseCode.CONFLICT, "공통코드에 영문 대문자, 숫자, 언더바(_)만 입력 가능합니다."); } Long existsCount = commonCodeRepository.findByParentIdCodeExists(req.getParentId(), req.getCode()); if (existsCount > 0) { - return new ResponseObj( - ApiResponseCode.DUPLICATE_DATA, "이미 사용중인 공통코드ID 입니다."); + return new ResponseObj(ApiResponseCode.DUPLICATE_DATA, "이미 사용중인 공통코드ID 입니다."); } CommonCodeEntity entity = @@ -208,13 +205,11 @@ public class CommonCodeCoreService String regex = "^([A-Z]+|[0-9]+|[A-Z0-9]+(_[A-Z0-9]+)+)$"; boolean isValid = code.matches(regex); if (!isValid) { - return new ResponseObj( - ApiResponseCode.CONFLICT, "공통코드에 영문 대문자, 숫자, 언더바(_)만 입력 가능합니다."); + return new ResponseObj(ApiResponseCode.CONFLICT, "공통코드에 영문 대문자, 숫자, 언더바(_)만 입력 가능합니다."); } if (existsCount > 0) { - return new ResponseObj( - ApiResponseCode.DUPLICATE_DATA, "이미 사용중인 공통코드ID 입니다."); + return new ResponseObj(ApiResponseCode.DUPLICATE_DATA, "이미 사용중인 공통코드ID 입니다."); } return new ResponseObj(ApiResponseCode.OK, ""); diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/MenuCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MenuCoreService.java index 627df05b..d6b7eece 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/MenuCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MenuCoreService.java @@ -3,11 +3,10 @@ package com.kamco.cd.kamcoback.postgres.core; import com.kamco.cd.kamcoback.menu.dto.MenuDto; import com.kamco.cd.kamcoback.postgres.entity.MenuEntity; import com.kamco.cd.kamcoback.postgres.repository.menu.MenuRepository; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import java.util.List; - @Service @RequiredArgsConstructor public class MenuCoreService { diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MenuEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MenuEntity.java index 3c6b7fc1..15c98cea 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MenuEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MenuEntity.java @@ -52,21 +52,20 @@ public class MenuEntity extends CommonDateEntity { @Column(name = "menu_api_uri") private String menuApiUri; - public MenuDto.Basic toDto(){ + public MenuDto.Basic toDto() { return new MenuDto.Basic( - this.menuUid, - this.menuNm, - this.menuUrl, - this.description, - this.menuOrder, - this.isUse, - this.deleted, - this.createdUid, - this.updatedUid, - this.children.stream().map(MenuEntity::toDto).toList(), - this.getCreatedDate(), - this.getModifiedDate(), - this.menuApiUri - ); + this.menuUid, + this.menuNm, + this.menuUrl, + this.description, + this.menuOrder, + this.isUse, + this.deleted, + this.createdUid, + this.updatedUid, + this.children.stream().map(MenuEntity::toDto).toList(), + this.getCreatedDate(), + this.getModifiedDate(), + this.menuApiUri); } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/ModelMngEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/ModelMngEntity.java index 98bef0ea..af04caae 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/ModelMngEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/ModelMngEntity.java @@ -5,6 +5,7 @@ import com.kamco.cd.kamcoback.postgres.CommonDateEntity; import jakarta.persistence.*; import jakarta.validation.constraints.Size; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import org.hibernate.annotations.ColumnDefault; @@ -12,6 +13,7 @@ import org.hibernate.annotations.ColumnDefault; @Setter @Entity @Table(name = "tb_model_mng") +@NoArgsConstructor public class ModelMngEntity extends CommonDateEntity { @Id diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/menu/MenuRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/menu/MenuRepositoryCustom.java index 9cfa8567..1e0fdf28 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/menu/MenuRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/menu/MenuRepositoryCustom.java @@ -1,7 +1,6 @@ package com.kamco.cd.kamcoback.postgres.repository.menu; import com.kamco.cd.kamcoback.postgres.entity.MenuEntity; - import java.util.List; public interface MenuRepositoryCustom { diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/menu/MenuRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/menu/MenuRepositoryImpl.java index 0c3c9471..60fde677 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/menu/MenuRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/menu/MenuRepositoryImpl.java @@ -1,14 +1,13 @@ package com.kamco.cd.kamcoback.postgres.repository.menu; +import static com.kamco.cd.kamcoback.postgres.entity.QMenuEntity.menuEntity; + import com.kamco.cd.kamcoback.postgres.entity.MenuEntity; import com.querydsl.core.types.dsl.Expressions; import com.querydsl.core.types.dsl.StringExpression; import com.querydsl.jpa.impl.JPAQueryFactory; -import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport; - import java.util.List; - -import static com.kamco.cd.kamcoback.postgres.entity.QMenuEntity.menuEntity; +import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport; public class MenuRepositoryImpl extends QuerydslRepositorySupport implements MenuRepositoryCustom { @@ -16,15 +15,12 @@ public class MenuRepositoryImpl extends QuerydslRepositorySupport implements Men private final StringExpression NULL_STRING = Expressions.stringTemplate("cast(null as text)"); public MenuRepositoryImpl(JPAQueryFactory queryFactory) { - super(MenuEntity.class); + super(MenuEntity.class); this.queryFactory = queryFactory; } @Override public List getFindAll() { - return queryFactory - .selectFrom(menuEntity) - .where(menuEntity.deleted.isFalse()) - .fetch(); + return queryFactory.selectFrom(menuEntity).where(menuEntity.deleted.isFalse()).fetch(); } }