@Transactional
public void updateCharacterList(String username) {
// 1. 회원 조회
Member member = memberDao.get(username);
// 2. 대표캐릭터 조회
String mainCharacter = member.getMainCharacterName();
// 3. 거래소, 콘텐츠 통계 데이터 조회
Map<String, Market> contentResource = marketDao.findContentResource();
List<DayContent> chaos = contentDao.findDayContent(Category.카오스던전);
List<DayContent> guardian = contentDao.findDayContent(Category.가디언토벌);
// 4. 대표캐릭터 이름으로 로스트아크 오픈 API를 통해 원정대 조회
List<CharacterJsonDto> characterJsonDtoList = lostarkCharacterDao.getCharacterJsonDtoList(mainCharacter, member.getApiKey());
for (CharacterJsonDto dto : characterJsonDtoList) {
// 4-1. 캐릭터 이미지 추가(캐릭터 조회 오픈 API)
dto.setCharacterImage(lostarkCharacterDao.getCharacterImageUrl(dto.getCharacterName(), member.getApiKey()));
// 4-2. 등록된 캐릭터와 이름같은 데이터 찾기
Optional<Character> find = member.getCharacters().stream()
.filter(character -> character.getCharacterName().equals(dto.getCharacterName())).findFirst();
// 4-3. 업데이트된 아이템 레벨을 바탕으로 일일숙제 수익 수정
DayTodo dayContent = new DayTodo().createDayContent(chaos, guardian, dto.getItemMaxLevel());
if (find.isPresent()) { // 4-4.이름 같은게 있으면 업데이트
Character character = find.get();
updateCharacter(character, dto, dayContent, contentResource);
} else { // 4-5. 이름 같은게 없으면 추가
Character character = addCharacter(dto, dayContent, member);
calculateDayTodo(character, contentResource);
member.getCharacters().add(character);
}
}
}
문제
메인캐릭터 닉네임이 변경된다면 '4. 대표캐릭터 이름으로 로스트아크 오픈 API를 통해 원정대 조회' 가 정상적으로 처리되지 않음
그외 다른 캐릭터의 닉네임이 변경된다면 새롭게 데이터가 추가되고, 개인이 기존 캐릭터를 삭제 -> 추후 기존 데이터로 쌓은 기록이 삭제됨
2. 수정
1) 이미지 URL에 있는 UUID(추정) 사용
이미지를 불러왔을 때 URL을 보면 끝에 UUID로 추정되는 64자리 문자열이 보인다.
이것을 이용해서 변경된 캐릭터 닉네임을 판단해서 업데이트를 하려고 한다.
2) 코드 수정
UUID 찾기 / 비교 메소드
public static String getUUID64(String url) {
String regex = "([A-Z0-9]{64})";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(url.toUpperCase());
if (matcher.find()) {
return matcher.group(1);
} else {
throw new IllegalArgumentException("UUID를 찾을 수 없습니다.");
}
}
public static boolean isSameUUID(String url1, String url2) {
if (url1 == null || url2 == null) {
return false;
}
return getUUID64(url1).equals(getUUID64(url2));
}
원정대 검색할 캐릭터 닉네임 찾는 메소드
// 원정대 검색할 캐릭터 닉네임 찾기
// 캐릭터 이미지가 있으면서 UUID가 일치하는 첫번째 캐릭터
private String findSiblingCharacterName(Member member) {
return member.getCharacters().stream()
.filter(character -> character.getCharacterImage() != null)
.filter(character -> {
CharacterJsonDto updatedCharacter = lostarkCharacterDao.getCharacter(character.getCharacterName(), member.getApiKey());
return isMatchingCharacter(character, updatedCharacter);
})
.map(Character::getCharacterName)
.findFirst()
.orElseThrow(() -> new IllegalArgumentException(CHARACTER_NOT_FOUND));
}
private boolean isMatchingCharacter(Character character, CharacterJsonDto updatedCharacter) {
if (updatedCharacter == null || updatedCharacter.getCharacterImage() == null) {
return false;
} else {
return isSameUUID(updatedCharacter.getCharacterImage(), character.getCharacterImage());
}
}
lostarkCharacterDao.getCharacter - 로스트아크 오픈 API로 캐릭터 단건 정보를 가져온다.
isMatchingCharacter - 데이터들이 null이 아니고 imageUrl도 있는 데이터 중 같은 UUID가 있는 첫번째 데이터를 찾아낸다.
원정대 업데이트
// 원정대 업데이트
private void updateSiblings(String searchCharacterName, Member member, List<DayContent> chaos, List<DayContent> guardian,
Map<String, Market> contentResource, String mainCharacter) {
List<CharacterJsonDto> siblings = lostarkCharacterDao.getSiblings(searchCharacterName, member.getApiKey());
siblings.stream()
.map(dto -> {
// 캐릭터 이미지 업데이트
CharacterJsonDto updatedCharacter = lostarkCharacterDao.getCharacter(dto.getCharacterName(), member.getApiKey());
if (updatedCharacter.getCharacterImage() != null) {
dto.setCharacterImage(updatedCharacter.getCharacterImage());
}
return dto;
})
.forEach(dto -> updateCharacter(dto, member, chaos, guardian, contentResource, mainCharacter));
}
private void updateCharacter(CharacterJsonDto dto, Member member, List<DayContent> chaos, List<DayContent> guardian,
Map<String, Market> contentResource, String mainCharacter) {
Optional<Character> matchingCharacter = member.getCharacters().stream()
.filter(character -> character.getCharacterImage() != null)
.filter(character -> isSameUUID(character.getCharacterImage(), dto.getCharacterImage()))
.findFirst();
DayTodo dayContent = new DayTodo().createDayContent(chaos, guardian, dto.getItemMaxLevel());
if (matchingCharacter.isPresent()) {
// 캐릭터가 존재할 경우 업데이트
Character character = matchingCharacter.get();
if (character.getCharacterName().equals(mainCharacter)) {
member.setMainCharacter(dto.getCharacterName()); // 메인 캐릭터 이름 변경
}
character.updateCharacter(dto, dayContent, contentResource);
} else {
// UUID가 일치하지 않으면 이름으로 캐릭터 찾기
Optional<Character> characterByName = member.getCharacters().stream()
.filter(character -> character.getCharacterName().equals(dto.getCharacterName()))
.findFirst();
if (characterByName.isPresent()) {
// 이름으로 찾은 캐릭터가 있으면 업데이트
characterByName.get().updateCharacter(dto, dayContent, contentResource);
} else {
// UUID도, 이름도 일치하는 캐릭터가 없으면 새로 추가
Character newCharacter = addCharacter(dto, dayContent, member);
calculateDayTodo(newCharacter, contentResource);
member.getCharacters().add(newCharacter);
}
}
}
lostarkCharacterDao.getSiblings - 로스트아크 오픈 API로 원정대 정보를 가져오는데, 여기엔 이미지 URL 값이 없기 때문에 따로 단건 조회 후 저장해준다.