클라이언트에서
헤더를 넣어서 보내보자
<code />
package com.example.client.service;
import com.example.client.dto.UserRequest;
import com.example.client.dto.UserResponse;
import org.apache.catalina.User;
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","Hyerin")
.queryParam("age",26)
.encode()
.build()
.toUri();
System.out.println(uri.toString());
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<UserResponse> result = restTemplate.getForEntity(uri,UserResponse.class);
System.out.println(result.getStatusCode());
System.out.println(result.getBody());
return result.getBody();
}
public void post(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/server/user/{userId}/name/{userName}")
.encode()
.build()
.expand(100,"steve")
.toUri();
System.out.println(uri);
UserRequest req = new UserRequest();
req.setName("steve");
req.setAge(10);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.postForEntity(uri,req,String.class);
System.out.println(response.getStatusCode());
System.out.println(response.getHeaders());
System.out.println(response.getBody());
//return response.getBody(); 없애버렷
}
public UserResponse exchange(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/server/user/{userId}/name/{userName}")
.encode()
.build()
.expand(100,"steve")
.toUri();
System.out.println(uri);
UserRequest req = new UserRequest();
req.setName("steve");
req.setAge(10);
RequestEntity<UserRequest> requestEntity = RequestEntity
.post(uri) //post로 uri 넣을 것
.contentType(MediaType.APPLICATION_JSON) //미디어 타입은 json으로
.header("x-authorization","abcd") //header 내용
.header("custom-header","fffff") //계속해서 이렇게 값을 넣어도 된다
.body(req); //request body 내용 -> 위에서 만든 오브젝트 넣을 것임
RestTemplate restTemplate = new RestTemplate();
//호출하기
ResponseEntity<UserResponse> response = restTemplate.exchange(requestEntity,UserResponse.class); //헤더 싣고 보냄
return response.getBody();
}
}
<code />
public UserResponse exchange(){
메소드 추가됨
<code />
RequestEntity<UserRequest> requestEntity = RequestEntity
.post(uri) //post로 uri 넣을 것
.contentType(MediaType.APPLICATION_JSON) //미디어 타입은 json으로
.header("x-authorization","abcd") //header 내용
.header("custom-header","fffff") //계속해서 이렇게 값을 넣어도 된다
.body(req); //request body 내용 -> 위에서 만든 오브젝트 넣을 것임
requestEntity에 주소 넣고 헤더 넣고 바디 넣어서 보내기로 했다
이제는 서버에서 받을 준비를 하자
<code />
package com.example.server.controller;
import com.example.server.dto.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
@Slf4j
@RestController
@RequestMapping("/api/server")
public class ServerApiController {
@GetMapping("/hello")
public User hello(@RequestParam String name, @RequestParam int age){
User user = new User();
user.setAge(age); //echo 방식으로 동작할 것이기 때문에 age, name 넣자
user.setName(name);
return user;
}
//서버에서 헤더를 받을 준비를 하자~!
@PostMapping("/user/{userId}/name/{userName}") //변경되는 값을 변수로 매칭해주자 (아래 @PathVariable로)
public User post(@RequestBody User user,//@RequestBody로 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 : {}, custom : {}",authorization,customHeader);
log.info("client req : {}",user);
return user;
}
}
이제 클라이언트에서 서버로 값이 잘 넘어가는 지 확인해보자!
<code />
package com.example.client.controller;
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 {
private final RestTemplateService restTemplateService;
public ApiController(RestTemplateService restTemplateService) {
this.restTemplateService = restTemplateService;
}
@GetMapping("/hello")
public UserResponse getHello(){
restTemplateService.exchange();
return new UserResponse();
}
}


항상 위와 같은 json의 형태면 좋겠지만,

위와 같은 형식이고
바디의 내용이 계속 바뀐다면?
실무에서는 위와 같은 API를 많이 보게 될 것이다.
(헤더의 내용은 항상 같지만 바디의 내용이 계속 바뀌는 형태)
Client - Dto - Req.java
<java />
package com.example.client.dto;
public class Req<T> { //바디의 내용이 자꾸 바뀔 것이므로 제네릭 타입으로 받자
private Header header;
private T rBody;
public static class Header{
private String responseCode;
public String getResponseCode() { //Getter
return responseCode;
}
public void setResponseCode(String responseCode) { //Setter
this.responseCode = responseCode;
}
@Override
public String toString() {
return "Header{" +
"responseCode='" + responseCode + '\'' +
'}';
}
}
public Header getHeader() {
return header;
}
public void setHeader(Header header) {
this.header = header;
}
public T getrBody() {
return rBody;
}
public void setrBody(T rBody) {
this.rBody = rBody;
}
@Override
public String toString() {
return "Req{" +
"header=" + header +
", body=" + rBody +
'}';
}
}
서버에도 만들어주자
<code />
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 body;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Header{
private String responseCode;
}
}

