Burninghering's Blog
article thumbnail
Published 2022. 7. 16. 20:50
Server to server - header Spring

클라이언트에서

헤더를 넣어서 보내보자

<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
profile

Burninghering's Blog

@개발자 김혜린

안녕하세요! 반갑습니다.