Part3 - CH7. REST Template(3) Header, exchange
REST Template (3)
Header
REST Template의 exchange메소드를 활용해보자.
이전 시간에는 Request를 보낼 때 dto와 objectMapper의 기능을 이용해 JSON만 보냈지만 이번 시간에는 RequestEntity를 사용하여 Header을 추가하는 방법에 대해 알아본다.
restTemplateService 클래스안에 exchange()메소드를 만든다.
public UserResponse exchange(){
//http://localhost:9091/api/server/user/{userId}/name/{userName}
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9091")
.path("/api/server/user/{userId}/name/{userName}")
.encode()
.buildAndExpand(100, "dboo") //userId, userName
// .build().expand() 따로 해줘도 무방
.toUri();
log.info(uri.toString());
// http body -> object -> object mapper -> JSON -> rest template -> http body json
UserRequest req = new UserRequest();
req.setName("dboo");
req.setAge(31);
RequestEntity<UserRequest> requestEntity = RequestEntity
.post(uri)
.contentType(MediaType.APPLICATION_JSON)
.header("x-authorization", "abcd")
.header("custom-header", "fffff")
.body(req);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<UserResponse> response = restTemplate.exchange(requestEntity, UserResponse.class);
return response.getBody();
}
그리고 클라이언트 컨트롤러에서 exchange()메소드를 타도록 해준다.
@PostMapping("/exchange")
public UserResponse exchangeHello(){
return restTemplateService.exchange();
}
요청에 들어온 헤더를 서버측에서 꺼내 읽어보자.
@PostMapping("/user/{userId}/name/{userName}")
public User post(@RequestBody User user,
@PathVariable int userId,
@PathVariable String userName,
@RequestHeader("x-authorization") String authorization,
@RequestHeader("custom-header") String customHeader){
log.info("Header => auth : {} , custom : {}", authorization, customHeader);
log.info("PathVariable => userId : {}, userName : {}", userId, userName);
log.info("client req => user객체 : {}", user);
return user;
}
현업에서의 JSON
현업에서 사용하는 JSON의 구조를 상정해보자.
{
"header" : {
},
"body" : {
}
}
위와 같은 형태로 내려오는데 매번 header와 body의 내용이 변한다고 생각해보자.
{
"header" : {
"response_code" : "OK"
},
"body" : {
"name" : "dboo",
"age" : 31,
"book" : "spring boot",
"page" : 1024
}
}
body에는 name,age 가 들어올 수도 있고 book, page가 들어올 수도 있다고 생각해보고
이러한 JSON을 받기 위한 구조를 디자인 해보자.
일단, 클라이언트에서 JSON을 보내기위한 dto를 만든다.
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Req<T> {
private Header header;
private T body; //제네릭 타입, 매번 내용이 바뀌기 때문에.
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Header{
private String responseCode;
}
}
body에는 어떤내용이 들어올지 모르기때문에 제네릭 타입으로 선언해준다.
서버측에도 동일한 dto를 만들어둔다.
이제 이 JSON을 서버로 보내기 위한 컨트롤러단과 서비스단을 수정해준다.
@RestController
@RequestMapping("/api/client")
@RequiredArgsConstructor
public class ApiController {
private final RestTemplateService restTemplateService;
@GetMapping("")
public UserResponse getHello(){
return restTemplateService.hello();
}
@PostMapping("")
public UserResponse postHello(){
return restTemplateService.post();
}
@PostMapping("/exchange")
public UserResponse exchangeHello(){
return restTemplateService.exchange();
}
@PostMapping("/genericExchange")
public Req<UserResponse> genericExchangeHello(){
return restTemplateService.genericExchange();
}
}
일단 genericExchange라는 메소드를 통해 동작하게하고, 서비스단에 genericExchange메소드를 생성한다.
public Req<UserResponse> genericExchange(){
//http://localhost:9091/api/server/user/{userId}/name/{userName}
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9091")
.path("/api/server/user/{userId}/name/{userName}")
.encode()
.buildAndExpand(100, "dboo") //userId, userName
// .build().expand() 따로 해줘도 무방
.toUri();
log.info(uri.toString());
// http body -> object -> object mapper -> JSON -> rest template -> http body json
UserRequest userRequest = new UserRequest();
userRequest.setName("dboo");
userRequest.setAge(31);
Req<UserRequest> req = new Req<UserRequest>();
req.setHeader(new Req.Header());
req.setBody(userRequest);
RequestEntity<Req<UserRequest>> requestEntity = RequestEntity
.post(uri)
.contentType(MediaType.APPLICATION_JSON)
.body(req);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<Req<UserResponse>> response
= restTemplate.exchange(requestEntity,
// Generic타입의 경우 타입클래스.class로 클래스타입지정할수 없기 때문에 ParameterizedTypeReference를 사용한다.
//new ParameterizedTypeReference<Req<UserResponse>>(){});
new ParameterizedTypeReference<>(){}); // returnType이 지정되어있기 때문에 생략가능
//return response.getBody().getBody();
// response.getBody() => Req , response.getBody().getBody() => Req안의 body인 UserResponse
return response.getBody();
}
이제 서버에서 generic타입 멤버변수를 포함하는 객체로 요청을 받아서 처리하는 컨트롤러를 추가해보자.
public Req<User> post(
// HttpEntity<String> entity,
@RequestBody Req<User> user,
@PathVariable int userId,
@PathVariable String userName,
@RequestHeader("x-authorization") String authorization,
@RequestHeader("custom-header") String customHeader){
// log.info("entity : {}", entity.getBody());
log.info("Header => auth : {} , custom : {}", authorization, customHeader);
log.info("PathVariable => userId : {}, userName : {}", userId, userName);
log.info("client req => user객체 : {}", user);
Req<User> response = new Req<>();
response.setHeader(new Req.Header());
response.setBody(user.getBody());
return response;
}
return을 할때에 Req
HttpEntity 의 경우 순수한 http엔티티가 들어온다. 주의할 점은 HttpEntity를 찍어보려면 RequestBody 부분을 주석처리하고 해야한다.