HttpEntity 는 Spring Framework에서 HTTP 요청 또는 응답을 표현하기 위한 객체입니다. 주로 요청 헤더, 본문(body), 상태 정보 등을 다루기 위해 사용됩니다. HttpEntity 클래스는 HTTP 메시지를 추상화하며, 제네릭 타입으로 본문 데이터의 타입을 정의할 수 있습니다.
헤더(Header)
HTTP 요청이나 응답에 포함될 헤더 정보를 설정할 수 있습니다.
예: Content-Type, Authorization 등
본문(Body)
요청 또는 응답에 포함될 데이터를 설정할 수 있습니다.
JSON, XML, String, 객체 등 다양한 형식의 데이터를 지원합니다.
Immutable(불변성)
HttpEntity 객체는 기본적으로 불변(immutable)입니다. 생성 시 설정된 값을 변경할 수 없습니다.
HttpEntity는 두 가지 주요 생성자를 제공합니다:
HttpEntity() : 빈 헤더와 본문으로 객체를 생성합니다.
HttpEntity(T body, HttpHeaders headers)
본문과 헤더를 지정하여 객체를 생성합니다.
HttpEntity는 요청/응답의 헤더와 본문을 캡슐화합니다.
RequestEntity와 ResponseEntity로 구체화되어 HTTP 요청 및 응답에 활용됩니다.
RestTemplate 또는 WebClient와 함께 사용하면 HTTP 클라이언트 통신을 간단하게 처리할 수 있습니다.
RequestEntity
HTTP 요청을 표현하기 위해 사용되며, HTTP 메서드(GET, POST 등)와 URL을 추가로 지정할 수 있습니다.
ResponseEntity
HTTP 응답을 표현하기 위해 사용되며, 상태 코드와 헤더, 본문을 포함합니다.
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
String jsonBody = "{\"name\":\"John\", \"age\":30}";
HttpEntity<String> requestEntity = new HttpEntity<>(jsonBody, headers);
ResponseEntity<String> response = restTemplate.exchange(
"https://example.com/api",
HttpMethod.POST,
requestEntity,
String.class
);
System.out.println(response.getBody());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
String responseBody = "{\"status\":\"success\"}";
ResponseEntity<String> responseEntity = new ResponseEntity<>(responseBody, headers, HttpStatus.OK);
return responseEntity;
Spring Framework에서 HTTP 요청/응답 처리를 위한 주요 클래스는 RestTemplate와 WebClient입니다. 두 클래스 모두 외부 API와의 통신을 쉽게 처리할 수 있도록 지원하지만, 사용 목적과 구조가 다릅니다.
1. RestTemplate
RestTemplate은 동기 방식의 HTTP 클라이언트입니다.
특징: 요청이 완료될 때까지 호출이 블로킹됩니다.
사용 사례: 간단한 HTTP 요청/응답 처리에 적합하며, 레거시 코드에서 많이 사용됩니다.
상태: Spring 5 이후에는 사용이 비추천(deprecated)되고, WebClient로 대체되는 추세입니다.
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
public class RestTemplateExample {
public static void main(String[] args) {
RestTemplate restTemplate = new RestTemplate();
// GET 요청
String url = "https://jsonplaceholder.typicode.com/posts/1";
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
System.out.println("Response: " + response.getBody());
// POST 요청
String postUrl = "https://jsonplaceholder.typicode.com/posts";
Post post = new Post("New Title", "This is the content.", 1);
ResponseEntity<Post> postResponse = restTemplate.postForEntity(postUrl, post, Post.class);
System.out.println("Created Post: " + postResponse.getBody());
}
@Getter //반드시 있어야 함 (Post 클래스 직렬화)
@Setter //반드시 있어야 함 (Post 클래스 직렬화)
static class Post {
private String title;
private String body;
private int userId;
// Constructors, getters, setters
public Post(String title, String body, int userId) {
this.title = title;
this.body = body;
this.userId = userId;
}
public Post() {} //반드시 기본 생성자가 있어야 함 (Post 클래스 직렬화)
@Override
public String toString() {
return "Post{" +
"title='" + title + '\'' +
", body='" + body + '\'' +
", userId=" + userId +
'}';
}
}
}
2. WebClient
WebClient는 Spring 5부터 제공된 비동기 방식의 HTTP 클라이언트입니다.
특징: 비동기/논블로킹 방식으로 동작하며, Reactive Streams를 기반으로 동시성과 성능이 뛰어납니다.
사용 사례: 고성능이 요구되거나 많은 병렬 요청을 처리해야 할 때 적합합니다.
추천: 최신 Spring 프로젝트에서는 RestTemplate 대신 사용이 권장됩니다.
Post 객체를 JSON으로 변환하려면 Jackson 라이브러리가 필요합니다. 아래 의존성을 추가해야 한다.
implementation 'com.fasterxml.jackson.core:jackson-databind'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
예제
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
public class WebClientExample {
public static void main(String[] args) {
WebClient webClient = WebClient.create();
// GET 요청
String getUrl = "https://jsonplaceholder.typicode.com/posts/1";
Mono<String> getResponse = webClient.get()
.uri(getUrl)
.retrieve()
.bodyToMono(String.class);
getResponse.subscribe(response -> System.out.println("GET Response: " + response));
// POST 요청
String postUrl = "https://jsonplaceholder.typicode.com/posts";
Post post = new Post("Reactive Title", "This is reactive content.", 1);
Mono<Post> postResponse = webClient.post()
.uri(postUrl)
.bodyValue(post)
.retrieve()
.bodyToMono(Post.class);
postResponse.subscribe(createdPost -> System.out.println("Created Post: " + createdPost));
}
@Getter //(Post 클래스 직렬화)
@Setter //(Post 클래스 직렬화)
static class Post {
private String title;
private String body;
private int userId;
// Constructors, getters, setters
public Post(String title, String body, int userId) {
this.title = title;
this.body = body;
this.userId = userId;
}
public Post() {} //(Post 클래스 직렬화)
@Override
public String toString() {
return "Post{" +
"title='" + title + '\'' +
", body='" + body + '\'' +
", userId=" + userId +
'}';
}
}
}
윗 코드를 적용하였지만 콘솔 결과창에는 아무 것도 출력이 되지 않았다

