
목차
12 서버 간 통신
ㄴ12.1 RestTemplate이란?
ㄴ12.1.1 RestTemplate의 동작원리
ㄴ12.1.2 RestTemplate의 대표적인 메서드
ㄴ12.2 RestTemplate 사용하기
ㄴ12.2.1 서버 프로젝트 생성하기
ㄴ12.2.2 RestTemplate 구현하기
ㄴ12.2.3 RestTemplate 커스텀 설정
ㄴ12.3 WebClient란?
ㄴ12.3.1 WebClient 구성
ㄴ12.4 WebClient 사용하기
ㄴ12.4.1 WebClient 구현
ㄴ12.5 정리
현재 개발되는 서비스들은 MSA(Micro Service Architecture)를 주로 채택하여 내가 만들고 있는 서비스가 요청을 받는 서버가 될 수 있고 다른 서비스로 요청을 할 수 있는 클라이언트가 되는 경우도 많다. 이럴 때 각 애플리케이션은 자신이 가진 API 기능을 외부에 노출하고, 다른 서버에서 그렇게 노출된 API를 호출해서 사용하게 된다.
이렇게 다른 서버로 웹 요청을 보내고 응답을 받을 수 있게 도와주는 것들이 Client 라이브러리 or Rest Client라고 불리운다.
그 종류로는 RestTemplate, WebClient, 현재는 HTTP interface 등이 나와있다.
- RestTemplate
- Spring 3부터 지원, REST API 호출이후 응답을 받을 때까지 기다리는 동기 방식
- AsyncRestTemplate
- Spring 4에 추가된 비동기 RestTemplate
- WebClient
- Spring 5에 추가된 논블럭, 리엑티브 웹 클라이언트로 동기, 비동기 방식을 지원
현재 RestTemplate는 완전히 deprecated된 상태라고 볼 순 없으나 WebClient를 더 지향하라고 하는 추세긴 하나,
각 현업에서 사용하는 것을 잘 숙지하고 사용하면 될 듯하다.
12.1 RestTemplate이란?
RestTemplate 특징
- HTTP 프로토콜의 메서드에 맞는 여러 메서드를 제공
- RESTful 형식을 갖춘 템플릿
- HTTP 요청 후, JSON, XML, 문자열 등의 다양한 형식으로 응답 받을 수 있음
- 블로킹(blocking), I/O 기반의 동기 방식 사용
- 다른 API를 호출할 때 HTTP 헤더에 다양한 값을 설정할 수 있음
RestTemplate의 동작 원리

