예제 RestTemplate - getForEntity
서버 간의 통신을 위한 client 서버를 우선 만듭니다.
client 서버를 통해서 다른 서버와 http 통신을 하여 response를 받아옵니다.
package com.example.client.controller;
import com.example.client.dto.Req;
import com.example.client.dto.UserResponse;
import com.example.client.service.RestTemplateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/client")
public class ApiController {
@Autowired
private RestTemplateService restTemplateService;
public ApiController(RestTemplateService restTemplateService) {
this.restTemplateService = restTemplateService;
}
@GetMapping("/hello")
public UserResponse getHello() {
return restTemplateService.hello();
}
}
package com.example.client.service;
import com.example.client.dto.Req;
import com.example.client.dto.UserRequest;
import com.example.client.dto.UserResponse;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
@Service
public class RestTemplateService {
// http://localhost/api/server/hello
// response
public UserResponse hello() {
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/server/hello")
.queryParam("name", "steve")
.queryParam("age", 10)
.encode()
.build()
.toUri();
System.out.println(uri.toString());
RestTemplate restTemplate = new RestTemplate();
//String result = restTemplate.getForObject(uri, String.class);
ResponseEntity<UserResponse> result = restTemplate.getForEntity(uri, UserResponse.class);
System.out.println(result.getStatusCode());
System.out.println(result.getBody());
return result.getBody();
}
}
UriComponentsBuilder 라이브러리를 통해서 통신을 위한 uri를 만들어 줍니다.
fromUriString에는 도메인 주소를
path에는 url 경로를
queryParam에는 get으로 보낼 파라미터를 기술하면 됩니다.
파라미터가 여러개인 경우는 queryParam를 여러번 나열해서 기술하면 됩니다.
package com.example.server.controller;
import com.example.server.dto.Req;
import com.example.server.dto.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
@RestController
@RequestMapping("/api/server")
@Slf4j
public class ServerApiController {
@GetMapping("/hello")
public User hello(@RequestParam String name, @RequestParam int age) {
User user = new User();
user.setName(name);
user.setAge(age);
return user;
}
}
다른 프로젝트에서 서버간 통신을 위한 컨트롤러를 만듭니다.
client 서버에서 보낸 uri를 받을 수 있도록 get형식으로 만들고 파라미터들을 받아줍니다.
server 서버에서 return으로 response를 넘겨주면 client 서버에서 response를 받습니다.
clicnt 서버에서 RestTemplate 라이브러리로 인스턴스로 만든 부분에서 서버 간의 통신이 이루어집니다.
ResponseEntity<UserResponse> result = restTemplate.getForEntity(uri, UserResponse.class);
이 부분에서 서버간 request와 response가 모두 이루어지며, ResponseEntity<> 타입으로 response를 받게 됩니다.
RestTemplate 라이브러리에 대한 설명은 이전 글을 참고하시면 좋을 것 같습니다.
https://getthismoment.tistory.com/91
예제 RestTemplate - exchange
package com.example.client.controller;
import com.example.client.dto.Req;
import com.example.client.dto.UserResponse;
import com.example.client.service.RestTemplateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/client")
public class ApiController {
@Autowired
private RestTemplateService restTemplateService;
public ApiController(RestTemplateService restTemplateService) {
this.restTemplateService = restTemplateService;
}
@GetMapping("/genericExchange")
public Req<UserResponse> genericExchange() {
return restTemplateService.genericExchange();
}
}
package com.example.client.service;
import com.example.client.dto.Req;
import com.example.client.dto.UserRequest;
import com.example.client.dto.UserResponse;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
@Service
public class RestTemplateService {
public Req<UserResponse> genericExchange() {
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/server/user/{userId}/name/{userName}")
.encode()
.build()
.expand("100", "steve") // PathVariable 에 넣어줄 값을 이어서 넣어준다.
.toUri();
System.out.println(uri);
// http body -> object -> object mapper -> json -> rest template -> http body json
UserRequest userRequest = new UserRequest();
userRequest.setName("steve");
userRequest.setAge(10);
Req<UserRequest> req = new Req<>();
req.setHeader(
new Req.Header()
);
req.setHttpResponseBody(
userRequest
);
RequestEntity<Req<UserRequest>> requestEntity = RequestEntity
.post(uri)
.contentType(MediaType.APPLICATION_JSON)
.header("x-authorization", "abcd")
.header("custom-header", "fffff")
.body(req);
RestTemplate restTemplate = new RestTemplate();
// 이 부분에서 다른 서버에 요청을 주고 받는다.
ResponseEntity<Req<UserResponse>> response
= restTemplate.exchange(requestEntity, new ParameterizedTypeReference<Req<UserResponse>>(){}); // 제네릭은 class를 붙일 수 없기 때문에 ParameterizedTypeReference 객체를 이용한다.
return response.getBody();
}
}
RestTemplate 을 사용하되 getForEntity 예제와 달리 header에 값을 넣어서 보냅니다.
header에 값을 값을 넣기 위해서는 단순히 UriComponentsBuilder를 사용하여 uri를 만드는 것뿐만 아니라,
RequestEntity 를 사용하여 request 데이터를 만들어야합니다.
header를 담은 RequestEntity 를 ResponseEntity에 넘겨주어 서버간 통신을 하면, 통신한 서버에서 정상적으로 header 데이터를 읽을 수 있습니다.
요청 받은 서버의 코드는 다음과 같습니다.
package com.example.server.controller;
import com.example.server.dto.Req;
import com.example.server.dto.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
@RestController
@RequestMapping("/api/server")
@Slf4j
public class ServerApiController {
@PostMapping("/user/{userId}/name/{userName}")
public Req<User> post(
//HttpEntity<String> entity, client 가 무슨 파라미터를 보냈는지 알기위해 씀.
@RequestBody Req<User> user,
@PathVariable int userId,
@PathVariable String userName,
@RequestHeader("x-authorization") String authorization,
@RequestHeader("custom-header") String customHeader)
{
log.info("userId : {}, userName : {}", userId, userName);
log.info("authorization : {}, customHeader : {}", authorization, customHeader);
log.info("client req : {} ", user);
Req<User> response = new Req<>();
Req.Header header = new Req.Header();
header.setResponseCode(authorization);
response.setHeader(header);
response.setHttpResponseBody(user.getHttpResponseBody());
return response;
}
}
@RequestHeader 어노테이션으로 헤더 데이터를 받습니다.
response에 받은 헤더와 데이터를 그대로 전달합니다.
(별 다른 처리없이 서버 통신 확인용으로 데이터를 그대로 전달합니다.)
Req DTO 스키마는 다음과 같습니다.
package com.example.server.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Req<T> {
private Header header;
private T httpResponseBody;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Header {
private String responseCode = "555";
}
}
제네릭으로 파라미터를 받기 때문에 httpResponseBody 속성은 제네릭으로 받은 타입과 같은 속성을 같게 됩니다.
package com.example.server.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String name;
private int age;
}
response : <200 OK,
{
data={
status=400, message=required param strCd is null
},
totalCount=0,
responseCode=200,
responseMessage=success
},
{
Set-Cookie=[JSESSIONID=2D101087844E6F355A35F6248A428EA9; Path=/; HttpOnly],
Vary=[Origin, Access-Control-Request-Method, Access-Control-Request-Headers],
X-Content-Type-Options=[nosniff],
X-XSS-Protection=[1; mode=block],
Cache-Control=[no-cache,
no-store,
max-age=0, must-revalidate],
Pragma=[no-cache],
Expires=[0],
X-Frame-Options=[DENY],
Content-Type=[application/json;charset=UTF-8],
Transfer-Encoding=[chunked],
Date=[Thu, 27 Jul 2023 05:17:14 GMT],
Keep-Alive=[timeout=60],
Connection=[keep-alive]
}
>
'Spring Boot' 카테고리의 다른 글
Spring Boot - 정적 파일 경로 지정 (0) | 2021.11.05 |
---|---|
Spring Boot - Swagger (0) | 2021.10.01 |
Spring Boot - 서버 간 통신 RestTemplate 정의 (0) | 2021.09.25 |
Spring Boot - Interceptor (0) | 2021.09.23 |
Spring Boot - Exception 구현 예제 (0) | 2021.09.13 |
댓글