이번 프로젝트에서 로그인 쪽 보안 강화 한다고
ip검증하고 otp 추가하는 요구사항이 들어왔는데
ip검증할때 api 호출하는 서비스를 만들어야 했다!
참고하라는 소스는 자바 HttpURLConnection을 사용했고
소스를 보니깐 불필요한 코드들이 많은 것 같아서
스프링 라이브러리를 사용하려고 GPT한테 물어보니깐
RestTemplate(스프링3.0부터), webClient(스프링5.0부터)이 있었다.
지금 프로젝트는 5.0보다 낮은 버전에 스프링을 사용하고 있어서
RestTemplate을 사용해서 구현하고 있다.
그 김에 정리 할 겸 싸- 악 정리해본다.
HttpURLConnection
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class ApiCaller {
public static void main(String[] args) {
String urlString = "https://api.example.com/data"; // 호출할 API URL
String method = "GET"; // 요청 방법 (GET, POST 등)
String apiKey = "your_api_key"; // 필요한 경우 API 키
try {
// URL 객체 생성
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 요청 메서드 설정
conn.setRequestMethod(method);
conn.setRequestProperty("Content-Type", "application/json");
// 필요한 경우 API 키 헤더에 추가
conn.setRequestProperty("Authorization", "Bearer " + apiKey);
// POST 요청의 경우, 데이터를 전송하기 위해 출력 스트림 열기
if ("POST".equalsIgnoreCase(method)) {
conn.setDoOutput(true);
String jsonInputString = "{\"key\": \"value\"}"; // 전송할 JSON 데이터
try(OutputStream os = conn.getOutputStream()) {
byte[] input = jsonInputString.getBytes("utf-8");
os.write(input, 0, input.length);
}
}
// 응답 코드 확인
int responseCode = conn.getResponseCode();
System.out.println("Response Code: " + responseCode);
// 응답 읽기
try(BufferedReader br = new BufferedReader(
new InputStreamReader(conn.getInputStream(), "utf-8"))) {
StringBuilder response = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
System.out.println("Response: " + response.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
- URL url = new URL(urlString);: 호출할 API의 URL을 설정합니다.
- conn.setRequestMethod(method);: HTTP 요청 방법을 설정합니다.
- conn.setRequestProperty("Content-Type", "application/json");: 요청 헤더를 설정합니다.
- conn.setRequestProperty("Authorization", "Bearer " + apiKey);: API 키를 헤더에 추가합니다 (필요한 경우).
- conn.setDoOutput(true);: POST 요청의 경우, 출력 스트림을 열어 데이터를 전송할 준비를 합니다.
- try(OutputStream os = conn.getOutputStream()) { ... }: 요청 본문 데이터를 전송합니다 (POST 요청의 경우).
- int responseCode = conn.getResponseCode();: 응답 코드를 확인합니다.
- try(BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"))) { ... }: 응답 데이터를 읽습니다.
실제 연결은 어느 시점에 되는걸까?
- 연결 (명시적):connect() 메서드를 호출하면 이 시점에서 서버와 연결이 설정됩니다. 그러나 이것은 선택사항이며, 보통 생략됩니다.
- conn.connect();
- 연결 (암시적): 만약 connect()를 명시적으로 호출하지 않더라도, 다음 메서드들이 호출되는 시점에 자동으로 연결이 설정됩니다:
- conn.getInputStream()
- conn.getOutputStream()
- conn.getResponseCode()
- 연결 (명시적):connect() 메서드를 호출하면 이 시점에서 서버와 연결이 설정됩니다. 그러나 이것은 선택사항이며, 보통 생략됩니다.
-
java코드 복사conn.connect();
- 연결 (암시적): 만약 connect()를 명시적으로 호출하지 않더라도, 다음 메서드들이 호출되는 시점에 자동으로 연결이 설정됩니다:
- conn.getInputStream()
- conn.getOutputStream()
- conn.getResponseCode()
RestTemplate
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
public class ApiCaller {
public static void main(String[] args) {
String url = "https://api.example.com/data"; // 호출할 API URL
String method = "GET"; // 요청 방법 (GET, POST 등)
String apiKey = "your_api_key"; // 필요한 경우 API 키
// RestTemplate 객체 생성
RestTemplate restTemplate = new RestTemplate();
// 헤더 설정
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/json");
headers.set("Authorization", "Bearer " + apiKey);
// 요청 엔티티 생성 (헤더와 바디를 포함할 수 있음)
HttpEntity<String> entity = new HttpEntity<>(headers);
// 요청 실행
ResponseEntity<String> response = null;
if ("GET".equalsIgnoreCase(method)) {
response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
} else if ("POST".equalsIgnoreCase(method)) {
String jsonInputString = "{\"key\": \"value\"}"; // 전송할 JSON 데이터
HttpEntity<String> postEntity = new HttpEntity<>(jsonInputString, headers);
response = restTemplate.exchange(url, HttpMethod.POST, postEntity, String.class);
}
// 응답 출력
if (response != null) {
System.out.println("Response Code: " + response.getStatusCodeValue());
System.out.println("Response Body: " + response.getBody());
}
}
}
- RestTemplate restTemplate = new RestTemplate();: RestTemplate 객체를 생성합니다.
- HttpHeaders headers = new HttpHeaders();: 요청 헤더를 설정합니다.
- headers.set("Content-Type", "application/json");: 콘텐츠 타입을 JSON으로 설정합니다.
- headers.set("Authorization", "Bearer " + apiKey);: 필요한 경우 API 키를 헤더에 추가합니다.
- HttpEntity<String> entity = new HttpEntity<>(headers);: 요청 엔티티를 생성합니다.
- response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);: GET 요청을 실행합니다.
- String jsonInputString = "{\"key\": \"value\"}";: POST 요청의 경우 전송할 JSON 데이터를 설정합니다.
- HttpEntity<String> postEntity = new HttpEntity<>(jsonInputString, headers);: POST 요청을 위한 엔티티를 생성합니다.
- response = restTemplate.exchange(url, HttpMethod.POST, postEntity, String.class);: POST 요청을 실행합니다.
- response.getStatusCodeValue(), response.getBody(): 응답 코드를 확인하고 응답 본문을 출력합니다.
RestTemplate을 사용할 때 실제로 서버와의 연결이 이루어지는 시점은 exchange(), getForObject(), getForEntity(), postForObject(), postForEntity() 등 HTTP 요청을 수행하는 메서드가 호출되는 시점입니다. 이 메서드들이 호출되면 RestTemplate은 내부적으로 HTTP 연결을 설정하고, 요청을 전송하며, 응답을 받습니다.
WebClient
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
public class ApiCaller {
public static void main(String[] args) {
String url = "https://api.example.com/data"; // 호출할 API URL
String apiKey = "your_api_key"; // 필요한 경우 API 키
// WebClient 객체 생성
WebClient webClient = WebClient.builder()
.baseUrl(url)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + apiKey)
.build();
// GET 요청
Mono<String> getResponse = webClient.get()
.retrieve()
.bodyToMono(String.class);
// 응답 처리
getResponse.subscribe(response -> {
System.out.println("GET Response: " + response);
}, error -> {
System.err.println("Error: " + error.getMessage());
});
// POST 요청
String jsonInputString = "{\"key\": \"value\"}"; // 전송할 JSON 데이터
Mono<String> postResponse = webClient.post()
.bodyValue(jsonInputString)
.retrieve()
.bodyToMono(String.class);
// 응답 처리
postResponse.subscribe(response -> {
System.out.println("POST Response: " + response);
}, error -> {
System.err.println("Error: " + error.getMessage());
});
// 비동기 호출이 완료될 때까지 메인 스레드 대기
try {
Thread.sleep(5000); // 비동기 호출이 완료될 때까지 대기 (예제 용도)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
HttpURLConnection , RestTemplate , WebClient 비교
HttpURLConnection: 간단한 HTTP 요청을 보내거나, Spring과 같은 프레임워크를 사용하지 않는 경우.
RestTemplate: Spring 애플리케이션에서 동기식 REST 호출이 필요한 경우.
WebClient: Spring 애플리케이션에서 비동기 및 반응형 프로그래밍이 필요한 경우.
결론
- 단순한 HTTP 요청 또는 기본 자바 라이브러리를 사용해야 하는 경우에는 HttpURLConnection을 선택할 수 있습니다.
- 동기식 HTTP 요청이 필요한 Spring 애플리케이션에서는 RestTemplate을 사용할 수 있지만, 이는 이제 WebClient로 대체되고 있습니다.
- 비동기 및 반응형 프로그래밍이 필요한 경우, 특히 높은 성능과 비동기 처리 요구사항이 있는 경우에는 WebClient가 적합합니다.
반응형
'개발 > 자바' 카테고리의 다른 글
[Java] 엑셀 셀 병합 기능에서 for문과 람다식 비교해보기 (3) | 2024.07.24 |
---|---|
[JAVA] Login Error로직 Enum 사용기 (0) | 2024.06.21 |
[Java] 자바 Stack 영역 Stack Frame 구성 요소 (0) | 2024.05.23 |
[Java] Enum 부수기 👊 (0) | 2024.04.23 |
[JAVA] 정적 팩토리 메서드 패턴 너 뭔데..? (0) | 2024.04.03 |