티스토리 뷰
거래소 검색에 이어 캐릭터 정보 검색하는 기능 구현에 대해 알아보겠습니다. 전체소스는 GitHub를 참고해 주세요.
1. 컨트롤러 추가
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class ApiController {
private final ApiService _apiService;
...
/**
* 캐릭터 기본정보 조회
*/
@PostMapping("/character/search")
public ResponseEntity<CharacterRes> characterSearch(@RequestBody CharacterReq params){
return _apiService.characterSearch(params);
}
}
2. DTO 구현
@Getter
@Setter
public class CharacterReq {
private String characterName;
}
@Getter
@Setter
public class CharacterRes {
private List<CharacterInfo> characterInfo;
}
@Getter
@Setter
public class CharacterInfo {
@JsonProperty("ServerName")
private String serverName;
@JsonProperty("CharacterName")
private String characterName;
@JsonProperty("CharacterLevel")
private Integer characterLevel;
@JsonProperty("CharacterClassName")
private String characterClassName;
@JsonProperty("ItemAvgLevel")
private String itemAvgLevel;
@JsonProperty("ItemMaxLevel")
private String itemMaxLevel;
private ArmoryProfile armoryProfile;
@Getter
@Setter
public static class ArmoryProfile {
@JsonProperty("CharacterImage")
private String characterImage;
@JsonProperty("ExpeditionLevel")
private Integer expeditionLevel;
@JsonProperty("TownName")
private String townName;
@JsonProperty("TotalSkillPoint")
private Integer totalSkillPoint;
}
}
3. 서비스 구현
@Service
public class ApiService {
@Value("${loa.apiKey}")
private String apiKey;
@Value("${loa.apiUrl}")
private String apiUrl;
HttpHeaders headers;
RestTemplate restTemplate;
@PostConstruct
public void init() {
headers = new HttpHeaders();
headers.set("Accept", "application/json");
headers.set("Authorization", "bearer " + apiKey);
restTemplate = new RestTemplate();
}
...
/**
* 캐릭터 기본정보 조회(GET)
*/
public ResponseEntity<CharacterRes> characterSearch(CharacterReq params) {
ResponseEntity<String> jsonResult = restTemplate.exchange(
apiUrl + "/characters/" + params.getCharacterName() + "/siblings",
HttpMethod.GET,
_getEntity(null),
String.class);
List<CharacterInfo> characterInfo = _getArrayData(jsonResult, CharacterInfo.class);
if(characterInfo == null){
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
for(CharacterInfo info : characterInfo){
String name = info.getCharacterName();
CharacterInfo.ArmoryProfile armoryProfile = restTemplate.exchange(
apiUrl + "/armories/characters/" + name + "/profiles",
HttpMethod.GET,
_getEntity(null),
CharacterInfo.ArmoryProfile.class).getBody();
info.setArmoryProfile(armoryProfile);
}
CharacterRes res = new CharacterRes();
res.setCharacterInfo(characterInfo);
return new ResponseEntity<>(res, HttpStatus.OK);
}
/**
* HttpEntity 획득
*/
private HttpEntity _getEntity(Object obj) {
return obj == null ? new HttpEntity<>(headers) : new HttpEntity<>(obj, headers);
}
/**
* JsonArray 데이터 파싱
*/
private <T> List<T> _getArrayData(ResponseEntity<String> str, Class<T> clazz) {
String jsonArray = str.getBody();
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.readValue(jsonArray, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
4. 화면 구현
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<th:block th:replace="~{fragments/head.html :: headFragment}"/>
<body>
<th:block th:replace="~{fragments/top.html :: topFragment}"/>
<main>
<div class="search-container">
<label for="characterName">캐릭터 이름:</label>
<input type="text" id="characterName" placeholder="캐릭터 이름 입력" onkeydown="javascript: if(event.keyCode==13){ searchCharacters(); return false; }">
<button onclick="searchCharacters()">검색</button>
</div>
<div id="characterList" class="character-list"></div>
</main>
<script th:inline="javascript">
function searchCharacters() {
let characterName = document.getElementById('characterName').value;
let data = { characterName: characterName };
postApi('/api/character/search', data, onSearchCharactersSuccess, onApiError);
}
function onSearchCharactersSuccess(data) {
const characterList = document.getElementById('characterList');
characterList.innerHTML = '';
data.characterInfo.forEach((character, index) => {
const characterDiv = document.createElement('div');
characterDiv.className = 'character';
var profileCheck = character.armoryProfile;
if(profileCheck){
characterDiv.innerHTML = `
<div class="accordion" onclick="toggleAccordion(${index})">
<h3>${character.CharacterName} (${character.CharacterClassName})</h3>
</div>
<div class="panel" id="panel${index}">
<img class="profile-img" src="${character.armoryProfile.CharacterImage}" alt="${character.armoryProfile.CharacterName} 이미지">
<p><strong>서버:</strong> ${character.ServerName}</p>
<p><strong>아이템 레벨:</strong> ${character.ItemAvgLevel}</p>
<p><strong>캐릭터 레벨:</strong> ${character.CharacterLevel}</p>
<p><strong>원정대 레벨:</strong> ${character.armoryProfile.ExpeditionLevel}</p>
</div>
`;
} else {
characterDiv.innerHTML = `
<div class="accordion" onclick="toggleAccordion(${index})">
<h3>${character.CharacterName} (${character.CharacterClassName})</h3>
</div>
<div class="panel" id="panel${index}">
<img class="profile-img" src="/images/default.png" alt="이미지">
<p><strong>서버:</strong> ${character.ServerName}</p>
<p><strong>아이템 레벨:</strong> ${character.ItemAvgLevel}</p>
<p><strong>캐릭터 레벨:</strong> ${character.CharacterLevel}</p>
</div>
`;
}
characterList.appendChild(characterDiv);
});
}
function toggleAccordion(index) {
const panel = document.getElementById(`panel${index}`);
panel.style.display = panel.style.display === 'block' ? 'none' : 'block';
}
</script>
</body>
</html>
5. 실행화면

감사합니다.
'프로그래밍 언어 > API' 카테고리의 다른 글
[LostArkAPI] 거래소 검색사이트 간단하게 구현하기 (24) | 2024.07.16 |
---|---|
[ElasticSearch] 계정 생성하기 (0) | 2024.05.21 |
[ElasticSearch] Window 에 설치하기 (0) | 2024.05.21 |
[YoutubeAPI] SpringBoot + Kotlin 으로 구현하기 (0) | 2024.05.21 |
[YoutubeAPI] Youtube Data API v3 사용방법 (0) | 2024.05.21 |
최근에 올라온 글
- Total
- Today
- Yesterday