- 애플리케이션에서 RestTemplate 선언 한 후 URI, HTTP 메서드, Body를 설정한뒤 외부 API로 요청보냄
- RestTemplate에서 HttpMessageConverter를 통해 RequestEntity를 요청 메시지로 변환함
- 변환된 요청 메세지를 ClientHttpRequestFactory를 통해 ClientHttpRequest로 가져온 후 외부 API로 요청을 보냄.
- 외부에서 요청에 대한 응답을 받으면 ResponseErrorHandler로 오류를 확인하고 오류가 있다면 ClientHttpResponse에서 응답 데이터를 처리함
- 응답데이터에 오류가 없다면 HttpMessageConverter를 거쳐 자바 객체로 변환한 후 애플리케이션으로 반환한다.
RestTemplate의 대표적인 메서드
Method | HTTP Method | Return Type | 설명 |
getForObject() | GET | Object | GET 요청에 대한 결과를 객체로 반환합니다 |
getForEntity() | GET | ResponseEntity | GET 요청에 대한 결과를 ResponseEntity로 반환합니다 |
postForLocation() | POST | URI | POST 요청에 대한 결과로 헤더에 저장된 URI 반환합니다 |
postForObject() | POST | Object | POST 요청에 대한 결과를 객체로 반환합니다 |
postForEntity() | POST | ResponseEntity | POST 요청에 대한 결과를 ResponseEntity로 반환합니다 |
put() | PUT | void | PUT 요청을 실행합니다 |
patchForObject() | PATCH | Object | PATCH 요청을 실행하고 결과를 객체로 반환합니다 |
delete() | DELETE | void | DELETE 요청을 실행합니다 |
headForHeaders() | HEADER | HttpHeaders | 헤더 정보를 추출하고 HTTP HEAD 메서드를 사용합니다 |
optionsForAllow() | OPTIONS | Set<HttpMethod> | 지원되는 HTTP 메서드를 추출합니다 |
exchange() | any | ResponseEntity | 헤더를 생성하고 모든 요청 방법을 허용합니다 |
execute() | any | T | 요청/응답 콜백을 수정합니다 |
12.2 RestTemplate 사용하기
의존성 추가
build.gradle
implementation 'org.springframework.boot:spring-boot-starter-web'
실습을 할 때에는 한 컴퓨터에 프로젝트 2개를 가동시켜야하기 때문에 한 프로젝트의 톰캣 포트를 변경해야한다.
serer.port=9090
컨트롤러
> PUT, DELETE는 GET, POST 형식과 구성방식이 같으므로 생략했으며 GET, POST 메서드만 구현함.
@RestController
@RequestMapping("/api/v1/crud-api")
public class CrudController {
@GetMapping
public String getName(){
return "Flature";
}
@GetMapping(value = "/{variable}")
public String getVariable(@PathVariable String variable){
return variable;
}
@GetMapping("/param")
public String getNameWithParam(@RequestParam String name){
return "Hello. " + name + "!";
}
@PostMapping
public ResponseEntity<MemberDto> getMember(
@RequestBody MemberDto request,
@RequestParam String name,
@RequestParam String email,
@RequestParam String organization
){
System.out.println(request.getName());
System.out.println(request.getEmail());
System.out.println(request.getOrganization());
MemberDto memberDto = new MemberDto();
memberDto.setName(name);
memberDto.setEmail(email);
memberDto.setOrganization(organization);
return ResponseEntity.status(HttpStatus.OK).body(memberDto);
}
@PostMapping(value = "/add-header")
public ResponseEntity<MemberDto> addHeader(@RequestHeader("my-header") String header,
@RequestBody MemberDto memberDto){
System.out.println(header);
return ResponseEntity.status(HttpStatus.OK).body(memberDto);
}
}
MemberDto
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
public class MemberDto {
private String name;
private String email;
private String organization;
@Override
public String toString() {
return "MemberDto{" +
"name='" + name + '\'' +
", email='" + email + '\'' +
", organization='" + organization + '\'' +
'}';
}
}
RestTemplate 구현하기

