*/Spring

Java 통신 인터페이스 실습

sssbin 2023. 12. 30. 18:39

| 실습 환경: Spring Boot 3.2.1 / Java 17 / Gradle

1. HttpURLConnection 실습

❓ HttpURLConnection

  • HTTP와 관련된 기능을 지원하는 URLConnection
  • URLConnection은 Java 애플리케이션과 URL 간의 연결 관련한 모든 클래스의 수퍼 클래스
  • Spring 같은 프레임워크 없이도 사용이 가능하다는 장점!

🔌 코드

private String baseUrl = "https://dapi.kakao.com/v2/local/search/keyword.JSON";
private String header = "Authorization";

@GetMapping("/http-url-connection")
public JSONObject httpUrlConnection(@RequestHeader("Authorization") String auth,
                                    @RequestParam("query") String query) throws IOException, ParseException {
    // URL 객체 생성
    URL url = new URL(baseUrl + "?query=" + encode(query));

    // connection 생성
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();

    StringBuilder sb = new StringBuilder();
    if (conn != null) {
        conn.setConnectTimeout(10000); // 10초 동안 기다린 후 응답이 없으면 종료
        conn.setRequestMethod("GET"); // Http 메서드 설정
        conn.setRequestProperty(header, auth); // Http 헤더 설정
        conn.setDoInput(true);
        conn.setDoOutput(true);

        int resCode = conn.getResponseCode(); // 요청 전송
        if (resCode == HttpURLConnection.HTTP_OK) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));

            String line;
            while (true) {
                line = reader.readLine();
                if (line == null)
                    break;
                sb.append(line);
            }
            reader.close();
        }
        conn.disconnect();
    }

        // json 변환 후 반환
    return stringToJson(sb.toString());
}

private String encode(String str) throws UnsupportedEncodingException {
    return URLEncoder.encode(str, "UTF-8");
}

private JSONObject stringToJson(String str) throws ParseException {
    JSONParser parser = new JSONParser();
    JSONObject jsonObject = (JSONObject) parser.parse(str);
    return jsonObject;
}
  • URLEncoder.encode(query, "UTF-8");
    • 쿼리 파라미터 한글 처리!
  • JSONParser
    • String to Json
    • 스트링 빌더에 저장되어 있는 문자열을 json으로 변환시켜서 반환한다.
    • build.gradle에 dependency 추가해줘야 함.
    • implementation 'com.googlecode.json-simple:json-simple:1.1.1'

💡 결과값

2. RestTemplate 실습

❓ RestTemplate

  • HttpURLConnection과 같은 기본적인 HTTP 클라이언트 대신에 사용할 수 있는 동기식 클라이언트
  • HTTP 서버와의 통신을 단순화하고 RESTful 원칙을 지킨다.
  • 템플릿 API를 노출해서 일반적인 시나리오에 대한 HTTP 메서드를 제공

🔌 코드

@GetMapping("/rest-template")
public JSONObject restTemplate(@RequestHeader("Authorization") String auth,
                               @RequestParam("query") String query) throws UnsupportedEncodingException, ParseException {
    // RestTemplate 객체 생성
    RestTemplate restTemplate = new RestTemplate();

    // HttpHeader 설정
    HttpHeaders headers = new HttpHeaders();
    headers.add(header, auth);

    // HttpEntity 생성
    HttpEntity entity = new HttpEntity<>(headers);

    // API 호출
    ResponseEntity response = restTemplate.exchange(
            getUri(query),
            HttpMethod.GET,
            entity,
            String.class);

    // json 변환 후 반환
    return stringToJson(response.getBody().toString());
}

private URI getUri(String query) {
    return UriComponentsBuilder.fromHttpUrl(baseUrl)
            .queryParam("query", query)
            .encode(Charset.forName("UTF-8"))
            .encode()
            .build()
            .toUri();
}
  • URI 설정
    • RestTemplate을 이용하면 URLEncoder.*encode*(query, "UTF-8");을 통한 쿼리 파라미터 한글 처리가 되지 않는다.
      UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseUrl).queryParam("query", encode(query));
    • 따라서 URI를 설정하면서 인코딩을 해주자.
    • .encode(Charset.forName("UTF-8"))

💡 결과값

3. WebClient 실습

