init
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
package com.caliverse.admin.global.common.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DynamoDBTransaction {
|
||||
// 트랜잭션 타임아웃 설정
|
||||
long timeout() default 10000;
|
||||
|
||||
// 트랜잭션 실패 시 재시도 횟수
|
||||
int retryCount() default 1;
|
||||
|
||||
// 작업 설명 (로깅용)
|
||||
String description() default "";
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.caliverse.admin.global.common.aspect;
|
||||
|
||||
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.component.transaction.DynamoDBTransactionContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.stereotype.Component;
|
||||
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
|
||||
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
|
||||
import software.amazon.awssdk.enhanced.dynamodb.model.TransactWriteItemsEnhancedRequest;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
@Slf4j
|
||||
public class DynamoDBTransactionAspect {
|
||||
private final DynamoDbEnhancedClient enhancedClient;
|
||||
|
||||
public DynamoDBTransactionAspect(DynamoDbEnhancedClient enhancedClient) {
|
||||
this.enhancedClient = enhancedClient;
|
||||
}
|
||||
|
||||
@Around("@annotation(com.caliverse.admin.global.common.annotation.DynamoDBTransaction)")
|
||||
public Object executeInTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
TransactWriteItemsEnhancedRequest.Builder transactionBuilder =
|
||||
TransactWriteItemsEnhancedRequest.builder();
|
||||
|
||||
try {
|
||||
// 메서드 실행 전 트랜잭션 컨텍스트 설정
|
||||
DynamoDBTransactionContext.setTransactionBuilder(transactionBuilder);
|
||||
|
||||
// 실제 메서드 실행
|
||||
Object result = joinPoint.proceed();
|
||||
|
||||
// 트랜잭션 커밋
|
||||
TransactWriteItemsEnhancedRequest transactionRequest =
|
||||
DynamoDBTransactionContext.getTransactionBuilder().build();
|
||||
if (!transactionRequest.transactWriteItems().isEmpty()) {
|
||||
enhancedClient.transactWriteItems(transactionRequest);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (DynamoDbException e) {
|
||||
log.error("DynamoDB transaction failed: {}", e.getMessage());
|
||||
throw new RestApiException(CommonCode.ERROR.getHttpStatus(),
|
||||
ErrorCode.DYNAMODB_PROCESS_ERROR.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("DynamoDB operation error: {}", e.getMessage());
|
||||
throw new RestApiException(CommonCode.ERROR.getHttpStatus(),
|
||||
ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
|
||||
} finally {
|
||||
// 트랜잭션 컨텍스트 정리
|
||||
DynamoDBTransactionContext.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.caliverse.admin.global.common.aspect;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
@Slf4j
|
||||
public class LoggingAspect {
|
||||
// private static final Logger log = LoggerFactory.getLogger("METHOD_LOGGER");
|
||||
|
||||
@Pointcut("@within(org.springframework.stereotype.Component) || " +
|
||||
"@within(org.springframework.stereotype.Service) || " +
|
||||
"@within(org.springframework.stereotype.Repository) || " +
|
||||
"@within(org.springframework.stereotype.Controller)")
|
||||
public void pointcut() {}
|
||||
|
||||
@Pointcut("within(com.caliverse.admin.domain.api..*) || " +
|
||||
"within(com.caliverse.admin.domain.service..*) || " +
|
||||
"within(com.caliverse.admin.scheduler..*) || " +
|
||||
"within(com.caliverse.admin.dynamodb.repository..*) || " +
|
||||
"within(com.caliverse.admin.dynamodb.service..*)")
|
||||
public void specificPackages() {}
|
||||
|
||||
@Around("pointcut() && specificPackages()")
|
||||
public Object logging(ProceedingJoinPoint pjp) throws Throwable {
|
||||
String methodName = pjp.getSignature().getName();
|
||||
String className = pjp.getSignature().getDeclaringTypeName();
|
||||
|
||||
String format = String.format("%s.%s",className,methodName);
|
||||
MDC.put("method", methodName);
|
||||
|
||||
try {
|
||||
log.info("{} method start", format);
|
||||
Object result = pjp.proceed();
|
||||
log.info("{} method end", format);
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("[{}] method error: {}", methodName, e.getMessage());
|
||||
throw e;
|
||||
} finally {
|
||||
MDC.remove("method");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.caliverse.admin.global.common.aspect;
|
||||
|
||||
import com.caliverse.admin.global.component.transaction.TransactionIdManager;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class TransactionIdAspect {
|
||||
private final TransactionIdManager transactionIdManager;
|
||||
private static final String TRANSACTION_ID_KEY = "TRANSACTION_ID";
|
||||
|
||||
@Around("@annotation(org.springframework.transaction.annotation.Transactional)")
|
||||
public Object setTransactionId(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
boolean isNewTransaction = !TransactionSynchronizationManager.hasResource(TRANSACTION_ID_KEY);
|
||||
|
||||
if (isNewTransaction) {
|
||||
transactionIdManager.getCurrentTransactionId(); // 새로운 트랜잭션 ID 생성
|
||||
}
|
||||
|
||||
try {
|
||||
return joinPoint.proceed();
|
||||
} finally {
|
||||
if (isNewTransaction) {
|
||||
TransactionSynchronizationManager.unbindResource(TRANSACTION_ID_KEY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.caliverse.admin.global.common.code;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum CommonCode{
|
||||
|
||||
SUCCESS(HttpServletResponse.SC_OK,"SUCCESS"),
|
||||
ERROR(-1, "ERROR")
|
||||
;
|
||||
|
||||
private final int httpStatus;
|
||||
private final String result;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.caliverse.admin.global.common.code;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum ErrorCode {
|
||||
SUCCESS("성공"),
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
// json
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
USER_GAME_LOGIN_JSON_MAPPER_PARSE_ERROR("유저 게임세션 데이터 파싱하는 도중 에러가 발생했습니다."),
|
||||
|
||||
|
||||
WRONG_TYPE_TOKEN("잘못된 타입의 토큰입니다."),
|
||||
EXPIRED_TOKEN("만료된 토큰입니다."),
|
||||
PWD_EXPIRATION("비밀번호 기간 만료"),
|
||||
UNSUPPORTED_TOKEN("지원하지않는 토큰입니다."),
|
||||
WRONG_TOKEN( "잘못된 토큰입니다."),
|
||||
DOFILTER_ERROR( "doFilterInternal() 오류"),
|
||||
AUTHENTICATION_FAILED("인증에 실패했습니다."),
|
||||
BAD_REQUEST("잘못된 요청입니다."),
|
||||
SIGNATURE_ERROR("잘못된 서명의 토큰입니다."),
|
||||
|
||||
INACTIVE_USER("User is inactive"),
|
||||
|
||||
PASSWORD_INCLUDE("기존 사용 이력이 있는 비밀번호는 재사용할 수 없습니다."),
|
||||
PASSWORD_ERROR("입력된 현재 비밀번호가 틀립니다."),
|
||||
|
||||
NOT_FOUNT_TEAM("입력한 팀을 찾지 못했습니다."),
|
||||
NOT_FOUNT_POSITION( "입력한 직급을 찾지 못했습니다."),
|
||||
NOT_MATCH_USER("이메일 또는 비밀번호가 일치하지않습니다."),
|
||||
DUPLICATED_EMAIL("동일한 이메일이 존재합니다."),
|
||||
NOT_PERMITTED("로그인 권한이 없습니다. 계정 관련 관리자에게 문의하세요."),
|
||||
NOT_FOUND_USER("ID또는 비밀번호가 일치하지 않습니다."),
|
||||
DUPLICATED_GROUPNAME("동일한 관리자 그룹명이 존재합니다."),
|
||||
|
||||
//meta data
|
||||
NOT_ITEM("존재하지 않는 아이템코드입니다."),
|
||||
|
||||
//excel upload
|
||||
ERROR_EXCEL_UPLOAD("엑셀 업로드중 오류 발생하였습니다."),
|
||||
ERROR_EXCEL_DOWN("엑셀 다운로드중 오류 발생하였습니다."),
|
||||
NOT_EXIT_EXCEL("Excel 파일을 선택해주세요."),
|
||||
DUPLICATE_EXCEL("중복된 유저 정보가 있습니다."),
|
||||
USERTYPE_CHECK_EXCEL("타입을 확인해주세요."),
|
||||
|
||||
ERROR_API_CALL("API 호출에 실패하였습니다."),
|
||||
|
||||
//calium
|
||||
ERROR_CALIUM_FINISH("충전 완료된 칼리움입니다."),
|
||||
|
||||
//Land
|
||||
ERROR_LAND_AUCTION_IMPOSSIBLE("경매를 진행할 수 없는 랜드입니다."),
|
||||
ERROR_AUCTION_STATUS_IMPOSSIBLE("수정할 수 없는 경매상태입니다."),
|
||||
ERROR_AUCTION_LAND_OWNER("해당 랜드는 소유자가 존재하여 경매를 진행할 수 없습니다."),
|
||||
|
||||
//Battle
|
||||
ERROR_BATTLE_EVENT_TIME_OVER("해당 시간에 속하는 이벤트가 존재합니다."),
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
// DyanamoDB
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
GUID_CHECK("Guid를 확인해주세요."),
|
||||
EMAIL_CHECK("Email을 확인해주세요"),
|
||||
GUID_LENGTH_CHECK("guid(32자)를 확인해주세요."),
|
||||
DYNOMODB_CHECK("gameDB에 닉네임이 없습니다."),
|
||||
DYNAMODB_CONNECTION_ERROR("dynamoDB_connection_error"),
|
||||
DYNAMODB_CONDITION_CHECK_ERROR("dynamoDB_Conditional_Check_error"),
|
||||
DYNAMODB_PROCESS_ERROR("dynamoDB 처리 중 에러발생"),
|
||||
DYNAMODB_INSERT_ERROR("dynamoDB_Insert_error"),
|
||||
DYNAMODB_UPDATE_ERROR("dynamoDB_Update_error"),
|
||||
DYNAMODB_DELETE_ERROR("dynamoDB_Delete_error"),
|
||||
DYNAMODB_EXIT_ERROR("dynamodb_exit_error"),
|
||||
DYNAMODB_ITEM_DELETE_FAIL("아이템 삭제에 실패하였습니다."),
|
||||
DYNAMODB_CONVERT_ERROR("형변환 도중 에러가 발생하였습니다."),
|
||||
DYNAMODB_JSON_PARSE_ERROR("dynamoDB Json 변환 중 에러 발생"),
|
||||
|
||||
|
||||
ADMINDB_EXIT_ERROR("admindb_exit_error"),
|
||||
|
||||
NICKNAME_EXIT_ERROR("변경 닉네임이 존재합니다. 다시 시도해주세요."),
|
||||
NICKNAME_NUMBER_ERROR("닉네임은 첫번째 글자에 숫자를 허용하지 않습니다. 다시 시도해주세요."),
|
||||
NICKNAME_SPECIALCHAR_ERROR("닉네임은 특수문자를 사용할 수 없습니다. 다시 시도해주세요."),
|
||||
NICKNAME_LANGTH_ERROR("닉네임은 최소 2글자에서 최대 12글자까지 허용 합니다. 다시 시도해주세요."),
|
||||
|
||||
|
||||
SENDMAIL_ERROR("메일 발송중 오류가 발생하였습니다. 관리자에게 문의주세요."),
|
||||
|
||||
EXCEPTION_INVALID_PROTOCOL_BUFFER_EXCEPTION_ERROR("InvalidProtocolBufferException"),
|
||||
EXCEPTION_IO_EXCEPTION_ERROR("IOException"),
|
||||
EXCEPTION_INTERRUMPTED_EXCEPTION_ERROR("InterruptedException"),
|
||||
;
|
||||
|
||||
private final String message;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.caliverse.admin.global.common.code;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum SuccessCode {
|
||||
SAVE("저장 하였습니다."),
|
||||
UPDATE("수정 하였습니다."),
|
||||
DELETE("삭제 하였습니다."),
|
||||
INIT("비밀번호 초기화 하였습니다."),
|
||||
NULL_DATA("조회된 데이터가 없습니다."),
|
||||
EXCEL_UPLOAD("파일 업로드 하였습니다."),
|
||||
REGISTRATION("등록 하였습니다."),
|
||||
ITEM_EXIST("아이템이 존재합니다"),
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
// DyanamoDB
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
DYNAMODB_ITEM_DELETE_SUCCESS("아이템 삭제에 성공하였습니다."),
|
||||
|
||||
;
|
||||
|
||||
private final String message;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.caliverse.admin.global.common.constants;
|
||||
|
||||
public class AdminConstants {
|
||||
public static final String MONGO_DB_COLLECTION_AU = "au";
|
||||
public static final String MONGO_DB_COLLECTION_DAU = "dau";
|
||||
public static final String MONGO_DB_COLLECTION_MAU = "mau";
|
||||
public static final String MONGO_DB_COLLECTION_MCU = "mcu";
|
||||
public static final String MONGO_DB_COLLECTION_WAU = "wau";
|
||||
public static final String MONGO_DB_COLLECTION_DGLC = "dglc";
|
||||
public static final String MONGO_DB_COLLECTION_NRU = "nru";
|
||||
public static final String MONGO_DB_COLLECTION_PLAYTIME = "playtime";
|
||||
public static final String MONGO_DB_COLLECTION_CAPACITY = "capacity";
|
||||
public static final String MONGO_DB_COLLECTION_UGQ_CREATE = "ugqcreate";
|
||||
public static final String MONGO_DB_COLLECTION_METAVER_SERVER = "metaverseserver";
|
||||
public static final String MONGO_DB_COLLECTION_LOG = "Log";
|
||||
|
||||
public static final String MONGO_DB_KEY_LOGTIME = "logTime";
|
||||
public static final String MONGO_DB_KEY_LOGMONTH = "logMonth";
|
||||
public static final String MONGO_DB_KEY_LOGDAY = "logDay";
|
||||
public static final String MONGO_DB_KEY_LOGHOUR = "logHour";
|
||||
public static final String MONGO_DB_KEY_LOGMINUTE = "logMinute";
|
||||
|
||||
public static final String MONGO_DB_KEY_MESSAGE = "message";
|
||||
|
||||
public static final String MONGO_DB_KEY_USER_GUID = "userGuid";
|
||||
public static final String MONGO_DB_KEY_ACCOUNT_ID = "accountId";
|
||||
public static final String MONGO_DB_KEY_ACCOUNT_IDS_COUNT = "accountIdListCount";
|
||||
public static final String MONGO_DB_KEY_LANGUAGE_TYPE = "languageType";
|
||||
public static final String MONGO_DB_KEY_LOGIN_TIME = "loginTime";
|
||||
public static final String MONGO_DB_KEY_LOGOUT_TIME = "logoutTime";
|
||||
public static final String MONGO_DB_KEY_TRAN_ID = "tranId";
|
||||
public static final String MONGO_DB_KEY_ACTION = "action";
|
||||
public static final String MONGO_DB_KEY_SERVER_TYPE = "serverType";
|
||||
|
||||
public static final String MONGO_DB_KEY_USER_GUID_LIST = "userGuidList";
|
||||
public static final String MONGO_DB_KEY_USER_GUID_LIST_COUNT = "userGuidListCount";
|
||||
public static final String MONGO_DB_KEY_MAX_COUNT_USER = "maxCountUser";
|
||||
public static final String MONGO_DB_KEY_TOTAL_PLAY_TIME_COUNT = "totalPlayTimeCount";
|
||||
public static final String MONGO_DB_KEY_CHARACTER_CREATE_COUNT = "characterCreateCount";
|
||||
public static final String MONGO_DB_KEY_CAPACITY_READ_TOTAL = "consumeReadTotal";
|
||||
public static final String MONGO_DB_KEY_CAPACITY_WRITE_TOTAL = "consumeWriteTotal";
|
||||
public static final String MONGO_DB_KEY_UGQ_CREATE_COUNT = "ugqCrateCount";
|
||||
public static final String MONGO_DB_KEY_SERVER_COUNT = "serverCount";
|
||||
|
||||
public static final String REGEX_MSG_LOGIN_TO_USER_AUTH = "\"Action\":\"LoginToUserAuth\"";
|
||||
public static final String REGEX_MSG_LOGIN_TO_GAME = "\"Action\":\"LoginToGame\"";
|
||||
public static final String REGEX_MSG_USER_LOGOUT = "\"Action\":\"UserLogout\"";
|
||||
public static final String REGEX_MSG_CHARACTER_CREATE = "\"Action\":\"CharacterCreate\"";
|
||||
public static final String REGEX_MSG_PLAY_TIME = "\"Action\":\"UserLogout\"";
|
||||
public static final String REGEX_MSG_UGQ_CREATE = "\"Action\":\"UgqApiQuestCraete\"";
|
||||
|
||||
public static final int STAT_DAY_NUM = 1;
|
||||
public static final int STAT_WEEK_NUM = 7;
|
||||
public static final int STAT_MONTH_NUM = 30;
|
||||
|
||||
|
||||
public static final String INDICATORS_KEY_DAU_BY_LANG = "dauByLang";
|
||||
public static final String INDICATORS_KEY_START_DATE = "startDate";
|
||||
public static final String INDICATORS_KEY_END_DATE = "endDate";
|
||||
public static final String INDICATORS_KEY_ITEM_ID = "itemId";
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.caliverse.admin.global.common.constants;
|
||||
|
||||
public class CommonConstants {
|
||||
public static final String TRUE = "True";
|
||||
public static final String FALSE = "False";
|
||||
public static final String NONE = "None";
|
||||
public static final int BATTLE_SERVER_WAIT_TIME = 600; // (seconds) 이벤트 홍보시간이 300초인데 여유있게 처리하게 하기위해 600으로 준다.
|
||||
public static final String SCHEDULE = "Schedule";
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.caliverse.admin.global.common.constants;
|
||||
|
||||
public class DynamoDBConstants {
|
||||
public static final String NAMESPACE = "AWS/DynamoDB";
|
||||
public static final String CONSUMED_READ_CAPACITY = "ConsumedReadCapacityUnits";
|
||||
public static final String CONSUMED_WRITE_CAPACITY = "ConsumedWriteCapacityUnits";
|
||||
|
||||
//PK
|
||||
public static final String PK_KEY_CALIUM = "calium#storage";
|
||||
public static final String PK_KEY_SYSTEM_MAIL = "management_system_meta_mail#global";
|
||||
public static final String PK_KEY_LAND_AUCTION = "land_auction_registry#global";
|
||||
public static final String PK_KEY_LAND_AUCTION_ACTIVE = "land_auction_activity#global";
|
||||
public static final String PK_KEY_LAND_AUCTION_HIGHEST_USER = "land_auction_highest_bid_user#global";
|
||||
public static final String PK_KEY_USER_NICKNAME_REGISTRY = "user_nickname_registry#global";
|
||||
public static final String PK_KEY_MONEY = "money#";
|
||||
public static final String PK_KEY_LAND = "land#";
|
||||
public static final String PK_KEY_OWNED_LAND = "owned_land#";
|
||||
public static final String PK_KEY_BUILDING = "building#";
|
||||
public static final String PK_KEY_OWNED_BUILDING = "owned_building#";
|
||||
//SK
|
||||
|
||||
//Attribute
|
||||
public static final String ATTRIB_CALIUM = "CaliumStorageAttrib";
|
||||
public static final String ATTRIB_SYSTEMMAIL = "SystemMetaMailAttrib";
|
||||
public static final String ATTRIB_LANDAUCTION = "LandAuctionRegistryAttrib";
|
||||
public static final String ATTRIB_LANDAUCTION_ACTIVE = "LandAuctionActivityAttrib";
|
||||
public static final String ATTRIB_LANDAUCTION_HIGHEST_USER = "LandAuctionHighestBidUserAttrib";
|
||||
public static final String ATTRIB_USER_NICKNAME_REGISTRY = "UserNicknameRegistryAttrib";
|
||||
|
||||
//DOC
|
||||
public static final String DOC_SYSTEMMAIL = "SystemMetaMailDoc";
|
||||
public static final String DOC_LANDAUCTION = "LandAuctionRegistryDoc";
|
||||
public static final String DOC_LANDAUCTION_ACTIVE = "LandAuctionActivityDoc";
|
||||
public static final String DOC_LANDAUCTION_HIGHEST_USER = "LandAuctionHighestBidUserDoc";
|
||||
public static final String DOC_USER_NICKNAME_REGISTRY = "UserNicknameRegistryDoc";
|
||||
|
||||
//SCHEMA
|
||||
public static final String SCHEMA_UPDATE_TIME = "UpdatedDateTime";
|
||||
|
||||
//ETC
|
||||
public static final String EMPTY = "empty";
|
||||
public static final String MIN_DATE = "1970-01-01T00:00:00.000Z";
|
||||
public static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSS";
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
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";
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.caliverse.admin.global.common.constants;
|
||||
|
||||
public class MysqlConstants {
|
||||
public static String TABLE_NAME_LAND_AUCTION = "land_auction";
|
||||
public static String TABLE_NAME_CALIUM_REQUEST = "calium_request";
|
||||
public static String TABLE_NAME_EVENT = "event";
|
||||
public static String TABLE_NAME_MAIL = "mail";
|
||||
public static String TABLE_NAME_NOTICE = "notice";
|
||||
public static String TABLE_NAME_BATTLE_EVENT = "battle_event";
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.caliverse.admin.global.common.constants;
|
||||
|
||||
public class Web3Constants {
|
||||
public static final String DB_NAME = "calium#storage";
|
||||
public static final String SERVER_NAME = "caliverse";
|
||||
public static final String URL_SERVER_TYPE = "/web/v3/repo_history/server_type/" + SERVER_NAME;
|
||||
public static final String URL_REQUEST = "/web/v3/repo_history/request";
|
||||
public static final String URL_REQUEST_CONFIRM = "/web/v3/repo_history/request/";
|
||||
public static final String URL_REQUEST_LIST = "/web/v3/repo_history/list";
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.caliverse.admin.global.common.exception;
|
||||
|
||||
import com.caliverse.admin.domain.response.ExceptionResponse;
|
||||
import com.caliverse.admin.global.common.code.CommonCode;
|
||||
import com.caliverse.admin.global.common.code.ErrorCode;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
|
||||
//전체 서비스단의 exception을 캐치
|
||||
@ControllerAdvice
|
||||
public class GlobalException extends ResponseEntityExceptionHandler {
|
||||
@ExceptionHandler
|
||||
public ResponseEntity<ExceptionResponse> handleException(RestApiException restApiException){
|
||||
return ResponseEntity.ok().body(
|
||||
ExceptionResponse.builder()
|
||||
.result(CommonCode.ERROR.getResult())
|
||||
.status(restApiException.getStatusCode())
|
||||
.data(ExceptionResponse.ExceptionData.builder().message(restApiException.getMessage()).build())
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
// 토큰 없을경우 exception 캐치하여 응답한다
|
||||
@ExceptionHandler(AuthenticationException.class)
|
||||
public ResponseEntity<ExceptionResponse> authenticationException(AuthenticationException authenticationException){
|
||||
return ResponseEntity.ok().body(
|
||||
ExceptionResponse.builder()
|
||||
.result(CommonCode.ERROR.getResult())
|
||||
.status(HttpServletResponse.SC_UNAUTHORIZED)
|
||||
.data(ExceptionResponse.ExceptionData.builder().message(ErrorCode.WRONG_TYPE_TOKEN.getMessage()).build())
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
//전체 exception 처리
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<ExceptionResponse> exceptionAll(Exception exception){
|
||||
return ResponseEntity.ok().body(
|
||||
ExceptionResponse.builder()
|
||||
.result(CommonCode.ERROR.getResult())
|
||||
.status(CommonCode.ERROR.getHttpStatus())
|
||||
.data(ExceptionResponse.ExceptionData.builder().message(exception.getMessage()).build())
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.caliverse.admin.global.common.exception;
|
||||
|
||||
public class MetaDataException extends RuntimeException{
|
||||
public MetaDataException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public MetaDataException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.caliverse.admin.global.common.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class RestApiException extends RuntimeException {
|
||||
@Getter
|
||||
private final int statusCode;
|
||||
private final String message;
|
||||
|
||||
public RestApiException(int statusCode, String message) {
|
||||
super(message);
|
||||
this.statusCode = statusCode;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
package com.caliverse.admin.global.common.utils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.*;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.*;
|
||||
|
||||
import com.caliverse.admin.domain.entity.DiffStatus;
|
||||
import com.caliverse.admin.global.common.code.CommonCode;
|
||||
import com.caliverse.admin.global.common.exception.RestApiException;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.caliverse.admin.domain.dao.admin.AdminMapper;
|
||||
import com.caliverse.admin.domain.entity.Admin;
|
||||
import com.caliverse.admin.global.common.code.ErrorCode;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class CommonUtils {
|
||||
private static final Logger logger = LoggerFactory.getLogger(CommonUtils.class);
|
||||
private static UserDetails userDetails;
|
||||
private static AdminMapper adminMapper;
|
||||
|
||||
public static Admin getAdmin(){
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication != null && authentication.getPrincipal() instanceof UserDetails) {
|
||||
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
|
||||
return (Admin) userDetails;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getClientIp() {
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (attributes != null) {
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
String ip = request.getHeader("X-Forwarded-For");
|
||||
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("WL-Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getRemoteAddr();
|
||||
}
|
||||
if ("0:0:0:0:0:0:0:1".equals(ip)) {
|
||||
return "127.0.0.1";
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String objectToString(Object object){
|
||||
if (object == null) {
|
||||
return "";
|
||||
} else if (object instanceof Integer) {
|
||||
return Integer.toString((Integer) object);
|
||||
} else if (object instanceof Boolean) {
|
||||
return Boolean.toString((boolean)object);
|
||||
} else {
|
||||
return object.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static Integer objectToInteger(Object object){
|
||||
if (object == null) {
|
||||
return 0;
|
||||
} else if (object instanceof Integer) {
|
||||
return (Integer)object;
|
||||
} else if (object instanceof Boolean) {
|
||||
return (Integer)object;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static Long objectToLong(Object object) {
|
||||
if (object == null) {
|
||||
return 0L;
|
||||
} else if (object instanceof Long) {
|
||||
return (Long) object;
|
||||
} else if (object instanceof Boolean) {
|
||||
return (Boolean) object ? 1L : 0L;
|
||||
} else if (object instanceof String) {
|
||||
try {
|
||||
return Long.parseLong((String) object);
|
||||
} catch (NumberFormatException e) {
|
||||
return 0L;
|
||||
}
|
||||
} else if (object instanceof Integer) {
|
||||
return ((Integer) object).longValue();
|
||||
} else {
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
public static int[] objectToIntArray(Object object){
|
||||
if (object == null) {
|
||||
return new int[0];
|
||||
} else if (object instanceof List) {
|
||||
List<Integer> list = (List<Integer>) object;
|
||||
int[] intArray = list.stream().mapToInt(i -> i).toArray();
|
||||
return intArray;
|
||||
} else {
|
||||
return new int[0];
|
||||
}
|
||||
}
|
||||
|
||||
public static String[] objectToStringArray(Object object){
|
||||
if (object == null) {
|
||||
return new String[0];
|
||||
} else if (object instanceof List) {
|
||||
List<String> list = (List<String>) object;
|
||||
String[] stringArray = list.toArray(new String[0]);
|
||||
return stringArray;
|
||||
} else {
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<String, String> pageSetting(Map<String, String> map){
|
||||
if(map.get("page_no") != null && map.get("page_size")!=null){
|
||||
int pageNo = Integer.parseInt(map.get("page_no"));
|
||||
int pageSize = Integer.parseInt(map.get("page_size"));
|
||||
|
||||
int offset = (pageNo - 1) * pageSize;
|
||||
|
||||
map.put("pageSize", Integer.valueOf(pageSize).toString());
|
||||
map.put("offset", Integer.valueOf(offset).toString());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public static String setFileName(String fileName){
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
|
||||
String timestamp = now.format(formatter);
|
||||
|
||||
// 파일 확장자 추출
|
||||
String fileExtension = fileName.substring(fileName.lastIndexOf("."));
|
||||
|
||||
String newFileName = fileName.replace(fileExtension, "_" + timestamp + fileExtension);
|
||||
return newFileName;
|
||||
}
|
||||
|
||||
public static LocalDateTime stringToDateTime(String str){
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
|
||||
return LocalDateTime.parse(str, formatter);
|
||||
}
|
||||
|
||||
public static String convertIsoByDatetime(String isoDate){
|
||||
Instant instant = Instant.parse(isoDate);
|
||||
LocalDateTime localDateTime = instant.atZone(ZoneOffset.UTC).toLocalDateTime();
|
||||
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
return localDateTime.format(formatter);
|
||||
}
|
||||
|
||||
public static List<LocalDate> dateRange(String startDt, String endDt){
|
||||
// 시작 날짜와 종료 날짜를 LocalDate로 변환
|
||||
LocalDate startDate = LocalDate.parse(startDt);
|
||||
LocalDate endDate = LocalDate.parse(endDt);
|
||||
// 날짜 범위를 얻기 위한 리스트 생성
|
||||
List<LocalDate> dateRange = new ArrayList<>();
|
||||
|
||||
// 시작 날짜부터 종료 날짜까지 날짜를 리스트에 추가
|
||||
LocalDate currentDate = startDate;
|
||||
while (!currentDate.isAfter(endDate)) {
|
||||
dateRange.add(currentDate);
|
||||
currentDate = currentDate.plusDays(1);
|
||||
}
|
||||
return dateRange;
|
||||
}
|
||||
|
||||
/**
|
||||
* input : 2023-09-03
|
||||
* output: "2023-09-03 00:00:00"
|
||||
*/
|
||||
public static String startOfDay(LocalDate localDate){
|
||||
LocalDateTime startOfDay = localDate.atStartOfDay();
|
||||
String formattedDateTime = startOfDay.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
return formattedDateTime;
|
||||
}
|
||||
/**
|
||||
* input : 2023-09-03
|
||||
* output: "2023-09-03 23:59:59"
|
||||
*/
|
||||
public static String endOfDay(LocalDate localDate){
|
||||
LocalDateTime endOfDay = localDate.atTime(LocalTime.MAX);
|
||||
String formattedDateTime = endOfDay.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
return formattedDateTime;
|
||||
}
|
||||
|
||||
public static int calculateMonths(LocalDateTime startDt, LocalDateTime endDt) {
|
||||
int startYear = startDt.getYear();
|
||||
int endYear = endDt.getYear();
|
||||
int startMonth = startDt.getMonthValue();
|
||||
int endMonth = endDt.getMonthValue();
|
||||
|
||||
return (endYear - startYear) * 12 + (endMonth - startMonth) + 1;
|
||||
}
|
||||
|
||||
public static ErrorCode isValidNickname(String nickname){
|
||||
// 첫번째 글자가 숫자인지 체크 한다.
|
||||
if (Pattern.matches("[0-9]", Character.toString(nickname.charAt(0)))) {
|
||||
return ErrorCode.NICKNAME_NUMBER_ERROR;
|
||||
}
|
||||
|
||||
// 특수문자가 포함되어 있는지 체크 한다.
|
||||
if (isContainSpecialChars(nickname)) {
|
||||
return ErrorCode.NICKNAME_SPECIALCHAR_ERROR;
|
||||
}
|
||||
|
||||
// 길이 체크
|
||||
if(nickname.length() < 2 || nickname.length() > 12){
|
||||
return ErrorCode.NICKNAME_LANGTH_ERROR;
|
||||
}
|
||||
|
||||
// 금지어 여부 체크 추후
|
||||
|
||||
return ErrorCode.SUCCESS;
|
||||
}
|
||||
|
||||
public static boolean isContainSpecialChars(String values) {
|
||||
Pattern pattern = Pattern.compile("[^a-zA-Z0-9ㄱ-ㅎ가-힣\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uff66-\uff9f]");
|
||||
Matcher matcher = pattern.matcher(values);
|
||||
|
||||
return matcher.find();
|
||||
}
|
||||
|
||||
public static Map<String, Object> stringByObject(String string) {
|
||||
try {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
return objectMapper.readValue(string, new TypeReference<>() {});
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static Integer stringToInt(String string) {
|
||||
try{
|
||||
return Integer.parseInt(string);
|
||||
}catch (NumberFormatException e){
|
||||
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.SENDMAIL_ERROR.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static long intervalToMillis(String interval) {
|
||||
String[] parts = interval.split(":");
|
||||
long hour = Long.parseLong(parts[0]);
|
||||
long minute = Long.parseLong(parts[1]);
|
||||
long second = Long.parseLong(parts[2]);
|
||||
|
||||
return TimeUnit.HOURS.toMillis(hour) + TimeUnit.MINUTES.toMillis(minute) + TimeUnit.SECONDS.toMillis(second);
|
||||
}
|
||||
|
||||
public static ByteString stringEncoding(String text){
|
||||
return ByteString.copyFrom(text.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
public static String stringToByte(String text){
|
||||
return Base64.getEncoder().encodeToString(text.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public static String convertUTCDate(LocalDateTime date){
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
|
||||
return date.atOffset(ZoneOffset.UTC).format(formatter);
|
||||
}
|
||||
|
||||
public static LocalTime stringToTime(String time){
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
|
||||
return LocalTime.parse(time, formatter);
|
||||
}
|
||||
|
||||
public static String getDiffStatus(int cnt, int pre_cnt){
|
||||
return cnt - pre_cnt > 0 ? DiffStatus.UP.getStatus() :
|
||||
cnt - pre_cnt < 0 ? DiffStatus.DOWN.getStatus() :
|
||||
DiffStatus.EQUAL.getStatus();
|
||||
}
|
||||
|
||||
public static String getDiffRate(int cnt, int pre_cnt){
|
||||
// 이전 값이 0인 경우
|
||||
if (pre_cnt == 0) {
|
||||
if (cnt == 0) {
|
||||
return "0";
|
||||
}
|
||||
return String.valueOf(cnt * 100);
|
||||
}
|
||||
|
||||
double changeRate = Math.abs((double) (cnt - pre_cnt) / pre_cnt * 100);
|
||||
return String.valueOf((int) Math.round(changeRate));
|
||||
}
|
||||
|
||||
public static int getLengthOfLastMonth(LocalDate date){
|
||||
LocalDate localDate = date.minusMonths(1);
|
||||
return localDate.lengthOfMonth();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.caliverse.admin.global.common.utils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class DateUtils {
|
||||
public static String dateToString(LocalDateTime date) {
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
return date.format(formatter);
|
||||
}
|
||||
|
||||
public static String nowDateTime(){
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
return dateToString(now);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.caliverse.admin.global.common.utils;
|
||||
|
||||
import com.caliverse.admin.domain.RabbitMq.message.LanguageType;
|
||||
import com.caliverse.admin.domain.entity.Item;
|
||||
import com.caliverse.admin.domain.entity.LANGUAGETYPE;
|
||||
import com.caliverse.admin.domain.entity.Message;
|
||||
import com.caliverse.admin.dynamodb.entity.MailItem;
|
||||
import com.caliverse.admin.dynamodb.entity.SystemMessage;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class DynamodbUtil {
|
||||
public static String getSenderByLanguage(Message msg) {
|
||||
LANGUAGETYPE langType = LANGUAGETYPE.valueOf(msg.getLanguage());
|
||||
switch (langType) {
|
||||
case EN:
|
||||
return "CALIVERSE";
|
||||
case JA:
|
||||
return "カリバース";
|
||||
case KO:
|
||||
return "칼리버스";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Integer getLanguageType(String language) {
|
||||
LANGUAGETYPE langType = LANGUAGETYPE.valueOf(language);
|
||||
switch (langType) {
|
||||
case EN:
|
||||
return LanguageType.LanguageType_en.getNumber();
|
||||
case JA:
|
||||
return LanguageType.LanguageType_ja.getNumber();
|
||||
case KO:
|
||||
return LanguageType.LanguageType_ko.getNumber();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<SystemMessage> createSystemMessages(List<Message> messages, Function<Message, String> textExtractor) {
|
||||
return messages.stream()
|
||||
.map(msg -> SystemMessage.builder()
|
||||
.languageType(getLanguageType(msg.getLanguage()))
|
||||
.text(textExtractor.apply(msg))
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<MailItem> createMailItems(List<Item> items) {
|
||||
return items.stream()
|
||||
.map(item -> MailItem.builder()
|
||||
.itemId(CommonUtils.stringToInt(item.getItem()))
|
||||
.count(item.getItemCnt())
|
||||
.isRepeatProduct(false)
|
||||
.productId(0)
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,561 @@
|
||||
package com.caliverse.admin.global.common.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.formula.eval.ErrorEval;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
|
||||
import org.apache.poi.xssf.usermodel.XSSFColor;
|
||||
import org.apache.poi.xssf.usermodel.XSSFFont;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.caliverse.admin.domain.entity.Currencys;
|
||||
import com.caliverse.admin.domain.entity.ROUTE;
|
||||
import com.caliverse.admin.domain.entity.Excel;
|
||||
import com.caliverse.admin.domain.response.IndicatorsResponse;
|
||||
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.fasterxml.jackson.databind.exc.InvalidFormatException;
|
||||
|
||||
import jakarta.servlet.ServletOutputStream;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ExcelUtils {
|
||||
|
||||
@Value("${excel.file-path}")
|
||||
private String filePath;
|
||||
// 각 셀의 데이터타입에 맞게 값 가져오기
|
||||
public String getCellValue(Cell cell) {
|
||||
|
||||
String value = "";
|
||||
|
||||
if(cell == null){
|
||||
return value;
|
||||
}
|
||||
|
||||
switch (cell.getCellType()) {
|
||||
case STRING: // getRichStringCellValue() 메소드를 사용하여 컨텐츠를 읽음
|
||||
value = cell.getRichStringCellValue().getString();
|
||||
break;
|
||||
case NUMERIC: // 날짜 또는 숫자를 포함 할 수 있으며 아래와 같이 읽음
|
||||
if (DateUtil.isCellDateFormatted(cell))
|
||||
value = cell.getLocalDateTimeCellValue().toString();
|
||||
else
|
||||
value = String.valueOf(cell.getNumericCellValue());
|
||||
if (value.endsWith(".0"))
|
||||
value = value.substring(0, value.length() - 2);
|
||||
break;
|
||||
case BOOLEAN:
|
||||
value = String.valueOf(cell.getBooleanCellValue());
|
||||
break;
|
||||
case FORMULA:
|
||||
value = String.valueOf(cell.getCellFormula());
|
||||
break;
|
||||
case ERROR:
|
||||
value = ErrorEval.getText(cell.getErrorCellValue());
|
||||
break;
|
||||
case BLANK:
|
||||
case _NONE:
|
||||
default:
|
||||
value = "";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public Workbook loadExcel(String fileName){
|
||||
String fullPath = filePath + fileName;
|
||||
|
||||
try (FileInputStream fis = new FileInputStream(new File(fullPath))) {
|
||||
return WorkbookFactory.create(fis);
|
||||
}catch(Exception e){
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 엑셀파일의 데이터 목록 가져오기 (파일명기준)
|
||||
public List<Excel> getExcelListData(String fileName){
|
||||
|
||||
List<Excel> excelList = new ArrayList<>();
|
||||
|
||||
try {
|
||||
Workbook workbook = loadExcel(fileName);
|
||||
|
||||
// 첫번째 시트
|
||||
Sheet sheet = workbook.getSheetAt(0);
|
||||
|
||||
int rowIndex = 0;
|
||||
|
||||
// 첫번째 행(0)은 컬럼 명이기 때문에 두번째 행(1) 부터 검색
|
||||
for (rowIndex = 1; rowIndex < sheet.getLastRowNum() + 1; rowIndex++) {
|
||||
Row row = sheet.getRow(rowIndex);
|
||||
|
||||
// 빈 행은 Skip
|
||||
if (row != null && row.getCell(0) != null && !row.getCell(0).toString().isBlank()) {
|
||||
|
||||
Cell cell = row.getCell(0);
|
||||
Cell cell2 = row.getCell(1);
|
||||
|
||||
Excel excel = Excel.builder().user(getCellValue(cell)).type(getCellValue(cell2)).build();
|
||||
excelList.add(excel);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Exception Excel Format:" + e.getMessage());
|
||||
}
|
||||
|
||||
return excelList;
|
||||
}
|
||||
|
||||
// 엑셀파일의 데이터 목록 가져오기 (파라미터들은 위에서 설명함)
|
||||
public List<String> getListData(MultipartFile file, int startRowNum, int columnLength){
|
||||
|
||||
List<String> excelList = new ArrayList<String>();
|
||||
|
||||
try {
|
||||
Workbook workbook = null;
|
||||
|
||||
String ext = FilenameUtils.getExtension(file.getOriginalFilename()).toLowerCase();
|
||||
if(!ext.equals("xlsx") && !ext.equals("xls")){
|
||||
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.NOT_EXIT_EXCEL.getMessage() ); //Excel 파일을 선택해주세요.
|
||||
}
|
||||
if (ext.equals("xls")){
|
||||
workbook = new HSSFWorkbook(file.getInputStream());
|
||||
}else{
|
||||
workbook = new XSSFWorkbook(file.getInputStream());
|
||||
}
|
||||
|
||||
// 첫번째 시트
|
||||
Sheet sheet = workbook.getSheetAt(0);
|
||||
|
||||
int rowIndex = 0;
|
||||
int columnIndex = 0;
|
||||
|
||||
// 첫번째 행(0)은 컬럼 명이기 때문에 두번째 행(1) 부터 검색
|
||||
for (rowIndex = startRowNum; rowIndex < sheet.getLastRowNum() + 1; rowIndex++) {
|
||||
Row row = sheet.getRow(rowIndex);
|
||||
|
||||
// 빈 행은 Skip
|
||||
if (row != null && row.getCell(0) != null && !row.getCell(0).toString().isBlank()) {
|
||||
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
|
||||
int cells = columnLength;
|
||||
|
||||
for (columnIndex = 0; columnIndex <= cells; columnIndex++) {
|
||||
Cell cell = row.getCell(columnIndex);
|
||||
Cell cell2 = row.getCell(columnIndex+1);
|
||||
if(getCellValue(cell2).equals("GUID")){
|
||||
if(isString32Characters(getCellValue(cell))){
|
||||
excelList.add(getCellValue(cell));
|
||||
}else{
|
||||
log.error("getListData : Excel Upload Guid Check Fail type {}, user {}", cell2, cell);
|
||||
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.GUID_LENGTH_CHECK.getMessage() ); //guid 32자 체크
|
||||
}
|
||||
}else if(getCellValue(cell2).equals("NICKNAME")){
|
||||
excelList.add(getCellValue(cell));
|
||||
}else if(getCellValue(cell2).equals("EMAIL")){
|
||||
excelList.add(getCellValue(cell));
|
||||
}else{
|
||||
log.error("getListData : Excel Upload Type Error type {}, user {}", cell2, cell);
|
||||
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.USERTYPE_CHECK_EXCEL.getMessage() );
|
||||
}
|
||||
/*map.put(String.valueOf(columnIndex), getCellValue(cell));
|
||||
log.info(rowIndex + " 행 : " + columnIndex+ " 열 = " + getCellValue(cell));*/
|
||||
}
|
||||
|
||||
//excelList.add(map);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (InvalidFormatException e) {
|
||||
log.info("getListData Invalid Excel Format:" + e.getMessage());
|
||||
} catch (IOException e) {
|
||||
log.info("getListData IOException Excel Format:" + e.getMessage());
|
||||
}
|
||||
|
||||
return excelList;
|
||||
}
|
||||
|
||||
public void excelDownload(String sheetName, String headerNames[], String bodyDatass[][],String outfileName
|
||||
, HttpServletResponse res) throws IOException {
|
||||
|
||||
Workbook workbook = new XSSFWorkbook();
|
||||
ServletOutputStream servletOutputStream = res.getOutputStream();
|
||||
try {
|
||||
|
||||
Sheet sheet = workbook.createSheet(sheetName); // 엑셀 sheet 이름
|
||||
|
||||
/**
|
||||
* header font style
|
||||
*/
|
||||
XSSFFont headerXSSFFont = (XSSFFont) workbook.createFont();
|
||||
headerXSSFFont.setColor(new XSSFColor(new byte[]{(byte) 255, (byte) 255, (byte) 255}));
|
||||
|
||||
/**
|
||||
* header cell style
|
||||
*/
|
||||
XSSFCellStyle headerXssfCellStyle = (XSSFCellStyle) workbook.createCellStyle();
|
||||
|
||||
// 테두리 설정
|
||||
headerXssfCellStyle.setBorderLeft(BorderStyle.THIN);
|
||||
headerXssfCellStyle.setBorderRight(BorderStyle.THIN);
|
||||
headerXssfCellStyle.setBorderTop(BorderStyle.THIN);
|
||||
headerXssfCellStyle.setBorderBottom(BorderStyle.THIN);
|
||||
|
||||
// 배경 설정
|
||||
/*headerXssfCellStyle.setFillForegroundColor(new XSSFColor(new byte[]{(byte) 34, (byte) 37, (byte) 41}));
|
||||
headerXssfCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||
headerXssfCellStyle.setFont(headerXSSFFont);*/
|
||||
|
||||
/**
|
||||
* body cell style
|
||||
*/
|
||||
XSSFCellStyle bodyXssfCellStyle = (XSSFCellStyle) workbook.createCellStyle();
|
||||
|
||||
// 테두리 설정
|
||||
bodyXssfCellStyle.setBorderLeft(BorderStyle.THIN);
|
||||
bodyXssfCellStyle.setBorderRight(BorderStyle.THIN);
|
||||
bodyXssfCellStyle.setBorderTop(BorderStyle.THIN);
|
||||
bodyXssfCellStyle.setBorderBottom(BorderStyle.THIN);
|
||||
|
||||
/**
|
||||
* header data
|
||||
*/
|
||||
int rowCount = 0; // 데이터가 저장될 행
|
||||
|
||||
Row headerRow = null;
|
||||
Cell headerCell = null;
|
||||
|
||||
headerRow = sheet.createRow(rowCount++);
|
||||
for(int i=0; i<headerNames.length; i++) {
|
||||
headerCell = headerRow.createCell(i);
|
||||
headerCell.setCellValue(headerNames[i]); // 데이터 추가
|
||||
headerCell.setCellStyle(headerXssfCellStyle); // 스타일 추가
|
||||
}
|
||||
|
||||
Row bodyRow = null;
|
||||
Cell bodyCell = null;
|
||||
|
||||
for(String[] bodyDatas : bodyDatass) {
|
||||
bodyRow = sheet.createRow(rowCount++);
|
||||
|
||||
for(int i=0; i<bodyDatas.length; i++) {
|
||||
bodyCell = bodyRow.createCell(i);
|
||||
bodyCell.setCellValue(bodyDatas[i]); // 데이터 추가
|
||||
bodyCell.setCellStyle(bodyXssfCellStyle); // 스타일 추가
|
||||
sheet.autoSizeColumn(i);
|
||||
sheet.setColumnWidth(i, (sheet.getColumnWidth(i))+1024); //너비 더 넓게
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* download
|
||||
*/
|
||||
res.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
res.setHeader("Content-Disposition", "attachment;filename=" + outfileName + ".xlsx");
|
||||
|
||||
workbook.write(servletOutputStream);
|
||||
workbook.close();
|
||||
servletOutputStream.flush();
|
||||
servletOutputStream.close();
|
||||
}catch (IOException exception){
|
||||
exception.getMessage();
|
||||
}finally {
|
||||
workbook.close();
|
||||
servletOutputStream.flush();
|
||||
servletOutputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
public String saveExcelFile(MultipartFile file){
|
||||
try{
|
||||
String fileName = CommonUtils.setFileName(file.getOriginalFilename());
|
||||
String path = filePath + File.separator + fileName;
|
||||
Path destinationPath = Path.of(path);
|
||||
|
||||
Files.copy(file.getInputStream(), destinationPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
return fileName;
|
||||
}catch (IOException e){
|
||||
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_EXCEL_UPLOAD.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean hasDuplicates(List<String> dataList) {
|
||||
Set<String> uniqueValues = new HashSet<>();
|
||||
|
||||
for (String value : dataList) {
|
||||
if (uniqueValues.contains(value)) {
|
||||
return true;
|
||||
}
|
||||
uniqueValues.add(value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isString32Characters(String input) {
|
||||
if (input == null) {
|
||||
return false;
|
||||
}
|
||||
return input.length() == 32;
|
||||
}
|
||||
|
||||
//재화 지표 엑셀 다운 샘플
|
||||
public static void exportToExcelByDailyGoods(List<IndicatorsResponse.DailyGoods> dailyGoodsList
|
||||
,HttpServletResponse res) throws IOException {
|
||||
ServletOutputStream servletOutputStream = res.getOutputStream();
|
||||
try (Workbook workbook = new XSSFWorkbook()) {
|
||||
// 엑셀 시트 생성
|
||||
Sheet sheet = workbook.createSheet("DailyGoodsData");
|
||||
|
||||
// 첫 번째 라인 - 일자
|
||||
Row dateRow = sheet.createRow(0);
|
||||
dateRow.createCell(0).setCellValue("일자");
|
||||
sheet.autoSizeColumn(0);
|
||||
sheet.setColumnWidth((0), (sheet.getColumnWidth(0))+1024*2); //너비 더 넓게
|
||||
for (int i = 0; i < dailyGoodsList.size(); i++) {
|
||||
dateRow.createCell((i+1) + 1).setCellValue(dailyGoodsList.get(i).getDate().toString());
|
||||
//sheet 넓이 auto
|
||||
sheet.autoSizeColumn((i+2));
|
||||
}
|
||||
|
||||
// 두 번째 라인 - ACQUIRE 총량
|
||||
Row acquireRow = sheet.createRow(1);
|
||||
acquireRow.createCell(0).setCellValue("(Total)생산량");
|
||||
|
||||
for (int i = 0; i < dailyGoodsList.size(); i++) {
|
||||
List<IndicatorsResponse.Total> totals = dailyGoodsList.get(i).getTotal();
|
||||
for (int j = 0; j < totals.size(); j++) {
|
||||
if ("ACQUIRE".equals(totals.get(j).getDeltaType())) {
|
||||
acquireRow.createCell((i+1) + 1).setCellValue(totals.get(j).getQuantity());
|
||||
}
|
||||
}
|
||||
}
|
||||
// 세번째 라인 - CONSUME 총량
|
||||
Row consumeRow = sheet.createRow(2);
|
||||
consumeRow.createCell(0).setCellValue("(Total)소진량");
|
||||
|
||||
for (int i = 0; i < dailyGoodsList.size(); i++) {
|
||||
List<IndicatorsResponse.Total> totals = dailyGoodsList.get(i).getTotal();
|
||||
for (int j = 0; j < totals.size(); j++) {
|
||||
if ("CONSUME".equals(totals.get(j).getDeltaType())) {
|
||||
consumeRow.createCell((i+1) + 1).setCellValue(totals.get(j).getQuantity());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 나머지 라인 - Route 별 quantity
|
||||
List<ROUTE> acquireRoutes = Arrays.asList(
|
||||
ROUTE.QUEST_REWARD, ROUTE.SEASON_PASS, ROUTE.FROM_PROP,
|
||||
ROUTE.CLAIM_REWARD, ROUTE.USE_ITEM, ROUTE.TATTOO_ENHANCE,
|
||||
ROUTE.TATTOO_CONVERSION, ROUTE.SHOP_BUY, ROUTE.SHOP_SELL,
|
||||
ROUTE.PAID_PRODUCT, ROUTE.TRADE_ADD, ROUTE.NFT_LOCKIN
|
||||
);
|
||||
int rowIndex = 3; // 시작 행 인덱스
|
||||
|
||||
for (ROUTE route : acquireRoutes) {
|
||||
Row routeRow = sheet.createRow(rowIndex++);
|
||||
routeRow.createCell(0).setCellValue("GET");
|
||||
routeRow.createCell(1).setCellValue(route.getDescription());
|
||||
|
||||
for (int i = 0; i < dailyGoodsList.size(); i++) {
|
||||
List<IndicatorsResponse.DailyData> dailyDataList = dailyGoodsList.get(i).getDailyData();
|
||||
for (IndicatorsResponse.DailyData dailyData : dailyDataList) {
|
||||
if(dailyData.getDeltaType().equals("ACQUIRE")){
|
||||
List<Currencys> data = dailyData.getData();
|
||||
for (Currencys currencys : data) {
|
||||
if (route.getDescription().equals(currencys.getRoute())) {
|
||||
routeRow.createCell((i+1) + 1).setCellValue(currencys.getQuantity());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
List<ROUTE> consumeRoutes = Arrays.asList(
|
||||
ROUTE.SHOP_BUY, ROUTE.SHOP_SELL, ROUTE.USE_PROP,
|
||||
ROUTE.USE_TAXI, ROUTE.TATTOO_ENHANCE, ROUTE.TATTOO_CONVERSION,
|
||||
ROUTE.SHOUT, ROUTE.SUMMON, ROUTE.CREATE_PARTYROOM,
|
||||
ROUTE.INVENTORY_EXPAND, ROUTE.TRADE_REMOVE, ROUTE.NFT_UNLOCK
|
||||
);
|
||||
for (ROUTE route : consumeRoutes) {
|
||||
Row routeRow = sheet.createRow(rowIndex++);
|
||||
routeRow.createCell(0).setCellValue("USE");
|
||||
routeRow.createCell(1).setCellValue(route.getDescription());
|
||||
|
||||
for (int i = 0; i < dailyGoodsList.size(); i++) {
|
||||
List<IndicatorsResponse.DailyData> dailyDataList = dailyGoodsList.get(i).getDailyData();
|
||||
for (IndicatorsResponse.DailyData dailyData : dailyDataList) {
|
||||
if(dailyData.getDeltaType().equals("CONSUME")){
|
||||
List<Currencys> data = dailyData.getData();
|
||||
for (Currencys currencys : data) {
|
||||
if (route.getDescription().equals(currencys.getRoute())) {
|
||||
routeRow.createCell((i+1) + 1).setCellValue(currencys.getQuantity());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//cell 머지
|
||||
sheet.addMergedRegion(CellRangeAddress.valueOf("A1:B1"));
|
||||
sheet.addMergedRegion(CellRangeAddress.valueOf("A2:B2"));
|
||||
sheet.addMergedRegion(CellRangeAddress.valueOf("A3:B3"));
|
||||
sheet.addMergedRegion(CellRangeAddress.valueOf("A4:A15"));
|
||||
sheet.addMergedRegion(CellRangeAddress.valueOf("A16:A27"));
|
||||
/**
|
||||
* download
|
||||
*/
|
||||
res.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
res.setHeader("Content-Disposition", "attachment;filename=DailyGoodsData_" + LocalDateTime.now().getNano()
|
||||
+ ".xlsx");
|
||||
|
||||
workbook.write(servletOutputStream);
|
||||
workbook.close();
|
||||
servletOutputStream.flush();
|
||||
servletOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
log.error("exportToExcelByDailyGoods IOException: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
//유저 지표 Retention 엑셀 다운 샘플
|
||||
public static void exportToExcelByRentention(List<IndicatorsResponse.Retention> list
|
||||
,HttpServletResponse res) throws IOException {
|
||||
ServletOutputStream servletOutputStream = res.getOutputStream();
|
||||
try (Workbook workbook = new XSSFWorkbook()) {
|
||||
// 엑셀 시트 생성
|
||||
Sheet sheet = workbook.createSheet("Retention");
|
||||
|
||||
// 첫 번째 라인 - 일자
|
||||
Row dateRow = sheet.createRow(0);
|
||||
dateRow.createCell(0).setCellValue("국가");
|
||||
dateRow.createCell(1).setCellValue("일자");
|
||||
dateRow.createCell(2).setCellValue("NRU");
|
||||
|
||||
for (int i = 1; i < list.size(); i++) {
|
||||
dateRow.createCell(i+2).setCellValue("D+"+i);
|
||||
//sheet 넓이 auto
|
||||
sheet.autoSizeColumn(i+2);
|
||||
}
|
||||
|
||||
int rowIndex = 1; // 시작 행 인덱스
|
||||
// 두 번째 라인
|
||||
for (IndicatorsResponse.Retention retention : list){
|
||||
Row row = sheet.createRow(rowIndex++);
|
||||
row.createCell(0).setCellValue("ALL");
|
||||
List<IndicatorsResponse.Dday> dDay = retention.getDDay();
|
||||
row.createCell(1).setCellValue(retention.getDate().toString());
|
||||
for (int j = 0; j < dDay.size(); j++) {
|
||||
row.createCell(j+2).setCellValue(dDay.get(j).getDif());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//cell 머지
|
||||
sheet.addMergedRegion(CellRangeAddress.valueOf("A2:A"+(list.size()+1)));
|
||||
/*sheet.addMergedRegion(CellRangeAddress.valueOf("A1:B1"));
|
||||
sheet.addMergedRegion(CellRangeAddress.valueOf("A2:B2"));
|
||||
sheet.addMergedRegion(CellRangeAddress.valueOf("A3:B3"));
|
||||
sheet.addMergedRegion(CellRangeAddress.valueOf("A4:A15"));
|
||||
sheet.addMergedRegion(CellRangeAddress.valueOf("A16:A27"));*/
|
||||
/**
|
||||
* download
|
||||
*/
|
||||
res.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
res.setHeader("Content-Disposition", "attachment;filename=Retention_" + LocalDateTime.now().getNano()
|
||||
+ ".xlsx");
|
||||
|
||||
workbook.write(servletOutputStream);
|
||||
workbook.close();
|
||||
servletOutputStream.flush();
|
||||
servletOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
log.error("exportToExcelByRentention IOException: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
//유저 지표 Retention 엑셀 다운 샘플
|
||||
public static void exportToExcelBySegment(List<IndicatorsResponse.Segment> list,LocalDate startDt,
|
||||
LocalDate endDt,HttpServletResponse res) throws IOException {
|
||||
ServletOutputStream servletOutputStream = res.getOutputStream();
|
||||
try (Workbook workbook = new XSSFWorkbook()) {
|
||||
// 엑셀 시트 생성
|
||||
Sheet sheet = workbook.createSheet("Segment");
|
||||
sheet.autoSizeColumn(0);
|
||||
sheet.autoSizeColumn(1);
|
||||
sheet.autoSizeColumn(2);
|
||||
sheet.addMergedRegion(CellRangeAddress.valueOf("B1:C1"));
|
||||
sheet.setColumnWidth(0,sheet.getColumnWidth(0)+1024*4);
|
||||
|
||||
|
||||
int rowIndex = 0;
|
||||
// 첫 번째 라인 - 일자
|
||||
Row headerRow = sheet.createRow(rowIndex++);
|
||||
headerRow.createCell(0).setCellValue(startDt.toString()+"~"+endDt.toString());
|
||||
headerRow.createCell(1).setCellValue("KIP");
|
||||
|
||||
Row subHeaderRow = sheet.createRow(rowIndex++);
|
||||
subHeaderRow.createCell(0).setCellValue("세그먼트 분류");
|
||||
subHeaderRow.createCell(1).setCellValue("AU");
|
||||
subHeaderRow.createCell(2).setCellValue("AU Percentage by User Segment (%)");
|
||||
|
||||
Row dataRow = null;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
dataRow = sheet.createRow(i+rowIndex);
|
||||
dataRow.createCell(0).setCellValue(list.get(i).getType());
|
||||
dataRow.createCell(1).setCellValue(list.get(i).getAu());
|
||||
dataRow.createCell(2).setCellValue(list.get(i).getDif());
|
||||
}
|
||||
|
||||
//cell 머지
|
||||
/*sheet.addMergedRegion(CellRangeAddress.valueOf("A1:B1"));
|
||||
sheet.addMergedRegion(CellRangeAddress.valueOf("A2:B2"));
|
||||
sheet.addMergedRegion(CellRangeAddress.valueOf("A3:B3"));
|
||||
sheet.addMergedRegion(CellRangeAddress.valueOf("A4:A15"));
|
||||
sheet.addMergedRegion(CellRangeAddress.valueOf("A16:A27"));*/
|
||||
/**
|
||||
* download
|
||||
*/
|
||||
res.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
res.setHeader("Content-Disposition", "attachment;filename=Segment_" + LocalDateTime.now().getNano()
|
||||
+ ".xlsx");
|
||||
|
||||
workbook.write(servletOutputStream);
|
||||
workbook.close();
|
||||
servletOutputStream.flush();
|
||||
servletOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
log.error("exportToExcelBySegment IOException: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.caliverse.admin.global.common.utils;
|
||||
|
||||
import com.caliverse.admin.domain.RabbitMq.message.MailItem;
|
||||
import com.caliverse.admin.dynamodb.entity.SystemMessage;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class JsonUtils {
|
||||
private static final Logger logger = LoggerFactory.getLogger(CommonUtils.class);
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
public static ObjectNode createSystemMessage(SystemMessage message) {
|
||||
ObjectNode node = objectMapper.createObjectNode();
|
||||
node.put("LanguageType", message.getLanguageType());
|
||||
node.put("Text", message.getText());
|
||||
return node;
|
||||
}
|
||||
|
||||
public static ObjectNode createMAilItem(MailItem mailItem) {
|
||||
ObjectNode node = objectMapper.createObjectNode();
|
||||
node.put("ItemId", mailItem.getItemId());
|
||||
node.put("Count", mailItem.getCount());
|
||||
node.put("ProductId", 0);
|
||||
node.put("isRepeatProduct", false);
|
||||
return node;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.caliverse.admin.global.component;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class AdminApplicationContextProvider implements ApplicationContextAware {
|
||||
|
||||
@Getter
|
||||
private static ApplicationContext context;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
context = applicationContext;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.caliverse.admin.global.component.transaction;
|
||||
|
||||
import software.amazon.awssdk.enhanced.dynamodb.model.TransactWriteItemsEnhancedRequest;
|
||||
|
||||
public class DynamoDBTransactionContext {
|
||||
private static final ThreadLocal<TransactWriteItemsEnhancedRequest.Builder> currentTransaction = new ThreadLocal<>();
|
||||
|
||||
public static void setTransactionBuilder(
|
||||
TransactWriteItemsEnhancedRequest.Builder builder) {
|
||||
currentTransaction.set(builder);
|
||||
}
|
||||
|
||||
public static TransactWriteItemsEnhancedRequest.Builder getTransactionBuilder() {
|
||||
return currentTransaction.get();
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
currentTransaction.remove();
|
||||
}
|
||||
|
||||
public static boolean isInTransaction() {
|
||||
return currentTransaction.get() != null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.caliverse.admin.global.component.transaction;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Component
|
||||
public class TransactionIdManager {
|
||||
private static final String TRANSACTION_ID_KEY = "TRANSACTION_ID";
|
||||
|
||||
public String getCurrentTransactionId() {
|
||||
String currentId = (String) TransactionSynchronizationManager.getResource(TRANSACTION_ID_KEY);
|
||||
if (currentId == null) {
|
||||
currentId = generateTransactionId();
|
||||
TransactionSynchronizationManager.bindResource(TRANSACTION_ID_KEY, currentId);
|
||||
}
|
||||
return currentId;
|
||||
}
|
||||
|
||||
private String generateTransactionId() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
import com.caliverse.admin.domain.dao.admin.AdminMapper;
|
||||
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class ApplicationConfig {
|
||||
|
||||
private final AdminMapper userMapper;
|
||||
|
||||
@Bean
|
||||
public UserDetailsService userDetailsService(){
|
||||
|
||||
return email -> userMapper.findByEmail(email)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationProvider authenticationProvider(){
|
||||
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
|
||||
authProvider.setUserDetailsService(userDetailsService());
|
||||
authProvider.setPasswordEncoder(passwordEncoder());
|
||||
return authProvider;
|
||||
}
|
||||
|
||||
|
||||
@Lazy
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception{
|
||||
return config.getAuthenticationManager();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@RequiredArgsConstructor
|
||||
public class AuthenticationConfig {
|
||||
private final JwtAuthenticationFilter jwtAuthFilter;
|
||||
private final AuthenticationProvider authenticationProvider;
|
||||
private final LogoutHandler logoutHandler;
|
||||
private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
|
||||
|
||||
return httpSecurity
|
||||
.httpBasic().disable()
|
||||
.csrf().disable() // jwt사용하기 때문에 사용안한다.
|
||||
.cors(cors -> cors.configurationSource(request -> {
|
||||
CorsConfiguration corsConfiguration = new CorsConfiguration();
|
||||
corsConfiguration.setAllowedOrigins(List.of(
|
||||
"http://localhost:3000",
|
||||
"http://10.20.20.23:8080",
|
||||
"http://qa-admintool.caliverse.io:8080",
|
||||
"http://stage-admintool.caliverse.io:8080",
|
||||
"http://live-admintool.caliverse.io:8080"
|
||||
));
|
||||
corsConfiguration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PATCH"));
|
||||
corsConfiguration.setAllowedHeaders(List.of("Authorization","Content-Type"));
|
||||
corsConfiguration.setAllowCredentials(true);
|
||||
return corsConfiguration;
|
||||
}))
|
||||
.authorizeHttpRequests()
|
||||
.requestMatchers("/api/v1/auth/login","/api/v1/auth/register","/v3/api-docs/**","/swagger-ui/**","swagger-ui.html", "/dev-test/**").permitAll() // login,register은 언제나 가능
|
||||
.requestMatchers(HttpMethod.POST,"/api/v1/**").authenticated()
|
||||
.anyRequest()
|
||||
.authenticated()
|
||||
.and()
|
||||
.sessionManagement(session -> session .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) //jwt 사용하는 경우 씀
|
||||
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
|
||||
.exceptionHandling(handler -> handler.authenticationEntryPoint(jwtAuthenticationEntryPoint))
|
||||
.authenticationProvider(authenticationProvider)
|
||||
.logout()
|
||||
.logoutUrl("/api/v1/auth/logout")
|
||||
.addLogoutHandler(logoutHandler)
|
||||
.logoutSuccessHandler(((request, response, authentication) -> SecurityContextHolder.clearContext()))
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
import com.caliverse.admin.domain.batch.CustomProcessor;
|
||||
import com.caliverse.admin.domain.batch.CustomReader;
|
||||
import com.caliverse.admin.domain.batch.CustomWriter;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;
|
||||
import org.springframework.batch.core.job.builder.JobBuilder;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.step.builder.StepBuilder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@Configuration
|
||||
public class BatchConfiguration {
|
||||
//public class BatchConfiguration extends DefaultBatchConfiguration {
|
||||
|
||||
// @Autowired
|
||||
// @Qualifier("dataSource")
|
||||
// private DataSource dataSource;
|
||||
//
|
||||
// @Autowired
|
||||
// @Qualifier("batchTransactionManager")
|
||||
// private PlatformTransactionManager transactionManger;
|
||||
//
|
||||
// @Override
|
||||
// public DataSource getDataSource() {
|
||||
// return dataSource;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public PlatformTransactionManager getTransactionManager() {
|
||||
// return transactionManger;
|
||||
//
|
||||
// }
|
||||
//
|
||||
//
|
||||
// @Bean
|
||||
// public Job createJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
|
||||
// return new JobBuilder("testJob", jobRepository)
|
||||
// .flow(createStep(jobRepository, transactionManager)).end().build();
|
||||
// }
|
||||
//
|
||||
// @Bean
|
||||
// Step createStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
|
||||
// return new StepBuilder("testStep", jobRepository)
|
||||
// .<String, String> chunk(3, transactionManager)
|
||||
// .allowStartIfComplete(true)
|
||||
// .reader(new CustomReader())
|
||||
// .processor(new CustomProcessor())
|
||||
// .writer(new CustomWriter())
|
||||
// .build();
|
||||
// }
|
||||
|
||||
|
||||
// @Bean
|
||||
// public org.springframework.batch.core.Job testJob(JobRepository jobRepository,PlatformTransactionManager transactionManager) throws DuplicateJobException {
|
||||
// org.springframework.batch.core.Job job = new JobBuilder("testJob",jobRepository)
|
||||
// .start(testStep(jobRepository,transactionManager))
|
||||
// .build();
|
||||
// return job;
|
||||
// }
|
||||
|
||||
// public Step testStep(JobRepository jobRepository,PlatformTransactionManager transactionManager){
|
||||
// Step step = new StepBuilder("testStep",jobRepository)
|
||||
// .tasklet(testTasklet(),transactionManager)
|
||||
// .build();
|
||||
// return step;
|
||||
// }
|
||||
|
||||
// public Tasklet testTasklet(){
|
||||
// return ((contribution, chunkContext) -> {
|
||||
// System.out.println("***** hello batch! *****");
|
||||
// // 원하는 비지니스 로직 작성
|
||||
// return RepeatStatus.FINISHED;
|
||||
// });
|
||||
// }
|
||||
|
||||
|
||||
// @Bean
|
||||
// public JobRepository jobRepository() {
|
||||
// JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
|
||||
// factory.setDataSource(dataSource);
|
||||
// factory.setTransactionManager(transactionManager);
|
||||
// try {
|
||||
// return factory.getObject();
|
||||
// } catch (Exception e) {
|
||||
// // TODO Auto-generated catch block
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// @Bean
|
||||
// public JobLauncher jobLauncher() {
|
||||
// TaskExecutorJobLauncher jobLauncher = new TaskExecutorJobLauncher();
|
||||
// jobLauncher.setJobRepository(jobRepository());
|
||||
// jobLauncher.setTaskExecutor(new SyncTaskExecutor()); // Optional: You can use a different TaskExecutor
|
||||
// return jobLauncher;
|
||||
// }
|
||||
|
||||
// @Bean
|
||||
// public JobLauncher jobLauncher() {
|
||||
// JobLauncherFactoryBean factory = new JobLauncherFactoryBean();
|
||||
// factory.setJobRepository(jobRepository());
|
||||
// return factory.getObject();
|
||||
// }
|
||||
|
||||
// tag::readerwriterprocessor[]
|
||||
// @Bean
|
||||
// public FlatFileItemReader<Person> reader() {
|
||||
// return new FlatFileItemReaderBuilder<Person>()
|
||||
// .name("personItemReader")
|
||||
// .resource(new ClassPathResource("sample-data.csv"))
|
||||
// .delimited()
|
||||
// .names("firstName", "lastName")
|
||||
// .targetType(Person.class)
|
||||
// .build();
|
||||
// }
|
||||
|
||||
// @Bean
|
||||
// public PersonItemProcessor processor() {
|
||||
// return new PersonItemProcessor();
|
||||
// }
|
||||
|
||||
// @Bean
|
||||
// public JdbcBatchItemWriter<Person> writer(DataSource dataSource) {
|
||||
// return new JdbcBatchItemWriterBuilder<Person>()
|
||||
// .sql("INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName)")
|
||||
// .dataSource(dataSource)
|
||||
// .beanMapped()
|
||||
// .build();
|
||||
// }
|
||||
// // end::readerwriterprocessor[]
|
||||
|
||||
// // tag::jobstep[]
|
||||
// @Bean
|
||||
// public Job importUserJob(JobRepository jobRepository,Step step1, JobCompletionNotificationListener listener) {
|
||||
// return new JobBuilder("importUserJob", jobRepository)
|
||||
// .listener(listener)
|
||||
// .start(step1)
|
||||
// .build();
|
||||
// }
|
||||
|
||||
// @Bean
|
||||
// public Step step1(JobRepository jobRepository, DataSourceTransactionManager transactionManager,
|
||||
// FlatFileItemReader<Person> reader, PersonItemProcessor processor, JdbcBatchItemWriter<Person> writer) {
|
||||
// return new StepBuilder("step1", jobRepository)
|
||||
// .<Person, Person> chunk(3, transactionManager)
|
||||
// .reader(reader)
|
||||
// .processor(processor)
|
||||
// .writer(writer)
|
||||
// .build();
|
||||
|
||||
// end::jobstep[]
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
import com.caliverse.admin.domain.entity.CLOTHSMALLTYPE;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import software.amazon.awssdk.auth.credentials.*;
|
||||
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
|
||||
import software.amazon.awssdk.regions.Region;
|
||||
import software.amazon.awssdk.services.cloudwatch.CloudWatchClient;
|
||||
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
||||
|
||||
@Configuration
|
||||
public class DynamoDBConfig {
|
||||
@Value("${amazon.dynamodb.endpoint}")
|
||||
private String amazonDynamoDBEndpoint;
|
||||
|
||||
@Value("${amazon.aws.accesskey}")
|
||||
private String amazonAWSAccessKey;
|
||||
|
||||
@Value("${amazon.aws.secretkey}")
|
||||
private String amazonAWSSecretKey;
|
||||
|
||||
@Value("${amazon.aws.region}")
|
||||
private String amazonAWSRegion;
|
||||
|
||||
@Bean
|
||||
public DynamoDbClient dynamoDbClient() {
|
||||
var builder = DynamoDbClient.builder()
|
||||
.region(Region.US_WEST_2)
|
||||
.credentialsProvider(awsCredentialsProvider());
|
||||
|
||||
if (amazonDynamoDBEndpoint != null && !amazonDynamoDBEndpoint.isEmpty()) {
|
||||
builder.endpointOverride(java.net.URI.create(amazonDynamoDBEndpoint));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AwsCredentialsProvider awsCredentialsProvider() {
|
||||
if (amazonAWSAccessKey == null || amazonAWSAccessKey.isEmpty() ||amazonAWSSecretKey == null || amazonAWSSecretKey.isEmpty()) {
|
||||
return StaticCredentialsProvider.create(AwsBasicCredentials.create("fakeAccesskey", "fakeSecretKey"));
|
||||
}
|
||||
return StaticCredentialsProvider.create(AwsBasicCredentials.create(amazonAWSAccessKey, amazonAWSSecretKey));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CloudWatchClient cloudWatchClient() {
|
||||
return CloudWatchClient.builder()
|
||||
.region(Region.US_WEST_2)
|
||||
.credentialsProvider(awsCredentialsProvider())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DynamoDbEnhancedClient dynamoDbEnhancedClient(DynamoDbClient dynamoDbClient) {
|
||||
return DynamoDbEnhancedClient.builder()
|
||||
.dynamoDbClient(dynamoDbClient)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||
|
||||
@Component
|
||||
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||
private final HandlerExceptionResolver resolver;
|
||||
|
||||
public JwtAuthenticationEntryPoint(@Qualifier("handlerExceptionResolver") HandlerExceptionResolver resolver) {
|
||||
this.resolver = resolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) {
|
||||
|
||||
resolver.resolveException(request, response, null, authException);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import com.caliverse.admin.domain.dao.admin.TokenMapper;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
private final JwtService jwtService;
|
||||
private final UserDetailsService userDetailsService;
|
||||
private final TokenMapper tokenMapper;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(
|
||||
@NonNull HttpServletRequest request,
|
||||
@NonNull HttpServletResponse response,
|
||||
@NonNull FilterChain filterChain
|
||||
) throws ServletException, IOException {
|
||||
|
||||
if (request.getServletPath().contains("/api/v1/auth") || request.getServletPath().contains("/api-docs") || request.getServletPath().contains("/swagger-ui") || request.getServletPath().equals("/favicon.ico")) {
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
final String authHeader = request.getHeader("Authorization");
|
||||
if (authHeader == null ||!authHeader.startsWith("Bearer ")) {
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
final String jwt = authHeader.substring(7);
|
||||
String userEmail = null;
|
||||
|
||||
try{
|
||||
userEmail = jwtService.extractUseremail(jwt);
|
||||
} catch (Exception e){
|
||||
request.setAttribute("exception", e);
|
||||
}
|
||||
|
||||
|
||||
if (userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||
UserDetails userDetails = this.userDetailsService.loadUserByUsername(userEmail);
|
||||
var isTokenValid = tokenMapper.findByToken(jwt)
|
||||
.map(t -> !t.isExpired() && !t.isRevoked())
|
||||
.orElse(false);
|
||||
if (jwtService.isTokenValid(jwt, userDetails) && isTokenValid) {
|
||||
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
|
||||
userDetails,
|
||||
null,
|
||||
userDetails.getAuthorities()
|
||||
);
|
||||
authToken.setDetails(
|
||||
new WebAuthenticationDetailsSource().buildDetails(request)
|
||||
);
|
||||
SecurityContextHolder.getContext().setAuthentication(authToken);
|
||||
}
|
||||
}
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
import com.caliverse.admin.global.common.code.ErrorCode;
|
||||
import com.caliverse.admin.global.common.exception.RestApiException;
|
||||
import io.jsonwebtoken.*;
|
||||
import io.jsonwebtoken.io.Decoders;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import io.jsonwebtoken.security.SignatureException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.security.Key;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Service
|
||||
public class JwtService {
|
||||
|
||||
@Value("${spring.jwt.secret_key}")
|
||||
private String secretKey;
|
||||
@Value("${spring.jwt.expiration}")
|
||||
private long jwtExpiration;
|
||||
@Value("${spring.jwt.refresh-token.expiration}")
|
||||
private long refreshExpiration;
|
||||
|
||||
|
||||
|
||||
public String extractUseremail(String token) {
|
||||
return extractClaim(token, Claims::getSubject);
|
||||
}
|
||||
|
||||
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver){
|
||||
final Claims claims = extractAllClaims(token);
|
||||
return claimsResolver.apply(claims);
|
||||
}
|
||||
|
||||
public String generateToken(UserDetails userDetails){
|
||||
return generateToken(new HashMap<>(), userDetails);
|
||||
}
|
||||
|
||||
public String generateToken(
|
||||
Map<String, Object> extraClaims,
|
||||
UserDetails userDetails
|
||||
){
|
||||
return buildToken(extraClaims, userDetails, jwtExpiration);
|
||||
}
|
||||
|
||||
public String generateRefreshToken(
|
||||
UserDetails userDetails
|
||||
){
|
||||
return buildToken(new HashMap<>(), userDetails, refreshExpiration);
|
||||
}
|
||||
|
||||
private String buildToken(
|
||||
Map<String, Object> extraClaims,
|
||||
UserDetails userDetails,
|
||||
long expiration
|
||||
){
|
||||
return Jwts
|
||||
.builder()
|
||||
.setClaims(extraClaims)
|
||||
.setSubject(userDetails.getUsername())
|
||||
.setIssuedAt(new Date(System.currentTimeMillis()))
|
||||
.setExpiration(new Date(System.currentTimeMillis() + expiration))
|
||||
.signWith(getSignInKey(), SignatureAlgorithm.HS256)
|
||||
.compact();
|
||||
}
|
||||
|
||||
public Boolean isTokenValid(String token, UserDetails userDetails){
|
||||
final String username = extractUseremail(token);
|
||||
return (username.equals(userDetails.getUsername())) && !isTokenExpired(token);
|
||||
}
|
||||
|
||||
public Boolean isTokenExpired(String token){
|
||||
return extractExpiration(token).before(new Date());
|
||||
}
|
||||
|
||||
private Date extractExpiration(String token) {
|
||||
return extractClaim(token, Claims::getExpiration);
|
||||
}
|
||||
|
||||
private Claims extractAllClaims(String token){
|
||||
try{
|
||||
return Jwts
|
||||
.parserBuilder()
|
||||
.setSigningKey(getSignInKey())
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
}catch (SecurityException | MalformedJwtException e){
|
||||
throw new RestApiException(-1 , ErrorCode.WRONG_TYPE_TOKEN.getMessage());
|
||||
} catch (ExpiredJwtException e) {
|
||||
throw new RestApiException(-1 , ErrorCode.EXPIRED_TOKEN.getMessage());
|
||||
} catch (UnsupportedJwtException e) {
|
||||
throw new RestApiException(-1 , ErrorCode.UNSUPPORTED_TOKEN.getMessage());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RestApiException(-1 , ErrorCode.WRONG_TOKEN.getMessage());
|
||||
} catch (SignatureException e){
|
||||
throw new RestApiException(-1 , ErrorCode.SIGNATURE_ERROR.getMessage());
|
||||
} catch (Exception e){
|
||||
throw new RestApiException(-1 , ErrorCode.AUTHENTICATION_FAILED.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Key getSignInKey() {
|
||||
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
|
||||
return Keys.hmacShaKeyFor(keyBytes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
|
||||
import com.caliverse.admin.history.repository.MongoAdminRepository;
|
||||
import com.mongodb.client.MongoClient;
|
||||
import com.mongodb.client.MongoClients;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mongodb.MongoDatabaseFactory;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
|
||||
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableMongoRepositories(basePackages = "com.caliverse.admin.history.repository", mongoTemplateRef = "mongoAdminTemplate")
|
||||
public class MongoAdminConfig {
|
||||
|
||||
@Value("${mongodb.host}")
|
||||
String businessLogHost;
|
||||
@Value("${mongodb.admin.username}")
|
||||
String username;
|
||||
@Value("${mongodb.admin.password}")
|
||||
String password;
|
||||
@Value("${mongodb.admin.db}")
|
||||
String db;
|
||||
|
||||
@Bean(name = "mongoAdminClient")
|
||||
public MongoClient mongoStatClient() {
|
||||
String encodePassword = URLEncoder.encode(password, StandardCharsets.UTF_8);
|
||||
String auth = username.isEmpty() ? "" : String.format("%s:%s@",username, encodePassword);
|
||||
String connection = String.format("mongodb://%s%s/?authSource=%s", auth, businessLogHost, db);
|
||||
return MongoClients.create(connection);
|
||||
}
|
||||
|
||||
@Bean(name = "mongoAdminFactory")
|
||||
public MongoDatabaseFactory mongoIndicatorFactory(@Qualifier("mongoAdminClient") MongoClient mongoIndicatorClient) {
|
||||
return new SimpleMongoClientDatabaseFactory(mongoIndicatorClient, db);
|
||||
}
|
||||
|
||||
@Bean(name = "mongoAdminTemplate")
|
||||
public MongoTemplate mongoIndicatorTemplate(@Qualifier("mongoAdminFactory") MongoDatabaseFactory mongoIndicatorFactory) {
|
||||
return new MongoTemplate(mongoIndicatorFactory);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mongodb.MongoDatabaseFactory;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
|
||||
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
|
||||
|
||||
import com.caliverse.admin.logs.logrepository.mongobusinesslogrepository.MongoBusinessLogRepository;
|
||||
import com.mongodb.client.MongoClient;
|
||||
import com.mongodb.client.MongoClients;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableMongoRepositories(basePackageClasses = MongoBusinessLogRepository.class, mongoTemplateRef = "mongoBusinessLogTemplate")
|
||||
public class MongoBusinessLogConfig {
|
||||
|
||||
@Value("${mongodb.host}")
|
||||
String businessLogHost;
|
||||
@Value("${mongodb.business-log.username}")
|
||||
String username;
|
||||
@Value("${mongodb.business-log.password}")
|
||||
String password;
|
||||
@Value("${mongodb.business-log.db}")
|
||||
String businessLogdb;
|
||||
|
||||
|
||||
@Bean(name = "mongoBusinessLogClient")
|
||||
public MongoClient mongoBusinessLogClient() {
|
||||
String encodePassword = URLEncoder.encode(password, StandardCharsets.UTF_8);
|
||||
String auth = username.isEmpty() ? "" : String.format("%s:%s@",username, encodePassword);
|
||||
String connection = String.format("mongodb://%s%s/?authSource=%s", auth, businessLogHost, businessLogdb);
|
||||
return MongoClients.create(connection);
|
||||
}
|
||||
|
||||
@Bean(name = "mongoBusinessLogFactory")
|
||||
public MongoDatabaseFactory mongoBusinessLogFactory(@Qualifier("mongoBusinessLogClient") MongoClient mongoClient) {
|
||||
return new SimpleMongoClientDatabaseFactory(mongoClient, businessLogdb);
|
||||
}
|
||||
|
||||
@Bean(name = "mongoBusinessLogTemplate")
|
||||
public MongoTemplate mongoBusinessLogTemplate(@Qualifier("mongoBusinessLogFactory") MongoDatabaseFactory mongoFactory) {
|
||||
return new MongoTemplate(mongoFactory);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
|
||||
import com.caliverse.admin.Indicators.indicatorrepository.MongoIndicatorRepository;
|
||||
import com.mongodb.client.MongoClient;
|
||||
import com.mongodb.client.MongoClients;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mongodb.MongoDatabaseFactory;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
|
||||
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableMongoRepositories(basePackageClasses = MongoIndicatorRepository.class, mongoTemplateRef = "mongoIndicatorTemplate")
|
||||
public class MongoIndicatorConfig {
|
||||
|
||||
// @Value("${mongodb.indicator.uri}")
|
||||
// String uri;
|
||||
@Value("${mongodb.host}")
|
||||
String businessLogHost;
|
||||
@Value("${mongodb.indicator.username}")
|
||||
String username;
|
||||
@Value("${mongodb.indicator.password}")
|
||||
String password;
|
||||
@Value("${mongodb.indicator.db}")
|
||||
String db;
|
||||
|
||||
@Bean(name = "mongoIndicatorClient")
|
||||
public MongoClient mongoStatClient() {
|
||||
String encodePassword = URLEncoder.encode(password, StandardCharsets.UTF_8);
|
||||
String auth = username.isEmpty() ? "" : String.format("%s:%s@",username, encodePassword);
|
||||
String connection = String.format("mongodb://%s%s/?authSource=%s", auth, businessLogHost, db);
|
||||
return MongoClients.create(connection);
|
||||
}
|
||||
|
||||
@Bean(name = "mongoIndicatorFactory")
|
||||
public MongoDatabaseFactory mongoIndicatorFactory(@Qualifier("mongoIndicatorClient") MongoClient mongoIndicatorClient) {
|
||||
return new SimpleMongoClientDatabaseFactory(mongoIndicatorClient, db);
|
||||
}
|
||||
|
||||
@Bean(name = "mongoIndicatorTemplate")
|
||||
public MongoTemplate mongoIndicatorTemplate(@Qualifier("mongoIndicatorFactory") MongoDatabaseFactory mongoIndicatorFactory) {
|
||||
return new MongoTemplate(mongoIndicatorFactory);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||
import org.mybatis.spring.SqlSessionTemplate;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@Configuration
|
||||
@MapperScan(value = "com.caliverse.admin.domain.dao.admin", sqlSessionFactoryRef = "SqlSessionFactory")
|
||||
@EnableTransactionManagement
|
||||
public class MybatisConfig {
|
||||
@Value("${spring.mybatis.mapper-locations}")
|
||||
String mPath;
|
||||
|
||||
@Bean(name = "dataSource")
|
||||
@ConfigurationProperties(prefix = "spring.datasource")
|
||||
public DataSource DataSource() {
|
||||
return DataSourceBuilder.create().build();
|
||||
}
|
||||
|
||||
|
||||
@Bean(name = "SqlSessionFactory")
|
||||
public SqlSessionFactory SqlSessionFactory(@Qualifier("dataSource") DataSource DataSource, ApplicationContext applicationContext) throws Exception {
|
||||
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
|
||||
sqlSessionFactoryBean.setDataSource(DataSource);
|
||||
sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources(mPath));
|
||||
return sqlSessionFactoryBean.getObject();
|
||||
}
|
||||
|
||||
@Bean(name = "SessionTemplate")
|
||||
public SqlSessionTemplate SqlSessionTemplate(@Qualifier("SqlSessionFactory") SqlSessionFactory firstSqlSessionFactory) {
|
||||
return new SqlSessionTemplate(firstSqlSessionFactory);
|
||||
}
|
||||
|
||||
@Bean(name = "transactionManager")
|
||||
public DataSourceTransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource) {
|
||||
return new DataSourceTransactionManager(dataSource);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
@Configuration
|
||||
public class ObjectMapperConfig {
|
||||
@Bean
|
||||
public ObjectMapper objectMapper() {
|
||||
return new ObjectMapper()
|
||||
.registerModule(new JavaTimeModule())
|
||||
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
|
||||
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
|
||||
.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
import com.rabbitmq.client.Connection;
|
||||
import com.rabbitmq.client.ConnectionFactory;
|
||||
import com.rabbitmq.client.SslContextFactory;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.io.IOException;
|
||||
import java.security.*;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class RabbitMqConfig
|
||||
{
|
||||
@Value("${rabbitmq.url}")
|
||||
String m_rabbitmq_host;
|
||||
@Value("${rabbitmq.port}")
|
||||
int m_rabbitmq_port;
|
||||
@Value("${rabbitmq.username}")
|
||||
String m_rabbitmq_username;
|
||||
@Value("${rabbitmq.password}")
|
||||
String m_rabbitmq_password;
|
||||
@Value("${rabbitmq.ssl}")
|
||||
boolean m_rabbitmq_ssl;
|
||||
|
||||
@Bean
|
||||
public Connection rabbitMqClient() throws IOException, TimeoutException, NoSuchAlgorithmException, KeyManagementException {
|
||||
var factory = new ConnectionFactory();
|
||||
setConnectionInfo(factory);
|
||||
|
||||
if(m_rabbitmq_ssl)
|
||||
{
|
||||
// SSLContext 초기화
|
||||
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
|
||||
// 기본 TrustManager 로드
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
try{
|
||||
tmf.init((KeyStore) null); // 기본 Trust Store로 초기화
|
||||
}
|
||||
catch(KeyStoreException e){
|
||||
log.error(e.getMessage());
|
||||
return null;
|
||||
}
|
||||
// SSLContext를 기본 TrustManager와 SecureRandom으로 초기화
|
||||
sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());
|
||||
// SSLContext를 사용하도록 ConnectionFactory 설정
|
||||
factory.useSslProtocol(sslContext);
|
||||
}
|
||||
|
||||
return factory.newConnection();
|
||||
}
|
||||
|
||||
private void setConnectionInfo(ConnectionFactory factory){
|
||||
factory.setHost(m_rabbitmq_host);
|
||||
factory.setPort(m_rabbitmq_port);
|
||||
factory.setUsername(m_rabbitmq_username);
|
||||
factory.setPassword(m_rabbitmq_password);
|
||||
factory.setAutomaticRecoveryEnabled(true);
|
||||
factory.setRequestedHeartbeat(60);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||
import org.springframework.data.redis.connection.RedisClusterConfiguration;
|
||||
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
|
||||
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class RedisConfig {
|
||||
|
||||
@Value("${redis.host}")
|
||||
private String host;
|
||||
|
||||
@Value("${redis.port}")
|
||||
private int port;
|
||||
|
||||
@Value("${redis.password}")
|
||||
private String password;
|
||||
|
||||
@Value("${redis.async-timeout}")
|
||||
private int asyncTimeout;
|
||||
|
||||
@Value("${redis.sync-timeout}")
|
||||
private int syncTimeout;
|
||||
|
||||
@Value("${redis.ssl}")
|
||||
private boolean ssl;
|
||||
|
||||
@Value("${redis.abort-connect}")
|
||||
private boolean abortConnect;
|
||||
|
||||
@Value("${spring.profiles.active}")
|
||||
private String activeProfile;
|
||||
|
||||
@Bean
|
||||
public JedisConnectionFactory jedisConnectionFactory() {
|
||||
// String activeProfile = System.getProperty("active.profile", "local");
|
||||
log.info("RedisConfig Active profile: {}", activeProfile);
|
||||
|
||||
if(activeProfile.equals("local") || activeProfile.equals("dev")){
|
||||
log.info("RedisConfig local config Set");
|
||||
/// Redis Standalone 설정
|
||||
RedisStandaloneConfiguration standaloneConfig = new RedisStandaloneConfiguration();
|
||||
standaloneConfig.setHostName(host);
|
||||
standaloneConfig.setPort(port);
|
||||
if (password != null && !password.isEmpty()) {
|
||||
standaloneConfig.setPassword(password);
|
||||
}
|
||||
|
||||
JedisClientConfiguration.JedisClientConfigurationBuilder jedisClientConfig = JedisClientConfiguration.builder();
|
||||
jedisClientConfig.connectTimeout(java.time.Duration.ofMillis(asyncTimeout)); // AsyncTimeout
|
||||
jedisClientConfig.readTimeout(java.time.Duration.ofMillis(syncTimeout)); // SyncTimeout
|
||||
if (ssl) {
|
||||
jedisClientConfig.useSsl();
|
||||
}
|
||||
//if (!abortConnect) { jedisClientConfig.blockOnReconnect(false);}
|
||||
|
||||
return new JedisConnectionFactory(standaloneConfig, jedisClientConfig.build());
|
||||
}
|
||||
|
||||
log.info("RedisConfig deploy config Set");
|
||||
//cluster로 변경 수정
|
||||
JedisPoolConfig poolConfig = new JedisPoolConfig();
|
||||
poolConfig.setMaxTotal(128); // 연결 풀 설정
|
||||
|
||||
// Redis 클러스터 진입점 노드만 지정
|
||||
RedisClusterConfiguration clusterConfig = new RedisClusterConfiguration();
|
||||
clusterConfig.clusterNode(host, port);
|
||||
clusterConfig.setPassword(password); // 패스워드 설정
|
||||
clusterConfig.setMaxRedirects(5);
|
||||
var builder = JedisClientConfiguration.builder();
|
||||
builder.usePooling().poolConfig(poolConfig);
|
||||
if(ssl){
|
||||
builder.useSsl();
|
||||
}
|
||||
JedisClientConfiguration clientConfig = builder.build();
|
||||
|
||||
JedisConnectionFactory factory = new JedisConnectionFactory(clusterConfig, clientConfig);
|
||||
|
||||
factory.afterPropertiesSet();
|
||||
|
||||
try {
|
||||
factory.getConnection().ping(); // Redis 서버에 Ping 명령어를 전송해 응답을 확인
|
||||
log.info("Successfully connected to Redis server: {}", factory.getHostName());
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to connect to Redis server: {}", e.getMessage());
|
||||
}
|
||||
|
||||
return factory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RedisTemplate<String, Object> redisTemplate() {
|
||||
RedisTemplate<String, Object> template = new RedisTemplate<>();
|
||||
template.setConnectionFactory(jedisConnectionFactory());
|
||||
template.setKeySerializer(new StringRedisSerializer());
|
||||
template.setValueSerializer(new StringRedisSerializer());
|
||||
template.setHashKeySerializer(new StringRedisSerializer());
|
||||
template.setHashValueSerializer(new StringRedisSerializer());
|
||||
|
||||
try {
|
||||
template.getConnectionFactory().getConnection().ping();
|
||||
log.info("redisTemplate Successfully connected to Redis server");
|
||||
} catch (Exception e) {
|
||||
log.error("redisTemplate Failed to connect to Redis server: {}", e.getMessage());
|
||||
}
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RedisCacheManager cacheManager(JedisConnectionFactory jedisConnectionFactory) {
|
||||
RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig()
|
||||
.entryTtl(Duration.ofMinutes(60)) // 캐시 TTL 설정
|
||||
.disableCachingNullValues(); // null 값 캐싱 금지
|
||||
|
||||
return RedisCacheManager.builder(jedisConnectionFactory)
|
||||
.cacheDefaults(cacheConfig)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.retry.backoff.FixedBackOffPolicy;
|
||||
import org.springframework.retry.policy.SimpleRetryPolicy;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class RestConfig {
|
||||
@Value("${web3.timeout}")
|
||||
private int timeout;
|
||||
@Value("${web3.url}")
|
||||
private String url;
|
||||
@Value("${web3.delay}")
|
||||
private long delay;
|
||||
@Value("${web3.max-retry}")
|
||||
private int maxRetry;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
// Timeout 설정
|
||||
HttpComponentsClientHttpRequestFactory factory =
|
||||
new HttpComponentsClientHttpRequestFactory();
|
||||
factory.setConnectTimeout(timeout);
|
||||
factory.setConnectionRequestTimeout(timeout);
|
||||
restTemplate.setRequestFactory(factory);
|
||||
|
||||
// MessageConverter 설정
|
||||
MappingJackson2HttpMessageConverter converter =
|
||||
new MappingJackson2HttpMessageConverter(objectMapper);
|
||||
restTemplate.setMessageConverters(Collections.singletonList(converter));
|
||||
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RetryTemplate retryTemplate() {
|
||||
RetryTemplate retryTemplate = new RetryTemplate();
|
||||
|
||||
//retry 2초간격 3회
|
||||
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
|
||||
backOffPolicy.setBackOffPeriod(delay);
|
||||
|
||||
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
|
||||
retryPolicy.setMaxAttempts(maxRetry);
|
||||
|
||||
retryTemplate.setBackOffPolicy(backOffPolicy);
|
||||
retryTemplate.setRetryPolicy(retryPolicy);
|
||||
|
||||
return retryTemplate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
|
||||
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
|
||||
import software.amazon.awssdk.regions.Region;
|
||||
import software.amazon.awssdk.services.s3.S3Client;
|
||||
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class S3Config {
|
||||
@Value("${amazon.aws.accesskey}")
|
||||
private String accessKey;
|
||||
|
||||
@Value("${amazon.aws.secretkey}")
|
||||
private String secretKey;
|
||||
|
||||
@Value("${amazon.aws.region}")
|
||||
private String region;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "amazon.s3.enabled", havingValue = "true")
|
||||
public S3Client s3Client() {
|
||||
AwsBasicCredentials credentials = AwsBasicCredentials.create(accessKey, secretKey);
|
||||
return S3Client.builder()
|
||||
.credentialsProvider(StaticCredentialsProvider.create(credentials))
|
||||
.region(Region.of(region))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
import io.swagger.v3.oas.models.Components;
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class SwaggerConfig {
|
||||
|
||||
@Bean
|
||||
public OpenAPI openAPI() {
|
||||
return new OpenAPI()
|
||||
.components(new Components())
|
||||
.info(apiInfo());
|
||||
}
|
||||
|
||||
private Info apiInfo() {
|
||||
return new Info()
|
||||
.title("칼리버스 API 명세서")
|
||||
.description("칼리버스 어드민 툴 스웨거 ")
|
||||
.version("v1");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;
|
||||
import org.springframework.batch.core.job.builder.JobBuilder;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.step.builder.StepBuilder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import com.caliverse.admin.domain.batch.CustomProcessor;
|
||||
import com.caliverse.admin.domain.batch.CustomReader;
|
||||
import com.caliverse.admin.domain.batch.CustomWriter;
|
||||
|
||||
@Configuration
|
||||
//public class TestBatchConfiguration extends DefaultBatchConfiguration {
|
||||
public class TestBatchConfiguration {
|
||||
// @Autowired
|
||||
// @Qualifier("dataSource-normal")
|
||||
// private DataSource dataSource;
|
||||
//
|
||||
// @Autowired
|
||||
// @Qualifier("batchTransactionManager")
|
||||
// private PlatformTransactionManager transactionManger;
|
||||
//
|
||||
// @Override
|
||||
// public DataSource getDataSource() {
|
||||
// return dataSource;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public PlatformTransactionManager getTransactionManager() {
|
||||
// return transactionManger;
|
||||
//
|
||||
// }
|
||||
//
|
||||
//
|
||||
// @Bean
|
||||
// public Job createJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
|
||||
// return new JobBuilder("testJob", jobRepository)
|
||||
// .flow(createStep(jobRepository, transactionManager)).end().build();
|
||||
// }
|
||||
//
|
||||
// @Bean
|
||||
// Step createStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
|
||||
// return new StepBuilder("testStep", jobRepository)
|
||||
// .<String, String> chunk(3, transactionManager)
|
||||
// .allowStartIfComplete(true)
|
||||
// .reader(new CustomReader())
|
||||
// .processor(new CustomProcessor())
|
||||
// .writer(new CustomWriter())
|
||||
// .build();
|
||||
// }
|
||||
|
||||
|
||||
// @Bean
|
||||
// public org.springframework.batch.core.Job testJob(JobRepository jobRepository,PlatformTransactionManager transactionManager) throws DuplicateJobException {
|
||||
// org.springframework.batch.core.Job job = new JobBuilder("testJob",jobRepository)
|
||||
// .start(testStep(jobRepository,transactionManager))
|
||||
// .build();
|
||||
// return job;
|
||||
// }
|
||||
|
||||
// public Step testStep(JobRepository jobRepository,PlatformTransactionManager transactionManager){
|
||||
// Step step = new StepBuilder("testStep",jobRepository)
|
||||
// .tasklet(testTasklet(),transactionManager)
|
||||
// .build();
|
||||
// return step;
|
||||
// }
|
||||
|
||||
// public Tasklet testTasklet(){
|
||||
// return ((contribution, chunkContext) -> {
|
||||
// System.out.println("***** hello batch! *****");
|
||||
// // 원하는 비지니스 로직 작성
|
||||
// return RepeatStatus.FINISHED;
|
||||
// });
|
||||
// }
|
||||
|
||||
|
||||
// @Bean
|
||||
// public JobRepository jobRepository() {
|
||||
// JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
|
||||
// factory.setDataSource(dataSource);
|
||||
// factory.setTransactionManager(transactionManager);
|
||||
// try {
|
||||
// return factory.getObject();
|
||||
// } catch (Exception e) {
|
||||
// // TODO Auto-generated catch block
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// @Bean
|
||||
// public JobLauncher jobLauncher() {
|
||||
// TaskExecutorJobLauncher jobLauncher = new TaskExecutorJobLauncher();
|
||||
// jobLauncher.setJobRepository(jobRepository());
|
||||
// jobLauncher.setTaskExecutor(new SyncTaskExecutor()); // Optional: You can use a different TaskExecutor
|
||||
// return jobLauncher;
|
||||
// }
|
||||
|
||||
// @Bean
|
||||
// public JobLauncher jobLauncher() {
|
||||
// JobLauncherFactoryBean factory = new JobLauncherFactoryBean();
|
||||
// factory.setJobRepository(jobRepository());
|
||||
// return factory.getObject();
|
||||
// }
|
||||
|
||||
// tag::readerwriterprocessor[]
|
||||
// @Bean
|
||||
// public FlatFileItemReader<Person> reader() {
|
||||
// return new FlatFileItemReaderBuilder<Person>()
|
||||
// .name("personItemReader")
|
||||
// .resource(new ClassPathResource("sample-data.csv"))
|
||||
// .delimited()
|
||||
// .names("firstName", "lastName")
|
||||
// .targetType(Person.class)
|
||||
// .build();
|
||||
// }
|
||||
|
||||
// @Bean
|
||||
// public PersonItemProcessor processor() {
|
||||
// return new PersonItemProcessor();
|
||||
// }
|
||||
|
||||
// @Bean
|
||||
// public JdbcBatchItemWriter<Person> writer(DataSource dataSource) {
|
||||
// return new JdbcBatchItemWriterBuilder<Person>()
|
||||
// .sql("INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName)")
|
||||
// .dataSource(dataSource)
|
||||
// .beanMapped()
|
||||
// .build();
|
||||
// }
|
||||
// // end::readerwriterprocessor[]
|
||||
|
||||
// // tag::jobstep[]
|
||||
// @Bean
|
||||
// public Job importUserJob(JobRepository jobRepository,Step step1, JobCompletionNotificationListener listener) {
|
||||
// return new JobBuilder("importUserJob", jobRepository)
|
||||
// .listener(listener)
|
||||
// .start(step1)
|
||||
// .build();
|
||||
// }
|
||||
|
||||
// @Bean
|
||||
// public Step step1(JobRepository jobRepository, DataSourceTransactionManager transactionManager,
|
||||
// FlatFileItemReader<Person> reader, PersonItemProcessor processor, JdbcBatchItemWriter<Person> writer) {
|
||||
// return new StepBuilder("step1", jobRepository)
|
||||
// .<Person, Person> chunk(3, transactionManager)
|
||||
// .reader(reader)
|
||||
// .processor(processor)
|
||||
// .writer(writer)
|
||||
// .build();
|
||||
|
||||
// end::jobstep[]
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.caliverse.admin.global.configuration;
|
||||
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||
import org.mybatis.spring.SqlSessionTemplate;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@Configuration
|
||||
@MapperScan(value = "com.caliverse.admin.domain.dao.total", sqlSessionFactoryRef = "TotalSqlSessionFactory")
|
||||
@EnableTransactionManagement
|
||||
public class TotalMybatisConfig{
|
||||
@Value("${spring.mybatis.mapper-locations}")
|
||||
String mPath;
|
||||
|
||||
@Bean(name = "totalDataSource")
|
||||
@ConfigurationProperties(prefix = "spring.total-datasource")
|
||||
public DataSource DataSource() {
|
||||
return DataSourceBuilder.create().build();
|
||||
}
|
||||
|
||||
@Bean(name = "TotalSqlSessionFactory")
|
||||
public SqlSessionFactory TotalSqlSessionFactory(@Qualifier("totalDataSource") DataSource DataSource, ApplicationContext applicationContext) throws Exception {
|
||||
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
|
||||
sqlSessionFactoryBean.setDataSource(DataSource);
|
||||
sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources(mPath));
|
||||
return sqlSessionFactoryBean.getObject();
|
||||
}
|
||||
|
||||
@Bean(name = "TotalSessionTemplate")
|
||||
public SqlSessionTemplate SqlSessionTemplate(@Qualifier("TotalSqlSessionFactory") SqlSessionFactory firstSqlSessionFactory) {
|
||||
return new SqlSessionTemplate(firstSqlSessionFactory);
|
||||
}
|
||||
|
||||
@Bean(name = "totalTransactionManager")
|
||||
public DataSourceTransactionManager totalTransactionManager(@Qualifier("totalDataSource") DataSource dataSource) {
|
||||
return new DataSourceTransactionManager(dataSource);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user