This commit is contained in:
2025-02-12 18:32:21 +09:00
commit aff0f4eeda
767 changed files with 285356 additions and 0 deletions

View File

@@ -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 "";
}

View File

@@ -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();
}
}
}

View File

@@ -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");
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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";
}

View File

@@ -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";
}

View File

@@ -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";
}

View File

@@ -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";
}

View File

@@ -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";
}

View File

@@ -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";
}

View File

@@ -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()
);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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());
}
}

View File

@@ -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());
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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[]
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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"));
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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");
}
}

View File

@@ -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[]
}

View File

@@ -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);
}
}