❓ WebClient

  • 웹으로 API를 호출하기 위해 사용되는 HttpClient
  • RestTemplate은 Multi-Thread와 Blocking 방식으로 동작하는 반면, WebClient는 Single-Thread와 Non-Blocking 방식으로 동작
    • Multi-Thread & Blocking : 1요청 당 1스레드가 할당되고 응답이 올 때까지 그 스레드는 다른 요청에 할당되지 않는다.
    • Single-Thread & Non-Blocking : 각 요청은 Event Loop에 Job으로 등록되고 Event Loop는 각 Job을 제공자에게 요청한 후, 결과를 기다리지 않고 다른 Job을 처리할 수 있다. 제공자로부터 Callback 응답이 오면 그 결과를 요청자에게 제공한다.
  • 이벤트에 대해서 반응형으로 설계되어 있다.

🔌 코드

@GetMapping("/web-client")
public JSONObject webClient(@RequestHeader("Authorization") String auth,
                            @RequestParam("query") String query) throws ParseException {
    String response = WebClient.create()
            .get() // GET 방식
            .uri(getUri(query)) // URI 설정
            .header(header, auth) // 헤더 설정
            .retrieve()
            .bodyToMono(String.class)
            .block();
    return stringToJson(response);
}
  • build.gradle에 dependency 추가
  • implementation 'org.springframework.boot:spring-boot-starter-webflux'
  • 1개의 값을 리턴할 때는 bodyToMono, 복수의 값을 리턴할 때는 bodyToFlux를 사용
    • String으로 변환하기 위해서는 bodyToMono를 사용하고, .block(); 처리를 해줘야 한다.

💡 결과값


전체 코드

import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;

@RestController
public class TestController {

    private String baseUrl = "https://dapi.kakao.com/v2/local/search/keyword.JSON";
    private String header = "Authorization";

    @GetMapping("/http-url-connection")
    public JSONObject httpUrlConnection(@RequestHeader("Authorization") String auth,
                                        @RequestParam("query") String query) throws IOException, ParseException {
        // URL 객체 생성
        URL url = new URL(baseUrl + "?query=" + encode(query));

        // connection 생성
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        StringBuilder sb = new StringBuilder();
        if (conn != null) {
            conn.setConnectTimeout(10000); // 10초 동안 기다린 후 응답이 없으면 종료
            conn.setRequestMethod("GET"); // Http 메서드 설정
            conn.setRequestProperty(header, auth); // Http 헤더 설정
            conn.setDoInput(true);
            conn.setDoOutput(true);

            int resCode = conn.getResponseCode(); // 요청 전송
            if (resCode == HttpURLConnection.HTTP_OK) {
                BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));

                String line;
                while (true) {
                    line = reader.readLine();
                    if (line == null)
                        break;
                    sb.append(line);
                }
                reader.close();
            }
            conn.disconnect();
        }

        // json 변환 후 반환
        return stringToJson(sb.toString());
    }

    @GetMapping("/rest-template")
    public JSONObject restTemplate(@RequestHeader("Authorization") String auth,
                                   @RequestParam("query") String query) throws UnsupportedEncodingException, ParseException {
        // RestTemplate 객체 생성
        RestTemplate restTemplate = new RestTemplate();

        // HttpHeader 설정
        HttpHeaders headers = new HttpHeaders();
        headers.add(header, auth);

        // HttpEntity 생성
        HttpEntity entity = new HttpEntity<>(headers);

        // API 호출
        ResponseEntity response = restTemplate.exchange(
                getUri(query),
                HttpMethod.GET,
                entity,
                String.class);

        // json 변환 후 반환
        return stringToJson(response.getBody().toString());
    }

    @GetMapping("/web-client")
    public JSONObject webClient(@RequestHeader("Authorization") String auth,
                                @RequestParam("query") String query) throws ParseException {
        String response = WebClient.create()
                .get() // GET 방식
                .uri(getUri(query)) // URI 설정
                .header(header, auth) // 헤더 설정
                .retrieve()
                .bodyToMono(String.class)
                .block();
        return stringToJson(response);
    }

    private String encode(String str) throws UnsupportedEncodingException {
        return URLEncoder.encode(str, "UTF-8");
    }

    private URI getUri(String query) {
        return UriComponentsBuilder.fromHttpUrl(baseUrl)
                .queryParam("query", query)
                .encode(Charset.forName("UTF-8"))
                .encode()
                .build()
                .toUri();
    }

    private JSONObject stringToJson(String str) throws ParseException {
        JSONParser parser = new JSONParser();
        JSONObject jsonObject = (JSONObject) parser.parse(str);
        return jsonObject;
    }
}