본문 바로가기
Spring Boot

스프링부트 Rest API Post 방식 호출하기 - (1)

by 코리늬 2019. 10. 23.

올해 결제내역이 있는 회원들의 현재 보유한 잔액, 쿠폰 잔여량을 조회해 달라는 요청이 들어왔다.

조회에필요한 테이블을 찾다보니 무려 6개..!

쿼리는 바로 포기ㅎ

문득 각 회원별로 로그인 할 때 보유 잔액을 api 호출을 사용해 구현이 되어있다는 것이 생각났다.

api 가이드를보니 로그인 user_id를 파라미터로 던지면 끝이었다

이렇게 간단할 수가?!?!

  1. 첫 시도

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

RestTemplate restTemplate = new RestTemplate();

String url = "api url";

MultiValueMap<String, String> map= new LinkedMultiValueMap<>();
map.add("user_id", "홍길동");

HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<(map,headers);
String answer = restTemplate.postForObject(url, entity, String.class);

System.out.println(answer);

구글링을 통해 소스를 찾아봤다.

  • header를 셋팅하고
  • map에 파라미터로 넣을 key, value 값을 넣고
  • HttpEntity에 파라미터와 헤더 정보를 담는다.
  • restTemplate의 메소드인 postForObject를 사용해 위에서 설정한 정보를 담아 넘겨준다.

(각각의 함수에 대해서는 따로 정리를 할 예정이다.)

결과는 당연히 실패 ㅎㅎ 처음부터 될리가

Bad Request 400 error발생

음,, 헤더 문제인가?

  1. header 수정

headers.add("Content-Type", MediaType.APPLICATION_JSON.toString());
headers.add("Accept", MediaType.APPLICATION_JSON.toString());

헤더를 바꿔줬다.

실패ㅎ

  1. header에 Authorization 추가

웹에서 호출된 header를 보니 Authorization 값이 있었다. 그래서 이것도 추가해봤다.

headers.add("Content-Type", MediaType.APPLICATION_JSON.toString());
headers.add("Accept", MediaType.APPLICATION_JSON.toString());
headers.add("Authorization", "웹 헤더에 있던 값");

실패ㅎㅎ

  • Authorization는 그럼 회원별로 값이 다 다를텐데 이건 아니지 않을까?
  • 헤더문제는 아닌 것 같다.

파라미터를 수정해보자.

콘솔 디버그에

{"user_id":[홍길동]} 이런식으로 출력이 되어있었다.

그럼이건가..?

  1. 갓택오버플로우

스택오버플로우에

String requestJson = "{\"user_id\":\"dlrudtn108\"}";

를 사용해서 map이 아닌 string으로 해결한 것을 보고 바로 시도했더니 성공!!

  • JSON 으로 파라미터를 넘겨줬어야 했다.(당연한건데..)

    • 근데 지금보니 map으로 넣더라도

      JSONObject feedback = (JSONObject) new JSONParser().parse(result);

      이런식으로 출력하면 된다는 글을 보았는데, 내일 해봐야겠다.


  • 디비에서 대상자를 뽑자. 3천명 정도가 나왔다.
  • 3천명을 배열에 넣어서 파라미터에 대입해주면 끝날 것 같은데.. 3천명을 언제 다 넣고있지?

무슨 방법이 좋을까

 

질문찬스

텍스트 파일에 3천명을 넣어서 파일을 한 줄 씩 읽으면 끝!

크으으

거의 최종 코드

ArrayList<String> userList = new ArrayList<>();
        try{
            File file = new File("C:\\Sample.txt");

            FileReader fileReader = new FileReader(file);

            BufferedReader bufferedReader = new BufferedReader(fileReader);

            String line = "";

            while((line = bufferedReader.readLine()) != null){
                userList.add(line);
            }
            bufferedReader.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException ez){
            System.out.println(ez);
        }

        System.out.println("사이즈 :"+userList.size());

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        RestTemplate restTemplate = new RestTemplate();

        String url = "api URL";


        JSONObject jsonObject = new JSONObject();

        ArrayList<String> list = new ArrayList<>();
        String answer = "";

        for(int i=0; i<userList.size(); i++) {
            jsonObject.put("user_id", userList.get(i));
            HttpEntity<String> entity = new HttpEntity<String>(jsonObject.toString(),headers);
             answer = restTemplate.postForObject(url, entity, String.class);
            list.add(answer);
        }

        System.out.println(Arrays.toString(new ArrayList[]{list}));

        }catch(Exception e){
            e.printStackTrace();
        }

기대에 부푼채 실행. 가즈아

근데 1700명 정도 읽더니 갑자기 connection failed

검색해보니 아마도 너무 많은 요청으로 인해 끊겼을 것 같았다.

또 구글링, 구글 없었으면 개발 못함

연결이 끊기면 재 연결시도를 해주는 코드를 찾았다! (마찬가지로 추가 정리 필요)

private static final int HTTP_CLIENT_RETRY_COUNT = 3;
private static final int MAXIMUM_TOTAL_CONNECTION = 10;
private static final int MAXIMUM_CONNECTION_PER_ROUTE = 5;
private static final int CONNECTION_VALIDATE_AFTER_INACTIVITY_MS = 10 * 1000;

HttpClientBuilder clientBuilder = HttpClients.custom();

        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();

        // Set the maximum number of total open connections.
        connectionManager.setMaxTotal(MAXIMUM_TOTAL_CONNECTION);
        // Set the maximum number of concurrent connections per route, which is 2 by default.
        connectionManager.setDefaultMaxPerRoute(MAXIMUM_CONNECTION_PER_ROUTE);

        connectionManager.setValidateAfterInactivity(CONNECTION_VALIDATE_AFTER_INACTIVITY_MS);

        clientBuilder.setConnectionManager(connectionManager);

        clientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(HTTP_CLIENT_RETRY_COUNT, true, new ArrayList<>()) {

            @Override
            public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
                return super.retryRequest(exception, executionCount, context);
            }

        });
  • 이렇게 해서 성공적으로 데이터 추출 완료.

++

하지만, 3천명보다 훨씬 많은 데이터를 호출해야 된다면?

위의 인공호흡 코드로는 역부족일 것이다.

마찬가지로 질문찬스를 통해, 파일을 읽을 때 100명씩 끊어서 읽고, api 호출도 100명씩 끊어서 서버에 부하를 덜 주는 방식을 고려해야 한다는 답변을 받았다.

또한 jvisualvm로 파일을 읽을 때나, api 호출 부분에서 메모리가 얼마나 치솟는지도 확인해야 한다고 한다.

사용법을 익혀야겠다.

이 부분까지 추가 개발을 해보고 2탄에 올려야겠다.

끝.

댓글