Compare commits

..

18 Commits

Author SHA1 Message Date
abd99cd1a5 전투시스템 종료시간 추가 2025-06-27 09:32:29 +09:00
a06e625cbd 엑셀 csv 형식으로 변경
전투시스템 종료시간 추가
메모리 버퍼 정리
2025-06-27 09:32:15 +09:00
1129f4017f 설정관련 수정
docker 환경설정
2025-06-27 09:30:22 +09:00
cfe9a7160d 메뉴배너 관련 수정 2025-06-27 09:29:58 +09:00
f979d4fa34 json 로드 방식 list name 제거
게임모드 로드
게임 FFA 데이터 로드
2025-06-19 18:55:44 +09:00
daf13e5e59 json 로드 방식 list name 제거
게임모드 로드
게임 FFA 데이터 로드
2025-06-19 18:55:23 +09:00
ccfa1d3afa json 로드 방식 list name 제거
게임모드 로드
게임 FFA 데이터 로드
2025-06-19 18:55:15 +09:00
4de51b663d 전투이벤트 중지 항목도 종료일자 지나면 상태종료 변경
종료된지 한달이상된 전투이벤트,이벤트우편 dynamodb 정보 삭제
전투이벤트 id 운영툴 기준으로 변경
2025-06-18 14:38:43 +09:00
1784c750f3 메타데이터 로드 폴더 방식 추가 2025-06-16 15:40:22 +09:00
b1fbd556e2 재화 로그 액션, 재화종류, 증감유형 조건 추가
재화 로그 잔량 필드 추가
재화 지표 export 추가
2025-06-16 15:40:04 +09:00
2f9ea432f4 메타데이터 패치 수정 2025-06-16 15:37:07 +09:00
7e97bf9fc9 currency api 추가 2025-06-12 14:20:13 +09:00
b14010f77b mongodb currency 관련 작업
currency 작업 스케줄 추가
2025-06-12 14:19:49 +09:00
bef9c41f31 공통 수정 2025-06-12 14:18:41 +09:00
ab7c6e53fe AmountDeltaType 추가
getInvenItems 예외 처리 추가
2025-06-12 14:17:51 +09:00
23850acf0f 캐시 handler 생성
로그 조회 갯수 캐싱 처리
로그 객체 생성
로그 엑셀 객체 생성
엑셀 진행률 관리 tracker 생성
2025-06-05 12:09:50 +09:00
fa67ae5e7c redis prefix 추가 2025-06-05 12:05:24 +09:00
8353c6c97d docker 환경변수 수정 2025-06-05 12:04:56 +09:00
86 changed files with 4756 additions and 491 deletions

View File

@@ -3,6 +3,36 @@ FROM openjdk:17-jdk-slim
ARG JAR_FILE=build/libs/CaliverseAdminAPI-dev.jar
COPY ${JAR_FILE} admintool.jar
#메모리 최소 2기가 최대 4기가
ENV JAVA_OPTS="-Xms2g -Xmx4g"
ENTRYPOINT ["java","-Dspring.profiles.active=dev","-jar","/admintool.jar"]
ENTRYPOINT ["java", \
"-Xms1g", \
"-Xmx2g", \
# GC 설정 (G1GC 최적화)
"-XX:+UseG1GC", \
"-XX:MaxGCPauseMillis=100", \
"-XX:G1HeapRegionSize=8m", \
"-XX:InitiatingHeapOccupancyPercent=20", \
# OutOfMemoryError 대응
"-XX:+HeapDumpOnOutOfMemoryError", \
"-XX:HeapDumpPath=/logs/heapdump-%t.hprof", \
"-XX:+ExitOnOutOfMemoryError", \
# GC 로깅 (문제 분석용)
"-Xlog:gc*:logs/gc.log:time,tags", \
"-XX:+UseStringDeduplication", \
# 메모리 최적화
"-XX:+UseCompressedOops", \
"-XX:+UseCompressedClassPointers", \
"-XX:+UseStringDeduplication", \
"-XX:MaxMetaspaceSize=256m", \
# 네트워크 최적화
"-Djava.net.preferIPv4Stack=true", \
"-Djava.io.tmpdir=/tmp", \
"-Dfile.encoding=UTF-8", \
"-Djava.awt.headless=true", \
"-Dspring.profiles.active=dev", \
"-jar", "/admintool.jar"]

View File

@@ -3,6 +3,38 @@ FROM openjdk:17
ARG JAR_FILE=build/libs/CaliverseAdminAPI-live.jar
COPY ${JAR_FILE} admintool.jar
#메모리 최소 2기가 최대 4기가
ENV JAVA_OPTS="-Xms2g -Xmx4g"
ENTRYPOINT ["java","-Dspring.profiles.active=live","-jar","/admintool.jar"]
ENTRYPOINT ["java", \
# 메모리 설정
"-Xms1g", \
"-Xmx4g", \
# GC 설정 (G1GC 최적화)
"-XX:+UseG1GC", \
"-XX:MaxGCPauseMillis=100", \
"-XX:G1HeapRegionSize=8m", \
"-XX:InitiatingHeapOccupancyPercent=20", \
# OutOfMemoryError 대응
"-XX:+HeapDumpOnOutOfMemoryError", \
"-XX:HeapDumpPath=/logs/heapdump-%t.hprof", \
"-XX:+ExitOnOutOfMemoryError", \
# GC 로깅 (문제 분석용)
"-Xlog:gc*:logs/gc.log:time,tags", \
"-XX:+UseStringDeduplication", \
# 메모리 최적화
"-XX:+UseCompressedOops", \
"-XX:+UseCompressedClassPointers", \
"-XX:+UseStringDeduplication", \
"-XX:MaxMetaspaceSize=256m", \
# 네트워크 최적화
"-Djava.net.preferIPv4Stack=true", \
"-Djava.io.tmpdir=/tmp", \
"-Dfile.encoding=UTF-8", \
"-Djava.awt.headless=true", \
"-Dspring.profiles.active=live", \
"-jar", "/admintool.jar"]

View File

@@ -3,6 +3,36 @@ FROM openjdk:17
ARG JAR_FILE=build/libs/CaliverseAdminAPI-qa.jar
COPY ${JAR_FILE} admintool.jar
#메모리 최소 2기가 최대 4기가
ENV JAVA_OPTS="-Xms2g -Xmx4g"
ENTRYPOINT ["java","-Dspring.profiles.active=qa","-jar","/admintool.jar"]
ENTRYPOINT ["java", \
"-Xms1g", \
"-Xmx2g", \
# GC 설정 (G1GC 최적화)
"-XX:+UseG1GC", \
"-XX:MaxGCPauseMillis=100", \
"-XX:G1HeapRegionSize=8m", \
"-XX:InitiatingHeapOccupancyPercent=20", \
# OutOfMemoryError 대응
"-XX:+HeapDumpOnOutOfMemoryError", \
"-XX:HeapDumpPath=/logs/heapdump-%t.hprof", \
"-XX:+ExitOnOutOfMemoryError", \
# GC 로깅 (문제 분석용)
"-Xlog:gc*:logs/gc.log:time,tags", \
"-XX:+UseStringDeduplication", \
# 메모리 최적화
"-XX:+UseCompressedOops", \
"-XX:+UseCompressedClassPointers", \
"-XX:+UseStringDeduplication", \
"-XX:MaxMetaspaceSize=256m", \
# 네트워크 최적화
"-Djava.net.preferIPv4Stack=true", \
"-Djava.io.tmpdir=/tmp", \
"-Dfile.encoding=UTF-8", \
"-Djava.awt.headless=true", \
"-Dspring.profiles.active=qa", \
"-jar", "/admintool.jar"]

View File

@@ -3,6 +3,37 @@ FROM openjdk:17
ARG JAR_FILE=build/libs/CaliverseAdminAPI-stage.jar
COPY ${JAR_FILE} admintool.jar
#메모리 최소 2기가 최대 4기가
ENV JAVA_OPTS="-Xms2g -Xmx4g"
ENTRYPOINT ["java","-Dspring.profiles.active=stage","-jar","/admintool.jar"]
ENTRYPOINT ["java", \
"-Xms1g", \
"-Xmx4g", \
# GC 설정 (G1GC 최적화)
"-XX:+UseG1GC", \
"-XX:MaxGCPauseMillis=100", \
"-XX:G1HeapRegionSize=8m", \
"-XX:InitiatingHeapOccupancyPercent=20", \
# OutOfMemoryError 대응
"-XX:+HeapDumpOnOutOfMemoryError", \
"-XX:HeapDumpPath=/logs/heapdump-%t.hprof", \
"-XX:+ExitOnOutOfMemoryError", \
# GC 로깅 (문제 분석용)
"-Xlog:gc*:logs/gc.log:time,tags", \
"-XX:+UseStringDeduplication", \
# 메모리 최적화
"-XX:+UseCompressedOops", \
"-XX:+UseCompressedClassPointers", \
"-XX:+UseStringDeduplication", \
"-XX:MaxMetaspaceSize=256m", \
# 네트워크 최적화
"-Djava.net.preferIPv4Stack=true", \
"-Djava.io.tmpdir=/tmp", \
"-Dfile.encoding=UTF-8", \
"-Djava.awt.headless=true", \
"-Dspring.profiles.active=stage", \
"-jar", "/admintool.jar"]

View File