일반적으로 RestTemplate은 별도의 유틸리티 클래스로 생성하거나, 서비스 또는 비지니스 계층에 구현된다.
앞서 생성한 서버 프로젝트에 요청을 날리기 위해 서버의 역할을 수행하면서 다른 서버로 요청하는 클라이언트 역할도 수행 할 수 있는 새로운 프로젝트를 생성한다.
- 클라이언트로부터 요청을 받는 컨트롤러
- RestTemplate을 활용해 다른 서버에 통신 요청을 하는 서비스
이 두가지 계층을 작성한다.
GET형식의 RestTemplate
@Service
public class RestTemplateService {
public String getName(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api")
.encode()
.build()
.toUri();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
return responseEntity.getBody();
}
public String getNameWithPathVariable(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api/{name}")
.encode()
.build()
.expand("Flature") // 복수의 값을 넣어야 할 경우 ,를 추가하여 구분
.toUri();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
return responseEntity.getBody();
}
public String getNameWithParameter(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api/param")
.queryParam("name", "Flature")
.encode()
.build()
.toUri();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
return responseEntity.getBody();
}
}
POST 형식의 RestTemplate 작성
@Service
public class RestTemplateService {
//
public ResponseEntity<MemberDto> postwithParamAndBody(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api")
.queryParam("name", "Flature")
.queryParam("email", "flature@wikibooks.co.kr")
.queryParam("organization", "WikiBooks")
.encode()
.build()
.toUri();
MemberDto memberDto = new MemberDto();
memberDto.setName("flature!!");
memberDto.setEmail("flature@gmail.com");
memberDto.setOrganization("Around Hub Studio");
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<MemberDto> responseEntity = restTemplate.postForEntity(
uri, memberDto, MemberDto.class
);
return responseEntity;
}
public ResponseEntity<MemberDto> postWithHeader(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api/add-header")
.encode()
.build()
.toUri();
MemberDto memberDto = new MemberDto();
memberDto.setName("flature");
memberDto.setEmail("flature@wikibooks.co.kr");
memberDto.setOrganization("Around Hub Studio");
RequestEntity<MemberDto> requestEntity = RequestEntity
.post(uri)
.header("my-header", "wikibooks API")
.body(memberDto);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<MemberDto> responseEntity = restTemplate.exchange(
requestEntity, MemberDto.class
);
return responseEntity;
}
}
API 호출을 쉽게 사용하기 위해 Swagger를 설정한다.
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {
@Bean
public Docket api(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.springboot.rest"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title("Spring Boot Open API Test with Swagger")
.description("설명 부분")
.version("1.0.0")
.build();
}
}
클라이언트로부터 요청 받고 위의 서비스 코드를 연결하는 컨트롤러 코드 예제 >
@RestController
@RequestMapping("/rest-template")
public class RestTemplateController {
private final RestTemplateService restTemplateService;
public RestTemplateController(RestTemplateService restTemplateService){
this.restTemplateService = restTemplateService;
}
@GetMapping
public String getName(){
return restTemplateService.getName();
}
@GetMapping("/path-variable")
public String getNameWithPathVariable(){
return restTemplateService.getNameWithPathVariable();
}
@GetMapping("/parameter")
public String getNameWithParameter(){
return restTemplateService.getNameWithParameter();
}
@PostMapping
public ResponseEntity<MemberDto> postDto(){
return restTemplateService.postWithParamAndBody();
}
@PostMapping("/header")
public ResponseEntity<MemberDto> postWithHeader(){
return restTemplateService.postWithHeader();
}
}
RestTemplate도 커스텀 설정이 가능한데 보통 아파치에서 제공하는 HttpClient로 대체해서 사용하는 방식을 사용한다.
HttpClient를 사용하기 위해 의존성을 추가해야한다.
12.3 WebClient란?
WebClient 특징
- 논블로킹(Non-blocking), I/O 기반의 동기 방식 사용
- 리액티브 스트림(Reactive Streams)의 백 프레셔(Back Pressure)를 지원
- 적은 하드웨어 리소스로 동시성을 지원
- 함수형 AI를 지원
- 동기, 비동기 상호작용을 지원
- 스트리밍을 지원
WebClient를 사용하기 위해서는 WebFlux 모듈에 대한 의존성을 추가해야한다.
의존성 추가
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependecy>
</dependencies>
12.4 WebClient 사용하기
WebClient를 생성하는 방법
- create() 메서드를 이용한 생성
- builcer()를 이용한 생성
WebClient를 활용한 GET 요청 ex>
@Service
public class WebClientService {
public String getName() {
WebClient webClient = WebClient.builder()
.baseUrl("http://localhost:9090")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
return webClient.get()
.uri("/api/v1/crud-api")
.retrieve()
.bodyToMono(String.class)
.block();
}
public String getNameWithPathVariable(){
WebClient webClient = WebClient.create("http://localhost:9090");
ResponseEntity<String> responseEntity = webClient.get()
.uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api/{name}")
.build("Flature"))
.retrieve().toEntity(String.class).block();
return responseEntity.getBody();
}
public String getNameWithParameter(){
WebClient webClient = WebClient.create("http://localhost:9090");
return webClient.get().uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api")
.queryParam("name", "Flature")
.build())
.exchangeToMono(clientResponse -> {
if(clientResponse.statusCode().equals(HttpStatus.OK)){
return clientResponse.bodyToMono(String.class);
} else{
return clientResponse.createException().flatMap(Mono::error);
}
})
.block();
}
}
WebClient를 활용한 POST요청 ex>
public ResponseEntity<MemberDto> postParamAndBody(){
WebClient webClient = WebClient.builder()
.baseUrl("http://localhost:9090")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
MemberDto memberDto = new MemberDto();
memberDto.setName("flature!!");
memberDto.setEmail("flature@gmail.com");
memberDto.setOrganization("Around Hub Studio");
return webClient.post().uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api")
.queryParam("name", "Flature")
.queryParam("email", "flature@wikibooks.co.kr")
.queryParam("organization", "Wikibooks")
.build())
.bodyValue(memberDto)
.retrieve()
.toEntity(MemberDto.class)
.block();
}
public ResponseEntity<MemberDto> postWithHeader(){
WebClient webClient = WebClient.builder()
.baseUrl("http://localhost:9090")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
MemberDto memberDto = new MemberDto();
memberDto.setName("flature!!");
memberDto.setEmail("flature@gmail.com");
memberDto.setOrganization("Around Hub Studio");
return webClient
.post()
.uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api/add-header")
.build())
.bodyValue(memberDto)
.header("my-header", "Wikibooks API")
.retrieve()
.toEntity(MemberDto.class)
.block();
}
자세한 WebClient의 사용법은 공식 문서에서 확인 가능
> https://docs.spring.io/spring-framework/reference/web/webflux-webclient.html
WebClient :: Spring Framework
Spring WebFlux includes a client to perform HTTP requests with. WebClient has a functional, fluent API based on Reactor, see Reactive Libraries, which enables declarative composition of asynchronous logic without the need to deal with threads or concurrenc
docs.spring.io
'BookStudy > 스프링 부트 핵심 가이드' 카테고리의 다른 글
스프링 부트 핵심 가이드 13. 서비스의 인증과 권한 부여 (1) | 2023.10.15 |
---|---|
[스프링 부트 핵심 가이드] 11 액추에이터 활용하기 (1) | 2023.10.08 |
[스프링 부트 핵심 가이드] 10 유효성 검사와 예외 처리 (0) | 2023.10.01 |
[스프링 부트 핵심 가이드] 09 연관관계 매핑 (0) | 2023.09.23 |
[스프링 부트 핵심 가이드] 08. Spring Data JPA 활용 (0) | 2023.09.17 |