위와 같은 형태로 호출하려면 어떻게 해야할까?
클라이언트
<code />
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","Hyerin")
.queryParam("age",26)
.encode()
.build()
.toUri();
System.out.println(uri.toString());
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<UserResponse> result = restTemplate.getForEntity(uri,UserResponse.class);
System.out.println(result.getStatusCode());
System.out.println(result.getBody());
return result.getBody();
}
public void post(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/server/user/{userId}/name/{userName}")
.encode()
.build()
.expand(100,"steve")
.toUri();
System.out.println(uri);
UserRequest req = new UserRequest();
req.setName("steve");
req.setAge(10);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.postForEntity(uri,req,String.class);
System.out.println(response.getStatusCode());
System.out.println(response.getHeaders());
System.out.println(response.getBody());
//return response.getBody(); 없애버렷
}
public UserResponse exchange(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/server/user/{userId}/name/{userName}")
.encode()
.build()
.expand(100,"steve")
.toUri();
System.out.println(uri);
UserRequest req = new UserRequest();
req.setName("steve");
req.setAge(10);
RequestEntity<UserRequest> requestEntity = RequestEntity
.post(uri) //post로 uri 넣을 것
.contentType(MediaType.APPLICATION_JSON) //미디어 타입은 json으로
.header("x-authorization","abcd") //header 내용
.header("custom-header","fffff") //계속해서 이렇게 값을 넣어도 된다
.body(req); //request body 내용 -> 위에서 만든 오브젝트 넣을 것임
RestTemplate restTemplate = new RestTemplate();
//호출하기
ResponseEntity<UserResponse> response = restTemplate.exchange(requestEntity,UserResponse.class); //헤더 싣고 보냄
return response.getBody();
}
//새로 만든 부분~!~!~!~!~!~!
public UserResponse genericExchange() {
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/server/user/{userId}/name/{userName}")
.encode()
.build()
.expand(100,"steve")
.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 클래스의 body는 제네릭 타입이기 때문에 <UserRequest>라고 지정
req.setHeader(new Req.Header());
req.setrBody(userRequest);
RequestEntity<Req<UserRequest>> requestEntity = RequestEntity //Req가 한 번 감싸는 것으로 한다
.post(uri) //post로 uri 넣을 것
.contentType(MediaType.APPLICATION_JSON) //미디어 타입은 json으로
.header("x-authorization","abcd") //header 내용
.header("custom-header","fffff") //계속해서 이렇게 값을 넣어도 된다
.body(req); //request body 내용 -> 위에서 만든 오브젝트 넣을 것임
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<Req<UserResponse>> response = restTemplate.exchange(requestEntity,new ParameterizedTypeReference<Req<UserResponse>>(){});
//requestEntity보낼 것이고, 우리가 원하는 응답은 Req<UserResponse>.class이지만 제네릭에는 class를 붙일 수 없다
//이것에 대응하기 위한 코드로 new ParameterizedTypeReference<Req<UserResponse>>(){}; 를 넣어주자
return response.getBody().getrBody();
//처음 getBody()는 ResponseEntity의 body를 가져온 것
//두 번째 getBody()는 그 안에 들어있는 Req<UserResponse>, Req 클래스에 지정해놓은 private T rBody
}
}
서버에서 받아보자
ServerApiController.java 수정
<java />
//서버에서 헤더를 받을 준비를 하자~!
@PostMapping("/user/{userId}/name/{userName}")
public Req<User> post(@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 : {}, custom : {}",authorization,customHeader);
log.info("client req : {}",user);
Req<User> response = new Req<>(); //response 만들어서
response.setHeader(
new Req.Header() //Header에 빈 값을 넣어준다
);
response.setBody(user.getBody()); //body에는 사용자가 보내왔던 user에서 getBody꺼내서
return response; //user라는 클래스를 echo로 내리겠다
}
클라이언트도 수정해주자
<java />
package com.example.client.controller;
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 {
private final RestTemplateService restTemplateService;
public ApiController(RestTemplateService restTemplateService) {
this.restTemplateService = restTemplateService;
}
@GetMapping("/hello")
public UserResponse getHello(){
restTemplateService.genericExchange(); <- 여기 수정
return new UserResponse();
}
}

