팀 프로젝트중 오픈 API를 사용하기로 했다.
이건데 오늘 이 부분을 구현하면서 Json 파싱 하는 방법이랑 오브젝트로 매핑하는 방법을 알았다.
오픈 API 사용법 부터 알아야겠지?
우선 라이브러리를 제공한다
처음엔 RestTemplate을 적용하려 했으나 라이브러리가 있으면 시간도 아낄 겸 활용하자 생각해서 라이브러리를 사용했다.
안에서 보면 getMovieList를 오버로딩하고 있다.
밑에껀 모든 검색 기준 넣어줘야 검색
위에껀 특정 검색 기준으로만 검색
검색 기준은 아래서 확인 가능하다
흠 나는 특정 검색 기준으로 사용하고 싶은 걸~?
key는 secretKey
그런 후 불러온 모든 값을 String 타입에 저장
이 부분에서 아 파싱을 하기는 했는데 어떻게 하지 고민을 되게 많이 했다.
파싱이 뭐야?
텍스트를 읽고 그 구조를 원하는 형태로 변환하는 걸 말한다
Json으로 구성이 되어 있으면 뭐 String으로 String에 있는 Json 형식의 문자열을 Json으로 변환 할 수 있다
파싱은 구글의 심플 Json을 사용했다
implementation group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1.1'
이걸 dependencies 에 넣어주면 된다
그리고 여기서 나온 JSONParser로 String 타입에 저장된 Json 형식의 문자열을 파싱 후에 object 형식으로 반환
object 형식을 JSONObject 으로 캐스팅
여기서 Json은 Key : Value로 이루어져 있다는 걸 알고 있을 것이다
그래서 캐스팅한 jsonObject.get("Key")를 하면 원하는 데이터를 가져올 수 있다
이걸 한번 더 movieListResult에 캐스팅
movieList는 이런 식으로 JSONArray로 되어 있다 그래서 JSONArray로 캐스팅
후에 뭐 어떻게 할 까 고민을 많이 헀다.
System.out.print()로 계속 찍어보면서
그러다가 ObjectMapper가 있는 것을 알았다.
ObjectMapper가 뭐야?
말그대로 객체 맵핑해주는 놈..? 이다
오브젝트 맵퍼에는
readValue(1,2)라는 메소드가 있는데
1에 Json을 String으로 변환 시킨 값, 2에는 맵핑할 클래스를 넣어주면 된다.
// 예시
Dto dto = objectMapper.readValue(json.toString(), Dto.class);
그럼 json을 읽고 Dto.class에서 맞는 이름이랑 맵핑을 시켜준다
정확한 로직은 나도 아직 잘몰라서 공부해야 함!!
이름에 맞게 맵핑한다는 정도만 기억하자
그래서 나는 안의 정보와 맞게 Dto를 만들어 줬다.
이걸 Entity 저장할 때 Dto에서 잘 꺼내써서 저장하면 되겠지?
public void updateMovies(String curPage, String itemPerPage, String openStartDt,
String openEndDt) {
String response = "";
Map<String, String> paramMap = new HashMap<>();
paramMap.put("openStartDt", openStartDt);
paramMap.put("openEndDt", openEndDt);
paramMap.put("curPage", curPage);
paramMap.put("itemPerPage", itemPerPage);
try {
KobisOpenAPIRestService service = new KobisOpenAPIRestService(key);
response = service.getMovieList(true, paramMap);
JSONParser jsonParser = new JSONParser();
Object obj = jsonParser.parse(response);
JSONObject jsonObject = (JSONObject) obj;
JSONObject movieListResult = (JSONObject) jsonObject.get("movieListResult");
JSONArray movieArr = (JSONArray) movieListResult.get("movieList");
ObjectMapper objectMapper = new ObjectMapper();
for (int i = 0; i < movieArr.size(); i++) {
Movie movie = new Movie();
JSONObject movieJson = (JSONObject) movieArr.get(i);
MovieDto movieDto = objectMapper.readValue(movieJson.toString(), MovieDto.class);
if (movieRepository.findById(movieDto.getMovieCd()).isPresent()) {
continue;
}
if (!movieDto.getDirectors().isEmpty()) {
movie.setDirector(movieDto.getDirectors().get(0).getPeopleNm());
} else {
movie.setDirector("감독 정보 없음");
}
movie.setTitle(movieDto.getMovieNm());
movie.setGenre(movieDto.getGenreAlt());
movie.setId(movieDto.getMovieCd());
movie.setRelease_date(movieDto.getOpenDt());
movieRepository.save(movie);
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
그래서 이렇게 짰다!
제어문 설명
// 이 부분은 레포지토리에 이미 아이디가 있다면
// for문을 건너 뛰어서 오류 방지 및 무결성을 보장하도록 했다.
if (movieRepository.findById(movieDto.getMovieCd()).isPresent()) {
continue;
}
// 이 부분은 작가가 여러명으로 되어 있어서 고민을 많이했는데..
// 감독 정보가 없는 영화도 있었고, 부감독이면 두번째 인덱스에 있지 않을까? 생각해서
// get(0) 만 해주었다.. 아직 실력 부족하무ㅜ
if (!movieDto.getDirectors().isEmpty()) {
movie.setDirector(movieDto.getDirectors().get(0).getPeopleNm());
} else {
movie.setDirector("감독 정보 없음");
}
Json 파일을 잘보면 movieCd가 있는데 이게 영화진흥원에서는 기본키로 사용하겠네~ 생각해서
Movie 엔티티의 기본키를 저 부분으로 설정되게 했다.
@Id
@Column
private Long id;
이렇게..
근데 저 제어문 부분 마음에 안 든다 내가 짰는데도 비효율적인 거 같다
계속 셀렉을 해줘야 되는데 흠.... 더 좋은 방법이 없을까?
고민해봐야 겠다.
쨋든
포스트맨으로 RequestDto에 맞춰서 값을 보내줬다
와 드디어... 해냈다... 3일 동안 쩔쩔맸는데 다행이다.
'TIL' 카테고리의 다른 글
TIL 2023-11-27 하나의 커스텀 예외 클래스로 모든 컨트롤러 예외 처리하기 feat(글로벌 예외 핸들러) (2) | 2023.11.27 |
---|---|
TIL 2023-11-24 영속성 컨텍스트 동일성 보장 (0) | 2023.11.24 |
TIL 2023-11-22 gradle 외부 라이브러리 jar 적용 오류 (0) | 2023.11.22 |
TIL 2023-11-21 PUT과 PATCH의 차이 (0) | 2023.11.21 |
TIL 2023-11-20 CascadeType.REMOVE orphanRemoval = true 차이 (0) | 2023.11.20 |