안녕하세요~

저번 시간에는 로스트아크의 오픈 API를 사용하기위해 키를 발급받고 간단한 테스트로 받아오는것을 해봤습니다.

이번에는 이제 우리의 서버에서 API를 호출하고 그 데이터를 다시 웹으로 전달하는 작업을 해보겠습니다.

 

1.  API 데이터 확인

저번에 API를 테스트해봤을때 보셨겠지만 기본 캐릭터 검색을 하게되면 정말 방대한 정보가 검색됩니다.

그래서 저는 일단 테스트를 위해 profiles의 정보만 가지고 확인해보도록 하겠습니다.

검색해보면 위쪽에 요청 url과 아래 필드 응답값들이 나오구요 페이지 맨 아래쪽으로 내리면 해당 모델의 정보를 확인하실 수 있습니다. 

저기서 필요한 정보들만 가져다 쓰도록 하겠습니다.

 

2. VO 생성

@Getter
@Setter
@JsonIgnoreProperties(ignoreUnknown = true)
public class AromoryProfile {
    private String characterImage; // 캐릭터 사진
    private String expeditionLevel; // 원정대 레벨
    private String title; // 칭호
    private String serverName; // 서버명
    private String characterName; // 캐릭터명
    private String characterClassName; // 클래스명
    private int characterLevel; // 캐릭터 레벨
    private String itemMaxLevel; // 아이템 레벨
}

당장 테스트를 위해 필요하다고 생각하는 요소들만 추가를 해줬습니다. 

@JsonIgnoreProperties 같은 경우 위 Object에서 매칭되지 않는 요소들은 무시해주기 위해서 추가했습니다.

 

3. Service 생성

@Service
public class CharacterService {

    static final String apiKey = "본인 API KEY";
    private AromoryProfile profiles;

    public AromoryProfile getUser(String characterName) throws IOException, InterruptedException {

        characterName = URLEncoder.encode(characterName,"utf-8");

        String url = "https://developer-lostark.game.onstove.com/armories/characters/"+characterName+"/profiles";

        HttpClient client = HttpClient.newHttpClient();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .header("Authorization","Bearer "+apiKey)
                .build();

        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

        if(response.statusCode() == 200) {
            String jsonResponse = response.body();

            ObjectMapper objectMapper = new ObjectMapper().configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES,true);
            profiles = objectMapper.readValue(jsonResponse, AromoryProfile.class);


        }else {
            System.out.println(response.statusCode());
        }

        return profiles;

    }
}

 

API를 요청할 service를 생성해줬습니다. 클라이언트에서 전달받은 캐릭터명을 인코딩해주고 URL을 httpClient를 통해 전송하고 로스트아크 서버로부터 JSON 응답을 받아옵니다. 그리고 ObjectMapper를 통해 우리가 생성한 ArmoryProfile의 필드값들과 매핑해줍니다.

 

4. Controller 생성

@RestController
@RequestMapping("/loa")
public class LostarkController {

    @Autowired
    private CharacterService characterService;

    @GetMapping("")
    public AromoryProfile getUser(@RequestParam String characterName) throws IOException, InterruptedException {
        return characterService.getUser(characterName);
    }
}

컨트롤러 에서는 서비스를 호출해주고 VO를 응답값으로 주겠습니다.

 

5. 클라이언트 값 확인

function getUser(characterName) {
  fetch("http://127.0.0.1:8080/loa?characterName=" + characterName,{
    method: 'GET',
    headers: {
      "Content-Type": "application/json",
    },
  })
      .then(res => res.json())
      .then(data => {
        console.log(data);
      })
      .catch(err => console.log(err));
}

당장은 화면에 출력은 못하기때문에 받아온 데이터를 json화 시켜서 콘솔창에서 확인해보도록 하겠습니다.

이렇게 정상적으로 응답을 받아오는것을 확인할 수 있습니다.

 

자 오늘은 클라이언트에서 전송한 데이터를 서버에서 API 요청으로 캐릭터의 정보를 받아오고 또 필요한 정보들만 추려서 다시 클라이언트로 전송하는것까지 진행했습니다. 다음은 요청 받은것들을 화면에 표시하는 작업을 해보겠습니다.

 

오류 더보기

더보기

1. Cannot deserialize value of type java.lang.Character from Object value (token JsonToken.START_OBJECT)

- 받으려는 데이터를 Character로 생각없이 만들어버렸다. ㅋㅋㅋㅋ Character는 Char를 처리하는 클래스이기 때문에 다른것으로 변경해서 사용하도록 하자.

 

2. Unrecognized field "ArmoryProfile" (class com.yeop.lostark.vo.LostarkCharacter), not marked as ignorable 

- 사실 처음에는 전체 데이터를 받아와서 ArmoryProfile만 뽑아오려 했다. 처음 구조는

루트>ArmoryProfile,등등

이런식이었는데 내가 루트를 가져와서 ArmoryProfile만 뽑아내려니 Jackson이 역직렬화를 할 때 루트 클래스가 매핑이 안되다보니 나온 오류였다.

 

2-1. 첫 번째 방법으로 루트에 해당하는 Profiles 객체를 만들고 그 안에 armoryProfile을 필드 객체로 추가해서 받아오는 방법을 생각했다. 최종적으로도 이렇게 가려고한다. 하지만 로스트아크 API가 전달하는 ArmoryProfile과 내가 필드로 넣은 armoryProfile이 대소문자가 일치하지 않아 매핑을 하지 못했다. (정말 귀찮다.) 이럴때는 객체 안에 @JsonProperty("필드명") 으로 이름이 다를경우에 맞춰서 매핑이 가능하다.

 

2-2. 일단은 ArmoryProfile만 받아오자는 생각으로 위 포스팅처럼 진행했다. ArmoryProfile 클래스를 만들고 ArmoryProfile만 제공하는 API로 해당 필드들을 받아오는것으로 했다.

 

3. 필드 대소문자 불일치

2번과 똑같은 오류인데 2-2 방법으로 진행하면서 이번엔 필드값들이 대소문자가 맞지 않는 오류가 발생했다.

그래서 내가 사용하는 ObjectMapper에 대소문자를 구분하지 않고 매핑하도록 설정을 해줬다.

ObjectMapper().configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES,true) 이 옵션으로 가능하다.

 

 

감사합니다!

엽바!

+ Recent posts