조금 꼬였다며
갑자기 코드를 수정한다...
꼬인 부분이 있으면 동영상 부분을 좀 고치고 내보내면 좋을텐데 항상 아쉬운 부분이다
(이런 쓸데없는 부분들 때문에 동영상 길이가 30분 정도로 늘어난다ㅠ.ㅠ)
클라이언트의 RestTemplateService.java 수정
<code />
public Req<UserResponse> genericExchange() {
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/server/user/{userId}/name/{userName}")
.encode()
.build()
.expand(100,"steve")
.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 클래스의 body는 제네릭 타입이기 때문에 <UserRequest>라고 지정
req.setHeader(new Req.Header());
req.setrBody(userRequest);
RequestEntity<Req<UserRequest>> requestEntity = RequestEntity //Req가 한 번 감싸는 것으로 한다
.post(uri) //post로 uri 넣을 것
.contentType(MediaType.APPLICATION_JSON) //미디어 타입은 json으로
.header("x-authorization","abcd") //header 내용
.header("custom-header","fffff") //계속해서 이렇게 값을 넣어도 된다
.body(req); //request body 내용 -> 위에서 만든 오브젝트 넣을 것임
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<Req<UserResponse>> response = restTemplate.exchange(requestEntity,new ParameterizedTypeReference<Req<UserResponse>>(){});
//requestEntity보낼 것이고, 우리가 원하는 응답은 Req<UserResponse>.class이지만 제네릭에는 class를 붙일 수 없다
//이것에 대응하기 위한 코드로 new ParameterizedTypeReference<Req<UserResponse>>(){}; 를 넣어주자
return response.getBody();
//처음 getBody()는 ResponseEntity의 body를 가져온 것
//두 번째 getBody()는 그 안에 들어있는 Req<UserResponse>, Req 클래스에 지정해놓은 private T rBody
}
또 수정
<code />
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 {
private final RestTemplateService restTemplateService;
public ApiController(RestTemplateService restTemplateService) {
this.restTemplateService = restTemplateService;
}
@GetMapping("/hello")
public Req<UserResponse> getHello(){
return restTemplateService.genericExchange();
}
}
json 부분의 body 부분만 바뀌기 때문에
이것을 재사용하기 위해 만드는 것이니
코드가 좀 어려울 수 있다는데...
뭐가 어떻게 어려운 지 설명을 잘 안해준다
결과