목차
12 서버 간 통신
ㄴ12.1 RestTemplate이란?
ㄴ12.1.1 RestTemplate의 동작원리
ㄴ12.1.2 RestTemplate의 대표적인 메서드
ㄴ12.2 RestTemplate 사용하기
ㄴ12.2.1 서버 프로젝트 생성하기
ㄴ12.2.2 RestTemplate 구현하기
ㄴ12.2.3 RestTemplate 커스텀 설정
ㄴ12.3 WebClient란?
ㄴ12.3.1 WebClient 구성
ㄴ12.4 WebClient 사용하기
ㄴ12.4.1 WebClient 구현
ㄴ12.5 정리
현재 개발되는 서비스들은 MSA(Micro Service Architecture)를 주로 채택하여 내가 만들고 있는 서비스가 요청을 받는 서버가 될 수 있고 다른 서비스로 요청을 할 수 있는 클라이언트가 되는 경우도 많다. 이럴 때 각 애플리케이션은 자신이 가진 API 기능을 외부에 노출하고, 다른 서버에서 그렇게 노출된 API를 호출해서 사용하게 된다.
이렇게 다른 서버로 웹 요청을 보내고 응답을 받을 수 있게 도와주는 것들이 Client 라이브러리 or Rest Client라고 불리운다.
그 종류로는 RestTemplate, WebClient, 현재는 HTTP interface 등이 나와있다.
- RestTemplate
- Spring 3부터 지원, REST API 호출이후 응답을 받을 때까지 기다리는 동기 방식
- AsyncRestTemplate
- Spring 4에 추가된 비동기 RestTemplate
- WebClient
- Spring 5에 추가된 논블럭, 리엑티브 웹 클라이언트로 동기, 비동기 방식을 지원
현재 RestTemplate는 완전히 deprecated된 상태라고 볼 순 없으나 WebClient를 더 지향하라고 하는 추세긴 하나,
각 현업에서 사용하는 것을 잘 숙지하고 사용하면 될 듯하다.
12.1 RestTemplate이란?
RestTemplate 특징
- HTTP 프로토콜의 메서드에 맞는 여러 메서드를 제공
- RESTful 형식을 갖춘 템플릿
- HTTP 요청 후, JSON, XML, 문자열 등의 다양한 형식으로 응답 받을 수 있음
- 블로킹(blocking), I/O 기반의 동기 방식 사용
- 다른 API를 호출할 때 HTTP 헤더에 다양한 값을 설정할 수 있음
RestTemplate의 동작 원리