@@ -9,7 +9,7 @@ pipeline {
DOCKER_NAME = 'admintool-back-live'
DOCKER_PORT = '23450'
DOCKERFILE_NAME = 'Dockerfile.live'
META_FOLDER = 'metadata/*'
META_FOLDER = 'metadata/**'
REMOTE_META_FOLDER = 'admintool'
}
@@ -135,6 +135,12 @@ pipeline {
--name ${DOCKER_NAME} \
--restart=always \
--log-opt max-size=10m \
--memory=6g \
--memory-swap=6g \
--cpus="1.8" \
--cpu-shares=1024 \
--oom-kill-disable=false \
--oom-score-adj=100 \
-e TZ=\${TZ:-Asia/Seoul} \
-v ./admintool/log:/logs \
-v ./admintool/upload:/upload \

View File

@@ -9,7 +9,7 @@ pipeline {
DOCKER_NAME = 'admintool-back-qa'
DOCKER_PORT = '23450'
DOCKERFILE_NAME = 'Dockerfile.qa'
META_FOLDER = 'metadata/*'
META_FOLDER = 'metadata/**'
REMOTE_META_FOLDER = 'admintool'
}

View File

@@ -9,7 +9,7 @@ pipeline {
DOCKER_NAME = 'admintool-back-stage'
DOCKER_PORT = '23450'
DOCKERFILE_NAME = 'Dockerfile.stage'
META_FOLDER = 'metadata/*'
META_FOLDER = 'metadata/**'
REMOTE_META_FOLDER = 'admintool'
}
@@ -135,6 +135,12 @@ pipeline {
--name ${DOCKER_NAME} \
--restart=always \
--log-opt max-size=10m \
--memory=6g \
--memory-swap=6g \
--cpus="1.8" \
--cpu-shares=1024 \
--oom-kill-disable=false \
--oom-score-adj=100 \
-e TZ=\${TZ:-Asia/Seoul} \
-v ./admintool/log:/logs \
-v ./admintool/upload:/upload \

View File

@@ -1,5 +1,6 @@
package com.caliverse.admin.Indicators.Indicatorsservice.aggregationservice;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -25,7 +26,8 @@ public class IndicatorsAuLoadService extends IndicatorsLogLoadServiceBase {
public <T extends IndicatorsLog> List<T> getIndicatorsLogData(String startTime, String endTime, Class<T> clazz) {
Criteria criteria = makeCriteria(startTime, endTime);
List<AggregationOperation> operations = setDefaultOperation(criteria);
// List<AggregationOperation> operations = setDefaultOperation(criteria);
List<AggregationOperation> operations = new ArrayList<>();
Aggregation aggregation = Aggregation.newAggregation(operations);

View File

@@ -1,19 +1,12 @@
package com.caliverse.admin.Indicators.Indicatorsservice.base;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;
import com.caliverse.admin.global.common.constants.AdminConstants;
@Service
public abstract class IndicatorsLogLoadServiceBase implements IndicatorsLogLoadService {
@@ -37,31 +30,6 @@ public abstract class IndicatorsLogLoadServiceBase implements IndicatorsLogLoadS
{
return makeCriteria(startDate, endDate, AdminConstants.MONGO_DB_KEY_LOGTIME);
}
// 24.12.13 현재 사용안함
private AggregationOperation getDefaultProjectOperationName(){
ProjectionOperation projectOperation = Aggregation.project()
.and(AdminConstants.MONGO_DB_KEY_LOGDAY).as(AdminConstants.MONGO_DB_KEY_LOGDAY)
.and(AdminConstants.INDICATORS_KEY_DAU_BY_LANG).as(AdminConstants.INDICATORS_KEY_DAU_BY_LANG)
;
return projectOperation;
}
// 24.12.13 현재 사용안함
protected List<AggregationOperation> setDefaultOperation(Criteria criteria){
List<AggregationOperation> operations = new ArrayList<>();
operations.add(Aggregation.match(criteria));
operations.add(getDefaultProjectOperationName());
return operations;
}
}

View File

@@ -0,0 +1,53 @@
package com.caliverse.admin.Indicators.entity;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.mongodb.core.mapping.Document;
@Getter
@Setter
@Document(collection = "currency")
public class CurrencyDetailLogInfo extends LogInfoBase{
private String id;
private String logDay;
private String accountId;
private String userGuid;
private String userNickname;
private String tranId;
private String action;
private String logTime;
private String currencyType;
private String amountDeltaType;
private Double deltaAmount;
private Double currencyAmount;
public CurrencyDetailLogInfo(String id,
String logDay,
String accountId,
String userGuid,
String userNickname,
String tranId,
String action,
String logTime,
String currencyType,
String amountDeltaType,
Double deltaAmount,
Double currencyAmount
) {
super(StatisticsType.CURRENCY);
this.id = id;
this.logDay = logDay;
this.accountId = accountId;
this.userGuid = userGuid;
this.userNickname = userNickname;
this.tranId = tranId;
this.action = action;
this.logTime = logTime;
this.currencyType = currencyType;
this.amountDeltaType = amountDeltaType;
this.deltaAmount = deltaAmount;
this.currencyAmount = currencyAmount;
}
}

View File

@@ -0,0 +1,84 @@
package com.caliverse.admin.Indicators.entity;
import com.caliverse.admin.logs.Indicatordomain.CurrencyMongoLog;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.List;
import java.util.Map;
@Getter
@Setter
@Document(collection = "currency")
public class CurrencyLogInfo extends LogInfoBase{
private String logDay;
private String accountId;
private String userGuid;
private String userNickname;
private Double sapphireAcquired;
private Double sapphireConsumed;
private Double sapphireNet;
private Double goldAcquired;
private Double goldConsumed;
private Double goldNet;
private Double caliumAcquired;
private Double caliumConsumed;
private Double caliumNet;
private Double beamAcquired;
private Double beamConsumed;
private Double beamNet;
private Double rubyAcquired;
private Double rubyConsumed;
private Double rubyNet;
private Integer totalCurrencies;
private List<CurrencyMongoLog.currency> currencies;
public CurrencyLogInfo(String logDay,
String accountId,
String userGuid,
String userNickname,
Double sapphireAcquired,
Double sapphireConsumed,
Double sapphireNet,
Double goldAcquired,
Double goldConsumed,
Double goldNet,
Double caliumAcquired,
Double caliumConsumed,
Double caliumNet,
Double beamAcquired,
Double beamConsumed,
Double beamNet,
Double rubyAcquired,
Double rubyConsumed,
Double rubyNet,
Integer totalCurrencies,
List<CurrencyMongoLog.currency> currencies
) {
super(StatisticsType.CURRENCY);
this.logDay = logDay;
this.accountId = accountId;
this.userGuid = userGuid;
this.userNickname = userNickname;
this.sapphireAcquired = sapphireAcquired;
this.sapphireConsumed = sapphireConsumed;
this.sapphireNet = sapphireNet;
this.goldAcquired = goldAcquired;
this.goldConsumed = goldConsumed;
this.goldNet = goldNet;
this.caliumAcquired = caliumAcquired;
this.caliumConsumed = caliumConsumed;
this.caliumNet = caliumNet;
this.beamAcquired = beamAcquired;
this.beamConsumed = beamConsumed;
this.beamNet = beamNet;
this.rubyAcquired = rubyAcquired;
this.rubyConsumed = rubyConsumed;
this.rubyNet = rubyNet;
this.totalCurrencies = totalCurrencies;
this.currencies = currencies;
}
}

View File

@@ -16,7 +16,8 @@ public enum StatisticsType {
SERVER_INFO,
MONEY,
USER_CREATE,
USER_LOGIN
USER_LOGIN,
CURRENCY
;
public static StatisticsType getStatisticsType(String type) {

View File

@@ -0,0 +1,7 @@
package com.caliverse.admin.Indicators.indicatorrepository;
import com.caliverse.admin.Indicators.entity.CurrencyLogInfo;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface IndicatorCurrencyRepository extends MongoRepository<CurrencyLogInfo, String> {
}

View File

@@ -38,6 +38,11 @@ public class BattleController {
public ResponseEntity<BattleEventResponse> getBattleRewardList(){
return ResponseEntity.ok().body( battleEventService.getBattleRewardList());
}
@GetMapping("/game-mode/list")
public ResponseEntity<BattleEventResponse> getGameModeList(){
return ResponseEntity.ok().body( battleEventService.getGameModeList());
}
@PostMapping("/event")
public ResponseEntity<BattleEventResponse> postBattleEvent(

View File

@@ -1,9 +1,12 @@
package com.caliverse.admin.domain.api;
import com.caliverse.admin.domain.request.LogGameRequest;
import com.caliverse.admin.domain.request.LogGenericRequest;
import com.caliverse.admin.domain.response.IndicatorsResponse;
import com.caliverse.admin.domain.response.LogResponse;
import com.caliverse.admin.domain.service.LogService;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@@ -22,4 +25,39 @@ public class LogController {
@RequestBody LogGenericRequest logGenericRequest){
return ResponseEntity.ok().body( logService.genericLogList(logGenericRequest));
}
@PostMapping("/generic/excel-export")
public void excelExport(HttpServletResponse response,
@RequestBody LogGenericRequest logGenericRequest){
logService.genericExcelExport(response, logGenericRequest);
}
@GetMapping("/progress/{taskId}")
public ResponseEntity<Map<String, Object>> getProgress(@PathVariable String taskId) {
return ResponseEntity.ok().body(logService.getProgress(taskId));
}
@GetMapping("/currency/list")
public ResponseEntity<LogResponse> currencyList(
@RequestParam Map<String, String> requestParams){
return ResponseEntity.ok().body( logService.getCurrencyLogList(requestParams));
}
@GetMapping("/currency/detail/list")
public ResponseEntity<LogResponse> currencyDetailList(
@RequestParam Map<String, String> requestParams){
return ResponseEntity.ok().body( logService.getCurrencyDetailLogList(requestParams));
}
@PostMapping("/currency/detail/excel-export")
public void currencyDetailExcelExport(HttpServletResponse response,
@RequestBody LogGameRequest logGameRequest){
logService.currencyDetailExcelExport(response, logGameRequest);
}
@PostMapping("/currency/excel-export")
public void currencyExcelExport(HttpServletResponse response,
@RequestBody LogGameRequest logGameRequest){
logService.currencyExcelExport(response, logGameRequest);
}
}

View File

@@ -0,0 +1,24 @@
package com.caliverse.admin.domain.cache;
import com.caliverse.admin.domain.datacomponent.MetaDataFileLoader;
import com.caliverse.admin.domain.request.LogGenericRequest;
import com.caliverse.admin.logs.logservice.businesslogservice.BusinessLogGenericService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.stereotype.Component;
@Slf4j
@Component
@EnableCaching(proxyTargetClass = true)
public class CommonCacheHandler {
@Autowired
private BusinessLogGenericService businessLogGenericService;
@Cacheable(value = "businessLogCount", keyGenerator = "logCountKeyGenerator")
public Integer getLogCount(LogGenericRequest logGenericRequest) {
log.info("Cache MISS - Executing actual DB query for count");
return businessLogGenericService.getRawLogCount(logGenericRequest);
}
}

View File

@@ -0,0 +1,40 @@
package com.caliverse.admin.domain.cache;
import com.caliverse.admin.domain.request.LogGenericRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.cache.interceptor.KeyGenerator;
import java.lang.reflect.Method;
@Component("logCountKeyGenerator")
@Slf4j
public class LogCountKeyGenerator implements KeyGenerator {
@Override
public Object generate(Object target, Method method, Object... params) {
LogGenericRequest request = (LogGenericRequest) params[0];
StringBuilder keyBuilder = new StringBuilder();
keyBuilder.append(request.getStartDt().toLocalDate())
.append("_")
.append(request.getEndDt().toLocalDate())
.append("_")
.append(request.getLogAction() != null ? request.getLogAction().name() : "ALL")
.append("_")
.append(request.getLogDomain() != null ? request.getLogDomain().name() : "ALL")
.append("_")
.append(request.getSearchData() != null ? request.getSearchData() : "ALL")
.append("_")
.append(request.getTranId() != null ? request.getTranId() : "ALL");
// 필터가 있으면 해시 추가
if (request.getFilters() != null && !request.getFilters().isEmpty()) {
keyBuilder.append("_").append(request.getFilters().hashCode());
}
String finalKey = keyBuilder.toString();
log.info("Generated cache key: '{}'", finalKey);
return finalKey;
}
}

View File

@@ -14,6 +14,7 @@ public interface MenuMapper {
MenuBanner getBannerDetail(Long id);
List<Message> getMessage(Long id);
List<MenuBanner> getScheduleBannerList();
int getMaxOrderId();
void insertBanner(MenuRequest mailRequest);
void insertMessage(Map map);

View File

@@ -11,9 +11,12 @@ import org.springframework.stereotype.Component;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
@Component
@Slf4j
@@ -27,45 +30,92 @@ public class JsonFileReader {
this.objectMapper = new ObjectMapper();
}
public List<Map<String, Object>> readJsonFile(String fileName, String listName) {
public List<Map<String, Object>> readJsonFile(String metaName) {
List<Map<String, Object>> resultMap = new ArrayList<>();
try {
File file = new File(metaDataPath, fileName);
log.info("loadDataFromJsonFile path: {}", file.getPath());
File metaFile = new File(metaDataPath, metaName);
log.info("Trying to load data from: {}", metaFile.getPath());
if (!file.exists()) {
log.error("File not found: {}", fileName);
return null;
}
if (metaFile.isDirectory()) {
// 디렉토리인 경우 모든 JSON 파일을 읽어서 결과를 합침
log.info("Found directory: {}, reading all JSON files", metaFile.getPath());
String fileContent = readFileAsString(file);
JsonNode rootNode = objectMapper.readTree(fileContent);
JsonNode listNode = rootNode.get(listName);
try (Stream<Path> paths = Files.walk(metaFile.toPath())) {
List<File> jsonFiles = paths
.filter(Files::isRegularFile)
.filter(p -> p.toString().toLowerCase().endsWith(".json"))
.map(Path::toFile)
.toList();
if (listNode == null) {
throw new MetaDataException("List name not found: " + listName);
}
resultMap = objectMapper.readValue(
listNode.toString(),
new TypeReference<>() {
if (jsonFiles.isEmpty()) {
log.warn("No JSON files found in directory: {}", metaFile.getPath());
return null;
}
);
log.debug("Successfully parsed JSON file: {}, items count: {}", fileName, resultMap.size());
for (File jsonFile : jsonFiles) {
log.info("Processing JSON file: {}", jsonFile.getPath());
List<Map<String, Object>> fileResult = parseJsonFile(jsonFile);
if (fileResult != null) {
resultMap.addAll(fileResult);
}
}
}
} else {
// 일반 파일인 경우
String jsonFileName = metaName + "Data.json";
metaFile = new File(metaDataPath, jsonFileName);
log.info("Original path not found, trying: {}", metaFile.getPath());
if (!metaFile.exists()) {
log.error("Neither directory nor file found: {} or {}", metaName, jsonFileName);
return null;
}
return parseJsonFile(metaFile);
}
} catch (JsonProcessingException e) {
log.error("Failed to parse JSON from file: {}", fileName, e);
throw new MetaDataException("Failed to parse JSON from file: " + fileName, e);
} catch (IOException e) {
log.error("Failed to read file: {}", fileName, e);
throw new MetaDataException("Failed to read file: " + fileName, e);
log.error("Failed to read from path: {}", metaName, e);
throw new MetaDataException("Failed to read from path: " + metaName, e);
}
return resultMap;
}
private List<Map<String, Object>> parseJsonFile(File file) {
try {
log.debug("Parsing JSON file: {}", file.getPath());
String fileContent = readFileAsString(file);
JsonNode rootNode = objectMapper.readTree(fileContent);
// JsonNode listNode = rootNode.get(listName);
if (!rootNode.isEmpty()) {
String firstFieldName = rootNode.fieldNames().next();
JsonNode firstNode = rootNode.get(firstFieldName);
List<Map<String, Object>> resultList = objectMapper.readValue(
firstNode.toString(),
new TypeReference<>() {}
);
log.debug("Successfully parsed JSON file: {}, first field: {}, items count: {}",
file.getName(), firstFieldName, resultList.size());
return resultList;
} else {
log.warn("No fields found in JSON file: {}", file.getPath());
return null;
}
} catch (JsonProcessingException e) {
log.error("Failed to parse JSON from file: {}", file.getName(), e);
throw new MetaDataException("Failed to parse JSON from file: " + file.getName(), e);
} catch (IOException e) {
log.error("Failed to read file: {}", file.getName(), e);
throw new MetaDataException("Failed to read file: " + file.getName(), e);
}
}
private String readFileAsString(File file) throws IOException {
StringBuilder fileContents = new StringBuilder((int)file.length());
try (BufferedReader br = new BufferedReader(

View File

@@ -6,7 +6,6 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import com.caliverse.admin.domain.entity.metadata.*;
import com.caliverse.admin.global.common.constants.MetadataConstants;
import com.caliverse.admin.global.common.exception.MetaDataException;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
@@ -27,12 +26,15 @@ public class MetaDataFileLoader {
private final Map<MetaQuestKey, MetaQuestData> quests;
private final Map<Integer, MetaBuildingData> buildings;
private final Map<Integer, MetaLandData> lands;
private final Map<Integer, MetaGameModeData> gameModes;
private final Map<Integer, MetaGameFFAConfigData> gameFFAConfigs;
private final Map<Integer, MetaBattleConfigData> battleConfigs;
private final Map<Integer, MetaBattleRewardData> battleRewards;
private final Map<String, MetaSystemMailData> systemMails;
public MetaDataFileLoader(JsonFileReader jsonFileReader) {
this.jsonFileReader = jsonFileReader;
this.gameModes = new ConcurrentHashMap<>();
this.items = new ConcurrentHashMap<>();
this.textStrings = new ConcurrentHashMap<>();
this.clothTypes = new ConcurrentHashMap<>();
@@ -44,6 +46,7 @@ public class MetaDataFileLoader {
this.battleConfigs = new ConcurrentHashMap<>();
this.battleRewards = new ConcurrentHashMap<>();
this.systemMails = new ConcurrentHashMap<>();
this.gameFFAConfigs = new ConcurrentHashMap<>();
}
@PostConstruct
@@ -75,6 +78,8 @@ public class MetaDataFileLoader {
loadBattleConfig();
loadBattleReward();
loadSystemMail();
loadGameMode();
loadGameModeFFAConfig();
}catch(MetaDataException e){
log.error("Failed to initialize metadata", e);
throw e;
@@ -144,9 +149,19 @@ public class MetaDataFileLoader {
return new ArrayList<>(lands.values());
}
public List<MetaGameModeData> getMetaGameModes() {
return new ArrayList<>(gameModes.values());
}
public List<MetaGameFFAConfigData> getMetaGameFFAConfigs() {
return new ArrayList<>(gameFFAConfigs.values());
}
// 추후 없어질것
public List<MetaBattleConfigData> getMetaBattleConfigs() {
return new ArrayList<>(battleConfigs.values());
}
// 추후 없어질것
public List<MetaBattleRewardData> getMetaBattleRewards() {
return battleRewards.values().stream()
.collect(Collectors.groupingBy(MetaBattleRewardData::getGroupID)) // groupId로 그룹화
@@ -155,6 +170,7 @@ public class MetaDataFileLoader {
.sorted(Comparator.comparing(MetaBattleRewardData::getGroupID)) // groupId 기준으로 정렬
.collect(Collectors.toList());
}
public List<MetaSystemMailData> getMetaSystemMail() {
return new ArrayList<>(systemMails.values());
}
@@ -169,10 +185,7 @@ public class MetaDataFileLoader {
// 문자 데이터 로드
private void loadTextStrings() {
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(
EMetaData.TEXT_STRING_DATA.getFileName(),
MetadataConstants.JSON_LIST_TEXT_STRING
);
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.TEXT_STRING_DATA.getFileName());
if(metaList == null || metaList.isEmpty()) {
log.warn("textStrings data is empty or file not found: {}", EMetaData.TOOL_DATA.getFileName());
return;
@@ -192,7 +205,7 @@ public class MetaDataFileLoader {
// 아이템 정보 데이터 로드
public void loadItems(){
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.ITEM_DATA.getFileName(), MetadataConstants.JSON_LIST_ITEM);
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.ITEM_DATA.getFileName());
if(metaList == null || metaList.isEmpty()) {
log.warn("item data is empty or file not found: {}", EMetaData.TOOL_DATA.getFileName());
return;
@@ -213,7 +226,7 @@ public class MetaDataFileLoader {
// 의상 타입 데이터 로드
public void loadClothType(){
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.CLOTH_TYPE_DATA.getFileName(), MetadataConstants.JSON_LIST_CLOTH_TYPE);
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.CLOTH_TYPE_DATA.getFileName());
if(metaList == null || metaList.isEmpty()) {
log.warn("clothType data is empty or file not found: {}", EMetaData.TOOL_DATA.getFileName());
return;
@@ -232,7 +245,7 @@ public class MetaDataFileLoader {
// 도구 정보 데이터 로드
public void loadToolItems(){
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.TOOL_DATA.getFileName(), MetadataConstants.JSON_LIST_TOOL);
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.TOOL_DATA.getFileName());
if(metaList == null || metaList.isEmpty()) {
log.warn("tool data is empty or file not found: {}", EMetaData.TOOL_DATA.getFileName());
return;
@@ -250,7 +263,7 @@ public class MetaDataFileLoader {
// 금지어 데이터 로드
public void loadBanWord(){
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.BAN_WORD_DATA.getFileName(), MetadataConstants.JSON_LIST_BAN_WORD);
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.BAN_WORD_DATA.getFileName());
if(metaList == null || metaList.isEmpty()) {
log.warn("ban data is empty or file not found: {}", EMetaData.BAN_WORD_DATA.getFileName());
return;
@@ -265,7 +278,7 @@ public class MetaDataFileLoader {
// 퀘스트 데이터 로드
public void loadQuests(){
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.QUEST_DATA.getFileName(), MetadataConstants.JSON_LIST_QUEST);
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.QUEST_DATA.getFileName());
if(metaList == null || metaList.isEmpty()) {
log.warn("quest data is empty or file not found: {}", EMetaData.QUEST_DATA.getFileName());
return;
@@ -287,7 +300,7 @@ public class MetaDataFileLoader {
// 빌딩 데이터 로드
public void loadBuilding(){
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.BUILDING_DATA.getFileName(), MetadataConstants.JSON_LIST_BUILDING);
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.BUILDING_DATA.getFileName());
if(metaList == null || metaList.isEmpty()) {
log.warn("building data is empty or file not found: {}", EMetaData.BUILDING_DATA.getFileName());
return;
@@ -313,7 +326,7 @@ public class MetaDataFileLoader {
// 랜드 데이터 로드
public void loadLand(){
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.LAND_DATA.getFileName(), MetadataConstants.JSON_LIST_LAND);
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.LAND_DATA.getFileName());
if(metaList == null || metaList.isEmpty()) {
log.warn("land data is empty or file not found: {}", EMetaData.LAND_DATA.getFileName());
return;
@@ -346,9 +359,85 @@ public class MetaDataFileLoader {
log.info("loadLand {} Load Complete", EMetaData.LAND_DATA.getFileName());
}
// 게임 모드 데이터 로드
public void loadGameMode(){
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.GAME_MODE_DATA.getFileName());
if(metaList == null || metaList.isEmpty()) {
log.warn("Game Mode data is empty or file not found: {}", EMetaData.GAME_MODE_DATA.getFileName());
return;
}
metaList.forEach(meta -> {
MetaGameModeData item = new MetaGameModeData();
item.setId((Integer)meta.get("GameModeID"));
item.setDesc((String)meta.get("GameModeDescription"));
item.setGenreType((String)meta.get("GameGenreType"));
item.setModeType((String)meta.get("GameModeType"));
item.setModeConfigId((Integer)meta.get("GameModeConfigID"));
item.setModeCommonId((Integer)meta.get("GameModeCommonID"));
item.setInstanceId((Integer)meta.get("InstanceID"));
item.setModeMatchId((Integer)meta.get("GameModeMatchID"));
item.setModeRewardGroupId((Integer)meta.get("GameModeRewardGroupID"));
item.setModeOptionId((Integer)meta.get("GameModeOptionID"));
item.setModeStartId((Integer)meta.get("GameModeStartID"));
item.setModeTeamId((Integer)meta.get("GameModeTeamID"));
gameModes.put((Integer)meta.get("GameModeID"), item);
});
log.info("loadGameMode {} Load Complete", EMetaData.GAME_MODE_DATA.getFileName());
}
// 게임 TPS_FFA 설정 데이터 로드
public void loadGameModeFFAConfig(){
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.GAME_MODE_FFA_DATA.getFileName());
if(metaList == null || metaList.isEmpty()) {
log.warn("gameMode TPS FFA data is empty or file not found: {}", EMetaData.GAME_MODE_FFA_DATA.getFileName());
return;
}
metaList.forEach(meta -> {
MetaGameFFAConfigData item = new MetaGameFFAConfigData();
item.setId((Integer)meta.get("GameModeTpsFfaID"));
item.setDesc((String)meta.get("GameModeTpsFfaDescription"));
item.setPlayerRespawnTime((Integer)meta.get("PlayerRespawnTime"));
item.setDefaultRoundCount((Integer)meta.get("DefaultRoundCount"));
item.setRoundTime((Integer)meta.get("RoundTime"));
item.setNextRoundWaitTime((Integer)meta.get("NextRoundWaitTime"));
item.setResultUIWaitTime((Integer)meta.get("ResultUIWaitTime"));
item.setGetRewardTime((Integer)meta.get("GetRewardTime"));
gameFFAConfigs.put((Integer)meta.get("GameModeTpsFfaID"), item);
});
log.info("loadGameModeFFAConfig {} Load Complete", EMetaData.GAME_MODE_FFA_DATA.getFileName());
}
// 게임 TPS_TDM 설정 데이터 로드
public void loadGameModeTDMConfig(){
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.GAME_MODE_TDM_DATA.getFileName());
if(metaList == null || metaList.isEmpty()) {
log.warn("Battle config data is empty or file not found: {}", EMetaData.GAME_MODE_TDM_DATA.getFileName());
return;
}
metaList.forEach(meta -> {
MetaBattleConfigData item = new MetaBattleConfigData();
item.setId((Integer)meta.get("Id"));
item.setDesc((String)meta.get("Description"));
item.setPlayerRespawnTime((Integer)meta.get("PlayerRespawnTime"));
item.setDefaultRoundCount((Integer)meta.get("DefaultRoundCount"));
item.setRoundTime((Integer)meta.get("RoundTime"));
item.setNextRoundWaitTime((Integer)meta.get("NextRoundWaitTime"));
item.setResultUIWaitTime((Integer)meta.get("ResultUIWaitTime"));
item.setGetRewardTime((Integer)meta.get("GetRewardTime"));
battleConfigs.put((Integer)meta.get("Id"), item);
});
log.info("loadBattleConfig {} Load Complete", EMetaData.GAME_MODE_TDM_DATA.getFileName());
}
// 전투 설정 데이터 로드
public void loadBattleConfig(){
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.BATTLE_CONFIG_DATA.getFileName(), MetadataConstants.JSON_LIST_BATTLE_CONFIG);
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.BATTLE_CONFIG_DATA.getFileName());
if(metaList == null || metaList.isEmpty()) {
log.warn("Battle config data is empty or file not found: {}", EMetaData.BATTLE_CONFIG_DATA.getFileName());
return;
@@ -372,7 +461,7 @@ public class MetaDataFileLoader {
// 전투 보상 데이터 로드
public void loadBattleReward(){
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.BATTLE_REWARD_DATA.getFileName(), MetadataConstants.JSON_LIST_BATTLE_REWARD);
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.BATTLE_REWARD_DATA.getFileName());
if(metaList == null || metaList.isEmpty()) {
log.warn("Battle reward data is empty or file not found: {}", EMetaData.BATTLE_REWARD_DATA.getFileName());
return;
@@ -395,7 +484,7 @@ public class MetaDataFileLoader {
// 시스템메일 데이터 로드
public void loadSystemMail(){
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.SYSTEM_MAIL_DATA.getFileName(), MetadataConstants.JSON_LIST_SYSTEM_META);
List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.SYSTEM_MAIL_DATA.getFileName());
if(metaList == null || metaList.isEmpty()) {
log.warn("System Mail data is empty or file not found: {}", EMetaData.SYSTEM_MAIL_DATA.getFileName());
return;

View File

@@ -79,6 +79,14 @@ public class MetaDataHandler {
return metadataFileLoader.getMetaBattleRewards();
}
public List<MetaGameModeData> getMetaGameModeListData() {
return metadataFileLoader.getMetaGameModes();
}
public List<MetaGameFFAConfigData> getMetaGameFFAConfigListData() {
return metadataFileLoader.getMetaGameFFAConfigs();
}
public List<MetaSystemMailData> getMetaSystemMailListData() {
return metadataFileLoader.getMetaSystemMail();
}

View File

@@ -31,6 +31,8 @@ public class BattleEvent {
// 시작 일자
@JsonProperty("event_start_dt")
private LocalDateTime eventStartDt;
@JsonProperty("event_end_time")
private LocalDateTime eventEndTime;
// 종료 일자
@JsonProperty("event_end_dt")
private LocalDateTime eventEndDt;
@@ -51,6 +53,8 @@ public class BattleEvent {
private Integer rewardGroupId;
@JsonProperty("instance_id")
private Integer instanceId;
@JsonProperty("game_mode_id")
private Integer gameModeId;
private boolean deleted;

View File

@@ -3,17 +3,20 @@ package com.caliverse.admin.domain.entity;
public enum EMetaData {
NONE("", false),
ITEM_DATA("ItemData.json", true),
CLOTH_TYPE_DATA("ClothEquipTypeData.json", true),
TOOL_DATA("ToolData.json", true),
BAN_WORD_DATA("BanWordData.json", true),
TEXT_STRING_DATA("TextStringData.json", true),
QUEST_DATA("QuestData.json", true),
LAND_DATA("LandData.json", true),
BUILDING_DATA("BuildingData.json", true),
BATTLE_CONFIG_DATA("BattleFFAConfigData.json", true),
BATTLE_REWARD_DATA("BattleFFARewardData.json", true),
SYSTEM_MAIL_DATA("SystemMailData.json", true)
ITEM_DATA("Item", true),
CLOTH_TYPE_DATA("ClothEquipType", true),
TOOL_DATA("Tool", true),
BAN_WORD_DATA("BanWord", true),
TEXT_STRING_DATA("TextString", true),
QUEST_DATA("Quest", true),
LAND_DATA("Land", true),
BUILDING_DATA("Building", true),
GAME_MODE_DATA("GameMode", true),
GAME_MODE_FFA_DATA("GameModeTpsFfa", true),
GAME_MODE_TDM_DATA("GameModeTpsTdm", true),
BATTLE_CONFIG_DATA("BattleFFAConfig", true),
BATTLE_REWARD_DATA("BattleFFAReward", true),
SYSTEM_MAIL_DATA("SystemMail", true)
;

View File

@@ -61,7 +61,8 @@ public enum HISTORYTYPEDETAIL {
NICKNAME_REGISTRY_DELETE("닉네임 레지스트리 삭제"),
NICKNAME_REGISTRY_ADD("닉네임 레지스트리 등록"),
NICKNAME_UPDATE("닉네임 수정"),
DATA_INIT_ADD("데이터 초기화 등록")
DATA_INIT_ADD("데이터 초기화 등록"),
SYSTEM_META_MAIL_DELETE("시스템 메타 메일 삭제"),
;
private String historyTypeDetail;
HISTORYTYPEDETAIL(String type) {

View File

@@ -11,6 +11,7 @@ public enum ITEMLARGETYPE {
TATTOO,
BEAUTY,
CURRENCY,
PRODUCT
PRODUCT,
SET_BOX
;
}

View File

@@ -29,6 +29,8 @@ public class MenuBanner {
private LocalDateTime endDt;
@JsonProperty("is_link")
private boolean isLink;
@JsonProperty("order_id")
private Integer orderId;
@JsonProperty("create_by")
private String createBy;

View File

@@ -0,0 +1,20 @@
package com.caliverse.admin.domain.entity.excel;
import lombok.Builder;
import lombok.Data;
import java.util.Map;
@Data
@Builder
public class ExcelBusinessLog {
private String logTime;
private String userGuid;
private String userNickname;
private String accountId;
private String action;
private String domain;
private String tranId;
private Map<String, Object> header;
private Map<String, Object> body;
}

View File

@@ -0,0 +1,21 @@
package com.caliverse.admin.domain.entity.log;
import lombok.Builder;
import lombok.Data;
import java.util.Map;
@Data
@Builder
public class GenericLog{
private String logTime;
private String userGuid;
private String userNickname;
private String accountId;
private String action;
private String domain;
private String tranId;
private Map<String, Object> header;
private Map<String, Object> body;
}

View File

@@ -0,0 +1,23 @@
package com.caliverse.admin.domain.entity.metadata;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class MetaGameFFAConfigData {
private Integer id;
private String desc;
@JsonProperty("player_respawn_time")
private Integer playerRespawnTime;
@JsonProperty("default_round_count")
private Integer defaultRoundCount;
@JsonProperty("round_time")
private Integer roundTime;
@JsonProperty("next_round_wait_time")
private Integer nextRoundWaitTime;
@JsonProperty("result_UI_wait_time")
private Integer resultUIWaitTime;
@JsonProperty("get_reward_time")
private Integer getRewardTime;
}

View File

@@ -0,0 +1,31 @@
package com.caliverse.admin.domain.entity.metadata;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class MetaGameModeData {
private Integer id;
private String desc;
@JsonProperty("genre_type")
private String genreType;
@JsonProperty("mode_type")
private String modeType;
@JsonProperty("mode_config_id")
private Integer modeConfigId;
@JsonProperty("mode_common_id")
private Integer modeCommonId;
@JsonProperty("instance_id")
private Integer instanceId;
@JsonProperty("mode_match_id")
private Integer modeMatchId;
@JsonProperty("mode_reward_group_id")
private Integer modeRewardGroupId;
@JsonProperty("mode_option_id")
private Integer modeOptionId;
@JsonProperty("mode_start_id")
private Integer modeStartId;
@JsonProperty("mode_team_id")
private Integer modeTeamId;
}

View File

@@ -31,6 +31,8 @@ public class BattleEventRequest {
// 시작 일자
@JsonProperty("event_start_dt")
private LocalDateTime eventStartDt;
@JsonProperty("event_end_time")
private LocalDateTime eventEndTime;
// 종료 일자
@JsonProperty("event_end_dt")
private LocalDateTime eventEndDt;
@@ -51,6 +53,8 @@ public class BattleEventRequest {
private Integer rewardGroupId;
@JsonProperty("instance_id")
private Integer instanceId;
@JsonProperty("game_mode_id")
private Integer gameModeId;
@JsonProperty("create_by")
private Long createBy;

View File

@@ -0,0 +1,47 @@
package com.caliverse.admin.domain.request;
import com.caliverse.admin.domain.entity.common.SearchUserType;
import com.caliverse.admin.dynamodb.entity.EAmountDeltaType;
import com.caliverse.admin.dynamodb.entity.ECurrencyType;
import com.caliverse.admin.logs.entity.LogAction;
import com.caliverse.admin.logs.entity.LogDomain;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class LogGameRequest {
@JsonProperty("search_type")
private SearchUserType searchType;
@JsonProperty("search_data")
private String searchData;
@JsonProperty("log_action")
private LogAction logAction;
@JsonProperty("log_domain")
private LogDomain logDomain;
@JsonProperty("tran_id")
private String tranId;
@JsonProperty("currency_type")
private ECurrencyType currencyType;
@JsonProperty("amount_delta_type")
private EAmountDeltaType amountDeltaType;
@JsonProperty("start_dt")
private LocalDateTime startDt;
@JsonProperty("end_dt")
private LocalDateTime endDt;
@JsonProperty("page_no")
private Integer pageNo;
@JsonProperty("page_size")
private Integer pageSize;
@JsonProperty("order_by")
private String orderBy;
private String taskId;
}

View File

@@ -40,6 +40,7 @@ public class LogGenericRequest {
private Integer pageSize;
@JsonProperty("order_by")
private String orderBy;
private String taskId;
@Data
public static class LogFilter{

View File

@@ -25,6 +25,8 @@ public class MenuRequest {
private boolean isLink;
@JsonProperty("link_list")
private List<Message> linkList;
@JsonProperty("order_id")
private Integer orderId;
@JsonProperty("create_by")
private Long createBy;

View File

@@ -4,6 +4,7 @@ import com.caliverse.admin.domain.entity.BattleEvent;
import com.caliverse.admin.domain.entity.LandAuction;
import com.caliverse.admin.domain.entity.metadata.MetaBattleConfigData;
import com.caliverse.admin.domain.entity.metadata.MetaBattleRewardData;
import com.caliverse.admin.domain.entity.metadata.MetaGameModeData;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
@@ -41,6 +42,9 @@ public class BattleEventResponse {
@JsonProperty("battle_reward_list")
private List<MetaBattleRewardData> battleRewardList;
@JsonProperty("game_mode_list")
private List<MetaGameModeData> gameModeList;
private String message;
private int total;

View File

@@ -1,5 +1,7 @@
package com.caliverse.admin.domain.response;
import com.caliverse.admin.Indicators.entity.CurrencyDetailLogInfo;
import com.caliverse.admin.domain.entity.log.GenericLog;
import com.caliverse.admin.logs.Indicatordomain.GenericMongoLog;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
@@ -32,7 +34,11 @@ public class LogResponse {
@JsonProperty("generic_list")
// private List<Map<String, Object>> genericList;
private List<GenericMongoLog> genericList;
private List<GenericLog> genericList;
@JsonProperty("currency_list")
private List<currencyLog> currencyList;
@JsonProperty("currency_detail_list")
private List<CurrencyDetailLogInfo> currencyDetailList;
private int total;
@JsonProperty("total_all")
@@ -41,5 +47,29 @@ public class LogResponse {
private int pageNo;
}
@Data
@Builder
public static class currencyLog {
private String logDay;
private String accountId;
private String userGuid;
private String userNickname;
private Double sapphireAcquired;
private Double sapphireConsumed;
private Double sapphireNet;
private Double goldAcquired;
private Double goldConsumed;
private Double goldNet;
private Double caliumAcquired;
private Double caliumConsumed;
private Double caliumNet;
private Double beamAcquired;
private Double beamConsumed;
private Double beamNet;
private Double rubyAcquired;
private Double rubyConsumed;
private Double rubyNet;
private Integer totalCurrencies;
}
}

View File

@@ -6,6 +6,8 @@ import com.caliverse.admin.domain.entity.BattleEvent;
import com.caliverse.admin.domain.entity.HISTORYTYPEDETAIL;
import com.caliverse.admin.domain.entity.metadata.MetaBattleConfigData;
import com.caliverse.admin.domain.entity.metadata.MetaBattleRewardData;
import com.caliverse.admin.domain.entity.metadata.MetaGameFFAConfigData;
import com.caliverse.admin.domain.entity.metadata.MetaGameModeData;
import com.caliverse.admin.domain.request.BattleEventRequest;
import com.caliverse.admin.domain.response.BattleEventResponse;
import com.caliverse.admin.dynamodb.service.DynamodbBattleEventService;
@@ -23,10 +25,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -75,6 +74,21 @@ public class BattleEventService {
.build();
}
//전투시스템 게임모드 데이터
public BattleEventResponse getGameModeList(){
List<MetaGameModeData> list = metaDataHandler.getMetaGameModeListData();
return BattleEventResponse.builder()
.status(CommonCode.SUCCESS.getHttpStatus())
.result(CommonCode.SUCCESS.getResult())
.resultData(BattleEventResponse.ResultData.builder()
.gameModeList(list)
.build()
)
.build();
}
// 전투시스템 이벤트 조회
public BattleEventResponse getBattleEventList(@RequestParam Map<String, String> requestParam){
@@ -112,6 +126,7 @@ public class BattleEventService {
.build();
}
// 전투시스템 이벤트 저장
@Transactional(transactionManager = "transactionManager")
public BattleEventResponse postBattleEvent(BattleEventRequest battleEventRequest){
if(battleEventRequest.getRepeatType().equals(BattleEvent.BATTLE_REPEAT_TYPE.NONE)){
@@ -130,11 +145,8 @@ public class BattleEventService {
}
battleEventRequest.setInstanceId(CommonConstants.BATTLE_INSTANCE_ID); //고정값으로 넣고 추후 맵정보가 늘어나면 선택하는 걸로
if(battleEventRequest.getRoundTime().equals(0)
|| battleEventRequest.getHotTime().equals(0)
|| battleEventRequest.getConfigId().equals(0)
if(battleEventRequest.getGameModeId().equals(0)
|| battleEventRequest.getRoundCount().equals(0)
|| battleEventRequest.getRewardGroupId().equals(0)
){
return BattleEventResponse.builder()
.status(CommonCode.ERROR.getHttpStatus())
@@ -142,10 +154,15 @@ public class BattleEventService {
.build();
}
int operation_time = calcEndTime(battleEventRequest);
// int operation_time = ffACalcEndTime(battleEventRequest);
LocalTime startTime = battleEventRequest.getEventStartDt().toLocalTime();
LocalTime endTime = battleEventRequest.getEventEndTime().toLocalTime();
long duration = Duration.between(startTime, endTime).getSeconds();
int operation_time = (int) duration;
battleEventRequest.setEventOperationTime(operation_time);
// int is_time = battleMapper.chkTimeOver(battleEventRequest);
List<BattleEvent> existingList = battleMapper.getCheckBattleEventList(battleEventRequest);
boolean isTime = isTimeOverlapping(existingList, battleEventRequest);
if(isTime){
@@ -155,14 +172,15 @@ public class BattleEventService {
.result(ErrorCode.ERROR_BATTLE_EVENT_TIME_OVER.toString())
.build();
}
int next_event_id = dynamodbBattleEventService.getEventId() + 1;
battleEventRequest.setEventId(next_event_id);
// dynamoDB 기준으로 id를 관리하려고했으나 종료된 데이터를 주기적으로 지워주다보니 id가 꼬일수 있어서 운영DB기준으로 변경
// int next_event_id = dynamodbBattleEventService.getEventId() + 1;
// battleEventRequest.setEventId(next_event_id);
int result = battleMapper.postBattleEvent(battleEventRequest);
log.info("AdminToolDB BattleEvent Save: {}", battleEventRequest);
long battle_event_id = battleEventRequest.getId();
battleEventRequest.setEventId((int) battle_event_id);
HashMap<String,String> map = new HashMap<>();
map.put("id",String.valueOf(battle_event_id));
@@ -187,6 +205,7 @@ public class BattleEventService {
.build();
}
// 전투시스템 이벤트 수정
@Transactional(transactionManager = "transactionManager")
public BattleEventResponse updateBattleEvent(Long id, BattleEventRequest battleEventRequest) {
battleEventRequest.setId(id);
@@ -211,7 +230,7 @@ public class BattleEventService {
.build();
}
int operation_time = calcEndTime(battleEventRequest);
int operation_time = ffACalcEndTime(battleEventRequest);
battleEventRequest.setEventOperationTime(operation_time);
// 일자만 필요해서 UTC시간으로 변경되다보니 한국시간(+9)을 더해서 마지막시간으로 설정
@@ -249,6 +268,7 @@ public class BattleEventService {
.build();
}
// 전투시스템 이벤트 중단
@Transactional(transactionManager = "transactionManager")
public BattleEventResponse updateStopBattleEvent(Long id){
Map<String,Object> map = new HashMap<>();
@@ -290,6 +310,7 @@ public class BattleEventService {
.build();
}
// 전투시스템 이벤트 삭제(사용안함)
@Transactional(transactionManager = "transactionManager")
public BattleEventResponse deleteBattleEvent(BattleEventRequest battleEventRequest){
Map<String,Object> map = new HashMap<>();
@@ -351,14 +372,25 @@ public class BattleEventService {
}
// 이벤트 동작 시간 계산
private int calcEndTime(BattleEventRequest battleEventRequest){
MetaBattleConfigData config = metaDataHandler.getMetaBattleConfigsListData().stream()
.filter(data -> data.getId().equals(battleEventRequest.getConfigId()))
private int ffACalcEndTime(BattleEventRequest battleEventRequest){
MetaGameModeData gameModeData = metaDataHandler.getMetaGameModeListData().stream()
.filter(data -> data.getId().equals(battleEventRequest.getGameModeId()))
.findFirst()
.orElse(null);
if(gameModeData == null) return 0;
MetaGameFFAConfigData config = metaDataHandler.getMetaGameFFAConfigListData().stream()
.filter(data -> data.getId().equals(gameModeData.getModeConfigId()))
.findFirst()
.orElse(null);
// MetaBattleConfigData config = metaDataHandler.getMetaBattleConfigsListData().stream()
// .filter(data -> data.getId().equals(battleEventRequest.getConfigId()))
// .findFirst()
// .orElse(null);
if(config == null) return 0;
int round_time = battleEventRequest.getRoundTime();
int round_time = config.getRoundTime();
int round_count = battleEventRequest.getRoundCount();
int round_wait_time = config.getNextRoundWaitTime();
int result_wait_time = config.getResultUIWaitTime();
@@ -379,12 +411,10 @@ public class BattleEventService {
BattleEvent.BATTLE_REPEAT_TYPE newRepeatType = battleEventRequest.getRepeatType();
return existingList.stream().anyMatch(existingEvent -> {
// 자기 자신은 제외 (수정 시)
if (battleEventRequest.getId() != null && battleEventRequest.getId().equals(existingEvent.getId())) {
return false;
}
// 기존 이벤트 정보
LocalDateTime existingStartDt = existingEvent.getEventStartDt();
LocalDateTime existingEndDt = existingEvent.getEventEndDt();
LocalDate existingStartDate = existingStartDt.toLocalDate();
@@ -394,60 +424,44 @@ public class BattleEventService {
BattleEvent.BATTLE_REPEAT_TYPE existingRepeatType = existingEvent.getRepeatType();
// 1. 두 이벤트가 모두 NONE 타입인 경우
if (newRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.NONE &&
existingRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.NONE) {
// 같은 날짜인지 확인
if (newRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.NONE && existingRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.NONE) {
if (newStartDate.equals(existingStartDate)) {
// 시간이 겹치는지 확인
return !existingStartTime.isAfter(newEndTime) && !newStartTime.isAfter(existingEndTime);
}
return false;
}
// 2. NONE 타입과 DAY 타입 간의 중복 체크
if (newRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.NONE &&
existingRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.DAY) {
// NONE 이벤트의 날짜가 DAY 이벤트의 기간 내에 있는지 확인
if (newRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.NONE && existingRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.DAY) {
if (isDateInRange(newStartDate, existingStartDate, existingEndDate)) {
// 시간이 겹치는지 확인
return !existingStartTime.isAfter(newEndTime) && !newStartTime.isAfter(existingEndTime);
}
return false;
}
// 3. DAY 타입과 NONE 타입 간의 중복 체크
if (newRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.DAY &&
existingRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.NONE) {
// NONE 이벤트의 날짜가 DAY 이벤트의 기간 내에 있는지 확인
if (newRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.DAY && existingRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.NONE) {
if (isDateInRange(existingStartDate, newStartDate, newEndDate)) {
// 시간이 겹치는지 확인
return !existingStartTime.isAfter(newEndTime) && !newStartTime.isAfter(existingEndTime);
}
return false;
}
// 4. 두 이벤트가 모두 DAY 타입인 경우
if (newRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.DAY &&
existingRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.DAY) {
// 날짜 범위가 겹치는지 확인
if (newRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.DAY && existingRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.DAY) {
if (datesOverlap(newStartDate, newEndDate, existingStartDate, existingEndDate)) {
// 시간이 겹치는지 확인
return !existingStartTime.isAfter(newEndTime) && !newStartTime.isAfter(existingEndTime);
}
return false;
}
// 5. NONE 타입과 요일 타입 간의 중복 체크
if (newRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.NONE &&
isWeekdayType(existingRepeatType)) {
// NONE 이벤트의 날짜가 요일 이벤트의 기간 내에 있는지 확인
if (newRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.NONE && isWeekdayType(existingRepeatType)) {
if (isDateInRange(newStartDate, existingStartDate, existingEndDate)) {
// NONE 이벤트의 요일이 요일 이벤트의 요일과 일치하는지 확인
DayOfWeek noneDayOfWeek = newStartDate.getDayOfWeek();
DayOfWeek weekdayType = getDayOfWeekFromRepeatType(existingRepeatType);
if (noneDayOfWeek == weekdayType) {
// 시간이 겹치는지 확인
return !existingStartTime.isAfter(newEndTime) && !newStartTime.isAfter(existingEndTime);
}
}
@@ -455,16 +469,12 @@ public class BattleEventService {
}
// 6. 요일 타입과 NONE 타입 간의 중복 체크
if (isWeekdayType(newRepeatType) &&
existingRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.NONE) {
// NONE 이벤트의 날짜가 요일 이벤트의 기간 내에 있는지 확인
if (isWeekdayType(newRepeatType) && existingRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.NONE) {
if (isDateInRange(existingStartDate, newStartDate, newEndDate)) {
// NONE 이벤트의 요일이 요일 이벤트의 요일과 일치하는지 확인
DayOfWeek noneDayOfWeek = existingStartDate.getDayOfWeek();
DayOfWeek weekdayType = getDayOfWeekFromRepeatType(newRepeatType);
if (noneDayOfWeek == weekdayType) {
// 시간이 겹치는지 확인
return !existingStartTime.isAfter(newEndTime) && !newStartTime.isAfter(existingEndTime);
}
}
@@ -472,13 +482,9 @@ public class BattleEventService {
}
// 7. DAY 타입과 요일 타입 간의 중복 체크
if (newRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.DAY &&
isWeekdayType(existingRepeatType)) {
// 날짜 범위가 겹치는지 확인
if (newRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.DAY && isWeekdayType(existingRepeatType)) {
if (datesOverlap(newStartDate, newEndDate, existingStartDate, existingEndDate)) {
// 날짜 범위 내에 해당 요일이 적어도 하나 있는지 확인
if (hasOverlappingWeekday(newStartDate, newEndDate, existingStartDate, existingEndDate, getDayOfWeekFromRepeatType(existingRepeatType))) {
// 시간이 겹치는지 확인
return !existingStartTime.isAfter(newEndTime) && !newStartTime.isAfter(existingEndTime);
}
}
@@ -486,13 +492,9 @@ public class BattleEventService {
}
// 8. 요일 타입과 DAY 타입 간의 중복 체크
if (isWeekdayType(newRepeatType) &&
existingRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.DAY) {
// 날짜 범위가 겹치는지 확인
if (isWeekdayType(newRepeatType) && existingRepeatType == BattleEvent.BATTLE_REPEAT_TYPE.DAY) {
if (datesOverlap(newStartDate, newEndDate, existingStartDate, existingEndDate)) {
// 날짜 범위 내에 해당 요일이 적어도 하나 있는지 확인
if (hasOverlappingWeekday(newStartDate, newEndDate, existingStartDate, existingEndDate, getDayOfWeekFromRepeatType(newRepeatType))) {
// 시간이 겹치는지 확인
return !existingStartTime.isAfter(newEndTime) && !newStartTime.isAfter(existingEndTime);
}
}
@@ -501,11 +503,8 @@ public class BattleEventService {
// 9. 두 이벤트가 모두 요일 타입인 경우
if (isWeekdayType(newRepeatType) && isWeekdayType(existingRepeatType)) {
// 같은 요일인지 확인
if (newRepeatType == existingRepeatType) {
// 날짜 범위가 겹치는지 확인
if (datesOverlap(newStartDate, newEndDate, existingStartDate, existingEndDate)) {
// 시간이 겹치는지 확인
return !existingStartTime.isAfter(newEndTime) && !newStartTime.isAfter(existingEndTime);
}
}
@@ -557,18 +556,18 @@ public class BattleEventService {
LocalDate overlapEnd = end1.isBefore(end2) ? end1 : end2;
if (overlapStart.isAfter(overlapEnd)) {
return false; // 겹치는 날짜 범위 없음
return false;
}
// 겹치는 날짜 범위 내에 해당 요일이 있는지 확인
LocalDate current = overlapStart;
while (!current.isAfter(overlapEnd)) {
if (current.getDayOfWeek() == dayOfWeek) {
return true; // 해당 요일 발견
return true;
}
current = current.plusDays(1);
}
return false; // 해당 요일 없음
return false;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +1,39 @@
package com.caliverse.admin.domain.service;
import com.caliverse.admin.Indicators.entity.CurrencyDetailLogInfo;
import com.caliverse.admin.Indicators.entity.CurrencyLogInfo;
import com.caliverse.admin.Indicators.entity.DauLogInfo;
import com.caliverse.admin.domain.cache.CommonCacheHandler;
import com.caliverse.admin.domain.entity.excel.ExcelBusinessLog;
import com.caliverse.admin.domain.entity.log.GenericLog;
import com.caliverse.admin.domain.request.LogGameRequest;
import com.caliverse.admin.domain.request.LogGenericRequest;
import com.caliverse.admin.domain.response.IndicatorsResponse;
import com.caliverse.admin.domain.response.LogResponse;
import com.caliverse.admin.global.common.code.CommonCode;
import com.caliverse.admin.global.common.code.ErrorCode;
import com.caliverse.admin.global.common.exception.RestApiException;
import com.caliverse.admin.global.common.utils.CommonUtils;
import com.caliverse.admin.global.common.utils.DateUtils;
import com.caliverse.admin.global.component.tracker.ExcelProgressTracker;
import com.caliverse.admin.logs.Indicatordomain.GenericMongoLog;
import com.caliverse.admin.logs.logservice.businesslogservice.BusinessLogGenericService;
import com.caliverse.admin.logs.logservice.indicators.IndicatorsCurrencyService;
import com.caliverse.admin.mongodb.dto.MongoPageResult;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.mongodb.UncategorizedMongoDbException;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
@Service
@@ -21,75 +42,488 @@ import java.util.stream.Collectors;
public class LogService {
private final BusinessLogGenericService businessLogGenericService;
private final ExcelService excelService;
private final CommonCacheHandler commonCacheHandler;
private final ExcelProgressTracker progressTracker;
private final IndicatorsCurrencyService indicatorsCurrencyService;
public LogResponse genericLogList(LogGenericRequest logGenericRequest){
int page = logGenericRequest.getPageNo();
int size = logGenericRequest.getPageSize();
// LocalDateTime startDt = logGenericRequest.getStartDt().plusHours(9);
// LocalDateTime endDt = logGenericRequest.getEndDt().plusHours(9).plusDays(1);
// logGenericRequest.setStartDt(startDt);
// logGenericRequest.setEndDt(endDt);
// List<Map<String, Object>> logList = businessLogGenericService.loadBusinessLogData(logGenericRequest);
LocalDateTime startDt = logGenericRequest.getStartDt().plusHours(9);
LocalDateTime endDt = logGenericRequest.getEndDt().plusHours(9).plusDays(1);
logGenericRequest.setStartDt(startDt);
logGenericRequest.setEndDt(endDt);
List<GenericMongoLog> logList = new ArrayList<>();
// 병렬 처리를 위한 CompletableFuture 생성
CompletableFuture<List<GenericLog>> logListFuture = CompletableFuture.supplyAsync(() -> {
try {
return businessLogGenericService.loadBusinessLogData(logGenericRequest, GenericLog.class);
} catch (UncategorizedMongoDbException e) {
if (e.getMessage().contains("Sort exceeded memory limit")) {
log.error("MongoDB Query memory limit error: {}", e.getMessage());
throw new RuntimeException("MEMORY_LIMIT_ERROR", e);
} else if (e.getMessage().contains("time limit")) {
log.error("MongoDB Query operation exceeded time limit: {}", e.getMessage());
throw new RuntimeException("TIME_LIMIT_ERROR", e);
} else {
log.error("MongoDB Query error", e);
throw new RuntimeException("MONGODB_QUERY_ERROR", e);
}
} catch (Exception e) {
log.error("businessLog error", e);
throw new RuntimeException("BUSINESS_LOG_ERROR", e);
}
});
CompletableFuture<Integer> totalCountFuture = CompletableFuture.supplyAsync(() -> commonCacheHandler.getLogCount(logGenericRequest));
try {
// 두 작업이 모두 완료될 때까지 대기
List<GenericLog> logList = logListFuture.get();
int totalAll = totalCountFuture.get();
int totalItems = logList.size();
return LogResponse.builder()
.resultData(LogResponse.ResultData.builder()
.genericList(logList)
.total(totalItems)
.totalAll(totalAll)
.pageNo(logGenericRequest.getPageNo() != null ? page : 1)
.build())
.status(CommonCode.SUCCESS.getHttpStatus())
.result(CommonCode.SUCCESS.getResult())
.build();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof RuntimeException) {
RuntimeException runtimeException = (RuntimeException) cause;
String message = runtimeException.getMessage();
if ("MEMORY_LIMIT_ERROR".equals(message)) {
return LogResponse.builder()
.status(CommonCode.ERROR.getHttpStatus())
.result(ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString())
.build();
} else if ("TIME_LIMIT_ERROR".equals(message)) {
return LogResponse.builder()
.status(CommonCode.ERROR.getHttpStatus())
.result(ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString())
.build();
} else if ("MONGODB_QUERY_ERROR".equals(message)) {
return LogResponse.builder()
.status(CommonCode.ERROR.getHttpStatus())
.result(ErrorCode.ERROR_MONGODB_QUERY.toString())
.build();
}
}
log.error("Parallel execution error", e);
return LogResponse.builder()
.status(CommonCode.ERROR.getHttpStatus())
.result(CommonCode.ERROR.getResult())
.build();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("Thread interrupted", e);
return LogResponse.builder()
.status(CommonCode.ERROR.getHttpStatus())
.result(CommonCode.ERROR.getResult())
.build();
}
}
// public LogResponse genericLogList(LogGenericRequest logGenericRequest){
// int page = logGenericRequest.getPageNo();
// int size = logGenericRequest.getPageSize();
//
//// LocalDateTime startDt = logGenericRequest.getStartDt().plusHours(9);
//// LocalDateTime endDt = logGenericRequest.getEndDt().plusHours(9).plusDays(1);
//// logGenericRequest.setStartDt(startDt);
//// logGenericRequest.setEndDt(endDt);
//
//// List<Map<String, Object>> logList = businessLogGenericService.loadBusinessLogData(logGenericRequest);
// LocalDateTime startDt = logGenericRequest.getStartDt().plusHours(9);
// LocalDateTime endDt = logGenericRequest.getEndDt().plusHours(9).plusDays(1);
// logGenericRequest.setStartDt(startDt);
// logGenericRequest.setEndDt(endDt);
//
// List<GenericLog> logList = new ArrayList<>();
// try{
// logList = businessLogGenericService.loadBusinessLogData(logGenericRequest, GenericLog.class);
// }catch(UncategorizedMongoDbException e){
// if (e.getMessage().contains("Sort exceeded memory limit")) {
// log.error("MongoDB Query memory limit error: {}", e.getMessage());
// return LogResponse.builder()
// .status(CommonCode.ERROR.getHttpStatus())
// .result(ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString())
// .build();
// } else if (e.getMessage().contains("time limit")) {
// log.error("MongoDB Query operation exceeded time limit: {}", e.getMessage());
// return LogResponse.builder()
// .status(CommonCode.ERROR.getHttpStatus())
// .result(ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString())
// .build();
// }else {
// log.error("MongoDB Query error", e);
// return LogResponse.builder()
// .status(CommonCode.ERROR.getHttpStatus())
// .result(ErrorCode.ERROR_MONGODB_QUERY.toString())
// .build();
// }
// }catch (Exception e){
// log.error("businessLog error", e);
// }
//
//// logList = logList.stream().map(logData -> {
//// try {
//// var header = logData.getMessage().get("Header");
//// var body = logData.getMessage().get("Body");
//// logData.setHeader((Map<String, Object>) header);
//// logData.setBody((Map<String, Object>) body);
//// logData.setMessage("");
//// return logData;
//// } catch (Exception e) {
//// log.error("Error parsing JSON from message field", e);
//// logData.setMessage(null);
//// return logData;
//// }
//// }).collect(Collectors.toList());
//
// int totalItems = logList.size();
// int totalAll = commonCacheHandler.getLogCount(logGenericRequest);
// return LogResponse.builder()
// .resultData(LogResponse.ResultData.builder()
// .genericList(logList)
// .total(totalItems)
// .totalAll(totalAll)
// .pageNo(logGenericRequest.getPageNo() != null ?
// page : 1)
// .build())
// .status(CommonCode.SUCCESS.getHttpStatus())
// .result(CommonCode.SUCCESS.getResult())
// .build();
//
// }
public void genericExcelExport(HttpServletResponse response, LogGenericRequest logGenericRequest){
String taskId = logGenericRequest.getTaskId();
LocalDateTime startDt = logGenericRequest.getStartDt().plusHours(9);
LocalDateTime endDt = logGenericRequest.getEndDt().plusHours(9).plusDays(1);
logGenericRequest.setStartDt(startDt);
logGenericRequest.setEndDt(endDt);
logGenericRequest.setPageNo(null);
logGenericRequest.setPageSize(null);
progressTracker.updateProgress(taskId, 5, 100, "엑셀 생성 준비 중...");
List<GenericLog> logList = new ArrayList<>();
try{
logList = businessLogGenericService.loadBusinessLogData(logGenericRequest, GenericMongoLog.class);
logList = businessLogGenericService.loadBusinessLogData(logGenericRequest, GenericLog.class);
progressTracker.updateProgress(taskId, 20, 100, "데이터 생성완료");
}catch(UncategorizedMongoDbException e){
if (e.getMessage().contains("Sort exceeded memory limit")) {
log.error("MongoDB Query memory limit error: {}", e.getMessage());
return LogResponse.builder()
.status(CommonCode.ERROR.getHttpStatus())
.result(ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString())
.build();
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
} else if (e.getMessage().contains("time limit")) {
log.error("MongoDB Query operation exceeded time limit: {}", e.getMessage());
return LogResponse.builder()
.status(CommonCode.ERROR.getHttpStatus())
.result(ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString())
.build();
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
}else {
log.error("MongoDB Query error", e);
return LogResponse.builder()
.status(CommonCode.ERROR.getHttpStatus())
.result(ErrorCode.ERROR_MONGODB_QUERY.toString())
.build();
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_MONGODB_QUERY.toString());
}
}catch (Exception e){
log.error("businessLog error", e);
log.error("ExcelExport Data Search Error", e);
}
logList = logList.stream().map(logData -> {
try {
var header = logData.getMessage().get("Header");
var body = logData.getMessage().get("Body");
logData.setHeader((Map<String, Object>) header);
logData.setBody((Map<String, Object>) body);
return logData;
} catch (Exception e) {
log.error("Error parsing JSON from message field", e);
return logData;
}
}).collect(Collectors.toList());
progressTracker.updateProgress(taskId, 25, 100, "데이터 파싱 준비중...");
List<ExcelBusinessLog> excelList = logList.stream()
.map(logData -> {
try {
return ExcelBusinessLog.builder()
.logTime(logData.getLogTime())
.accountId(logData.getAccountId())
.userGuid(logData.getUserGuid())
.userNickname(logData.getUserNickname())
.tranId(logData.getTranId())
.action(logData.getAction())
.domain(logData.getDomain())
.header(logData.getHeader())
.body(logData.getBody())
.build();
} catch (Exception e) {
log.error("Error parsing JSON from message field", e);
return null;
}
})
.filter(Objects::nonNull) // null 값 제거
.toList();
progressTracker.updateProgress(taskId, 30, 100, "데이터 파싱 완료...");
int totalItems = logList.size();
try{
excelService.generateExcelToResponse(
response,
excelList,
"비즈니스 로그 데이터",
"sheet1",
taskId
);
return LogResponse.builder()
.resultData(LogResponse.ResultData.builder()
.genericList(logList)
.total(totalItems)
.totalAll(totalItems)
.pageNo(logGenericRequest.getPageNo() != null ?
page : 1)
.build())
.status(CommonCode.SUCCESS.getHttpStatus())
.result(CommonCode.SUCCESS.getResult())
.build();
}catch (Exception e){
log.error("Excel Export Create Error", e);
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_EXCEL_DOWN.toString());
}
}
public Map<String, Object> getProgress(String taskId){
try {
ExcelProgressTracker.ProgressInfo progress = progressTracker.getProgress(taskId);
if (progress == null) {
Map<String, Object> response = new HashMap<>();
response.put("exists", false);
return (response);
}
Map<String, Object> response = new HashMap<>();
response.put("exists", true);
response.put("percentage", progress.getPercentage());
response.put("currentStep", progress.getCurrentStep());
response.put("totalSteps", progress.getTotalSteps());
response.put("message", progress.getMessage());
return response;
}catch (Exception e){
log.error(e.getMessage());
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_EXCEL_DOWN.toString());
}
}
public LogResponse getCurrencyLogList(Map<String, String> requestParams){
LocalDateTime startDt = DateUtils.stringISOToLocalDateTime(requestParams.get("start_dt"));
LocalDateTime endDt = DateUtils.stringISOToLocalDateTime(requestParams.get("end_dt"));
List<CurrencyLogInfo> currencyLogList = indicatorsCurrencyService.getIndicatorsLogData(
startDt.toString().substring(0, 10),
endDt.toString().substring(0, 10),
CurrencyLogInfo.class);
List<LogResponse.currencyLog> currencyList = new ArrayList<>();
for (CurrencyLogInfo info : currencyLogList){
LogResponse.currencyLog build = LogResponse.currencyLog.builder()
.logDay(info.getLogDay())
.accountId(info.getAccountId())
.userGuid(info.getUserGuid())
.userNickname(info.getUserNickname())
.goldAcquired(info.getGoldAcquired())
.goldConsumed(info.getGoldConsumed())
.goldNet(info.getGoldNet())
.sapphireAcquired(info.getSapphireAcquired())
.sapphireConsumed(info.getSapphireConsumed())
.sapphireNet(info.getSapphireNet())
.beamAcquired(info.getBeamAcquired())
.beamConsumed(info.getBeamConsumed())
.beamNet(info.getBeamNet())
.caliumAcquired(info.getCaliumAcquired())
.caliumConsumed(info.getCaliumConsumed())
.caliumNet(info.getCaliumNet())
.rubyAcquired(info.getRubyAcquired())
.rubyConsumed(info.getRubyConsumed())
.rubyNet(info.getRubyNet())
.totalCurrencies(info.getTotalCurrencies())
.build();
currencyList.add(build);
}
return LogResponse.builder()
.resultData(LogResponse.ResultData.builder()
.currencyList(currencyList)
.build())
.status(CommonCode.SUCCESS.getHttpStatus())
.result(CommonCode.SUCCESS.getResult())
.build();
}
public void currencyExcelExport(HttpServletResponse response, LogGameRequest logGameRequest){
String taskId = logGameRequest.getTaskId();
LocalDateTime startDt = logGameRequest.getStartDt().plusHours(9);
LocalDateTime endDt = logGameRequest.getEndDt().plusHours(9).plusDays(1);
logGameRequest.setStartDt(startDt);
logGameRequest.setEndDt(endDt);
logGameRequest.setPageNo(null);
logGameRequest.setPageSize(null);
progressTracker.updateProgress(taskId, 5, 100, "엑셀 생성 준비 중...");
List<CurrencyLogInfo> result = null;
try{
result = indicatorsCurrencyService.getIndicatorsLogData(
startDt.toString().substring(0, 10),
endDt.toString().substring(0, 10),
CurrencyLogInfo.class
);
progressTracker.updateProgress(taskId, 20, 100, "데이터 생성완료");
}catch(UncategorizedMongoDbException e){
if (e.getMessage().contains("Sort exceeded memory limit")) {
log.error("MongoDB Query memory limit error: {}", e.getMessage());
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
} else if (e.getMessage().contains("time limit")) {
log.error("MongoDB Query operation exceeded time limit: {}", e.getMessage());
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
}else {
log.error("MongoDB Query error", e);
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_MONGODB_QUERY.toString());
}
}catch (Exception e){
log.error("currencyExcelExport ExcelExport Data Search Error", e);
}
List<LogResponse.currencyLog> currencyList = new ArrayList<>();
for (CurrencyLogInfo info : result){
LogResponse.currencyLog build = LogResponse.currencyLog.builder()
.logDay(info.getLogDay())
.accountId(info.getAccountId())
.userGuid(info.getUserGuid())
.userNickname(info.getUserNickname())
.goldAcquired(info.getGoldAcquired())
.goldConsumed(info.getGoldConsumed())
.goldNet(info.getGoldNet())
.sapphireAcquired(info.getSapphireAcquired())
.sapphireConsumed(info.getSapphireConsumed())
.sapphireNet(info.getSapphireNet())
.beamAcquired(info.getBeamAcquired())
.beamConsumed(info.getBeamConsumed())
.beamNet(info.getBeamNet())
.caliumAcquired(info.getCaliumAcquired())
.caliumConsumed(info.getCaliumConsumed())
.caliumNet(info.getCaliumNet())
.rubyAcquired(info.getRubyAcquired())
.rubyConsumed(info.getRubyConsumed())
.rubyNet(info.getRubyNet())
.totalCurrencies(info.getTotalCurrencies())
.build();
currencyList.add(build);
}
progressTracker.updateProgress(taskId, 30, 100, "데이터 파싱 완료...");
try{
excelService.generateExcelToResponse(
response,
currencyList,
"재화 지표 데이터",
"sheet1",
taskId
);
}catch (Exception e){
log.error("currencyExcelExport Excel Export Create Error", e);
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_EXCEL_DOWN.toString());
}
}
public LogResponse getCurrencyDetailLogList(Map<String, String> requestParams){
String searchType = requestParams.get("search_type");
String searchData = requestParams.get("search_data");
String tranId = requestParams.get("tran_id");
String logAction = requestParams.get("log_action");
String currencyType = requestParams.get("currency_type");
String amountDeltaType = requestParams.get("amount_delta_type");
LocalDateTime startDt = DateUtils.stringISOToLocalDateTime(requestParams.get("start_dt"));
LocalDateTime endDt = DateUtils.stringISOToLocalDateTime(requestParams.get("end_dt"));
String orderBy = requestParams.get("orderby");
int pageNo = Integer.parseInt(requestParams.get("page_no"));
int pageSize = Integer.parseInt(requestParams.get("page_size"));
MongoPageResult<CurrencyDetailLogInfo> result = indicatorsCurrencyService.getCurrencyDetailLogData(
searchType,
searchData,
tranId,
logAction,
currencyType,
amountDeltaType,
startDt.toString().substring(0, 10),
endDt.toString().substring(0, 10),
orderBy,
pageNo,
pageSize,
CurrencyDetailLogInfo.class
);
List<CurrencyDetailLogInfo> currencyLogList = result.getItems();
int totalCount = result.getTotalCount();
return LogResponse.builder()
.resultData(LogResponse.ResultData.builder()
.currencyDetailList(currencyLogList)
.total(currencyLogList.size())
.totalAll(totalCount)
.pageNo(pageNo)
.build())
.status(CommonCode.SUCCESS.getHttpStatus())
.result(CommonCode.SUCCESS.getResult())
.build();
}
public void currencyDetailExcelExport(HttpServletResponse response, LogGameRequest logGameRequest){
String taskId = logGameRequest.getTaskId();
LocalDateTime startDt = logGameRequest.getStartDt().plusHours(9);
LocalDateTime endDt = logGameRequest.getEndDt().plusHours(9).plusDays(1);
logGameRequest.setStartDt(startDt);
logGameRequest.setEndDt(endDt);
logGameRequest.setPageNo(null);
logGameRequest.setPageSize(null);
progressTracker.updateProgress(taskId, 5, 100, "엑셀 생성 준비 중...");
MongoPageResult<CurrencyDetailLogInfo> result = null;
try{
result = indicatorsCurrencyService.getCurrencyDetailLogData(
logGameRequest.getSearchType().toString(),
logGameRequest.getSearchData(),
logGameRequest.getTranId(),
logGameRequest.getLogAction().name(),
logGameRequest.getCurrencyType().name(),
logGameRequest.getAmountDeltaType().name(),
startDt.toString().substring(0, 10),
endDt.toString().substring(0, 10),
logGameRequest.getOrderBy(),
logGameRequest.getPageNo(),
logGameRequest.getPageSize(),
CurrencyDetailLogInfo.class
);
progressTracker.updateProgress(taskId, 20, 100, "데이터 생성완료");
}catch(UncategorizedMongoDbException e){
if (e.getMessage().contains("Sort exceeded memory limit")) {
log.error("MongoDB Query memory limit error: {}", e.getMessage());
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
} else if (e.getMessage().contains("time limit")) {
log.error("MongoDB Query operation exceeded time limit: {}", e.getMessage());
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
}else {
log.error("MongoDB Query error", e);
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_MONGODB_QUERY.toString());
}
}catch (Exception e){
log.error("currencyDetailExcelExport ExcelExport Data Search Error", e);
}
List<CurrencyDetailLogInfo> currencyLogList = result.getItems();
progressTracker.updateProgress(taskId, 30, 100, "데이터 파싱 완료...");
try{
excelService.generateExcelToResponse(
response,
currencyLogList,
"게임 재화 로그 데이터",
"sheet1",
taskId
);
}catch (Exception e){
log.error("currencyDetailExcelExport Excel Export Create Error", e);
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_EXCEL_DOWN.toString());
}
}
}

View File

@@ -149,6 +149,9 @@ public class MenuService {
public MenuResponse postBanner(MenuRequest menuRequest){
menuRequest.setCreateBy(CommonUtils.getAdmin().getId());
int maxOrderId = menuMapper.getMaxOrderId();
menuRequest.setOrderId(maxOrderId+1);
menuMapper.insertBanner(menuRequest);
long banner_id = menuRequest.getId();
@@ -163,7 +166,8 @@ public class MenuService {
File file = fileUtils.loadFileObject(temp_file);
String fileUri = "";
try{
fileUri = s3Service.uploadFile(file, CommonConstants.S3_MENU_BANNER_DIRECTORY + banner_id, contentType);
String directory = String.format("%s/%s-%d", CommonConstants.S3_MENU_BANNER_DIRECTORY, CommonConstants.S3_MENU_BANNER_DIRECTORY, banner_id);
fileUri = s3Service.uploadFile(file, directory, contentType);
}catch (S3Exception e) {
log.error("S3 오류: {}", e.getMessage());
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_FILE_S3_UPLOAD.getMessage());

View File

@@ -31,6 +31,12 @@ public class S3Service {
@Value("${amazon.aws.region}")
private String region;
@Value("${amazon.s3.cloud-front}")
private String cloudFrontUrl;
@Value("${spring.profiles.active}")
private String activeProfile;
public Optional<GetObjectAttributesResponse> getObjectMetadata(String key) {
try {
GetObjectAttributesRequest request = GetObjectAttributesRequest.builder()
@@ -47,10 +53,10 @@ public class S3Service {
}
public String uploadFile(File file, String directoryName, String contentType) throws IOException, S3Exception {
String fileName = UUID.randomUUID().toString() + "-" + file.getName();
String fileName = UUID.randomUUID() + "-" + file.getName();
// S3 객체 키 (경로 + 파일명)
String objectKey = directoryName + "/" + fileName;
String objectKey = String.format("%s/%s/%s", activeProfile, directoryName, fileName);
try {
@@ -65,11 +71,8 @@ public class S3Service {
putObjectRequest,
RequestBody.fromBytes(Files.readAllBytes(file.toPath()))
);
//https://metaverse-myhomeugc-test.s3.us-west-2.amazonaws.com/0002896883264fc9af5be62134939ce4/552ec8a4302348edb3fbf1496811d75f.ugcinfo
return "https://" + bucketName + ".s3." +
s3Client.serviceClientConfiguration().region().toString() +
".amazonaws.com/" + objectKey;
// return "s3://" + bucketName + objectKey;
return cloudFrontUrl + objectKey;
}catch (S3Exception | IOException e) {
throw e;
}

View File

@@ -34,9 +34,13 @@ public class BattleEventAttrib extends DynamoDBAttribBase {
@JsonProperty("start_min")
private Integer startMin;
@JsonProperty("open_duration_minutes")
private Integer openDurationMinutes;
@JsonProperty("end_date")
private String endDate;
//추후 사용안함
@JsonProperty("instance_id")
private Integer instanceId;
@@ -46,16 +50,22 @@ public class BattleEventAttrib extends DynamoDBAttribBase {
@JsonProperty("day_of_week_type")
private HashSet<EDayOfWeekType> dayOfWeekType;
//추후 사용안함
@JsonProperty("ffa_config_data_id")
private Integer configDataId;
//추후 사용안함
@JsonProperty("ffa_reward_group_id")
private Integer rewardGroupId;
@JsonProperty("ffa_hot_time")
private Integer hotTime;
//추후 사용안함
@JsonProperty("round_count")
private Integer roundCount;
@JsonProperty("game_mode_id")
private Integer gameModeId;
}

View File

@@ -0,0 +1,44 @@
package com.caliverse.admin.dynamodb.entity;
import com.caliverse.admin.domain.entity.common.ValueEnum;
import com.fasterxml.jackson.annotation.JsonCreator;
public enum EAmountDeltaType implements ValueEnum {
None(0),
Acquire(1),
Consume(2),
Merge(3)
;
private final int value;
EAmountDeltaType(int value) {
this.value = value;
}
@Override
public int getValue() {
return value;
}
@JsonCreator
public static EAmountDeltaType fromValue(Object value) {
if (value instanceof Number) {
int intValue = ((Number) value).intValue();
for (EAmountDeltaType type : values()) {
if (type.value == intValue) {
return type;
}
}
} else if (value instanceof String) {
String stringValue = (String) value;
for (EAmountDeltaType type : values()) {
if (type.name().equalsIgnoreCase(stringValue)) {
return type;
}
}
}
throw new IllegalArgumentException("Invalid EAmountDeltaType value: " + value);
}
}

View File

@@ -2,6 +2,7 @@ package com.caliverse.admin.dynamodb.entity;
import com.caliverse.admin.domain.entity.common.ValueEnum;
import com.fasterxml.jackson.annotation.JsonCreator;
public enum ECurrencyType implements ValueEnum {
None(0),
@@ -22,4 +23,25 @@ public enum ECurrencyType implements ValueEnum {
public int getValue() {
return value;
}
@JsonCreator
public static ECurrencyType fromValue(Object value) {
if (value instanceof Number) {
int intValue = ((Number) value).intValue();
for (ECurrencyType type : values()) {
if (type.value == intValue) {
return type;
}
}
} else if (value instanceof String) {
String stringValue = (String) value;
for (ECurrencyType type : values()) {
if (type.name().equalsIgnoreCase(stringValue)) {
return type;
}
}
}
throw new IllegalArgumentException("Invalid ECurrencyType value: " + value);
}
}

View File

@@ -1,11 +1,15 @@
package com.caliverse.admin.dynamodb.entity;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SystemMessage {
@JsonProperty("LanguageType")
private Integer languageType;

View File

@@ -3,11 +3,12 @@ package com.caliverse.admin.dynamodb.repository;
import com.caliverse.admin.domain.entity.BattleEvent;
import com.caliverse.admin.domain.request.BattleEventRequest;
import com.caliverse.admin.dynamodb.domain.doc.BattleEventDoc;
import com.caliverse.admin.dynamodb.entity.DynamodbOperationResult;
public interface BattleEventRepository extends DynamoDBRepository<BattleEventDoc> {
int findEventId();
void insert(BattleEventRequest battleEventRequest);
void update(BattleEventRequest battleEventRequest);
void delete(BattleEventRequest battleEventRequest);
DynamodbOperationResult delete(String id);
void updateStop(BattleEvent battleEvent);
}

View File

@@ -5,6 +5,8 @@ import com.caliverse.admin.domain.entity.HISTORYTYPEDETAIL;
import com.caliverse.admin.domain.request.BattleEventRequest;
import com.caliverse.admin.dynamodb.domain.atrrib.BattleEventAttrib;
import com.caliverse.admin.dynamodb.domain.doc.BattleEventDoc;
import com.caliverse.admin.dynamodb.domain.doc.SystemMetaMailDoc;
import com.caliverse.admin.dynamodb.entity.DynamodbOperationResult;
import com.caliverse.admin.dynamodb.entity.EDayOfWeekType;
import com.caliverse.admin.dynamodb.entity.EOncePeriodRangeType;
import com.caliverse.admin.dynamodb.repository.BaseDynamoDBRepository;
@@ -21,6 +23,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import software.amazon.awssdk.enhanced.dynamodb.Key;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.HashSet;
@@ -101,6 +104,8 @@ public class BattleEventRepositoryImpl extends BaseDynamoDBRepository<BattleEven
attrib.setHotTime(battleEventRequest.getHotTime());
attrib.setRoundCount(battleEventRequest.getRoundCount());
attrib.setActive(true);
attrib.setGameModeId(battleEventRequest.getGameModeId());
attrib.setOpenDurationMinutes((int) Duration.ofSeconds(battleEventRequest.getEventOperationTime()).toMinutes());
BattleEventDoc doc = new BattleEventDoc();
doc.setPK(DynamoDBConstants.PK_KEY_BATTLE_EVENT);
@@ -151,6 +156,8 @@ public class BattleEventRepositoryImpl extends BaseDynamoDBRepository<BattleEven
attrib.setHotTime(battleEventRequest.getHotTime());
attrib.setRoundCount(battleEventRequest.getRoundCount());
attrib.setActive(true);
attrib.setGameModeId(battleEventRequest.getGameModeId());
attrib.setOpenDurationMinutes((int) Duration.ofSeconds(battleEventRequest.getEventOperationTime()).toMinutes());
afterDoc.setAttribValue(objectMapper.writeValueAsString(attrib));
afterDoc.setUpdatedDateTime(CommonUtils.convertUTCDate(nowDate));
@@ -172,8 +179,37 @@ public class BattleEventRepositoryImpl extends BaseDynamoDBRepository<BattleEven
}
@Override
public void delete(BattleEventRequest battleEventRequest) {
return;
public DynamodbOperationResult delete(String id) {
try{
Key key = Key.builder()
.partitionValue(DynamoDBConstants.PK_KEY_BATTLE_EVENT)
.sortValue(id)
.build();
BattleEventDoc doc = findById(key);
if(doc != null) {
Key detailKey = Key.builder()
.partitionValue(doc.getPK())
.sortValue(doc.getSK())
.build();
delete(detailKey);
log.info("BattleEventDoc Delete Success: {}", objectMapper.writeValueAsString(doc));
dynamodbHistoryLogService.deleteHistoryLog(
HISTORYTYPEDETAIL.BATTLE_EVENT_DELETE,
HISTORYTYPEDETAIL.BATTLE_EVENT_DELETE.name(),
doc
);
return new DynamodbOperationResult(true, "", doc);
}
return new DynamodbOperationResult(true, "null", doc);
}catch (Exception e){
log.error("delete BattleEventDoc Error: {}", e.getMessage());
return new DynamodbOperationResult(false, e.getMessage(), null);
}
}
@Override

View File

@@ -44,8 +44,6 @@ public class LandAuctionRegistryRepositoryImpl extends BaseDynamoDBRepository<La
LandAuctionRegistryDoc latestDoc = docs.stream().min((doc1, doc2) -> doc2.getSK().compareTo(doc1.getSK()))
.orElse(null);
if(latestDoc == null) return 0;
LandAuctionRegistryAttrib attrib = latestDoc.getAttribValue();
return attrib.getAuctionNumber();

View File

@@ -4,7 +4,9 @@ import com.caliverse.admin.domain.entity.Event;
import com.caliverse.admin.domain.entity.HISTORYTYPEDETAIL;
import com.caliverse.admin.domain.entity.Message;
import com.caliverse.admin.dynamodb.domain.atrrib.SystemMetaMailAttrib;
import com.caliverse.admin.dynamodb.domain.doc.LandAuctionRegistryDoc;
import com.caliverse.admin.dynamodb.domain.doc.SystemMetaMailDoc;
import com.caliverse.admin.dynamodb.entity.DynamodbOperationResult;
import com.caliverse.admin.dynamodb.repository.BaseDynamoDBRepository;
import com.caliverse.admin.dynamodb.repository.SystemMetaMailRepository;
import com.caliverse.admin.dynamodb.service.DynamoDBOperations;
@@ -17,6 +19,7 @@ import com.caliverse.admin.mongodb.service.DynamodbHistoryLogService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import software.amazon.awssdk.enhanced.dynamodb.Key;
import java.time.LocalDateTime;
@@ -69,4 +72,38 @@ public class SystemMetaMailRepositoryImpl extends BaseDynamoDBRepository<SystemM
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
}
}
@Override
public DynamodbOperationResult delete(String id) {
try{
Key key = Key.builder()
.partitionValue(DynamoDBConstants.PK_KEY_SYSTEM_MAIL)
.sortValue(id)
.build();
SystemMetaMailDoc doc = findById(key);
if(doc != null) {
Key detailKey = Key.builder()
.partitionValue(doc.getPK())
.sortValue(doc.getSK())
.build();
delete(detailKey);
log.info("SystemMetaMailDoc Delete Success: {}", objectMapper.writeValueAsString(doc));
dynamodbHistoryLogService.deleteHistoryLog(
HISTORYTYPEDETAIL.SYSTEM_META_MAIL_DELETE,
HISTORYTYPEDETAIL.SYSTEM_META_MAIL_DELETE.name(),
doc
);
return new DynamodbOperationResult(true, "", doc);
}
return new DynamodbOperationResult(true, "null", doc);
}catch (Exception e){
log.error("oldMetaMailClear SystemMetaMailDoc Error: {}", e.getMessage());
return new DynamodbOperationResult(false, e.getMessage(), null);
}
}
}

View File

@@ -4,9 +4,11 @@ import com.caliverse.admin.domain.entity.Event;
import com.caliverse.admin.domain.entity.Item;
import com.caliverse.admin.domain.entity.Message;
import com.caliverse.admin.dynamodb.domain.doc.SystemMetaMailDoc;
import com.caliverse.admin.dynamodb.entity.DynamodbOperationResult;
import java.util.List;
public interface SystemMetaMailRepository extends DynamoDBRepository<SystemMetaMailDoc> {
void insert(Event event);
DynamodbOperationResult delete(String id);
}

View File

@@ -2,11 +2,24 @@ package com.caliverse.admin.dynamodb.service;
import com.caliverse.admin.domain.entity.BattleEvent;
import com.caliverse.admin.domain.request.BattleEventRequest;
import com.caliverse.admin.dynamodb.domain.atrrib.BattleEventAttrib;
import com.caliverse.admin.dynamodb.domain.atrrib.SystemMetaMailAttrib;
import com.caliverse.admin.dynamodb.domain.doc.BattleEventDoc;
import com.caliverse.admin.dynamodb.domain.doc.SystemMetaMailDoc;
import com.caliverse.admin.dynamodb.entity.EOncePeriodRangeType;
import com.caliverse.admin.dynamodb.repository.BattleEventRepository;
import com.caliverse.admin.global.common.annotation.DynamoDBTransaction;
import com.caliverse.admin.global.common.constants.DynamoDBConstants;
import com.caliverse.admin.global.common.utils.CommonUtils;
import com.caliverse.admin.global.common.utils.DateUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import software.amazon.awssdk.enhanced.dynamodb.Key;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
@Service
@RequiredArgsConstructor
@@ -33,4 +46,33 @@ public class DynamodbBattleEventService {
battleEventRepository.updateStop(battleEvent);
}
@DynamoDBTransaction
public void oldBattleEventClear(){
Key key = Key.builder()
.partitionValue(DynamoDBConstants.PK_KEY_BATTLE_EVENT)
.build();
List<BattleEventDoc> eventList = battleEventRepository.findAll(key);
eventList.forEach(event -> {
try {
BattleEventAttrib attrib = CommonUtils.stringByObject(event.getAttribValue(), BattleEventAttrib.class);
EOncePeriodRangeType oncePeriodRangeType = attrib.getOncePeriodType();
LocalDateTime startTime = DateUtils.stringToDateTime(attrib.getStartDay());
LocalDateTime expiredTime = LocalDateTime.now().minusMonths(1);
if (Objects.requireNonNull(oncePeriodRangeType) == EOncePeriodRangeType.NONE) {
if (startTime.isBefore(expiredTime)) {
battleEventRepository.delete(event.getSK());
}
} else {
LocalDateTime endDate = DateUtils.stringToDateTime(attrib.getEndDate());
if (endDate.isBefore(expiredTime)) {
battleEventRepository.delete(event.getSK());
}
}
}catch (Exception e){
log.error("oldSystemMetaMail Clear Fail: {}",e.getMessage());
}
});
}
}

View File

@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
@@ -51,33 +52,107 @@ public class DynamodbItemService {
List<UsersResponse.Item> etcList = new ArrayList<>();
Map<String, AttributeValue> pageKey = null;
final AtomicInteger processedItems = new AtomicInteger(0);
do {
PageResult<ItemDoc> itemList = itemRepository.getItemListWithPaging(guid, "", DynamoDBConstants.ATTRIB_ITEM, EFilterOperator.CONTAINS,"\"equiped_inven_type\":0", pageKey, false);
itemList.getItems().forEach(item -> {
ItemAttrib attrib = CommonUtils.stringByObject(item.getAttribValue(), ItemAttrib.class);
int item_id = attrib.getItemMetaId();
String item_name = metaDataHandler.getTextStringData(metaDataHandler.getMetaItemNameData(item_id));
String item_type = metaDataHandler.getMetaItemLargeTypeData(item_id);
try {
processedItems.incrementAndGet();
UsersResponse.Item inventory = UsersResponse.Item.builder()
.itemId(item_id)
.itemName(item_name)
.count(attrib.getItemStackCount())
.itemGuid(attrib.getItemGuid())
.build();
// 2. ItemAttrib 파싱 예외 처리
ItemAttrib attrib = null;
try {
attrib = CommonUtils.stringByObject(item.getAttribValue(), ItemAttrib.class);
if (attrib == null) {
log.warn("Failed to parse ItemAttrib for pk: {}, sk: {}",
item.getPK(), item.getSK());
return;
}
} catch (Exception e) {
log.error("Exception while parsing ItemAttrib for pk: {}, sk: {}, error: {}",
item.getPK(), item.getSK(), e.getMessage(), e);
return;
}
if(item_type.isEmpty()) {
etcList.add(inventory);
}else{
switch (ITEMLARGETYPE.valueOf(item_type)){
case CLOTH -> clothList.add(inventory);
case PROP -> propList.add(inventory);
case BEAUTY -> beautyList.add(inventory);
case TATTOO -> tattooList.add(inventory);
case CURRENCY -> currencyList.add(inventory);
default -> etcList.add(inventory);
}}
// 3. 메타데이터 조회 예외 처리
int item_id = attrib.getItemMetaId();
String item_name = "";
String item_type = "";
try {
item_name = metaDataHandler.getTextStringData(
metaDataHandler.getMetaItemNameData(item_id));
if (item_name == null) {
item_name = "Unknown Item"; // 기본값 설정
log.warn("Item name is null for itemId: {}, guid: {}", item_id, guid);
}
} catch (Exception e) {
item_name = "Unknown Item";
log.error("Failed to get item name for itemId: {}, guid: {}, error: {}",
item_id, guid, e.getMessage(), e);
}
try {
item_type = metaDataHandler.getMetaItemLargeTypeData(item_id);
if (item_type == null) {
item_type = ""; // 기본값 설정
log.warn("Item type is null for itemId: {}, guid: {}", item_id, guid);
}
} catch (Exception e) {
item_type = "";
log.error("Failed to get item type for itemId: {}, guid: {}, error: {}",
item_id, guid, e.getMessage(), e);
}
// 4. UsersResponse.Item 생성 예외 처리
UsersResponse.Item inventory = null;
try {
inventory = UsersResponse.Item.builder()
.itemId(item_id)
.itemName(item_name)
.count(attrib.getItemStackCount())
.itemGuid(attrib.getItemGuid())
.build();
} catch (Exception e) {
log.error("Failed to build inventory item for itemId: {}, guid: {}, error: {}",
item_id, guid, e.getMessage(), e);
return;
}
// 5. 아이템 분류 예외 처리
try {
if (item_type.isEmpty()) {
etcList.add(inventory);
} else {
try {
ITEMLARGETYPE itemLargeType = ITEMLARGETYPE.valueOf(item_type);
switch (itemLargeType) {
case CLOTH -> clothList.add(inventory);
case PROP -> propList.add(inventory);
case BEAUTY -> beautyList.add(inventory);
case TATTOO -> tattooList.add(inventory);
case CURRENCY -> currencyList.add(inventory);
default -> etcList.add(inventory);
}
} catch (IllegalArgumentException e) {
// ENUM 값이 존재하지 않는 경우
log.warn("Unknown item type: {} for itemId: {}, guid: {}, adding to etc list",
item_type, item_id, guid);
etcList.add(inventory);
}
}
} catch (Exception e) {
log.error("Failed to categorize item for itemId: {}, guid: {}, error: {}, adding to etc list",
item_id, guid, e.getMessage(), e);
etcList.add(inventory);
}
} catch (Exception e) {
log.error("Unexpected error processing item for guid: {}, error: {}",
guid, e.getMessage(), e);
}
});
pageKey = itemList.getLastEvaluatedKey();

View File

@@ -10,6 +10,7 @@ import com.caliverse.admin.domain.request.LandRequest;
import com.caliverse.admin.dynamodb.domain.atrrib.*;
import com.caliverse.admin.dynamodb.domain.doc.MailDoc;
import com.caliverse.admin.dynamodb.domain.doc.MailJsonDoc;
import com.caliverse.admin.dynamodb.domain.doc.SystemMetaMailDoc;
import com.caliverse.admin.dynamodb.dto.PageResult;
import com.caliverse.admin.dynamodb.entity.KeyParam;
import com.caliverse.admin.dynamodb.repository.*;
@@ -18,6 +19,7 @@ import com.caliverse.admin.global.common.constants.AdminConstants;
import com.caliverse.admin.global.common.constants.CommonConstants;
import com.caliverse.admin.global.common.constants.DynamoDBConstants;
import com.caliverse.admin.global.common.utils.CommonUtils;
import com.caliverse.admin.global.common.utils.DateUtils;
import com.caliverse.admin.logs.Indicatordomain.StartEndTime;
import com.caliverse.admin.logs.logservice.LogServiceHelper;
import com.caliverse.admin.logs.logservice.indicators.IndicatorsMoneyService;
@@ -28,6 +30,7 @@ import org.springframework.stereotype.Service;
import software.amazon.awssdk.enhanced.dynamodb.Key;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -142,4 +145,24 @@ public class DynamodbMailService {
mailRepository.deleteMailItem(key, itemId, count, newCount);
}
}
@DynamoDBTransaction
public void oldSystemMetaMailClear(){
Key key = Key.builder()
.partitionValue(DynamoDBConstants.PK_KEY_SYSTEM_MAIL)
.build();
List<SystemMetaMailDoc> mailList = systemMetaMailRepository.findAll(key);
mailList.forEach(mail -> {
try {
SystemMetaMailAttrib attrib = CommonUtils.stringByObject(mail.getAttribValue(), SystemMetaMailAttrib.class);
LocalDateTime endTime = DateUtils.stringISOToLocalDateTime(attrib.getEndTime());
LocalDateTime expiredTime = LocalDateTime.now().minusMonths(1);
if(endTime.isBefore(expiredTime)){
systemMetaMailRepository.delete(mail.getSK());
}
}catch (Exception e){
log.error("oldSystemMetaMail Clear Fail: {}",e.getMessage());
}
});
}
}

View File

@@ -16,6 +16,7 @@ public class AdminConstants {
public static final String MONGO_DB_COLLECTION_DATA_INIT_HISTORY = "dataInitHistory";
public static final String MONGO_DB_COLLECTION_API_LOG = "apiLog";
public static final String MONGO_DB_COLLECTION_HISTORY_LOG = "historyLog";
public static final String MONGO_DB_COLLECTION_CURRENCY = "currency";
public static final String MONGO_DB_KEY_LOGTIME = "logTime";
public static final String MONGO_DB_KEY_LOGMONTH = "logMonth";

View File

@@ -5,7 +5,7 @@ public class CommonConstants {
public static final String FALSE = "False";
public static final String NONE = "None";
public static final String SCHEDULE = "Schedule";
public static final int BATTLE_SERVER_WAIT_TIME = 600; // (seconds) 이벤트 홍보시간이 300초인데 여유있게 처리하게 하기위해 600으로 준다.
public static final int BATTLE_SERVER_WAIT_TIME = 300; // (seconds) 이벤트 홍보시간이 300초인데 여유있게 처리하게 하기위해 600으로 준다.
public static final int BATTLE_INSTANCE_ID = 1017007;
public static final String CALIUM_ITEM_CODE = "19010003";
public static final String CALIVERSE_CODE = "CALIVERSE";
@@ -16,7 +16,7 @@ public class CommonConstants {
public static final String LAND_EVENT = "event";
public static final String SYSTEM_MAIL_LAND_TRANS_KEY = "LandTrans";
public static final int DYNAMODB_PAGING_SIZE = 30;
public static final String S3_MENU_BANNER_DIRECTORY = "banner-";
public static final String S3_MENU_BANNER_DIRECTORY = "menuBanner";
public static final String GUID = "GUID";
public static final String NICKNAME = "NICKNAME";
public static final String EMAIL = "EMAIL";

View File

@@ -1,15 +0,0 @@
package com.caliverse.admin.global.common.constants;
public class MetadataConstants {
public static final String JSON_LIST_TEXT_STRING = "TextStringMetaDataList";
public static final String JSON_LIST_ITEM = "ItemMetaDataList";
public static final String JSON_LIST_CLOTH_TYPE = "ClothEquipTypeDataList";
public static final String JSON_LIST_TOOL = "ToolMetaDataList";
public static final String JSON_LIST_BAN_WORD = "BanWordMetaDataList";
public static final String JSON_LIST_QUEST = "QuestMetaDataList";
public static final String JSON_LIST_BUILDING = "BuildingMetaDataList";
public static final String JSON_LIST_LAND = "LandMetaDataList";
public static final String JSON_LIST_BATTLE_CONFIG = "BattleFFAConfigMetaDataList";
public static final String JSON_LIST_BATTLE_REWARD = "BattleFFARewardMetaDataList";
public static final String JSON_LIST_SYSTEM_META = "SystemMailMetaDataList";
}

View File

@@ -1,5 +1,7 @@
package com.caliverse.admin.global.common.utils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.time.*;
import java.time.format.DateTimeFormatter;
@@ -7,14 +9,15 @@ import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.*;
import com.caliverse.admin.domain.entity.AI.AIRole;
import com.caliverse.admin.domain.entity.DiffStatus;
import com.caliverse.admin.global.common.code.CommonCode;
import com.caliverse.admin.global.common.constants.CommonConstants;
import com.caliverse.admin.global.common.exception.RestApiException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.math3.dfp.DfpField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
@@ -310,7 +313,7 @@ public class CommonUtils {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(string, valueType);
} catch (JsonProcessingException e) {
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.JSON_PARSE_ERROR.getMessage());
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.JSON_PARSE_ERROR.getMessage() + " : " + e.getMessage());
}
}
@@ -319,10 +322,24 @@ public class CommonUtils {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.JSON_PARSE_ERROR.getMessage());
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.JSON_PARSE_ERROR.getMessage() + " : " + e.getMessage());
}
}
public static JsonNode stringByJsonNode(String data) {
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readTree(data);
} catch (JsonProcessingException e) {
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.JSON_PARSE_ERROR.getMessage() + " : " + e.getMessage());
}
}
public static <T> T nodeByValue(JsonNode node, Class<T> valueType) {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.convertValue(node, valueType);
}
public static Integer stringToInt(String string) {
try{
return Integer.parseInt(string);
@@ -393,7 +410,9 @@ public class CommonUtils {
}
}
public static Map<String, String> getAIMessage(AIRole role, String message){
return Map.of("role", role.toString(), "content", message);
public static double mathRoundDouble(double value){
return BigDecimal.valueOf(value)
.setScale(2, RoundingMode.HALF_UP)
.doubleValue();
}
}

View File

@@ -32,6 +32,10 @@ public class DateUtils {
return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
}
public static LocalDateTime stringToDateTime(String str){
return LocalDateTime.parse(str, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}
public static LocalDateTime stringToLocalDateTime(String date){
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return LocalDateTime.parse(date, formatter);

View File

@@ -58,7 +58,6 @@ public class ExcelUtils {
return value;
}
switch (cell.getCellType()) {
case STRING: // getRichStringCellValue() 메소드를 사용하여 컨텐츠를 읽음
value = cell.getRichStringCellValue().getString();

View File

@@ -0,0 +1,49 @@
package com.caliverse.admin.global.component.tracker;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
@Slf4j
public class ExcelProgressTracker {
private final Map<String, ProgressInfo> progressMap = new ConcurrentHashMap<>();
@Data
@AllArgsConstructor
public static class ProgressInfo {
private int currentStep;
private int totalSteps;
private String message;
private long timestamp;
public int getPercentage() {
return totalSteps > 0 ? (currentStep * 100) / totalSteps : 0;
}
}
public void updateProgress(String taskId, int currentStep, int totalSteps, String message) {
progressMap.put(taskId, new ProgressInfo(currentStep, totalSteps, message, System.currentTimeMillis()));
log.info("Progress [{}]: {}/{} - {}", taskId, currentStep, totalSteps, message);
}
public ProgressInfo getProgress(String taskId) {
return progressMap.get(taskId);
}
public void removeProgress(String taskId) {
progressMap.remove(taskId);
}
// 5분 이상 된 진행률 정보 자동 정리
@Scheduled(fixedRate = 300000) // 5분마다
public void cleanupOldProgress() {
long fiveMinutesAgo = System.currentTimeMillis() - 300000;
progressMap.entrySet().removeIf(entry -> entry.getValue().getTimestamp() < fiveMinutesAgo);
}
}

View File

@@ -48,7 +48,11 @@ public class MongoIndicatorConfig {
String auth = username.isEmpty() ? "" : String.format("%s:%s@",username, encodePassword);
String connection;
if(activeProfile.equals("local") || activeProfile.equals("dev")) {
connection = String.format("mongodb://%s%s/?authSource=%s", auth, businessLogHost, db);
if(businessLogHost.contains("metaverse")){
connection = String.format("mongodb+srv://%s%s/%s?retryWrites=true&w=majority", auth, businessLogHost, db);
}else{
connection = String.format("mongodb://%s%s/?authSource=%s", auth, businessLogHost, db);
}
}else{
connection = String.format("mongodb+srv://%s%s/%s?retryWrites=true&w=majority&appName=backoffice-%s", auth, businessLogHost, db, activeProfile);
}

View File

@@ -38,6 +38,9 @@ public class RedisConfig {
@Value("${redis.ssl}")
private boolean ssl;
@Value("${redis.prefix}")
private String prefix;
@Value("${redis.abort-connect}")
private boolean abortConnect;
@@ -124,7 +127,8 @@ public class RedisConfig {
public RedisCacheManager cacheManager(JedisConnectionFactory jedisConnectionFactory) {
RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(60)) // 캐시 TTL 설정
.disableCachingNullValues(); // null 값 캐싱 금지
.disableCachingNullValues() // null 값 캐싱 금지
.computePrefixWith(cacheName -> prefix + ":" + cacheName + ":");
return RedisCacheManager.builder(jedisConnectionFactory)
.cacheDefaults(cacheConfig)

View File

@@ -0,0 +1,45 @@
package com.caliverse.admin.logs.Indicatordomain;
import com.caliverse.admin.global.common.constants.AdminConstants;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.List;
@Document(collection = AdminConstants.MONGO_DB_COLLECTION_LOG)
@Getter
@Setter
public class CurrencyMongoLog extends MongoLogSearchBase{
private Double sapphireAcquired;
private Double sapphireConsumed;
private Double sapphireNet;
private Double goldAcquired;
private Double goldConsumed;
private Double goldNet;
private Double caliumAcquired;
private Double caliumConsumed;
private Double caliumNet;
private Double beamAcquired;
private Double beamConsumed;
private Double beamNet;
private Double rubyAcquired;
private Double rubyConsumed;
private Double rubyNet;
private Integer totalCurrencies;
private List<currency> currencies;
@Data
@Builder
public static class currency {
private String tranId;
private String action;
private String logTime;
private String currencyType;
private String amountDeltaType;
private Double deltaAmount;
private Double currencyAmount;
}
}

View File

@@ -16,12 +16,13 @@ public class GenericMongoLog extends MongoLogSearchBase{
private Map<String, Object> header;
private Map<String, Object> body;
private String message;
private Integer totalCount;
public Map getMessage() {
if (message == null || message.isEmpty()) {
return new HashMap<>();
}
return CommonUtils.stringByObject(message, Map.class);
}
// public Map getMessage() {
// if (message == null || message.isEmpty()) {
// return new HashMap<>();
// }
// return CommonUtils.stringByObject(message, Map.class);
// }
}

View File

@@ -0,0 +1,446 @@
package com.caliverse.admin.logs.logservice.businesslogservice;
import com.caliverse.admin.global.common.constants.AdminConstants;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
@Slf4j
@Service
public class BusinessLogCurrencyService extends BusinessLogServiceBase {
public BusinessLogCurrencyService(@Qualifier("mongoBusinessLogTemplate") MongoTemplate mongoTemplate) {
super(mongoTemplate);
}
public <T> List<T> loadBusinessLogData(String startTime, String endTime, Class<T> class1) {
Criteria criteria = makeCriteria(startTime, endTime);
List<AggregationOperation> operations = setDefaultOperation(criteria);
operations.add(context ->
new Document("$group",
new Document("_id", "$tranId")
.append("logDay", new Document("$first", "$logDay"))
.append("logTime", new Document("$first", "$logTime"))
.append("userGuid", new Document("$first", "$userGuid"))
.append("userNickname", new Document("$first", "$userNickname"))
.append("accountId", new Document("$first", "$accountId"))
.append("action", new Document("$first", "$action"))
.append("documents", new Document("$push", "$$ROOT"))
)
);
operations.add(context ->
new Document("$match",
new Document("documents",
new Document("$elemMatch",
new Document("message",
new Document("$regex", "\"Domain\":\"Currency\"")
)
)
)
)
);
operations.add(context ->
new Document("$sort",
new Document("logTime", 1)
)
);
operations.add(context ->
new Document("$addFields",
new Document("currencyDocuments",
new Document("$filter",
new Document("input", "$documents")
.append("as", "doc")
.append("cond",
new Document("$regexMatch",
new Document("input", "$$doc.message")
.append("regex", "\"Domain\":\"Currency\"")
)
)
)
)
)
);
operations.add(context ->
new Document("$addFields",
new Document("currencyInfo",
new Document("$map",
new Document("input", "$currencyDocuments")
.append("as", "doc")
.append("in",
new Document("currencyType",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$$doc.message")
.append("regex", "\"CurrencyType\":\"([^\"]+)\"")
)
)
)
.append("in",
new Document("$arrayElemAt",
Arrays.asList("$$found.captures", 0)
)
)
)
)
.append("amountDeltaType",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$$doc.message")
.append("regex", "\"AmountDeltaType\":\"([^\"]+)\"")
)
)
)
.append("in",
new Document("$arrayElemAt",
Arrays.asList("$$found.captures", 0)
)
)
)
)
.append("deltaAmount",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$$doc.message")
.append("regex", "\"DeltaAmount\":([^,}]+)")
)
)
)
.append("in",
new Document("$toDouble",
new Document("$arrayElemAt",
Arrays.asList("$$found.captures", 0)
)
)
)
)
)
.append("currencyAmount",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$$doc.message")
.append("regex", "\"CurrencyAmount\":([^,}]+)")
)
)
)
.append("in",
new Document("$toDouble",
new Document("$arrayElemAt",
Arrays.asList("$$found.captures", 0)
)
)
)
)
)
)
)
)
)
);
operations.add(context ->
new Document("$unwind", "$currencyInfo")
);
operations.add(context ->
new Document("$match",
new Document("currencyInfo.currencyType",
new Document("$ne", null)
)
.append("currencyInfo.amountDeltaType",
new Document("$ne", null)
)
.append("currencyInfo.deltaAmount",
new Document("$ne", null)
)
)
);
operations.add(context ->
new Document("$group",
new Document("_id",
new Document("logDay", "$logDay")
.append("accountId", "$accountId")
)
.append("userGuid", new Document("$first", "$userGuid"))
.append("userNickname", new Document("$first", "$userNickname"))
// Gold
.append("goldAcquired",
new Document("$sum",
new Document("$cond",
Arrays.asList(
new Document("$and",
Arrays.asList(
new Document("$eq", Arrays.asList("$currencyInfo.currencyType", "Gold")),
new Document("$eq", Arrays.asList("$currencyInfo.amountDeltaType", "Acquire"))
)
),
"$currencyInfo.deltaAmount",
0
)
)
)
)
.append("goldConsumed",
new Document("$sum",
new Document("$cond",
Arrays.asList(
new Document("$and",
Arrays.asList(
new Document("$eq", Arrays.asList("$currencyInfo.currencyType", "Gold")),
new Document("$eq", Arrays.asList("$currencyInfo.amountDeltaType", "Consume"))
)
),
new Document("$abs", "$currencyInfo.deltaAmount"),
0
)
)
)
)
// Sapphire
.append("sapphireAcquired",
new Document("$sum",
new Document("$cond",
Arrays.asList(
new Document("$and",
Arrays.asList(
new Document("$eq", Arrays.asList("$currencyInfo.currencyType", "Sapphire")),
new Document("$eq", Arrays.asList("$currencyInfo.amountDeltaType", "Acquire"))
)
),
"$currencyInfo.deltaAmount",
0
)
)
)
)
.append("sapphireConsumed",
new Document("$sum",
new Document("$cond",
Arrays.asList(
new Document("$and",
Arrays.asList(
new Document("$eq", Arrays.asList("$currencyInfo.currencyType", "Sapphire")),
new Document("$eq", Arrays.asList("$currencyInfo.amountDeltaType", "Consume"))
)
),
new Document("$abs", "$currencyInfo.deltaAmount"),
0
)
)
)
)
// Calium
.append("caliumAcquired",
new Document("$sum",
new Document("$cond",
Arrays.asList(
new Document("$and",
Arrays.asList(
new Document("$eq", Arrays.asList("$currencyInfo.currencyType", "Calium")),
new Document("$eq", Arrays.asList("$currencyInfo.amountDeltaType", "Acquire"))
)
),
"$currencyInfo.deltaAmount",
0
)
)
)
)
.append("caliumConsumed",
new Document("$sum",
new Document("$cond",
Arrays.asList(
new Document("$and",
Arrays.asList(
new Document("$eq", Arrays.asList("$currencyInfo.currencyType", "Calium")),
new Document("$eq", Arrays.asList("$currencyInfo.amountDeltaType", "Consume"))
)
),
new Document("$abs", "$currencyInfo.deltaAmount"),
0
)
)
)
)
// Beam
.append("beamAcquired",
new Document("$sum",
new Document("$cond",
Arrays.asList(
new Document("$and",
Arrays.asList(
new Document("$eq", Arrays.asList("$currencyInfo.currencyType", "Beam")),
new Document("$eq", Arrays.asList("$currencyInfo.amountDeltaType", "Acquire"))
)
),
"$currencyInfo.deltaAmount",
0
)
)
)
)
.append("beamConsumed",
new Document("$sum",
new Document("$cond",
Arrays.asList(
new Document("$and",
Arrays.asList(
new Document("$eq", Arrays.asList("$currencyInfo.currencyType", "Beam")),
new Document("$eq", Arrays.asList("$currencyInfo.amountDeltaType", "Consume"))
)
),
new Document("$abs", "$currencyInfo.deltaAmount"),
0
)
)
)
)
// Ruby
.append("rubyAcquired",
new Document("$sum",
new Document("$cond",
Arrays.asList(
new Document("$and",
Arrays.asList(
new Document("$eq", Arrays.asList("$currencyInfo.currencyType", "Ruby")),
new Document("$eq", Arrays.asList("$currencyInfo.amountDeltaType", "Acquire"))
)
),
"$currencyInfo.deltaAmount",
0
)
)
)
)
.append("rubyConsumed",
new Document("$sum",
new Document("$cond",
Arrays.asList(
new Document("$and",
Arrays.asList(
new Document("$eq", Arrays.asList("$currencyInfo.currencyType", "Ruby")),
new Document("$eq", Arrays.asList("$currencyInfo.amountDeltaType", "Consume"))
)
),
new Document("$abs", "$currencyInfo.deltaAmount"),
0
)
)
)
)
.append("totalCurrencies", new Document("$sum", 1))
.append("currencies",
new Document("$push",
new Document("tranId", "$_id")
.append("action", "$action")
.append("logTime", "$logTime")
.append("currencyType", "$currencyInfo.currencyType")
.append("amountDeltaType", "$currencyInfo.amountDeltaType")
.append("deltaAmount", "$currencyInfo.deltaAmount")
.append("currencyAmount", "$currencyInfo.currencyAmount")
)
)
)
);
operations.add(context ->
new Document("$project",
new Document("_id", 0)
.append("logDay", "$_id.logDay")
.append("accountId", "$_id.accountId")
.append("userGuid", 1)
.append("userNickname", 1)
.append("goldAcquired", 1)
.append("goldConsumed", 1)
.append("goldNet",
new Document("$subtract",
Arrays.asList("$goldAcquired", "$goldConsumed")
)
)
.append("sapphireAcquired", 1)
.append("sapphireConsumed", 1)
.append("sapphireNet",
new Document("$subtract",
Arrays.asList("$sapphireAcquired", "$sapphireConsumed")
)
)
.append("caliumAcquired", 1)
.append("caliumConsumed", 1)
.append("caliumNet",
new Document("$subtract",
Arrays.asList("$caliumAcquired", "$caliumConsumed")
)
)
.append("beamAcquired", 1)
.append("beamConsumed", 1)
.append("beamNet",
new Document("$subtract",
Arrays.asList("$beamAcquired", "$beamConsumed")
)
)
.append("rubyAcquired", 1)
.append("rubyConsumed", 1)
.append("rubyNet",
new Document("$subtract",
Arrays.asList("$rubyAcquired", "$rubyConsumed")
)
)
.append("totalCurrencies", 1)
.append("currencies", 1)
)
);
operations.add(context ->
new Document("$sort",
new Document("logTime", 1)
.append("accountId", 1)
)
);
Aggregation aggregation = Aggregation.newAggregation(operations);
log.info("loadBusinessLogData Currency Query: {}", aggregation);
AggregationResults<T> results = getMongoTemplate().aggregate(
aggregation.withOptions(AggregationOptions.builder().allowDiskUse(true).build())
, AdminConstants.MONGO_DB_COLLECTION_LOG
, class1
);
return results.getMappedResults();
}
protected Criteria makeCriteria(String startTime, String endTime) {
return new Criteria()
.andOperator(
Criteria.where(AdminConstants.MONGO_DB_KEY_LOGTIME).gte(startTime)
,Criteria.where(AdminConstants.MONGO_DB_KEY_LOGTIME).lt(endTime)
);
}
}

View File

@@ -1,12 +1,16 @@
package com.caliverse.admin.logs.logservice.businesslogservice;
import com.caliverse.admin.domain.entity.EInputType;
import com.caliverse.admin.domain.entity.Log;
import com.caliverse.admin.domain.entity.common.SearchUserType;
import com.caliverse.admin.domain.entity.log.GenericLog;
import com.caliverse.admin.domain.request.LogGenericRequest;
import com.caliverse.admin.global.common.constants.AdminConstants;
import com.caliverse.admin.global.common.utils.CommonUtils;
import com.caliverse.admin.logs.Indicatordomain.GenericMongoLog;
import com.caliverse.admin.logs.entity.LogAction;
import com.caliverse.admin.logs.entity.LogDomain;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.bson.Document;
@@ -24,6 +28,8 @@ import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Slf4j
@Service
@@ -38,14 +44,240 @@ public class BusinessLogGenericService extends BusinessLogServiceBase {
}
public <T> List<T> loadBusinessLogData(LogGenericRequest logGenericRequest, Class<T> class1){
return loadBusinessLogData(logGenericRequest, class1, false);
List<GenericMongoLog> rawLogs = loadRawLogData(logGenericRequest);
List<T> processedLogs = rawLogs.parallelStream()
.map(rawLog -> parseLog(rawLog, class1))
.filter(logData -> {
if (logData == null) {
log.warn("Failed to parse log data - null result returned");
return false;
}
return true;
})
// 추후 조건에 따른 조회방식 처리 필요할듯(정규식은 느리다)
// .filter(logData -> {
// LogAction action = logGenericRequest.getLogAction();
// if(action == null || action.equals(LogAction.None)) return true;
// GenericLog log = (GenericLog) logData;
// return action.name().equals(log.getAction());
// })
// .filter(logData -> {
// LogDomain domain = logGenericRequest.getLogDomain();
// if(domain == null || domain.equals(LogDomain.BASE)) return true;
// GenericLog log = (GenericLog) logData;
// return domain.name().equals(log.getDomain());
// })
// .filter(logData -> {
// SearchUserType searchType = logGenericRequest.getSearchType();
// String searchData = logGenericRequest.getSearchData();
// if(searchData == null || searchData.isEmpty()) return true;
//
// GenericLog log = (GenericLog) logData;
//
// switch (searchType) {
// case ACCOUNT:
// return searchData.equals(log.getAccountId());
// case GUID:
// return searchData.equals(log.getUserGuid());
// case NICKNAME:
// return searchData.equals(log.getUserNickname());
// default:
// return false;
// }
// })
// .filter(logData -> {
// String tranId = logGenericRequest.getTranId();
// if(tranId == null || tranId.isEmpty()) return true;
// GenericLog log = (GenericLog) logData;
// return tranId.equals(log.getTranId());
// })
.toList();
return processedLogs;
}
// public List<Map<String, Object>> loadBusinessLogData(LogGenericRequest logGenericRequest) {
public <T> List<T> loadBusinessLogData(LogGenericRequest logGenericRequest, Class<T> class1, boolean isSimple) {
// LocalDateTime startDt = logGenericRequest.getStartDt().plusHours(9);
// LocalDateTime endDt = logGenericRequest.getEndDt().plusHours(9).plusDays(1);
// 정규식으로 조회시간이 오래걸린다
// public <T> List<T> loadBusinessLogData(LogGenericRequest logGenericRequest, Class<T> class1) {
//
// String startTime = logGenericRequest.getStartDt().toString().substring(0, 10);
// String endTime = logGenericRequest.getEndDt().toString().substring(0, 10);
// LogAction logAction = logGenericRequest.getLogAction();
// LogDomain logDomain = logGenericRequest.getLogDomain();
// SearchUserType searchUserType = logGenericRequest.getSearchType();
// String searchData = logGenericRequest.getSearchData();
// String tranId = logGenericRequest.getTranId();
// List<LogGenericRequest.LogFilter> filters = logGenericRequest.getFilters();
//
// Criteria criteria = makeCriteria(startTime, endTime);
// if(logAction != null && !logAction.equals(LogAction.None)) {
// criteria.and(AdminConstants.MONGO_DB_KEY_MESSAGE)
// .regex(String.format(AdminConstants.REGEX_MSG_ACTION, logAction.name()));
// }
//
// List<AggregationOperation> operations = setDefaultOperation(criteria);
//
//
// if(logDomain != null && !logDomain.equals(LogDomain.BASE)) {
// operations.add(context ->
// new Document("$match",
// new Document(AdminConstants.MONGO_DB_KEY_DOMAIN, logDomain.name())
// )
// );
// }
//
// if(searchUserType != null && !searchData.isEmpty() && !searchUserType.equals(SearchUserType.NONE)) {
// switch(searchUserType){
// case ACCOUNT:
// operations.add(context ->
// new Document("$match",
// new Document(AdminConstants.MONGO_DB_KEY_ACCOUNT_ID, searchData)
// )
// );
// break;
// case GUID:
// operations.add(context ->
// new Document("$match",
// new Document(AdminConstants.MONGO_DB_KEY_USER_GUID, searchData)
// )
// );
// break;
// case NICKNAME:
// operations.add(context ->
// new Document("$match",
// new Document(AdminConstants.MONGO_DB_KEY_USER_NICKNAME, searchData)
// )
// );
// break;
// }
// }
//
// if(tranId != null && !tranId.isEmpty()) {
// operations.add(context ->
// new Document("$match",
// new Document(AdminConstants.MONGO_DB_KEY_TRAN_ID, tranId)
// )
// );
// }
//
// if(filters != null && !filters.isEmpty()) {
// List<Document> filterConditions = new ArrayList<>();
//
// for (LogGenericRequest.LogFilter filter : filters) {
// if (filter.getFieldName() != null && !filter.getFieldName().isEmpty() &&
// filter.getValue() != null) {
//
// Object convertedValue = null;
// String valueStr = filter.getValue();
//
// // OR 조건 패턴 확인 (괄호와 파이프 문자 포함)
// boolean isOrPattern = valueStr.startsWith("(") && valueStr.endsWith(")") && valueStr.contains("|");
//
// if (isOrPattern) {
// // OR 패턴은 문자열 그대로 사용
// convertedValue = valueStr;
// } else {
// // 일반 값 변환
// switch (filter.getFieldType()) {
// case Number:
// try {
// if (valueStr.contains(".")) {
// convertedValue = Double.parseDouble(valueStr);
// } else {
// convertedValue = Long.parseLong(valueStr);
// }
// } catch (NumberFormatException e) {
// log.warn("Failed to convert value to number: {}", valueStr, e);
// convertedValue = valueStr;
// }
// break;
//
// case Boolean:
// convertedValue = Boolean.parseBoolean(valueStr);
// break;
//
// case String:
// case None:
// default:
// convertedValue = valueStr;
// break;
// }
// }
//
// // 중첩된 JSON 구조에 맞게 $regex를 사용한 패턴 매칭
// String regexPattern;
//
// if (isOrPattern) {
// // OR 패턴 처리
// String innerValues = valueStr.substring(1, valueStr.length() - 1);
// String[] parts = innerValues.split("\\|");
//
// // 필드 이름과 함께 각 값에 대한 정규식 패턴 구성
// StringBuilder orPatternBuilder = new StringBuilder();
// orPatternBuilder.append("\"").append(filter.getFieldName()).append("\":(");
//
// for (int i = 0; i < parts.length; i++) {
// if (i > 0) orPatternBuilder.append("|");
//
// String part = parts[i].trim();
// // 필드 타입에 맞게 값 형식화
// if (filter.getFieldType() == EInputType.String) {
// orPatternBuilder.append("\"").append(part.replace("\"", "\\\"")).append("\"");
// } else {
// orPatternBuilder.append(part);
// }
// }
//
// orPatternBuilder.append(")");
// regexPattern = orPatternBuilder.toString();
// } else {
// // 단일 값 처리
// regexPattern = "\"" + filter.getFieldName() + "\":" + CommonUtils.formatValueForRegex(convertedValue);
// }
//
// Document filterDoc = new Document("message", new Document("$regex", regexPattern));
// filterConditions.add(filterDoc);
// }
// }
//
// if (!filterConditions.isEmpty()) {
// operations.add(context -> new Document("$match", new Document("$and", filterConditions)));
// }
// }
//
// // 최종 출력 형식
// operations.add(context ->
// new Document("$sort",
// new Document("logTime", logGenericRequest.getOrderBy().equals("ASC") ? 1 : -1)
// .append(AdminConstants.MONGO_DB_KEY_TRAN_ID, 1)
// )
// );
//
// if (logGenericRequest.getPageNo() != null && logGenericRequest.getPageSize() != null) {
// int skip = (logGenericRequest.getPageNo() - 1) * logGenericRequest.getPageSize();
// operations.add(context -> new Document("$skip", skip));
// operations.add(context -> new Document("$limit", logGenericRequest.getPageSize()));
// }
//
// AggregationOptions options = AggregationOptions.builder()
// .allowDiskUse(true)
// .maxTime(Duration.ofSeconds(600))
// .build();
// Aggregation aggregation = Aggregation.newAggregation(operations).withOptions(options);
// log.info("loadBusinessLogData Generic Query: {}", aggregation);
// AggregationResults<T> results = getMongoTemplate()
// .aggregate(aggregation, AdminConstants.MONGO_DB_COLLECTION_LOG, class1);
// return results.getMappedResults();
// }
protected Criteria makeCriteria(String startTime, String endTime) {
return new Criteria()
.andOperator(
Criteria.where(AdminConstants.MONGO_DB_KEY_LOGTIME).gte(startTime).lt(endTime)
);
}
private List<GenericMongoLog> loadRawLogData(LogGenericRequest logGenericRequest) {
String startTime = logGenericRequest.getStartDt().toString().substring(0, 10);
String endTime = logGenericRequest.getEndDt().toString().substring(0, 10);
LogAction logAction = logGenericRequest.getLogAction();
@@ -56,20 +288,309 @@ public class BusinessLogGenericService extends BusinessLogServiceBase {
List<LogGenericRequest.LogFilter> filters = logGenericRequest.getFilters();
Criteria criteria = makeCriteria(startTime, endTime);
if(logAction != null && !logAction.equals(LogAction.None)) {
criteria.and(AdminConstants.MONGO_DB_KEY_MESSAGE)
.regex(String.format(AdminConstants.REGEX_MSG_ACTION, logAction.name()));
List<AggregationOperation> operations = new ArrayList<>();
operations.add(Aggregation.match(criteria));
if(logDomain != null && !logDomain.equals(LogDomain.BASE)) {
operations.add(context ->
new Document("$match",
new Document(AdminConstants.MONGO_DB_KEY_MESSAGE,
new Document("$regex", String.format(AdminConstants.REGEX_MSG_DOMAIN, logDomain.name()))
)
)
);
}
List<AggregationOperation> operations = setDefaultOperation(criteria);
if(logAction != null && !logAction.equals(LogAction.None)) {
operations.add(context ->
new Document("$match",
new Document(AdminConstants.MONGO_DB_KEY_MESSAGE,
new Document("$regex", String.format(AdminConstants.REGEX_MSG_ACTION, logAction.name()))
)
)
);
}
// if(logAction != null && !logAction.equals(LogAction.None)) {
// operations.add(context ->
// new Document("$match",
// new Document(AdminConstants.MONGO_DB_KEY_ACTION, logAction.name())
// )
// );
// }
if(searchUserType != null && !searchData.isEmpty() && !searchUserType.equals(SearchUserType.NONE)) {
switch(searchUserType){
case ACCOUNT:
operations.add(context ->
new Document("$match",
new Document(AdminConstants.MONGO_DB_KEY_MESSAGE,
new Document("$regex", String.format("\"AccountId\":\"%s\"", searchData))
)
)
);
break;
case GUID:
operations.add(context ->
new Document("$match",
new Document(AdminConstants.MONGO_DB_KEY_MESSAGE,
new Document("$regex", String.format("\"UserGuid\":\"%s\"", searchData))
)
)
);
break;
case NICKNAME:
operations.add(context ->
new Document("$match",
new Document(AdminConstants.MONGO_DB_KEY_MESSAGE,
new Document("$regex", String.format("\"UserNickname\":\"%s\"", searchData))
)
)
);
break;
}
}
if(tranId != null && !tranId.isEmpty()) {
operations.add(context ->
new Document("$match",
new Document(AdminConstants.MONGO_DB_KEY_MESSAGE,
new Document("$regex", String.format("\"TranId\":\"%s\"", tranId))
)
)
);
}
operations.add(context ->
new Document("$project",
new Document(AdminConstants.MONGO_DB_KEY_LOGTIME, 1)
.append(AdminConstants.MONGO_DB_KEY_MESSAGE, 1)
)
);
if(filters != null && !filters.isEmpty()) {
List<Document> filterConditions = new ArrayList<>();
for (LogGenericRequest.LogFilter filter : filters) {
if (filter.getFieldName() != null && !filter.getFieldName().isEmpty() &&
filter.getValue() != null) {
Object convertedValue = null;
String valueStr = filter.getValue();
// OR 조건 패턴 확인 (괄호와 파이프 문자 포함)
boolean isOrPattern = valueStr.startsWith("(") && valueStr.endsWith(")") && valueStr.contains("|");
if (isOrPattern) {
// OR 패턴은 문자열 그대로 사용
convertedValue = valueStr;
} else {
// 일반 값 변환
switch (filter.getFieldType()) {
case Number:
try {
if (valueStr.contains(".")) {
convertedValue = Double.parseDouble(valueStr);
} else {
convertedValue = Long.parseLong(valueStr);
}
} catch (NumberFormatException e) {
log.warn("Failed to convert value to number: {}", valueStr, e);
convertedValue = valueStr;
}
break;
case Boolean:
convertedValue = Boolean.parseBoolean(valueStr);
break;
case String:
case None:
default:
convertedValue = valueStr;
break;
}
}
// 중첩된 JSON 구조에 맞게 $regex를 사용한 패턴 매칭
String regexPattern;
if (isOrPattern) {
// OR 패턴 처리
String innerValues = valueStr.substring(1, valueStr.length() - 1);
String[] parts = innerValues.split("\\|");
// 필드 이름과 함께 각 값에 대한 정규식 패턴 구성
StringBuilder orPatternBuilder = new StringBuilder();
orPatternBuilder.append("\"").append(filter.getFieldName()).append("\":(");
for (int i = 0; i < parts.length; i++) {
if (i > 0) orPatternBuilder.append("|");
String part = parts[i].trim();
// 필드 타입에 맞게 값 형식화
if (filter.getFieldType() == EInputType.String) {
orPatternBuilder.append("\"").append(part.replace("\"", "\\\"")).append("\"");
} else {
orPatternBuilder.append(part);
}
}
orPatternBuilder.append(")");
regexPattern = orPatternBuilder.toString();
} else {
// 단일 값 처리
regexPattern = "\"" + filter.getFieldName() + "\":" + CommonUtils.formatValueForRegex(convertedValue);
}
Document filterDoc = new Document("message", new Document("$regex", regexPattern));
filterConditions.add(filterDoc);
}
}
if (!filterConditions.isEmpty()) {
operations.add(context -> new Document("$match", new Document("$and", filterConditions)));
}
}
operations.add(context ->
new Document("$sort",
new Document("logTime", logGenericRequest.getOrderBy().equals("ASC") ? 1 : -1)
)
);
if (logGenericRequest.getPageNo() != null && logGenericRequest.getPageSize() != null) {
int skip = (logGenericRequest.getPageNo() - 1) * logGenericRequest.getPageSize();
operations.add(context -> new Document("$skip", skip));
operations.add(context -> new Document("$limit", logGenericRequest.getPageSize()));
}
AggregationOptions options = AggregationOptions.builder()
.allowDiskUse(true)
.maxTime(Duration.ofSeconds(600))
.build();
Aggregation aggregation = Aggregation.newAggregation(operations).withOptions(options);
log.info("loadRawLogData Generic Query: {}", aggregation);
AggregationResults<GenericMongoLog> results = getMongoTemplate()
.aggregate(aggregation, AdminConstants.MONGO_DB_COLLECTION_LOG, GenericMongoLog.class);
return results.getMappedResults();
}
public Integer getRawLogCount(LogGenericRequest logGenericRequest) {
String startTime = logGenericRequest.getStartDt().toString().substring(0, 10);
String endTime = logGenericRequest.getEndDt().toString().substring(0, 10);
LogAction logAction = logGenericRequest.getLogAction();
LogDomain logDomain = logGenericRequest.getLogDomain();
SearchUserType searchUserType = logGenericRequest.getSearchType();
String searchData = logGenericRequest.getSearchData();
String tranId = logGenericRequest.getTranId();
List<LogGenericRequest.LogFilter> filters = logGenericRequest.getFilters();
Criteria criteria = makeCriteria(startTime, endTime);
List<AggregationOperation> operations = new ArrayList<>();
operations.add(Aggregation.match(criteria));
operations.add(context ->
new Document("$addFields",
new Document("userGuid",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$message")
.append("regex", "\"UserGuid\":\"([^\"]+)\"")
)
)
)
.append("in",
new Document("$arrayElemAt", Arrays.asList("$$found.captures", 0))
)
)
)
.append("userNickname",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$message")
.append("regex", "\"UserNickname\":\"([^\"]+)\"")
)
)
)
.append("in",
new Document("$arrayElemAt", Arrays.asList("$$found.captures", 0))
)
)
)
.append("accountId",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$message")
.append("regex", "\"AccountId\":\"([^\"]+)\"")
)
)
)
.append("in",
new Document("$arrayElemAt", Arrays.asList("$$found.captures", 0))
)
)
)
.append("tranId",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$message")
.append("regex", "\"TranId\":\"([^\"]+)\"")
)
)
)
.append("in",
new Document("$arrayElemAt", Arrays.asList("$$found.captures", 0))
)
)
)
.append("action",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$message")
.append("regex", "\"Action\":\"([^\"]+)\"")
)
)
)
.append("in",
new Document("$arrayElemAt", Arrays.asList("$$found.captures", 0))
)
)
)
.append("domain",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$message")
.append("regex", "\"Domain\":\"([^\"]+)\"")
)
)
)
.append("in",
new Document("$arrayElemAt", Arrays.asList("$$found.captures", 0))
)
)
)
)
);
if(logAction != null && !logAction.equals(LogAction.None)) {
operations.add(context ->
new Document("$match",
new Document(AdminConstants.MONGO_DB_KEY_ACTION, logAction.name())
)
);
}
if(logDomain != null && !logDomain.equals(LogDomain.BASE)) {
operations.add(context ->
@@ -198,100 +719,93 @@ public class BusinessLogGenericService extends BusinessLogServiceBase {
}
}
if(isSimple){
operations.add(context ->
new Document("$project",
new Document(AdminConstants.MONGO_DB_KEY_ACCOUNT_ID, 1)
.append(AdminConstants.MONGO_DB_KEY_USER_GUID, 1)
.append(AdminConstants.MONGO_DB_KEY_USER_NICKNAME, 1)
.append(AdminConstants.MONGO_DB_KEY_LOGTIME, 1)
.append("body", 1)
)
);
}
// 최종 출력 형식
operations.add(context ->
new Document("$sort",
new Document("logTime", logGenericRequest.getOrderBy().equals("ASC") ? 1 : -1)
.append(AdminConstants.MONGO_DB_KEY_TRAN_ID, 1)
)
new Document("$count", "totalCount")
);
AggregationOptions options = AggregationOptions.builder()
.allowDiskUse(true)
.maxTime(Duration.ofSeconds(600))
.build();
Aggregation aggregation = Aggregation.newAggregation(operations).withOptions(options);
log.info("loadBusinessLogData Generic Query: {}", aggregation);
AggregationResults<T> results = getMongoTemplate()
.aggregate(aggregation, AdminConstants.MONGO_DB_COLLECTION_LOG, class1);
return results.getMappedResults();
log.info("loadRawLogData Generic Query: {}", aggregation);
AggregationResults<GenericMongoLog> results = getMongoTemplate()
.aggregate(aggregation, AdminConstants.MONGO_DB_COLLECTION_LOG, GenericMongoLog.class);
if (results.getMappedResults().isEmpty()) return 0;
return results.getMappedResults().get(0).getTotalCount();
}
protected Criteria makeCriteria(String startTime, String endTime) {
return new Criteria()
.andOperator(
Criteria.where(AdminConstants.MONGO_DB_KEY_LOGTIME).gte(startTime).lt(endTime)
);
}
private <T> T parseLog(GenericMongoLog rawLog, Class<T> class1) {
try {
JsonNode messageNode = CommonUtils.stringByJsonNode(rawLog.getMessage());
JsonNode header = messageNode.get("Header");
JsonNode body = messageNode.get("Body");
private Map<String, Object> flattenDocument(Document document) {
Map<String, Object> result = new LinkedHashMap<>();
flattenDocumentRecursive(document, "", result);
return result;
}
// 필드 추출 (정규식 대신 JSON 파싱)
String userGuid = extractStringValue(header, "UserGuid");
String userNickname = extractStringValue(header, "UserNickname");
String accountId = extractStringValue(header, "AccountId");
String tranId = extractStringValue(header, "TranId");
String action = extractStringValue(body, "Action");
String domain = extractDomainFromInfos(body);
private void flattenDocumentRecursive(Object obj, String prefix, Map<String, Object> result) {
if (obj instanceof Document) {
Document doc = (Document) obj;
for (String key : doc.keySet()) {
Object value = doc.get(key);
String newKey = prefix.isEmpty() ? key : prefix + "." + key;
// 타겟 객체 생성
if (class1 == GenericLog.class) {
Map<String, Object> headerMap = CommonUtils.nodeByValue(header, Map.class);
Map<String, Object> bodyMap = CommonUtils.nodeByValue(body, Map.class);
if (value instanceof Document || value instanceof Map) {
flattenDocumentRecursive(value, newKey, result);
} else if (value instanceof List) {
// 리스트의 각 항목에 대해 처리
List<?> list = (List<?>) value;
result.put(newKey, list);
GenericLog log = GenericLog.builder()
.logTime(rawLog.getLogTime())
.userGuid(userGuid)
.userNickname(userNickname)
.accountId(accountId)
.tranId(tranId)
.action(action)
.domain(domain)
.header(headerMap)
.body(bodyMap)
.build();
// 리스트 항목이 복잡한 객체인 경우 각각 평탄화
for (int i = 0; i < list.size(); i++) {
Object listItem = list.get(i);
if (listItem instanceof Document || listItem instanceof Map) {
flattenDocumentRecursive(listItem, newKey + "[" + i + "]", result);
}
}
} else {
result.put(newKey, value);
}
return (T) log;
}
} else if (obj instanceof Map) {
Map<?, ?> map = (Map<?, ?>) obj;
for (Map.Entry<?, ?> entry : map.entrySet()) {
String key = entry.getKey().toString();
Object value = entry.getValue();
String newKey = prefix.isEmpty() ? key : prefix + "." + key;
if (value instanceof Document || value instanceof Map) {
flattenDocumentRecursive(value, newKey, result);
} else if (value instanceof List) {
// 리스트의 각 항목에 대해 처리
List<?> list = (List<?>) value;
result.put(newKey, list);
} catch (Exception e) {
log.warn("Failed to parse log: {}", e.getMessage());
}
return null;
}
// 리스트 항목이 복잡한 객체인 경우 각각 평탄화
for (int i = 0; i < list.size(); i++) {
Object listItem = list.get(i);
if (listItem instanceof Document || listItem instanceof Map) {
flattenDocumentRecursive(listItem, newKey + "[" + i + "]", result);
}
}
} else {
result.put(newKey, value);
private String extractStringValue(JsonNode node, String fieldName) {
if (node == null) return "";
JsonNode valueNode = node.get(fieldName);
if(valueNode != null && !valueNode.isNull()) return valueNode.asText();
if(node.has("Actor")){
JsonNode actor = node.get("Actor");
JsonNode actorNode = actor.get(fieldName);
if(actorNode != null) {
return actorNode.isNull() ? "" : actorNode.asText();
}
}
return "";
}
private String extractDomainFromInfos(JsonNode body) {
if (body != null && body.has("Infos") && body.get("Infos").isArray()) {
JsonNode infos = body.get("Infos");
if (!infos.isEmpty()) {
JsonNode firstInfo = infos.get(0);
if (firstInfo.has("Domain")) {
return firstInfo.get("Domain").asText();
}
}
}
return "";
}
}

View File

@@ -103,7 +103,7 @@ public abstract class BusinessLogServiceBase implements IBusinessLogService {
new Document("$toString",
new Document("$arrayElemAt", List.of("$userGuid.captures", 0))
),
"None"
""
)
)
)
@@ -113,7 +113,7 @@ public abstract class BusinessLogServiceBase implements IBusinessLogService {
new Document("$toString",
new Document("$arrayElemAt", List.of("$userNickname.captures", 0))
),
"None"
""
)
)
)
@@ -123,7 +123,7 @@ public abstract class BusinessLogServiceBase implements IBusinessLogService {
new Document("$toString",
new Document("$arrayElemAt", List.of("$accountId.captures", 0))
),
"None"
""
)
)
)

View File

@@ -0,0 +1,241 @@
package com.caliverse.admin.logs.logservice.indicators;
import com.caliverse.admin.Indicators.Indicatordomain.IndicatorsLog;
import com.caliverse.admin.Indicators.Indicatorsservice.base.IndicatorsLogLoadServiceBase;
import com.caliverse.admin.Indicators.entity.CurrencyLogInfo;
import com.caliverse.admin.Indicators.indicatorrepository.IndicatorCurrencyRepository;
import com.caliverse.admin.domain.entity.common.SearchUserType;
import com.caliverse.admin.global.common.constants.AdminConstants;
import com.caliverse.admin.logs.Indicatordomain.CurrencyMongoLog;
import com.caliverse.admin.logs.logservice.businesslogservice.BusinessLogCurrencyService;
import com.caliverse.admin.mongodb.dto.MongoPageResult;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Slf4j
@Service
public class IndicatorsCurrencyService extends IndicatorsLogLoadServiceBase {
@Autowired private IndicatorCurrencyRepository indicatorCurrencyRepository;
@Autowired private BusinessLogCurrencyService currencyService;
public IndicatorsCurrencyService(@Qualifier("mongoIndicatorTemplate") MongoTemplate mongoTemplate) {
super(mongoTemplate);
}
public void collectCurrency(String startTime, String endTime){
String logTimeStr = startTime.substring(0, 10);
List<CurrencyMongoLog> indicatorsLog = null;
indicatorsLog = currencyService.loadBusinessLogData(startTime, endTime, CurrencyMongoLog.class);
if (indicatorsLog == null || indicatorsLog.isEmpty()) {
log.info("collectCurrency indicatorsLog Log logDay: {} null", logTimeStr);
return;
}
for(CurrencyMongoLog mongo_log : indicatorsLog){
String logDay = mongo_log.getLogDay();
CurrencyLogInfo currencyLog = new CurrencyLogInfo(logDay,
mongo_log.getAccountId(),
mongo_log.getUserGuid(),
mongo_log.getUserNickname(),
mongo_log.getSapphireAcquired(),
mongo_log.getSapphireConsumed(),
mongo_log.getSapphireNet(),
mongo_log.getGoldAcquired(),
mongo_log.getGoldConsumed(),
mongo_log.getGoldNet(),
mongo_log.getCaliumAcquired(),
mongo_log.getCaliumConsumed(),
mongo_log.getCaliumNet(),
mongo_log.getBeamAcquired(),
mongo_log.getBeamConsumed(),
mongo_log.getBeamNet(),
mongo_log.getRubyAcquired(),
mongo_log.getRubyConsumed(),
mongo_log.getRubyNet(),
mongo_log.getTotalCurrencies(),
mongo_log.getCurrencies()
);
log.info("collectCurrency Currency Log Save logDay: {}, info: {}", logDay, currencyLog);
saveStatLogData(currencyLog);
}
}
private void saveStatLogData(IndicatorsLog indicatorsLog) {
if (indicatorsLog instanceof CurrencyLogInfo logInfo) {
try {
indicatorCurrencyRepository.save(logInfo);
} catch (Exception e) {
log.error("Error Repository Write CurrencyLogInfo: {}, Message: {}", logInfo, e.getMessage());
}
} else {
log.error("Not instanceof CurrencyLogInfo");
}
}
@Override
public <T extends IndicatorsLog> List<T> getIndicatorsLogData(String startTime, String endTime, Class<T> clazz) {
Criteria criteria = makeCriteria(startTime, endTime, AdminConstants.MONGO_DB_KEY_LOGDAY);
ProjectionOperation projection = Aggregation.project()
.and("_id").as("id")
.and(AdminConstants.MONGO_DB_KEY_LOGDAY).as("logDay")
.and(AdminConstants.MONGO_DB_KEY_ACCOUNT_ID).as("accountId")
.and(AdminConstants.MONGO_DB_KEY_USER_GUID).as("userGuid")
.and(AdminConstants.MONGO_DB_KEY_USER_NICKNAME).as("userNickname")
.and("sapphireAcquired").as("sapphireAcquired")
.and("sapphireConsumed").as("sapphireConsumed")
.and("sapphireNet").as("sapphireNet")
.and("goldAcquired").as("goldAcquired")
.and("goldConsumed").as("goldConsumed")
.and("goldNet").as("goldNet")
.and("caliumAcquired").as("caliumAcquired")
.and("caliumConsumed").as("caliumConsumed")
.and("caliumNet").as("caliumNet")
.and("beamAcquired").as("beamAcquired")
.and("beamConsumed").as("beamConsumed")
.and("beamNet").as("beamNet")
.and("rubyAcquired").as("rubyAcquired")
.and("rubyConsumed").as("rubyConsumed")
.and("rubyNet").as("rubyNet")
.and("totalCurrencies").as("totalCurrencies")
.and("currencies").as("currencies");
List<AggregationOperation> operations = List.of(
Aggregation.match(criteria),
projection,
Aggregation.sort(Sort.Direction.ASC, AdminConstants.MONGO_DB_KEY_LOGDAY)
);
Aggregation aggregation = Aggregation.newAggregation(operations);
return mongoTemplate.aggregate(
aggregation.withOptions(AggregationOptions.builder().allowDiskUse(true).build())
, AdminConstants.MONGO_DB_COLLECTION_CURRENCY
, clazz
).getMappedResults();
}
public <T extends IndicatorsLog> MongoPageResult<T> getCurrencyDetailLogData(
String searchType,
String searchData,
String tranId,
String logAction,
String currencyType,
String amountDeltaType,
String startTime,
String endTime,
String orderBy,
Integer page,
Integer size,
Class<T> clazz
) {
Criteria criteria = makeCriteria(startTime, endTime, AdminConstants.MONGO_DB_KEY_LOGDAY);
if(tranId != null && !tranId.isEmpty()){
criteria.and("currencies.tranId").is(tranId);
}
if(searchData != null && !searchData.isEmpty()){
switch (searchType){
case "GUID":
criteria.and("userGuid").is(searchData);
break;
case "NICKNAME":
criteria.and("userNickname").is(searchData);
break;
case "ACCOUNT":
criteria.and("accountId").is(searchData);
break;
default:
log.error("searchType: {} not support", searchType);
return null;
}
}
UnwindOperation unwindOperation = Aggregation.unwind("currencies");
ProjectionOperation projection = Aggregation.project()
.and("_id").as("id")
.and(AdminConstants.MONGO_DB_KEY_LOGDAY).as("logDay")
.and(AdminConstants.MONGO_DB_KEY_ACCOUNT_ID).as("accountId")
.and(AdminConstants.MONGO_DB_KEY_USER_GUID).as("userGuid")
.and(AdminConstants.MONGO_DB_KEY_USER_NICKNAME).as("userNickname")
.and("currencies.tranId").as("tranId")
.and("currencies.logTime").as("logTime")
.and("currencies.action").as("action")
.and("currencies.currencyType").as("currencyType")
.and("currencies.amountDeltaType").as("amountDeltaType")
.and("currencies.deltaAmount").as("deltaAmount")
.and("currencies.currencyAmount").as("currencyAmount");
List<AggregationOperation> baseOperations = new ArrayList<>(List.of(
Aggregation.match(criteria),
unwindOperation,
projection,
Aggregation.sort(orderBy.equals("DESC") ? Sort.Direction.DESC : Sort.Direction.ASC, AdminConstants.MONGO_DB_KEY_LOGTIME)
));
Criteria postUnwindCriteria = new Criteria();
if(logAction != null && !logAction.isEmpty() && !logAction.equals("None")){
postUnwindCriteria.and("action").is(logAction);
}
if(currencyType != null && !currencyType.isEmpty() && !currencyType.equals("None")){
postUnwindCriteria.and("currencyType").is(currencyType);
}
if(amountDeltaType != null && !amountDeltaType.isEmpty() && !amountDeltaType.equals("None")){
postUnwindCriteria.and("amountDeltaType").is(amountDeltaType);
}
if (!postUnwindCriteria.getCriteriaObject().isEmpty()) {
baseOperations.add(Aggregation.match(postUnwindCriteria));
}
int totalCount = 0;
if(page != null && page != 0) {
List<AggregationOperation> countOperations = new ArrayList<>(baseOperations);
countOperations.add(Aggregation.count().as("total"));
Aggregation countAggregation = Aggregation.newAggregation(countOperations);
Document countResult = mongoTemplate.aggregate(
countAggregation.withOptions(AggregationOptions.builder().allowDiskUse(true).build()),
AdminConstants.MONGO_DB_COLLECTION_CURRENCY,
Document.class
).getUniqueMappedResult();
totalCount = countResult != null ? countResult.getInteger("total") : 0;
}
List<AggregationOperation> dataOperations = new ArrayList<>(baseOperations);
if(page != null && page != 0) {
int skip = (page - 1) * size;
dataOperations.add(Aggregation.skip((long) skip));
dataOperations.add(Aggregation.limit(size));
}
Aggregation aggregation = Aggregation.newAggregation(dataOperations);
List<T> items = mongoTemplate.aggregate(
aggregation.withOptions(AggregationOptions.builder().allowDiskUse(true).build()),
AdminConstants.MONGO_DB_COLLECTION_CURRENCY,
clazz
).getMappedResults();
return new MongoPageResult<>(items, totalCount);
}
}

View File

@@ -0,0 +1,16 @@
package com.caliverse.admin.mongodb.dto;
import lombok.Data;
import java.util.List;
@Data
public class MongoPageResult<T> {
private final List<T> items;
private final int totalCount;
public MongoPageResult(List<T> items, int totalCount) {
this.items = items;
this.totalCount = totalCount;
}
}

View File

@@ -104,12 +104,12 @@ public class DynamicScheduler {
map.put("status", change_status);
battleEventService.updateBattleEventStatus(map);
}
}else if(status.equals(BattleEvent.BATTLE_STATUS.RUNNING)){
}else if(status.equals(BattleEvent.BATTLE_STATUS.RUNNING) || status.equals(BattleEvent.BATTLE_STATUS.STOP)){
if(!(!now.isBefore(todayStart) && !now.isAfter(todayEnd))){
if(!baseDate.isBefore(end_dt.toLocalDate())){
change_status = BattleEvent.BATTLE_STATUS.END;
}else{
change_status = BattleEvent.BATTLE_STATUS.WAIT;
change_status = status.equals(BattleEvent.BATTLE_STATUS.STOP) ? BattleEvent.BATTLE_STATUS.STOP : BattleEvent.BATTLE_STATUS.WAIT;
}
log.info("battle event_id: {}, start_dt: {}, end_dt: {}, todayStart: {}, todayEnd: {} STATUS CHANGE {}", event.getId(), start_dt, end_dt, todayStart, todayEnd, change_status);
map.put("status", change_status);

View File

@@ -1,5 +1,6 @@
package com.caliverse.admin.scheduler;
import com.caliverse.admin.domain.service.DiagnosisService;
import com.caliverse.admin.dynamodb.service.DynamodbService;
import com.caliverse.admin.global.common.constants.AdminConstants;
import com.caliverse.admin.logs.Indicatordomain.StartEndTime;
@@ -31,24 +32,36 @@ public class OneTimeSchedule implements CommandLineRunner {
@Autowired private IndicatorsMetaverseServerService metaverseServerService;
@Autowired private IndicatorsUserCreateService userCreateService;
@Autowired private IndicatorsUserLoginService userLoginService;
@Autowired private IndicatorsCurrencyService currencyService;
@Autowired private DiagnosisService diagnosisService;
@Autowired private DynamodbService dynamodbService;
@Override
public void run(String... args) throws Exception {
log.info("=== OneTimeSchedule starting ===");
try{
log.info("Starting OneTimeSchedule");
// dynamodbService.saveUserMoney(); //유저별 재화 데이터 저장
LocalDate startDate = LocalDate.of(2024, 8, 28);
// LocalDate currentDate = LocalDate.of(2025, 1, 31);
// LocalDate startDate = LocalDate.of(2025, 4, 1);
// LocalDate currentDate = LocalDate.of(2025, 5, 1);
LocalDate currentDate = LocalDate.now();
//
log.info("Processing dates from {} to {}", startDate, currentDate);
for (LocalDate date = startDate; !date.isAfter(currentDate); date = date.plusDays(1)) {
log.info("Processing date: {}", date);
StartEndTime dayStartEndTime = LogServiceHelper.getCurrentLogSearchEndTime(date, AdminConstants.STAT_DAY_NUM);
StartEndTime weekStartEndTime = LogServiceHelper.getCurrentLogSearchEndTime(date, AdminConstants.STAT_WEEK_NUM);
StartEndTime monthStartEndTime = LogServiceHelper.getCurrentLogSearchEndTime(date, AdminConstants.STAT_MONTH_NUM);
log.info("Date: {}, StartTime: {}, EndTime: {}", date, dayStartEndTime.getStartTime(), dayStartEndTime.getEndTime());
// currencyService.collectCurrency(dayStartEndTime.getStartTime(), dayStartEndTime.getEndTime());
// userLoginService.collectUserLogin(dayStartEndTime.getStartTime(), dayStartEndTime.getEndTime());
// userCreateService.collectUserCreate(dayStartEndTime.getStartTime(), dayStartEndTime.getEndTime());
// metaverseServerService.collectMetaverseServerCount(dayStartEndTime.getStartTime(), dayStartEndTime.getEndTime(), 13);
@@ -63,9 +76,9 @@ public class OneTimeSchedule implements CommandLineRunner {
// ugqCreateService.collectUGQCreateCount(dayStartEndTime.getStartTime(), dayStartEndTime.getEndTime()); //체크
}
log.info("=== OneTimeSchedule completed successfully ===");
}catch (Exception e){
log.error(e.getMessage());
log.error("OneTimeSchedule execution failed", e);
}
}
}

View File

@@ -2,16 +2,19 @@ package com.caliverse.admin.scheduler;
import com.caliverse.admin.domain.entity.InGame;
import com.caliverse.admin.domain.entity.Mail;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.config.ScheduledTask;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
@Service
@Slf4j
public class ScheduleService {
private final Map<String, ScheduledFuture<?>> scheduledTasks = new ConcurrentHashMap<>();
@@ -19,6 +22,9 @@ public class ScheduleService {
private final Map<Long, Mail> mailTask = new ConcurrentHashMap<>();
private final Map<Long, InGame> noticeTask = new ConcurrentHashMap<>();
private static final int MAX_MAIL_TASKS = 500;
private static final int MAX_NOTICE_TASKS = 500;
public boolean isTaskExist(String key){
return scheduledTasks.containsKey(key);
}
@@ -35,22 +41,60 @@ public class ScheduleService {
}
}
// public boolean isTaskExist(String type, Long id) {
// switch (type) {
// case "mail" -> {
// return mailTask.containsKey(id);
// }
// case "notice" -> {
// return noticeTask.containsKey(id);
// }
// default -> {
// return false;
// }
// }
// }
//
// public void createTask(Mail mail) {
// mailTask.put(mail.getId(), mail);
// }
public void cleanupCompletedTasks() {
try {
Iterator<Map.Entry<String, ScheduledFuture<?>>> iterator = scheduledTasks.entrySet().iterator();
int removedCount = 0;
while (iterator.hasNext()) {
Map.Entry<String, ScheduledFuture<?>> entry = iterator.next();
ScheduledFuture<?> future = entry.getValue();
if (future.isDone() || future.isCancelled()) {
iterator.remove();
removedCount++;
}
}
if (removedCount > 0) {
log.info("Cleaned up {} completed scheduled tasks. Current task count: {}",
removedCount, scheduledTasks.size());
}
} catch (Exception e) {
log.error("Error during cleanup of completed tasks", e);
}
}
public void cleanupMailTasks() {
if (mailTask.size() > MAX_MAIL_TASKS) {
int toRemove = mailTask.size() - MAX_MAIL_TASKS;
Iterator<Long> iterator = mailTask.keySet().iterator();
int removed = 0;
while (iterator.hasNext() && removed < toRemove) {
iterator.next();
iterator.remove();
removed++;
}
// log.info("Cleaned up {} mail tasks due to size limit", removed);
}
}
public void cleanupNoticeTasks() {
if (noticeTask.size() > MAX_NOTICE_TASKS) {
int toRemove = noticeTask.size() - MAX_NOTICE_TASKS;
Iterator<Long> iterator = noticeTask.keySet().iterator();
int removed = 0;
while (iterator.hasNext() && removed < toRemove) {
iterator.next();
iterator.remove();
removed++;
}
// log.info("Cleaned up {} notice tasks due to size limit", removed);
}
}
}

View File

@@ -1,20 +1,12 @@
package com.caliverse.admin.scheduler.batch;
import com.caliverse.admin.domain.RabbitMq.MessageHandlerService;
import com.caliverse.admin.domain.service.BlackListService;
import com.caliverse.admin.domain.service.EventService;
import com.caliverse.admin.domain.service.MailService;
import com.caliverse.admin.domain.service.NoticeService;
import com.caliverse.admin.global.common.constants.AdminConstants;
import com.caliverse.admin.global.common.utils.ExcelUtils;
import com.caliverse.admin.logs.Indicatordomain.StartEndTime;
import com.caliverse.admin.logs.logservice.LogServiceHelper;
import com.caliverse.admin.logs.logservice.indicators.*;
import com.caliverse.admin.redis.service.RedisUserInfoService;
import com.caliverse.admin.scheduler.DynamicScheduler;
import com.caliverse.admin.scheduler.SchedulerManager;
import com.caliverse.admin.scheduler.batch.service.DataClearService;
import com.caliverse.admin.scheduler.batch.service.LogCompressService;
import com.caliverse.admin.scheduler.entity.SchedulerType;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -31,9 +23,11 @@ public class ScheduleRunnerBatch {
private final SchedulerManager schedulerManager;
@Autowired private LogCompressService logService;
@Autowired private DataClearService dataClearService;
@Autowired private IndicatorsUserCreateService userCreateService;
@Autowired private IndicatorsUserLoginService userLoginService;
@Autowired private IndicatorsCurrencyService currencyService;
//log backup
@Scheduled(cron = "00 00 00 1 * ?") // 매월 1일에 실행
@@ -41,6 +35,12 @@ public class ScheduleRunnerBatch {
logService.compressLastMonthLogs();
}
//오래된 데이터 삭제
@Scheduled(cron = "00 05 00 1 * ?") // 매월 1일에 실행
public void oldDataClear(){
dataClearService.oldDataClear();
}
@Scheduled(cron = "00 30 0 * * *") // 매일 UTC 기준 00시 30분 00초에 실행
public void userCreateScheduler() {
StartEndTime startEndTime = LogServiceHelper.getCurrentLogSearchEndTime(AdminConstants.STAT_DAY_NUM);
@@ -53,4 +53,10 @@ public class ScheduleRunnerBatch {
userLoginService.collectUserLogin(startEndTime.getStartTime(), startEndTime.getEndTime());
}
@Scheduled(cron = "00 31 0 * * *") // 매일 UTC 기준 00시 31분 00초에 실행
public void currencyInfoScheduler() {
StartEndTime startEndTime = LogServiceHelper.getCurrentLogSearchEndTime(AdminConstants.STAT_DAY_NUM);
currencyService.collectCurrency(startEndTime.getStartTime(), startEndTime.getEndTime());
}
}

View File

@@ -0,0 +1,5 @@
package com.caliverse.admin.scheduler.batch.service;
public interface DataClearService {
void oldDataClear();
}

View File

@@ -0,0 +1,22 @@
package com.caliverse.admin.scheduler.batch.service.impl;
import com.caliverse.admin.dynamodb.service.DynamodbBattleEventService;
import com.caliverse.admin.dynamodb.service.DynamodbMailService;
import com.caliverse.admin.scheduler.batch.service.DataClearService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@AllArgsConstructor
public class DataClearServiceImpl implements DataClearService {
private final DynamodbMailService dynamodbMailService;
private final DynamodbBattleEventService dynamodbBattleEventService;
@Override
public void oldDataClear() {
dynamodbMailService.oldSystemMetaMailClear();
dynamodbBattleEventService.oldBattleEventClear();
}
}

View File

@@ -9,5 +9,6 @@ public enum SchedulerType {
BATTLE_EVENT,
WEB3,
LAND_OWNER_CHANGES,
DATA_INITIALIZE
DATA_INITIALIZE,
CLEAN_UP
}

View File

@@ -68,6 +68,11 @@ public class ScheduleRunnerPolling {
schedulerManager.executeScheduler(SchedulerType.DATA_INITIALIZE);
}
@Scheduled(fixedRate = 300000)
public void cleanupJob(){
schedulerManager.executeScheduler(SchedulerType.CLEAN_UP);
}
/*
매일 UTC 기준 00시 50분 00초에 실행, (한국 시간 9시 50분) 30분에 돌릴경우 데이터가 다 넘어 오지 않는 경우 있어서 수정처리
이게 가장 먼저 실행 되어야 한다.

View File

@@ -0,0 +1,30 @@
package com.caliverse.admin.scheduler.polling.service;
import com.caliverse.admin.scheduler.CommonScheduler;
import com.caliverse.admin.scheduler.ScheduleService;
import com.caliverse.admin.scheduler.entity.SchedulerType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class cleanupScheduler extends CommonScheduler {
private final ScheduleService scheduleService;
public cleanupScheduler(ScheduleService scheduleService) {
this.scheduleService = scheduleService;
}
@Override
protected void executeInternal() {
scheduleService.cleanupCompletedTasks();
scheduleService.cleanupMailTasks();
scheduleService.cleanupNoticeTasks();
}
@Override
public SchedulerType getSchedulerType() {
return SchedulerType.CLEAN_UP;
}
}

View File

@@ -1,12 +1,13 @@
server:
tomcat:
max-http-form-post-size: 50MB
max-swallow-size: 50MB
spring:
servlet:
multipart:
max-file-size: 5MB
max-request-size: 10MB
## deploy
# profiles:
# active: stage
jwt:
secret_key: '81b659967735aea6e4cb0467d04ea12c4a6432b415254f59825055680f59a9823fec5a15e9adbd246b1365ef1522580477691bc5cb56a9364143e7d9385d9912'

View File

@@ -112,8 +112,9 @@ amazon:
secretkey: G82Bq5tCUTvSPe9InGayH8kONbtEnLxMrgzrAbCn
region: us-west-2
s3:
bucket-name: metaverse-myhomeugc-test
enabled: false
bucket-name: metaverse-admintool
cloud-front: https://d1yr1qrnuiu29u.cloudfront.net/
enabled: true
@@ -165,6 +166,7 @@ redis:
sync-timeout: 30000
ssl: false
abort-connect: false
prefix: backOffice
web3:
url: https://eco-system-dev-rollup-admin-api.caliverse.io/

View File

@@ -111,8 +111,9 @@ amazon:
secretkey: G82Bq5tCUTvSPe9InGayH8kONbtEnLxMrgzrAbCn
region: us-west-2
s3:
bucket-name: metaverse-myhomeugc-live
enabled: false
bucket-name: metaverse-admintool
cloud-front: https://d1yr1qrnuiu29u.cloudfront.net/
enabled: true
@@ -170,6 +171,7 @@ redis:
sync-timeout: 30000
ssl: true
abort-connect: false
prefix: backOffice
web3:

View File

@@ -102,18 +102,20 @@ excel:
################################################################################################################################################################################################
amazon:
dynamodb:
# endpoint: http://localhost:8000/
endpoint: https://dynamodb.us-west-2.amazonaws.com
endpoint: http://localhost:8000/
# endpoint: https://dynamodb.us-west-2.amazonaws.com
metaTable: Metaverse-Dev
# metaTable: Metaverse-Live
aws:
# accesskey: ""
# secretkey: ""
accesskey: AKIA4G3CB4Z5T6JUPHJN
secretkey: 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
region: us-west-2
accesskey: ""
secretkey: ""
region: ""
# accesskey: AKIA4G3CB4Z5T6JUPHJN
# secretkey: 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
# region: us-west-2
s3:
bucket-name: metaverse-myhomeugc-test
bucket-name: metaverse-admintool
cloud-front: https://d1yr1qrnuiu29u.cloudfront.net/
enabled: true
@@ -124,17 +126,17 @@ amazon:
# RabbitMq
################################################################################################################################################################################################
rabbitmq:
url: localhost
port: 5672
username: admin
password: admin
ssl: false
# dev
# url: 10.20.20.8
# url: localhost
# port: 5672
# username: admin
# password: admin
# ssl: false
# dev
url: 10.20.20.8
port: 5672
username: admin
password: admin
ssl: false
@@ -163,36 +165,23 @@ mongodb:
# username: ""
# password: ""
# db: IndicatorDB
#stage-atlas
# host: metaverse-stage.7d0do.mongodb.net
# business-log:
# username: metaversestagerw
# password: R1ed7GzdAZcZ321t
# db: BusinessLog-Db-Stage
# indicator:
# username: metaversestagerw
# password: R1ed7GzdAZcZ321t
# db: BackOffice-Db-Stage
#live
# host: localhost:27021
# host: metaverse-live.7d0do.mongodb.net
# business-log:
# username: calimongoread
# password: cali%lr9#1verse
# db: LogDB
# username: metaverseliverw
# password: K1spqwBbHrP2ZSMX
# db: BusinessLog-Db-Live
# indicator:
# username: lrwindiconnect
# password: live%sw9#3verse
# db: IndicatorDB
# admin:
# username: admin
# password: zk28fl@#qjtm
# db: admin
# username: metaverseliverw
# password: K1spqwBbHrP2ZSMX
# db: BackOffice-Db-Live
################################################################################################################################################################################################
# "Redis": "127.0.0.1:6379,password=KT-i5#i%-%LxKfZ5YJj6,AsyncTimeout=30000,SyncTimeout=30000,ssl=false,abortConnect=false",
################################################################################################################################################################################################
redis:
prefix: backOffice
host: localhost
port: 6379
password: KT-i5#i%-%LxKfZ5YJj6

View File

@@ -113,8 +113,9 @@ amazon:
secretkey: G82Bq5tCUTvSPe9InGayH8kONbtEnLxMrgzrAbCn
region: us-west-2
s3:
bucket-name: metaverse-myhomeugc-qa
enabled: false
bucket-name: metaverse-admintool
cloud-front: https://d1yr1qrnuiu29u.cloudfront.net/
enabled: true
@@ -173,6 +174,7 @@ redis:
sync-timeout: 30000
ssl: true
abort-connect: false
prefix: backOffice
web3:
url: https://eco-system-qa-rollup-admin-api.caliverse.io

View File

@@ -111,8 +111,9 @@ amazon:
secretkey: G82Bq5tCUTvSPe9InGayH8kONbtEnLxMrgzrAbCn
region: us-west-2
s3:
bucket-name: metaverse-myhomeugc-stage
enabled: false
bucket-name: metaverse-admintool
cloud-front: https://d1yr1qrnuiu29u.cloudfront.net/
enabled: true
@@ -170,6 +171,7 @@ redis:
sync-timeout: 30000
ssl: true
abort-connect: false
prefix: backOffice
web3:

View File

@@ -11,12 +11,14 @@
<result property="eventOperationTime" column="event_operation_time"/>
<result property="status" column="status"/>
<result property="eventStartDt" column="event_start_dt"/>
<result property="eventEndTime" column="event_end_time"/>
<result property="eventEndDt" column="event_end_dt"/>
<result property="roundTime" column="round_time"/>
<result property="roundCount" column="round_count"/>
<result property="hotTime" column="hot_time"/>
<result property="configId" column="config_id"/>
<result property="instanceId" column="instance_id"/>
<result property="gameModeId" column="game_mode_id"/>
<result property="rewardGroupId" column="reward_group_id"/>
<result property="createBy" column="create_by"/>
<result property="createDt" column="create_dt"/>
@@ -39,12 +41,14 @@
, a.event_operation_time
, a.status
, a.event_start_dt
, a.event_end_time
, a.event_end_dt
, a.round_time
, a.round_count
, a.hot_time
, a.config_id
, a.reward_group_id
, a.game_mode_id
, (SELECT email FROM admin WHERE id = a.create_by ) AS create_by
, a.create_dt
, (SELECT email FROM admin WHERE id = a.update_by ) AS update_by
@@ -142,7 +146,7 @@
</when>
<otherwise>
<if test="search_data != null and search_data != ''">
AND a.event_id = #{search_data}
AND a.id = #{search_data}
</if>
</otherwise>
</choose>
@@ -286,12 +290,14 @@
, a.event_operation_time
, a.status
, a.event_start_dt
, a.event_end_time
, a.event_end_dt
, a.round_time
, a.round_count
, a.hot_time
, a.config_id
, a.reward_group_id
, a.game_mode_id
, (SELECT email FROM admin WHERE id = a.create_by ) AS create_by
, a.create_dt
, (SELECT email FROM admin WHERE id = a.update_by ) AS update_by
@@ -302,8 +308,8 @@
<!--저장-->
<insert id="postBattleEvent" parameterType="com.caliverse.admin.domain.request.BattleEventRequest" useGeneratedKeys="true" keyProperty="id">
INSERT INTO battle_event (group_id, event_id, event_name, repeat_type, event_operation_time, event_start_dt, event_end_dt, config_id, reward_group_id, round_time, round_count, hot_time, instance_id, create_by, update_by)
VALUES (#{groupId}, #{eventId}, #{eventName}, #{repeatType}, #{eventOperationTime}, #{eventStartDt}, #{eventEndDt}, #{configId}, #{rewardGroupId}, #{roundTime}, #{roundCount}, #{hotTime}, #{instanceId}, #{createBy}, #{updateBy})
INSERT INTO battle_event (group_id, event_name, repeat_type, event_operation_time, event_start_dt, event_end_time, event_end_dt, config_id, reward_group_id, round_time, round_count, hot_time, instance_id, game_mode_id, create_by, update_by)
VALUES (#{groupId}, #{eventName}, #{repeatType}, #{eventOperationTime}, #{eventStartDt}, #{eventEndTime}, #{eventEndDt}, #{configId}, #{rewardGroupId}, #{roundTime}, #{roundCount}, #{hotTime}, #{instanceId}, #{gameModeId}, #{createBy}, #{updateBy})
</insert>
<!--수정-->
@@ -313,11 +319,13 @@
, event_operation_time = #{eventOperationTime}
, config_id = #{configId}
, event_start_dt = #{eventStartDt}
, event_end_time = #{eventEndTime}
, event_end_dt = #{eventEndDt}
, reward_group_id = #{rewardGroupId}
, round_time = #{roundTime}
, round_count = #{roundCount}
, hot_time = #{hotTime}
, game_mode_id = #{gameModeId}
, status = 'WAIT'
, update_by = #{updateBy}
, update_dt = NOW()
@@ -353,14 +361,16 @@
, event_operation_time
, status
, event_start_dt
, event_end_time
, event_end_dt
, round_time
, round_count
, hot_time
, config_id
, reward_group_id
, game_mode_id
FROM battle_event
WHERE (status = 'WAIT' or status = 'RUNNING' or status = 'REGISTER')
WHERE (status = 'WAIT' or status = 'RUNNING' or status = 'REGISTER' or status = 'STOP')
AND deleted = 0
</select>

View File

@@ -8,6 +8,7 @@
<result property="status" column="status"/>
<result property="startDt" column="start_dt"/>
<result property="endDt" column="end_dt"/>
<result property="orderId" column="order_id"/>
<result property="createBy" column="create_by"/>
<result property="createDt" column="create_dt"/>
<result property="updateBy" column="update_by"/>
@@ -21,43 +22,61 @@
<!--리스트 조회-->
<select id="getBannerList" resultMap="MenuResultMap" parameterType="map">
SELECT (@row_number:=@row_number + 1) AS row_num , c.*
FROM (
SELECT
a.id
, a.title
, a.is_link
, a.status
, a.start_dt
, a.end_dt
, (SELECT email FROM admin WHERE id = a.create_by ) AS create_by
, a.create_dt
, (SELECT email FROM admin WHERE id = a.update_by ) AS update_by
, a.update_dt
FROM menu_banner a
WHERE 1 = 1
AND a.deleted = 0
SELECT * FROM (
SELECT (@row_number:=@row_number + 1) AS row_num, c.*
FROM (
SELECT
a.id,
a.title,
a.is_link,
CASE
WHEN NOW() &lt; a.start_dt THEN 'WAIT'
WHEN NOW() &gt;= a.start_dt AND NOW() &lt;= a.end_dt THEN 'RUNNING'
WHEN NOW() &gt; a.end_dt THEN 'FINISH'
END AS status,
a.start_dt,
a.end_dt,
a.order_id,
(SELECT email FROM admin WHERE id = a.create_by) AS create_by,
a.create_dt,
(SELECT email FROM admin WHERE id = a.update_by) AS update_by,
a.update_dt
FROM menu_banner a
WHERE 1 = 1
AND a.deleted = 0
<if test="search_data != null and search_data != ''">
AND a.title LIKE CONCAT('%',#{searchData},'%')
</if>
<if test="search_data != null and search_data != ''">
AND a.title LIKE CONCAT('%',#{searchData},'%')
</if>
<if test="status != null and status != ''">
<choose>
<when test="status != 'ALL' ">
AND a.status = #{status}
</when>
</choose>
</if>
<if test="status != null and status != ''">
<choose>
<when test="status != 'ALL'">
AND CASE
WHEN NOW() &lt; a.start_dt THEN 'WAIT'
WHEN NOW() &gt;= a.start_dt AND NOW() &lt;= a.end_dt THEN 'RUNNING'
WHEN NOW() &gt; a.end_dt THEN 'FINISH'
END = #{status}
</when>
</choose>
</if>
<if test="start_dt != null and start_dt != '' and end_dt !=null and end_dt!= ''">
AND a.start_dt &gt;= #{startDate, jdbcType=TIMESTAMP}
AND a.end_dt &lt;= #{endDate, jdbcType=TIMESTAMP}
</if>
ORDER BY a.create_dt
)c
, (SELECT @row_number:=0) AS t
<if test="start_dt != null and start_dt != '' and end_dt !=null and end_dt!= ''">
AND a.start_dt &gt;= #{startDate, jdbcType=TIMESTAMP}
AND a.end_dt &lt;= #{endDate, jdbcType=TIMESTAMP}
</if>
) c,
(SELECT @row_number:=0) AS t
ORDER BY
CASE
WHEN c.status = 'RUNNING' THEN 0
WHEN c.status = 'WAIT' THEN 1
WHEN c.status = 'FINISH' THEN 2
ELSE 3
END,
c.order_id,
c.create_dt
) result
<if test="orderby != null and orderby != ''">
ORDER BY row_num ${orderby}
</if>
@@ -77,7 +96,12 @@
, a.is_link
, a.start_dt
, a.end_dt
, a.status
, CASE
WHEN NOW() &lt; a.start_dt THEN 'WAIT'
WHEN NOW() &gt;= a.start_dt AND NOW() &lt;= a.end_dt THEN 'RUNNING'
WHEN NOW() &gt; a.end_dt THEN 'FINISH'
END AS status
, a.order_id
, (SELECT email FROM admin WHERE id = a.create_by ) AS create_by
, a.create_dt
, (SELECT email FROM admin WHERE id = a.update_by ) AS update_by
@@ -88,16 +112,22 @@
</select>
<select id="getMessage" parameterType="java.lang.Long" resultMap="MessageResultMap" >
SELECT
*
SELECT *
FROM message
WHERE target_id = #{id}
AND type = 'BANNER'
</select>
<select id="getMaxOrderId" resultType="java.lang.Integer">
SELECT COALESCE(MAX(order_id), 0)
FROM menu_banner
WHERE deleted = 0
AND NOW() &lt;= end_dt
</select>
<insert id="insertBanner" parameterType="com.caliverse.admin.domain.request.MenuRequest" useGeneratedKeys="true" keyProperty="id">
INSERT INTO menu_banner (title, is_link, start_dt, end_dt)
VALUES (#{title}, #{isLink}, #{startDt}, #{endDt})
INSERT INTO menu_banner (title, is_link, start_dt, end_dt, order_id)
VALUES (#{title}, #{isLink}, #{startDt}, #{endDt}, #{orderId})
</insert>
<insert id="insertMessage" parameterType="map">
@@ -112,6 +142,7 @@
, send_type =#{sendType}
, mail_type = #{mailType}
, send_dt = #{sendDt}
, order_id = #{orderId}
, update_by = #{updateBy}
, update_dt = NOW()
WHERE id = #{id}