이번 프로젝트에 OPEN API에서 GET방식으로 파라미터를 전달하고, 데이터를 가져와야 하는 부분이 있었다.
js를 사용한 프론트단에선 ajax로 컨트롤러를 호출하듯이 쉽게 값을 가져올 수 있었지만,
백단에선 조금 다르게 호출한 다음 String값으로 오는 데이터를 처리해줘야 한다.
Http를 연결을 사용하기위해 필요한 것이 HttpURLConnection이다.
HttpURLConnection은 ?
URL 내용을 읽어오거나 , URL에 GET,POST 방식으로 데이터를 전달할 때 사용한다.
웹페이지나 서블릿에 데이터를 전달 할 수 있다.
URL url = new URL(https://api주소?파라미터1=111&파라미터2=222);
ObjectMapper mapper = new ObjectMapper();
StringBuilder sb = new StringBuilder();
BufferedReader br;
HttpURLConnection con = (HttpURLConnection)url.openConnection();
//Request Header 정의
con.setRequestProperty("appKey", "발급받은키");
//전송방식
con.setRequestMethod("GET");
//서버에 연결되는 Timeout 시간 설정
con.setConnectTimeout(5000);
//InputStream 읽어 오는 Timeout 시간 설정
con.setReadTimeout(5000);
//URLConnection에 대한 doOutput 필드값을 지정된 값으로 설정한다.
//URL 연결은 입출력에 사용될 수 있다.
//URL 연결을 출력용으로 사용하려는 경우 DoOutput 플래그를 true로 설정하고,
//그렇지 않은 경우는 false로 설정해야 한다. 기본값은 false이다.
// true로 설정하면 자동으로 POST로 설정된다. output으로 post값을 넣어주자
con.setDoOutput(false);
br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
SafeCasterVO safeCasterVO = mapper.readValue(sb.toString(), SafeCasterVO.class);
Density density = new Density();
//사용예제
String resortName = resort.get(i).get("resort").toString();
density.setResort(resortName);
density.setT00(safeCasterVO.getData().get(0).getFlowDensityPercentile());
density.setT03(safeCasterVO.getData().get(3).getFlowDensityPercentile());
density.setT09(safeCasterVO.getData().get(9).getFlowDensityPercentile());
density.setT12(safeCasterVO.getData().get(12).getFlowDensityPercentile());
density.setT15(safeCasterVO.getData().get(15).getFlowDensityPercentile());
density.setT18(safeCasterVO.getData().get(18).getFlowDensityPercentile());
density.setT21(safeCasterVO.getData().get(21).getFlowDensityPercentile());
densityService.dataInsert(density);
1. URL클래스를 이용해서 생성자를 만들어준다.
2. openConnection() 을 이용해서 url을 연결해주고
3. (있을 시) api 사이트에서 발급받은 개인key를 RequestHeader에 넣어주자.
api에 따라 url을 통해 파라미터를 전달 할 수도 있고, api문서에 나온 위치에 key를 넣어주자.
4. InputStream & Buffer 사용
br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
이제 데이터를 받아오자.
먼저 InputStream()은 연결된 객체의 값을 받아온다.
HttpURLConnection과 연결된 InputStream()은 api호출로 응답받은 데이터값을 가져온다.
InputStream은 데이터를 byte단위로 가져온다.
1byte인 영어나 숫자는 잘 출력되지만, 2byte 단위인 한글을 받아야한다.
byte형식으로 가져온 데이터를 char단위인 InputStreamReader를 이용해 UTF-8 형식의 문자열로 받는다.
그 값을 Buffer를 이용해 받는다.
왜 Buffue를 이용하는 걸까?
일단 버퍼는 동영상 스트리밍 중 발생하는 그 버퍼링의 버퍼이고,
cpu와 보조기억장치 사이에서 사용되는 임시 저장공간을 의미한다.
받은 데이터를 처리하는 CPU는 기억장치를 포함한 모든 컴퓨터 부품 중, 속도가 가장 빠른 장치이다.
CPU는 1초에 수십억bit, 그 이상의 데이터를 처리할 수 있지만
보조기억장치나 인터넷으로 받는 데이터는 빨라도 초당 1GB수준에 불과 할 것이다.
간단하게 설명하면, CPU는 1초에 100개의 데이터를 처리할 수 있지만, 정
작 처리할 데이터를 주는 쪽은 1초에 3개의 데이터 밖에 보내주지 않는 다는 것이고,
이것은 97개만큼의 효율성을 잃게 된 다는 것이다.
이 때, 버퍼를 사용하게 되는데 버퍼는 CPU다음으로 빠른 램을 이용하기 때문에,
훨씬 빠르게 데이터를 받을 수 있게 된다.
보조기억장치 -> cpu ////// 보조기억장치 -> 램 ( 버퍼 임시저장공간) -> CPU이다.
하지만 이렇게 중간과정을 거쳐가면 오히려 더 비효율적인게 아닌가? 라고 생각 할 수 있겠지만,
버퍼에 100개의 데이터가 쌓일때까지, 마련해둔 공간에 데이터를 쌓고 모두 쌓였다면 한번에 처리해서
훨씬 빠른 속도로 연산을 할 수가 있다.
CPU는 다른 일을 먼저 처리한 후, 버퍼에 데이터가 다 쌓일 때 까지 쌓였는지 확인만 해주면 되기 때문에
쓸 데 없는 자원을 낭비하지 않아도 된다.
사람으로 따지면 라면을 끓이고 설거지를 해야할 때,
물을 냄비에 받아서 가스레인지로 끓이는 동안 설거지를 한 후 라면을 바로 넣어서 끓여 먹는 것과
설거지를 다 하고 물을 냄비에 받아서 끓을 때 까지 기다리고 라면을 끓여먹는 것의 차이라고 보면 되겠다.
자바 알고리즘을 공부할 때 많이 사용하는 Scanner 로도 inputStream값을 받을 수 있는데,
Buffer와 비교하면 정말 엄청난 성능차이가 나는 것에 놀랐다.
대용량의 데이터를 처리하는데 Buffer는 0.8초만에 처리한 것에 반면, Scanner는 6초가 넘게 걸리는 차이가 났었다.
다중스레드를 구현할 때도 Buffer를 사용할 수 있으니,
나중에 더욱 깊게 공부해보려고 한다.
이제 문자열로 받은 값을 StringBuilder로 받자.
StringBuilder란 무엇일까?
이름만 봐도 문자열을 만드는 클래스라는 걸 알 수 있다.
String은 불변(immutable) 객체라고 한다.
String은 값이 변경되거나 연산될 때 새로운 String을 생성한다.
즉, String 객체와 String객체를 더할때(+)는 기존의 문자열에 문자열을 더 해 새로운 객체를 만드는
많은 연산과 과정을 수행하며 메모리할당과 해제를 발생시킨다.
당연히 String을 통으로 연산하는 것은 성능적으로 좋지 않겠다.
그래서 나온 것이 StringBuilder이다.
StringBuilder는 변경이 가능한 문자열을 만들어주기 때문에, 문자열을 연산하는 과정에서 하나의 대안이 될 수 있겠다.
해당 값을 문자열로 받을 때에는 toString()을 이용하면 된다.
그 다음 버퍼를 닫아준다.
5. ObjectMapper로 String값을 파싱하여 VO로 받기
jackson 라이브러리의 ObjectMapper 클래스이다.
보통 OpenAPI는 응답값을 json형식으로 전달해준다.
위에서 여러 처리로 json값을 String형식의 문자열로 받았는데,
readValue를 이용하면 쉽게 값을 받을 수 있다.
readValue( String , class );
이제 응답값에 맞는 VO ( getter )를 작성해서 값을 받아주면 되겠다.
이번 프로젝트에선 일정시간마다 스케줄러를 이용해서 API값을 VO에 넣고 DB에 insert시켜줬다.
사실 위의 HttpURLConnection과 Buffer, ObjectMapper를 이용하는 예제는 구글검색을 하면 손쉽게 찾을 수 있다.
하지만 중요한 것은 그 내용을 알고 사용하는지, 모르고 사용하는지 라고 생각한다.
InputStream을 사용하는 이유와 Buffer의 이해와 사용법, 더 나아가서 메모리의 활용과 성능의 연관관계 등..
한번 사용할 때 제대로 깊게 파고들어서 다음 비슷한 로직을 처리할 때,
점점 더 깊게 들어가며,
보고 가져다 쓰는 것이 아닌 상황에 맞는 설계와 사용이 곧 실력이 아닐까 한다.
아직 실력을 논하기에도 부족하지만 꾸준히 공부해서 자유자재로 활용 할 수 있게 되고 싶다.
'SPRING BOOT > WhiteRecord' 카테고리의 다른 글
카카오로그인과 OAuth2 (0) | 2022.02.10 |
---|---|
[스프링부트] 에디터 이미지업로드 시 임시폴더로 분리하기 (0) | 2022.02.05 |
스프링부트 Scheduler (4) | 2022.01.28 |
CK에디터로 올린 이미지에서 썸네일 뽑아내기 ( 정규식 ) (1) | 2022.01.28 |
지도 API 좌표값 소숫점 자르기 ( double형 소수값 자릿수 자르기 ) (3) | 2022.01.28 |