- 애플리케이션에서 RestTemplate 선언 한 후 URI, HTTP 메서드, Body를 설정한뒤 외부 API로 요청보냄
- RestTemplate에서 HttpMessageConverter를 통해 RequestEntity를 요청 메시지로 변환함
- 변환된 요청 메세지를 ClientHttpRequestFactory를 통해 ClientHttpRequest로 가져온 후 외부 API로 요청을 보냄.
- 외부에서 요청에 대한 응답을 받으면 ResponseErrorHandler로 오류를 확인하고 오류가 있다면 ClientHttpResponse에서 응답 데이터를 처리함
- 응답데이터에 오류가 없다면 HttpMessageConverter를 거쳐 자바 객체로 변환한 후 애플리케이션으로 반환한다.
RestTemplate의 대표적인 메서드
Method | HTTP Method | Return Type | 설명 |
getForObject() | GET | Object | GET 요청에 대한 결과를 객체로 반환합니다 |
getForEntity() | GET | ResponseEntity | GET 요청에 대한 결과를 ResponseEntity로 반환합니다 |
postForLocation() | POST | URI | POST 요청에 대한 결과로 헤더에 저장된 URI 반환합니다 |
postForObject() | POST | Object | POST 요청에 대한 결과를 객체로 반환합니다 |
postForEntity() | POST | ResponseEntity | POST 요청에 대한 결과를 ResponseEntity로 반환합니다 |
put() | PUT | void | PUT 요청을 실행합니다 |
patchForObject() | PATCH | Object | PATCH 요청을 실행하고 결과를 객체로 반환합니다 |
delete() | DELETE | void | DELETE 요청을 실행합니다 |
headForHeaders() | HEADER | HttpHeaders | 헤더 정보를 추출하고 HTTP HEAD 메서드를 사용합니다 |
optionsForAllow() | OPTIONS | Set<HttpMethod> | 지원되는 HTTP 메서드를 추출합니다 |
exchange() | any | ResponseEntity | 헤더를 생성하고 모든 요청 방법을 허용합니다 |
execute() | any | T | 요청/응답 콜백을 수정합니다 |
12.2 RestTemplate 사용하기
의존성 추가
build.gradle
implementation 'org.springframework.boot:spring-boot-starter-web'
실습을 할 때에는 한 컴퓨터에 프로젝트 2개를 가동시켜야하기 때문에 한 프로젝트의 톰캣 포트를 변경해야한다.
serer.port=9090
컨트롤러
> PUT, DELETE는 GET, POST 형식과 구성방식이 같으므로 생략했으며 GET, POST 메서드만 구현함.
@RestController
@RequestMapping("/api/v1/crud-api")
public class CrudController {
@GetMapping
public String getName(){
return "Flature";
}
@GetMapping(value = "/{variable}")
public String getVariable(@PathVariable String variable){
return variable;
}
@GetMapping("/param")
public String getNameWithParam(@RequestParam String name){
return "Hello. " + name + "!";
}
@PostMapping
public ResponseEntity<MemberDto> getMember(
@RequestBody MemberDto request,
@RequestParam String name,
@RequestParam String email,
@RequestParam String organization
){
System.out.println(request.getName());
System.out.println(request.getEmail());
System.out.println(request.getOrganization());
MemberDto memberDto = new MemberDto();
memberDto.setName(name);
memberDto.setEmail(email);
memberDto.setOrganization(organization);
return ResponseEntity.status(HttpStatus.OK).body(memberDto);
}
@PostMapping(value = "/add-header")
public ResponseEntity<MemberDto> addHeader(@RequestHeader("my-header") String header,
@RequestBody MemberDto memberDto){
System.out.println(header);
return ResponseEntity.status(HttpStatus.OK).body(memberDto);
}
}
MemberDto
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
public class MemberDto {
private String name;
private String email;
private String organization;
@Override
public String toString() {
return "MemberDto{" +
"name='" + name + '\'' +
", email='" + email + '\'' +
", organization='" + organization + '\'' +
'}';
}
}
RestTemplate 구현하기