rBody에 아무것도 안들어가있다?
에러 났다고 또 또 또 바꾼다
서버의
ServerApiController.java 변경
<code />
//서버에서 헤더를 받을 준비를 하자~!
@PostMapping("/user/{userId}/name/{userName}") //변경되는 값을 변수로 매칭해주자 (아래 @PathVariable로)
public Req<User> post(
HttpEntity<String> entity,
//@RequestBody Req<User> user,//사용자가 보내온 -> @RequestBody로 User를 받는다
@PathVariable int userId,
@PathVariable String userName,
@RequestHeader("x-authorization") String authorization, //괄호 안에 이름 매칭해준 것임
@RequestHeader("custom-header") String customHeader
){
log.info("req : {}",entity.getBody());
log.info("userId : {}, userName : {}",userId,userName);
log.info("authorization : {}, custom : {}",authorization,customHeader);
//log.info("client req : {}",user);
Req<User> response = new Req<>(); //response 만들어서
response.setHeader(
new Req.Header() //Header에 빈 값을 넣어준다
);
response.setBody(null); //body에는 사용자가 보내왔던 user에서 getBody꺼내서
return response; //user라는 클래스를 echo로 내리겠다
}

이제 매칭은 잘 되는데...

아무 값도 안들어가있는건 여-전
또 변경
<code />
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 rBody;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Header{
private String responseCode;
}
}
또 ServerApiController.java 변경
<java />
//서버에서 헤더를 받을 준비를 하자~!
@PostMapping("/user/{userId}/name/{userName}")
public Req<User> post(
HttpEntity<String> entity, //클라이언트가 내게 뭘 보내온지 모르겠다면, HttpEntity로
//@RequestBody Req<User> user,
@PathVariable int userId,
@PathVariable String userName,
@RequestHeader("x-authorization") String authorization,
@RequestHeader("custom-header") String customHeader
){
log.info("req : {}",entity.getBody()); //getBody를 해보면 된다
log.info("userId : {}, userName : {}",userId,userName);
log.info("authorization : {}, custom : {}",authorization,customHeader);
//log.info("client req : {}",user);
Req<User> response = new Req<>();
response.setHeader(
new Req.Header()
);
response.setRBody(response.getRBody()); <-여기 변경
return response;
}

또 null이다
강사님께선 본인이 오류를 해쳐나가는 과정을 우리에게 보여주고 싶으셨던 걸까
아니면 편집이 귀찮으셨던 걸까
"패스트캠퍼스 Spring 강의 후기" 검색어 유입 잔뜩 되기를...
오류가 나도 편집을 안하신다
<java />
//서버에서 헤더를 받을 준비를 하자~!
@PostMapping("/user/{userId}/name/{userName}")
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("req : {}",entity.getBody());
log.info("userId : {}, userName : {}",userId,userName);
log.info("authorization : {}, custom : {}",authorization,customHeader);
log.info("client req : {}",user);
Req<User> response = new Req<>();
response.setHeader(
new Req.Header()
);
response.setRBody(user.getRBody()); //response는 내가 만든것이니 user.getRBody를 해줘야지
return response;
}
강사님 왈, 하나하나씩 디버깅해가면서 찾아보자 라고 하시지만
한 두번정도 디버깅 과정이면 즐겁게 들을 것이다
하지만 벌써 4번째다
강사님도 헷갈릴 만큼 어려운 부분이라고 생각하고
인내심을 가지고 듣자
json의 구조가 재사용이 되는 형태라면
제네릭을 활용하면 된다
제네릭에 자신이 없다면
exchange하고
앞에서 했던 것처럼 class 하나씩 만들면 된다
trouble shooting :
계속해서
server에서 client req를 못받아오길래
client와 server의 dto-Req를 똑같이 해주었다
왜 중간에 변수명을 알아보기 쉽게 설정해보겠답시고 rBody, resBody 거리며 계속 바꾸어댔는지 이해가 안된다...


'Spring' 카테고리의 다른 글
Query Method 쿼리 메소드란? (0) | 2022.11.15 |
---|---|
Naver 지역 검색 API 사용하기 (0) | 2022.07.18 |
Server to server - POST (0) | 2022.06.27 |
Server to server - GET (0) | 2022.06.26 |
Spring Boot - Interceptor (0) | 2022.06.20 |