로그에 메뉴코드 매핑하여 insert 하기

This commit is contained in:
2025-12-10 10:05:42 +09:00
parent e24f6801b3
commit c9094f04c2
13 changed files with 135 additions and 79 deletions

View File

@@ -79,6 +79,7 @@ dependencies {
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5' runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.5' // JSON (Jackson) runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.5' // JSON (Jackson)
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
} }
configurations.configureEach { configurations.configureEach {

View File

@@ -5,11 +5,13 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.time.Duration; import java.time.Duration;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager; import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; 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.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisConnectionFactory;
@@ -43,7 +45,8 @@ public class RedisConfig {
} }
/** Redis에서 사용할 공통 ObjectMapper */ /** Redis에서 사용할 공통 ObjectMapper */
@Bean @Bean(name = "redisObjectMapper")
@Primary
public ObjectMapper redisObjectMapper() { public ObjectMapper redisObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper(); ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule()); objectMapper.registerModule(new JavaTimeModule());
@@ -56,7 +59,8 @@ public class RedisConfig {
/** 공통 Serializer (Template + Cache 둘 다 이거 사용) */ /** 공통 Serializer (Template + Cache 둘 다 이거 사용) */
@Bean @Bean
public GenericJackson2JsonRedisSerializer redisSerializer(ObjectMapper redisObjectMapper) { public GenericJackson2JsonRedisSerializer redisSerializer(
@Qualifier("redisObjectMapper") ObjectMapper redisObjectMapper) {
return new GenericJackson2JsonRedisSerializer(redisObjectMapper); return new GenericJackson2JsonRedisSerializer(redisObjectMapper);
} }

View File

@@ -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.EventStatus;
import com.kamco.cd.kamcoback.log.dto.EventType; import com.kamco.cd.kamcoback.log.dto.EventType;
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.springframework.web.util.ContentCachingRequestWrapper; import org.springframework.web.util.ContentCachingRequestWrapper;
@@ -116,4 +118,15 @@ public class ApiLogFunction {
public static EventStatus isSuccessFail(ApiResponseDto<?> apiResponse) { public static EventStatus isSuccessFail(ApiResponseDto<?> apiResponse) {
return apiResponse.getHttpStatus().is2xxSuccessful() ? EventStatus.SUCCESS : EventStatus.FAILED; return apiResponse.getHttpStatus().is2xxSuccessful() ? EventStatus.SUCCESS : EventStatus.FAILED;
} }
public static String getUriMenuInfo(List<MenuDto.Basic> 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";
}
} }

View File

@@ -1,9 +1,15 @@
package com.kamco.cd.kamcoback.config.api; 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.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.entity.AuditLogEntity;
import com.kamco.cd.kamcoback.postgres.repository.log.AuditLogRepository; import com.kamco.cd.kamcoback.postgres.repository.log.AuditLogRepository;
import jakarta.servlet.http.HttpServletRequest; 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.core.MethodParameter;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter;
@@ -24,9 +30,13 @@ import org.springframework.web.util.ContentCachingRequestWrapper;
public class ApiResponseAdvice implements ResponseBodyAdvice<Object> { public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
private final AuditLogRepository auditLogRepository; 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.auditLogRepository = auditLogRepository;
this.menuService = menuService;
} }
@Override @Override
@@ -75,13 +85,28 @@ public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
String requestBody = ApiLogFunction.getRequestBody(servletRequest, contentWrapper); String requestBody = ApiLogFunction.getRequestBody(servletRequest, contentWrapper);
requestBody = maskSensitiveFields(requestBody); // 로그 저장전에 중요정보 마스킹 requestBody = maskSensitiveFields(requestBody); // 로그 저장전에 중요정보 마스킹
// TODO: menuUid 를 동적으로 가져오게끔 해야함 List<?> list = menuService.getFindAll();
List<MenuDto.Basic> 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 = AuditLogEntity log =
new AuditLogEntity( new AuditLogEntity(
userid, userid,
ApiLogFunction.getEventType(servletRequest), ApiLogFunction.getEventType(servletRequest),
ApiLogFunction.isSuccessFail(apiResponse), ApiLogFunction.isSuccessFail(apiResponse),
"MU_01_01", ApiLogFunction.getUriMenuInfo(result, servletRequest.getRequestURI()),
ip, ip,
servletRequest.getRequestURI(), servletRequest.getRequestURI(),
requestBody, requestBody,

View File

@@ -1,5 +1,7 @@
package com.kamco.cd.kamcoback.menu; 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.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.menu.dto.MenuDto; import com.kamco.cd.kamcoback.menu.dto.MenuDto;
import com.kamco.cd.kamcoback.menu.service.MenuService; 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.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.LinkedHashMap;
import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Tag(name = "메뉴 관리", description = "메뉴 관리 API") @Tag(name = "메뉴 관리", description = "메뉴 관리 API")
@RestController @RestController
@RequiredArgsConstructor @RequiredArgsConstructor
@@ -24,6 +28,8 @@ public class MenuApiController {
private final MenuService menuService; private final MenuService menuService;
@Autowired private ObjectMapper objectMapper;
@Operation(summary = "목록 조회", description = "모든 메뉴 조회") @Operation(summary = "목록 조회", description = "모든 메뉴 조회")
@ApiResponses( @ApiResponses(
value = { value = {
@@ -41,4 +47,25 @@ public class MenuApiController {
public ApiResponseDto<List<MenuDto.Basic>> getFindAll() { public ApiResponseDto<List<MenuDto.Basic>> getFindAll() {
return ApiResponseDto.ok(menuService.getFindAll()); return ApiResponseDto.ok(menuService.getFindAll());
} }
@GetMapping("/find-uri")
public ApiResponseDto<String> getFindAllByUid(@RequestParam String apiUri) {
List<?> list = menuService.getFindAll();
List<MenuDto.Basic> 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));
}
} }

View File

@@ -2,11 +2,10 @@ package com.kamco.cd.kamcoback.menu.dto;
import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm; import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.util.List; import java.util.List;
import lombok.Getter;
import lombok.NoArgsConstructor;
public class MenuDto { public class MenuDto {
@@ -27,11 +26,9 @@ public class MenuDto {
private List<MenuDto.Basic> children; private List<MenuDto.Basic> children;
@JsonFormatDttm @JsonFormatDttm private ZonedDateTime createdDttm;
private ZonedDateTime createdDttm;
@JsonFormatDttm @JsonFormatDttm private ZonedDateTime updatedDttm;
private ZonedDateTime updatedDttm;
private String menuApiUrl; private String menuApiUrl;

View File

@@ -2,19 +2,18 @@ package com.kamco.cd.kamcoback.menu.service;
import com.kamco.cd.kamcoback.menu.dto.MenuDto; import com.kamco.cd.kamcoback.menu.dto.MenuDto;
import com.kamco.cd.kamcoback.postgres.core.MenuCoreService; import com.kamco.cd.kamcoback.postgres.core.MenuCoreService;
import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class MenuService { public class MenuService {
private final MenuCoreService menuCoreService; private final MenuCoreService menuCoreService;
@Cacheable(value = "menuFindAll") @Cacheable(value = "menuFindAll")
public List<MenuDto.Basic> getFindAll(){ public List<MenuDto.Basic> getFindAll() {
return menuCoreService.getFindAll(); return menuCoreService.getFindAll();
} }
} }

View File

@@ -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.postgres.repository.code.CommonCodeRepository;
import com.kamco.cd.kamcoback.zoo.dto.AnimalDto.SearchReq; import com.kamco.cd.kamcoback.zoo.dto.AnimalDto.SearchReq;
import jakarta.persistence.EntityNotFoundException; import jakarta.persistence.EntityNotFoundException;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class CommonCodeCoreService public class CommonCodeCoreService
@@ -47,15 +46,13 @@ public class CommonCodeCoreService
String regex = "^([A-Z]+|[0-9]+|[A-Z0-9]+(_[A-Z0-9]+)+)$"; String regex = "^([A-Z]+|[0-9]+|[A-Z0-9]+(_[A-Z0-9]+)+)$";
boolean isValid = req.getCode().matches(regex); boolean isValid = req.getCode().matches(regex);
if (!isValid) { if (!isValid) {
return new ResponseObj( return new ResponseObj(ApiResponseCode.CONFLICT, "공통코드에 영문 대문자, 숫자, 언더바(_)만 입력 가능합니다.");
ApiResponseCode.CONFLICT, "공통코드에 영문 대문자, 숫자, 언더바(_)만 입력 가능합니다.");
} }
Long existsCount = Long existsCount =
commonCodeRepository.findByParentIdCodeExists(req.getParentId(), req.getCode()); commonCodeRepository.findByParentIdCodeExists(req.getParentId(), req.getCode());
if (existsCount > 0) { if (existsCount > 0) {
return new ResponseObj( return new ResponseObj(ApiResponseCode.DUPLICATE_DATA, "이미 사용중인 공통코드ID 입니다.");
ApiResponseCode.DUPLICATE_DATA, "이미 사용중인 공통코드ID 입니다.");
} }
CommonCodeEntity entity = CommonCodeEntity entity =
@@ -208,13 +205,11 @@ public class CommonCodeCoreService
String regex = "^([A-Z]+|[0-9]+|[A-Z0-9]+(_[A-Z0-9]+)+)$"; String regex = "^([A-Z]+|[0-9]+|[A-Z0-9]+(_[A-Z0-9]+)+)$";
boolean isValid = code.matches(regex); boolean isValid = code.matches(regex);
if (!isValid) { if (!isValid) {
return new ResponseObj( return new ResponseObj(ApiResponseCode.CONFLICT, "공통코드에 영문 대문자, 숫자, 언더바(_)만 입력 가능합니다.");
ApiResponseCode.CONFLICT, "공통코드에 영문 대문자, 숫자, 언더바(_)만 입력 가능합니다.");
} }
if (existsCount > 0) { if (existsCount > 0) {
return new ResponseObj( return new ResponseObj(ApiResponseCode.DUPLICATE_DATA, "이미 사용중인 공통코드ID 입니다.");
ApiResponseCode.DUPLICATE_DATA, "이미 사용중인 공통코드ID 입니다.");
} }
return new ResponseObj(ApiResponseCode.OK, ""); return new ResponseObj(ApiResponseCode.OK, "");

View File

@@ -3,11 +3,10 @@ package com.kamco.cd.kamcoback.postgres.core;
import com.kamco.cd.kamcoback.menu.dto.MenuDto; import com.kamco.cd.kamcoback.menu.dto.MenuDto;
import com.kamco.cd.kamcoback.postgres.entity.MenuEntity; import com.kamco.cd.kamcoback.postgres.entity.MenuEntity;
import com.kamco.cd.kamcoback.postgres.repository.menu.MenuRepository; import com.kamco.cd.kamcoback.postgres.repository.menu.MenuRepository;
import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class MenuCoreService { public class MenuCoreService {

View File

@@ -52,7 +52,7 @@ public class MenuEntity extends CommonDateEntity {
@Column(name = "menu_api_uri") @Column(name = "menu_api_uri")
private String menuApiUri; private String menuApiUri;
public MenuDto.Basic toDto(){ public MenuDto.Basic toDto() {
return new MenuDto.Basic( return new MenuDto.Basic(
this.menuUid, this.menuUid,
this.menuNm, this.menuNm,
@@ -66,7 +66,6 @@ public class MenuEntity extends CommonDateEntity {
this.children.stream().map(MenuEntity::toDto).toList(), this.children.stream().map(MenuEntity::toDto).toList(),
this.getCreatedDate(), this.getCreatedDate(),
this.getModifiedDate(), this.getModifiedDate(),
this.menuApiUri this.menuApiUri);
);
} }
} }

View File

@@ -5,6 +5,7 @@ import com.kamco.cd.kamcoback.postgres.CommonDateEntity;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import org.hibernate.annotations.ColumnDefault; import org.hibernate.annotations.ColumnDefault;
@@ -12,6 +13,7 @@ import org.hibernate.annotations.ColumnDefault;
@Setter @Setter
@Entity @Entity
@Table(name = "tb_model_mng") @Table(name = "tb_model_mng")
@NoArgsConstructor
public class ModelMngEntity extends CommonDateEntity { public class ModelMngEntity extends CommonDateEntity {
@Id @Id

View File

@@ -1,7 +1,6 @@
package com.kamco.cd.kamcoback.postgres.repository.menu; package com.kamco.cd.kamcoback.postgres.repository.menu;
import com.kamco.cd.kamcoback.postgres.entity.MenuEntity; import com.kamco.cd.kamcoback.postgres.entity.MenuEntity;
import java.util.List; import java.util.List;
public interface MenuRepositoryCustom { public interface MenuRepositoryCustom {

View File

@@ -1,14 +1,13 @@
package com.kamco.cd.kamcoback.postgres.repository.menu; 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.kamco.cd.kamcoback.postgres.entity.MenuEntity;
import com.querydsl.core.types.dsl.Expressions; import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.StringExpression; import com.querydsl.core.types.dsl.StringExpression;
import com.querydsl.jpa.impl.JPAQueryFactory; import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import java.util.List; import java.util.List;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import static com.kamco.cd.kamcoback.postgres.entity.QMenuEntity.menuEntity;
public class MenuRepositoryImpl extends QuerydslRepositorySupport implements MenuRepositoryCustom { public class MenuRepositoryImpl extends QuerydslRepositorySupport implements MenuRepositoryCustom {
@@ -22,9 +21,6 @@ public class MenuRepositoryImpl extends QuerydslRepositorySupport implements Men
@Override @Override
public List<MenuEntity> getFindAll() { public List<MenuEntity> getFindAll() {
return queryFactory return queryFactory.selectFrom(menuEntity).where(menuEntity.deleted.isFalse()).fetch();
.selectFrom(menuEntity)
.where(menuEntity.deleted.isFalse())
.fetch();
} }
} }