일반적으로 RestTemplate은 별도의 유틸리티 클래스로 생성하거나, 서비스 또는 비지니스 계층에 구현된다.
앞서 생성한 서버 프로젝트에 요청을 날리기 위해 서버의 역할을 수행하면서 다른 서버로 요청하는 클라이언트 역할도 수행 할 수 있는 새로운 프로젝트를 생성한다.
- 클라이언트로부터 요청을 받는 컨트롤러
- RestTemplate을 활용해 다른 서버에 통신 요청을 하는 서비스
이 두가지 계층을 작성한다.
GET형식의 RestTemplate
@Service
public class RestTemplateService {
public String getName(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api")
.encode()
.build()
.toUri();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
return responseEntity.getBody();
}
public String getNameWithPathVariable(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api/{name}")
.encode()
.build()
.expand("Flature") // 복수의 값을 넣어야 할 경우 ,를 추가하여 구분
.toUri();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
return responseEntity.getBody();
}
public String getNameWithParameter(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api/param")
.queryParam("name", "Flature")
.encode()
.build()
.toUri();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
return responseEntity.getBody();
}
}
POST 형식의 RestTemplate 작성
@Service
public class RestTemplateService {
//
public ResponseEntity<MemberDto> postwithParamAndBody(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api")
.queryParam("name", "Flature")
.queryParam("email", "flature@wikibooks.co.kr")
.queryParam("organization", "WikiBooks")
.encode()
.build()
.toUri();
MemberDto memberDto = new MemberDto();
memberDto.setName("flature!!");
memberDto.setEmail("flature@gmail.com");
memberDto.setOrganization("Around Hub Studio");
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<MemberDto> responseEntity = restTemplate.postForEntity(
uri, memberDto, MemberDto.class
);
return responseEntity;
}
public ResponseEntity<MemberDto> postWithHeader(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api/add-header")
.encode()
.build()
.toUri();
MemberDto memberDto = new MemberDto();
memberDto.setName("flature");
memberDto.setEmail("flature@wikibooks.co.kr");
memberDto.setOrganization("Around Hub Studio");
RequestEntity<MemberDto> requestEntity = RequestEntity
.post(uri)
.header("my-header", "wikibooks API")
.body(memberDto);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<MemberDto> responseEntity = restTemplate.exchange(
requestEntity, MemberDto.class
);
return responseEntity;
}
}
API 호출을 쉽게 사용하기 위해 Swagger를 설정한다.
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {
@Bean
public Docket api(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.springboot.rest"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title("Spring Boot Open API Test with Swagger")
.description("설명 부분")
.version("1.0.0")
.build();
}
}
클라이언트로부터 요청 받고 위의 서비스 코드를 연결하는 컨트롤러 코드 예제 >
@RestController
@RequestMapping("/rest-template")
public class RestTemplateController {
private final RestTemplateService restTemplateService;
public RestTemplateController(RestTemplateService restTemplateService){
this.restTemplateService = restTemplateService;
}
@GetMapping
public String getName(){
return restTemplateService.getName();
}
@GetMapping("/path-variable")
public String getNameWithPathVariable(){
return restTemplateService.getNameWithPathVariable();
}
@GetMapping("/parameter")
public String getNameWithParameter(){
return restTemplateService.getNameWithParameter();
}
@PostMapping
public ResponseEntity<MemberDto> postDto(){
return restTemplateService.postWithParamAndBody();
}
@PostMapping("/header")
public ResponseEntity<MemberDto> postWithHeader(){
return restTemplateService.postWithHeader();
}
}
RestTemplate도 커스텀 설정이 가능한데 보통 아파치에서 제공하는 HttpClient로 대체해서 사용하는 방식을 사용한다.
HttpClient를 사용하기 위해 의존성을 추가해야한다.
12.3 WebClient란?
WebClient 특징
- 논블로킹(Non-blocking), I/O 기반의 동기 방식 사용
- 리액티브 스트림(Reactive Streams)의 백 프레셔(Back Pressure)를 지원
- 적은 하드웨어 리소스로 동시성을 지원
- 함수형 AI를 지원
- 동기, 비동기 상호작용을 지원
- 스트리밍을 지원
WebClient를 사용하기 위해서는 WebFlux 모듈에 대한 의존성을 추가해야한다.
의존성 추가
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependecy>
</dependencies>
12.4 WebClient 사용하기
WebClient를 생성하는 방법
- create() 메서드를 이용한 생성
- builcer()를 이용한 생성
WebClient를 활용한 GET 요청 ex>
@Service
public class WebClientService {
public String getName() {
WebClient webClient = WebClient.builder()
.baseUrl("http://localhost:9090")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
return webClient.get()
.uri("/api/v1/crud-api")
.retrieve()
.bodyToMono(String.class)
.block();
}
public String getNameWithPathVariable(){
WebClient webClient = WebClient.create("http://localhost:9090");
ResponseEntity<String> responseEntity = webClient.get()
.uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api/{name}")
.build("Flature"))
.retrieve().toEntity(String.class).block();
return responseEntity.getBody();
}
public String getNameWithParameter(){
WebClient webClient = WebClient.create("http://localhost:9090");
return webClient.get().uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api")
.queryParam("name", "Flature")
.build())
.exchangeToMono(clientResponse -> {
if(clientResponse.statusCode().equals(HttpStatus.OK)){
return clientResponse.bodyToMono(String.class);
} else{
return clientResponse.createException().flatMap(Mono::error);
}
})
.block();
}
}
WebClient를 활용한 POST요청 ex>
public ResponseEntity<MemberDto> postParamAndBody(){
WebClient webClient = WebClient.builder()
.baseUrl("http://localhost:9090")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
MemberDto memberDto = new MemberDto();
memberDto.setName("flature!!");
memberDto.setEmail("flature@gmail.com");
memberDto.setOrganization("Around Hub Studio");
return webClient.post().uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api")
.queryParam("name", "Flature")
.queryParam("email", "flature@wikibooks.co.kr")
.queryParam("organization", "Wikibooks")
.build())
.bodyValue(memberDto)
.retrieve()
.toEntity(MemberDto.class)
.block();
}
public ResponseEntity<MemberDto> postWithHeader(){
WebClient webClient = WebClient.builder()
.baseUrl("http://localhost:9090")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
MemberDto memberDto = new MemberDto();
memberDto.setName("flature!!");
memberDto.setEmail("flature@gmail.com");
memberDto.setOrganization("Around Hub Studio");
return webClient
.post()
.uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api/add-header")
.build())
.bodyValue(memberDto)
.header("my-header", "Wikibooks API")
.retrieve()
.toEntity(MemberDto.class)
.block();
}
자세한 WebClient의 사용법은 공식 문서에서 확인 가능
> https://docs.spring.io/spring-framework/reference/web/webflux-webclient.html
WebClient :: Spring Framework
Spring WebFlux includes a client to perform HTTP requests with. WebClient has a functional, fluent API based on Reactor, see Reactive Libraries, which enables declarative composition of asynchronous logic without the need to deal with threads or concurrenc
docs.spring.io
'BookStudy > 스프링 부트 핵심 가이드' 카테고리의 다른 글
스프링 부트 핵심 가이드 13. 서비스의 인증과 권한 부여 (1) | 2023.10.15 |
---|---|
[스프링 부트 핵심 가이드] 11 액추에이터 활용하기 (1) | 2023.10.08 |
[스프링 부트 핵심 가이드] 10 유효성 검사와 예외 처리 (0) | 2023.10.01 |
[스프링 부트 핵심 가이드] 09 연관관계 매핑 (0) | 2023.09.23 |
[스프링 부트 핵심 가이드] 08. Spring Data JPA 활용 (0) | 2023.09.17 |