콘솔에 아무것도 출력되지 않는 이유는 WebClient의 비동기 처리 특성 때문일 가능성이 높습니다. WebClient는 비동기로 동작하므로 요청이 완료되기 전에 main 메서드가 종료될 수 있습니다.
이를 해결하려면 Mono 또는 Flux의 블로킹 방식을 사용하거나, 테스트 목적으로 적절한 동기화를 추가해야 합니다.
코드 수정
package com.cos.book.httptest;
import org.springframework.web.reactive.function.client.WebClient;
import lombok.Getter;
import lombok.Setter;
import reactor.core.publisher.Mono;
public class HttpTest {
public static void main(String[] args) {
WebClient webClient = WebClient.create();
// GET 요청
String getUrl = "https://jsonplaceholder.typicode.com/posts/1";
Mono<String> getResponse = webClient.get()
.uri(getUrl)
.retrieve()
.bodyToMono(String.class);
getResponse.subscribe(response -> System.out.println("GET Response: " + response));
// POST 요청
String postUrl = "https://jsonplaceholder.typicode.com/posts";
Post post = new Post("Reactive Title", "This is reactive content.", 1);
Post postResponse = webClient.post()
.uri(postUrl)
.bodyValue(post)
.retrieve()
.bodyToMono(Post.class)
.block();
System.out.println("Created Post: " + postResponse);
}
@Getter // (Post 클래스 직렬화)
@Setter//(Post 클래스 직렬화)
static class Post {
private String title;
private String body;
private int userId;
// Constructors, getters, setters
public Post(String title, String body, int userId) {
this.title = title;
this.body = body;
this.userId = userId;
}
public Post() {} //(Post 클래스 직렬화)
@Override
public String toString() {
return "Post{" +
"title='" + title + '\'' +
", body='" + body + '\'' +
", userId=" + userId +
'}';
}
}
}
수정 후 콘솔 창 결과가 출력되었음을 확인

추가 참고사항
블로킹 사용 주의: 실제 비동기 환경에서는 block()을 사용하는 것이 권장되지 않습니다. 하지만, 간단한 테스트나 콘솔 애플리케이션에서는 유용합니다.
subscribe() 사용: subscribe()를 사용하고 비동기 처리를 유지하려면 별도의 Thread.sleep() 또는 다른 방법으로 비동기 작업이 완료될 시간을 확보해야 합니다.
getResponse.subscribe(response -> System.out.println("GET Response: " + response));
Thread.sleep(2000); // 테스트 목적으로 추가
WebClient client = WebClient.create("https://api.example.com");
Mono<ResponseDTO> response = client.get()
.uri("/single-response")
.retrieve()
.bodyToMono(ResponseDTO.class);
response.subscribe(data -> {
System.out.println("응답 데이터: " + data);
});
WebClient client = WebClient.create("https://api.example.com");
Flux<ItemDTO> response = client.get()
.uri("/multi-response")
.retrieve()
.bodyToFlux(ItemDTO.class);
response.subscribe(item -> {
System.out.println("응답 데이터: " + item);
});
단일 값: 응답 데이터가 단일 객체라면 Mono를 사용합니다.
다중 값: 응답 데이터가 배열, 리스트, 또는 스트리밍 데이터라면 Flux를 사용합니다.
bodyToMono를 사용하면 단일 값을 처리하는 Mono를 반환합니다.
bodyToFlux를 사용하면 여러 값을 처리하는 Flux를 반환합니다.
따라서 상황에 따라 Mono나 Flux를 선택해서 사용하면 됩니다.