dynamodb 페이징 처리

This commit is contained in:
2025-04-02 19:01:28 +09:00
parent c764dcbaf1
commit 4b61af8909
15 changed files with 264 additions and 7 deletions

View File

@@ -31,6 +31,8 @@ public class UsersResponse {
private String message;
@JsonProperty("user_session")
private boolean userSession;
@JsonProperty("user_info")
private UserInfo userInfo;
@JsonProperty("char_info")

View File

@@ -4,16 +4,23 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import com.caliverse.admin.domain.entity.FriendRequest;
import com.caliverse.admin.domain.entity.HISTORYTYPE;
import com.caliverse.admin.domain.request.MailRequest;
import com.caliverse.admin.dynamodb.domain.atrrib.MailAttrib;
import com.caliverse.admin.dynamodb.domain.doc.MailDoc;
import com.caliverse.admin.dynamodb.dto.PageResult;
import com.caliverse.admin.dynamodb.service.DynamodbService;
import com.caliverse.admin.redis.service.RedisUserInfoService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import com.caliverse.admin.domain.datacomponent.MetaDataHandler;
@@ -34,6 +41,7 @@ public class UsersService {
private static final Logger logger = LoggerFactory.getLogger(UsersService.class);
private final DynamoDBService dynamoDBService;
private final DynamodbService dynamodbService;
private final HistoryService historyService;
private final UserGameSessionService userGameSessionService;
private final RedisUserInfoService redisUserInfoService;
@@ -41,6 +49,9 @@ public class UsersService {
//metadataHandler 어떻게 가져와야 되는가
@Autowired
private MetaDataHandler metaDataHandler;
@Qualifier("objectMapper")
@Autowired
private ObjectMapper objectMapper;
// 닉네임 변경
public UsersResponse changeNickname(UsersRequest usersRequest){
@@ -279,12 +290,52 @@ public class UsersService {
}
public UsersResponse getMail(String guid, String type){
// List<UsersResponse.Mail> mailList = dynamoDBService.getMail(guid, type);
PageResult<MailDoc> mailPageResult = dynamodbService.getMail(type, guid, "", "", "", null, false);
List<UsersResponse.Mail> mailList = new ArrayList<>();
List<UsersResponse.Mail> mailList = dynamoDBService.getMail(guid, type);;
mailPageResult.getItems().forEach(doc -> {
try {
MailAttrib attrib = objectMapper.readValue(doc.getAttribValue(), MailAttrib.class);
List<UsersResponse.MailItem> itemList = new ArrayList<>();
attrib.getItemList().forEach(item -> {
UsersResponse.MailItem mailItem = new UsersResponse.MailItem();
mailItem.setItemId(CommonUtils.objectToString(item.getItemId()));
mailItem.setCount(item.getCount());
String item_nm = metaDataHandler.getMetaItemNameData(item.getItemId());
mailItem.setItemName(metaDataHandler.getTextStringData(item_nm));
itemList.add(mailItem);
});
UsersResponse.Mail mail = UsersResponse.Mail.builder()
.mailGuid(attrib.getMailGuid())
.title(attrib.getTitle())
.content(attrib.getText())
.senderNickname(attrib.getSenderNickName())
.receiveNickname(attrib.getReceiverNickName())
.status(attrib.isRead())
.isSystemMail(attrib.isSystemMail())
.isGetItem(attrib.isGetItem())
.createDt(attrib.getCreateTime())
.mailItemList(itemList)
.build();
mailList.add(mail);
} catch (Exception e) {
log.error(e.getMessage());
return;
}
});
return UsersResponse.builder()
.resultData(
UsersResponse.ResultData.builder()
.mailList(mailList)
.pageKey(mailPageResult.getLastEvaluatedKey().entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue().s()
))
)
.build()
)
.status(CommonCode.SUCCESS.getHttpStatus())

View File

@@ -1,5 +1,6 @@
package com.caliverse.admin.dynamodb.domain.atrrib;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
@@ -11,6 +12,7 @@ import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
@Data
@NoArgsConstructor
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
@JsonIgnoreProperties(ignoreUnknown = true)
public abstract class DynamoDBAttribBase {
//객체일때는 사용안하고 Json으로 Attrib이 생성될때만 사용(상속 안받는걸로)
@JsonProperty("attrib_type")

View File

@@ -0,0 +1,28 @@
package com.caliverse.admin.dynamodb.dto;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import java.util.List;
import java.util.Map;
public class PageResult<T> {
private final List<T> items;
private final Map<String, AttributeValue> lastEvaluatedKey;
public PageResult(List<T> items, Map<String, AttributeValue> lastEvaluatedKey) {
this.items = items;
this.lastEvaluatedKey = lastEvaluatedKey;
}
public List<T> getItems() {
return items;
}
public Map<String, AttributeValue> getLastEvaluatedKey() {
return lastEvaluatedKey;
}
public boolean hasMorePages() {
return lastEvaluatedKey != null && !lastEvaluatedKey.isEmpty();
}
}

View File

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

View File

@@ -1,5 +1,6 @@
package com.caliverse.admin.dynamodb.repository;
import com.caliverse.admin.dynamodb.dto.PageResult;
import com.caliverse.admin.dynamodb.service.DynamoDBOperations;
import com.caliverse.admin.global.common.code.CommonCode;
import com.caliverse.admin.global.common.code.ErrorCode;
@@ -10,8 +11,10 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import software.amazon.awssdk.enhanced.dynamodb.Expression;
import software.amazon.awssdk.enhanced.dynamodb.Key;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import java.util.List;
import java.util.Map;
@RequiredArgsConstructor
public abstract class BaseDynamoDBRepository<T> implements DynamoDBRepository<T> {
@@ -87,4 +90,25 @@ public abstract class BaseDynamoDBRepository<T> implements DynamoDBRepository<T>
return operations.getItemsByPrefix(partitionKey, sortKeyPrefix, entityClass);
}
}
@Override
public PageResult<T> findByPaging(
String partitionKey,
String sortKeyPrefix,
String filterAttributeName,
String filterAttributeValue,
Map<String, AttributeValue> exclusiveStartKey,
boolean scanIndexForward
) {
return operations.queryItemsPaging(
partitionKey,
sortKeyPrefix,
filterAttributeName,
filterAttributeValue,
exclusiveStartKey,
scanIndexForward,
entityClass
);
}
}

View File

@@ -1,9 +1,12 @@
package com.caliverse.admin.dynamodb.repository;
import com.caliverse.admin.dynamodb.dto.PageResult;
import software.amazon.awssdk.enhanced.dynamodb.Expression;
import software.amazon.awssdk.enhanced.dynamodb.Key;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import java.util.List;
import java.util.Map;
public interface DynamoDBRepository<T> {
void save(T item);
@@ -17,4 +20,13 @@ public interface DynamoDBRepository<T> {
List<T> findAllScan(String prefix);
List<T> findAllScan(String prefix, String sortKey);
List<T> findByPrefix(String partitionKey, String sortKeyPrefix);
PageResult<T> findByPaging(
String partitionKey,
String sortKeyPrefix,
String filterAttributeName,
String filterAttributeValue,
Map<String, AttributeValue> exclusiveStartKey,
boolean scanIndexForward
);
}

View File

@@ -2,9 +2,11 @@ package com.caliverse.admin.dynamodb.repository.Impl;
import com.caliverse.admin.domain.entity.HISTORYTYPE;
import com.caliverse.admin.domain.entity.Mail;
import com.caliverse.admin.domain.entity.SEARCHTYPE;
import com.caliverse.admin.domain.entity.metadata.MetaSystemMailData;
import com.caliverse.admin.dynamodb.domain.atrrib.MailAttrib;
import com.caliverse.admin.dynamodb.domain.doc.MailDoc;
import com.caliverse.admin.dynamodb.dto.PageResult;
import com.caliverse.admin.dynamodb.entity.MailItem;
import com.caliverse.admin.dynamodb.repository.BaseDynamoDBRepository;
import com.caliverse.admin.dynamodb.repository.MailRepository;
@@ -19,12 +21,13 @@ import com.caliverse.admin.history.service.DynamodbHistoryLogService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import static com.caliverse.admin.global.common.utils.CommonUtils.convertUTCDate;
import static com.caliverse.admin.global.common.utils.DynamodbUtil.createMailItems;
@Component
@Slf4j
@@ -94,4 +97,47 @@ public class MailRepositoryImpl extends BaseDynamoDBRepository<MailDoc> implemen
public void insertSentMail(Mail mail) {
}
@Override
public List<MailDoc> getMailList(String type, String userGuid, String sortKeyPrefix) {
String pk;
if(type.equals(SEARCHTYPE.SEND.name())){
pk = DynamoDBConstants.PK_KEY_RECV_MAIL + userGuid;
}else{
pk = DynamoDBConstants.PK_KEY_SENT_MAIL + userGuid;
}
List<MailDoc> mailList = findByPrefix(pk, sortKeyPrefix);
return mailList;
}
@Override
public PageResult<MailDoc> getMailListWithPaging(
String type,
String userGuid,
String sortKeyPrefix,
String filterAttributeName,
String filterAttributeValue,
Map<String, AttributeValue> exclusiveStartKey,
boolean sortIndex
) {
String pk;
if(type.equals(SEARCHTYPE.SEND.name())){
pk = DynamoDBConstants.PK_KEY_SENT_MAIL + userGuid;
} else {
pk = DynamoDBConstants.PK_KEY_RECV_MAIL + userGuid;
}
return findByPaging(
pk,
sortKeyPrefix,
filterAttributeName,
filterAttributeValue,
exclusiveStartKey,
sortIndex
);
}
}

View File

@@ -4,11 +4,24 @@ import com.caliverse.admin.domain.entity.Mail;
import com.caliverse.admin.domain.entity.metadata.MetaSystemMailData;
import com.caliverse.admin.domain.request.MailRequest;
import com.caliverse.admin.dynamodb.domain.doc.MailDoc;
import com.caliverse.admin.dynamodb.dto.PageResult;
import com.caliverse.admin.dynamodb.entity.MailItem;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import java.util.List;
import java.util.Map;
public interface MailRepository extends DynamoDBRepository<MailDoc> {
void insertRecvSystemMail(String userGuid, String nickname, List<MailItem> mailItems, MetaSystemMailData systemMailData, List<String> arguments);
void insertSentMail(Mail mail);
List<MailDoc> getMailList(String type, String userGuid, String sortKeyPrefix);
PageResult<MailDoc> getMailListWithPaging(
String type,
String userGuid,
String sortKeyPrefix,
String filterAttributeName,
String filterAttributeValue,
Map<String, AttributeValue> exclusiveStartKey,
boolean sortIndex
);
}

View File

@@ -1,5 +1,7 @@
package com.caliverse.admin.dynamodb.service;
import com.caliverse.admin.dynamodb.dto.PageResult;
import com.caliverse.admin.global.common.constants.CommonConstants;
import com.caliverse.admin.global.component.transaction.DynamoDBTransactionContext;
import com.caliverse.admin.global.common.code.CommonCode;
import com.caliverse.admin.global.common.exception.RestApiException;
@@ -17,7 +19,9 @@ import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Component
@Slf4j
@@ -265,11 +269,6 @@ public class DynamoDBOperations {
public <T> List<T> getItemsByPrefix(String partitionKey, String sortKeyPrefix, Class<T> itemClass) {
DynamoDbTable<T> table = getTable(itemClass);
QueryConditional queryConditional = QueryConditional.keyEqualTo(b -> b
.partitionValue(partitionKey)
.sortValue(sortKeyPrefix)
.build());
return table.query(r -> r
.queryConditional(QueryConditional.sortBeginsWith(b -> b
.partitionValue(partitionKey)
@@ -293,4 +292,65 @@ public class DynamoDBOperations {
.toList();
}
public <T> PageResult<T> queryItemsPaging(
String partitionKey,
String sortKeyPrefix,
String filterAttributeName,
String filterAttributeValue,
Map<String, AttributeValue> exclusiveStartKey,
boolean scanIndexForward,
Class<T> itemClass) {
int PAGE_SIZE = CommonConstants.DYNAMODB_PAGING_SIZE;
DynamoDbTable<T> table = getTable(itemClass);
QueryConditional queryConditional;
if (sortKeyPrefix != null && !sortKeyPrefix.isEmpty()) {
queryConditional = QueryConditional.sortBeginsWith(b -> b
.partitionValue(partitionKey)
.sortValue(sortKeyPrefix));
} else {
queryConditional = QueryConditional.keyEqualTo(b -> b
.partitionValue(partitionKey));
}
// 필터
Expression filterExpression = null;
if (!filterAttributeName.isEmpty() && !filterAttributeValue.isEmpty()) {
filterExpression = Expression.builder()
.expression("begins_with(#filterAttr, :filterValue)")
.putExpressionName("#filterAttr", filterAttributeName)
.putExpressionValue(":filterValue", AttributeValue.builder().s(filterAttributeValue).build())
.build();
}
QueryEnhancedRequest.Builder requestBuilder = QueryEnhancedRequest.builder()
.queryConditional(queryConditional)
.scanIndexForward(scanIndexForward)
.limit(PAGE_SIZE);
if (filterExpression != null) {
requestBuilder.filterExpression(filterExpression);
}
// 마지막 키 설정 (페이징 시작점)
if (exclusiveStartKey != null && !exclusiveStartKey.isEmpty()) {
requestBuilder.exclusiveStartKey(exclusiveStartKey);
}
PageIterable<T> pageIterable = table.query(requestBuilder.build());
List<T> results = new ArrayList<>();
Map<String, AttributeValue> lastEvaluatedKey = null; // 다음 페이지 토큰
// 첫 페이지만 가져옴
for (Page<T> page : pageIterable) {
results.addAll(page.items());
lastEvaluatedKey = page.lastEvaluatedKey();
break;
}
return new PageResult<>(results, lastEvaluatedKey);
}
}

View File

@@ -8,6 +8,8 @@ import com.caliverse.admin.domain.entity.metadata.MetaSystemMailData;
import com.caliverse.admin.domain.request.LandRequest;
import com.caliverse.admin.dynamodb.domain.atrrib.MoneyAttrib;
import com.caliverse.admin.dynamodb.domain.atrrib.UserNicknameRegistryAttrib;
import com.caliverse.admin.dynamodb.domain.doc.MailDoc;
import com.caliverse.admin.dynamodb.dto.PageResult;
import com.caliverse.admin.dynamodb.entity.MailItem;
import com.caliverse.admin.dynamodb.repository.MailRepository;
import com.caliverse.admin.dynamodb.repository.MoneyRepository;
@@ -25,10 +27,12 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Slf4j
@Service
@@ -91,4 +95,9 @@ public class DynamodbService {
mailRepository.insertRecvSystemMail(guid, nickname, items, systemMailData, arguments);
}
public PageResult<MailDoc> getMail(String type, String guid, String sortKey, String filterName, String filterValue, Map<String, AttributeValue> pagingKey, boolean sortIndex){
PageResult<MailDoc> mailList = mailRepository.getMailListWithPaging(type, guid, sortKey, filterName, filterValue, pagingKey, sortIndex);
return mailList;
}
}

View File

@@ -38,6 +38,8 @@ public enum ErrorCode {
NOT_FOUND_USER("ID또는 비밀번호가 일치하지 않습니다."),
DUPLICATED_GROUPNAME("동일한 관리자 그룹명이 존재합니다."),
FAIL_USER_KICK("유저 킥 실패"),
//meta data
NOT_ITEM("존재하지 않는 아이템코드입니다."),

View File

@@ -14,6 +14,7 @@ public enum SuccessCode {
EXCEL_UPLOAD("파일 업로드 하였습니다."),
REGISTRATION("등록 하였습니다."),
ITEM_EXIST("아이템이 존재합니다"),
SUCCESS("성공 하였습니다."),
//------------------------------------------------------------------------------------------------------------------------------

View File

@@ -37,6 +37,8 @@ public class AdminConstants {
public static final String MONGO_DB_KEY_ACTION = "action";
public static final String MONGO_DB_KEY_DOMAIN = "domain";
public static final String MONGO_DB_KEY_SERVER_TYPE = "serverType";
public static final String MONGO_DB_KEY_CREATE_TIME = "createdTime";
public static final String MONGO_DB_KEY_IP = "ip";
public static final String MONGO_DB_KEY_USER_GUID_LIST = "userGuidList";
public static final String MONGO_DB_KEY_USER_GUID_LIST_COUNT = "userGuidListCount";

View File

@@ -15,6 +15,7 @@ public class CommonConstants {
public static final String LAND_AUCTION = "auction";
public static final String LAND_EVENT = "event";
public static final String SYSTEM_MAIL_LAND_TRANS_KEY = "LandTrans";
public static final int DYNAMODB_PAGING_SIZE = 20;
public static final String FORMAT_DATE_ISO_DATETIME_MILLIS = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
public static final String FORMAT_DATE_ISO_DATETIME_MILLIS_NANO = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'";