[Spring] RestTemplate

thingzoo·2023년 7월 1일
0

Spring

목록 보기
43/54
post-thumbnail

Server To Server

지금까지는 클라이언트(브라우저)로부터 요청을 받는 서버의 입장에서 개발을 진행해왔다.
하지만 어떤 경우에는 서버가 Client의 입장이 되어야 할때도 있다.
예를 들어 카카오에서 만든 주소 검색 API를 사용해야한다면 Kakao 서버에 요청을 보내야한다.
따라서 Spring에서는 서버에서 다른 서버로 간편하게 요청할 수 있도록 RestTemplate 기능을 제공하고 있다.

RestTemplate 사용법

RestTemplate는 spring-boot-starter-web 모듈에 포함돼 있는 기능으로 별도의 의존성을 추가할 필요 없다.

서버 두개 준비

프로젝트 2개를 만들어서 Client 입장의 서버는 8080포트(기본값), Server 입장의 서버는 7070포트(등 다른 포트)로 설정 후 동시에 실행시켜 확인해볼 수 있다.

Get 요청 방법: getForEntity()

Client 입장 서버

1. RestTemplate을 주입 받는다.

  • RestTemplateBuilder의 build()를 사용하여 RestTemplate을 생성해야 함
private final RestTemplate restTemplate; // DI 안됨

public RestTemplateService(RestTemplateBuilder builder) {
	this.restTemplate = builder.build();
}

2. RestTemplate의 getForEntity()를 사용하여 GET 요청한다.

2-1. 요청 받은 검색어를 Query String 방식으로 보내기
  • restTemplate.getForEntity(uri, ItemDto.class);: Get 방식으로 해당 URI의 서버에 요청을 진행
    • 첫번째 파라미터: URI
      • UriComponentsBuilder를 사용해서 URI 생성
    • 두 번째 파라미터: 전달 받을 데이터 클래스의 타입
    • response.getBody(): 두 번째 파라미터로 전달한 클래스 타입으로 자동 변환된 객체 반환
public ItemDto getCallObject(String query) {
	// 요청 URL 만들기
    URI uri = UriComponentsBuilder
    				.fromUriString("http://localhost:7070")
					.path("/api/server/get-call-obj")
                  	.queryParam("query", query)
                  	.encode()
                  	.build()
                  	.toUri();
	log.info("uri = " + uri);

    ResponseEntity<ItemDto> responseEntity = restTemplate.getForEntity(uri, ItemDto.class);

    log.info("statusCode = " + responseEntity.getStatusCode());

    return responseEntity.getBody();
}
2-2. 요청한 Item이 여러 개인 경우
  • 결과 값이 다중 JSON으로 넘어오기 때문에 JSON To Object를 사용하지 않고 일단 String 값 그대로를 가져온다.
public List<ItemDto> getCallList() {
	// 요청 URL 만들기
    URI uri = UriComponentsBuilder
    			.fromUriString("http://localhost:7070")
              	.path("/api/server/get-call-list")
              	.encode()
              	.build()
              	.toUri();
	log.info("uri = " + uri);

    ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);

    log.info("statusCode = " + responseEntity.getStatusCode());
    log.info("Body = " + responseEntity.getBody());

    return fromJSONtoItems(responseEntity.getBody());
}
  • JSON 처리를 도와주는 라이브러리를 추가하여 받아온 JSON 형태의 String을 처리한다.
implementation 'org.json:json:20230227'
public List<ItemDto> fromJSONtoItems(String responseEntity) {
    JSONObject jsonObject = new JSONObject(responseEntity);
    JSONArray items  = jsonObject.getJSONArray("items");
    List<ItemDto> itemDtoList = new ArrayList<>();

    for (Object item : items) {
        ItemDto itemDto = new ItemDto((JSONObject) item);
        itemDtoList.add(itemDto);
    }

    return itemDtoList;
}
  • ItemDto에 받아온 JSONObject를 사용하여 초기화하는 생성자를 추가 해준다.
@Getter
@NoArgsConstructor
public class ItemDto {
    private String title;
    private int price;

    public ItemDto(JSONObject itemJson) {
        this.title = itemJson.getString("title");
        this.price = itemJson.getInt("price");
    }
}

Server 입장 서버

1-1. itemList를 조회하여 요청받은 검색어에 맞는 Item을 반환

public Item getCallObject(String query) {
    for (Item item : itemList) {
        if(item.getTitle().equals(query)) {
            return item;
        }
    }
    return null;
}

1-2. itemList 반환

public ItemResponseDto getCallList() {
    ItemResponseDto responseDto = new ItemResponseDto();
    for (Item item : itemList) {
        responseDto.setItems(item);
    }
    return responseDto;
}

Post 요청 방법: postForEntity()

Client 입장 서버

RestTemplate의 postForEntity()를 사용하여 POST 요청한다.

  • restTemplate.postForEntity(uri, user, ItemDto.class);: Post 방식으로 해당 URI의 서버에 요청을 진행
    • 첫 번째 파라미터: URI
      • UriComponentsBuilder를 사용해서 URI 생성
      • expand를 사용하여 {query} 안의 값을 동적으로 처리 가능
    • 두 번째 파라미터: HTTP Body에 넣어줄 데이터
      • Java 객체를 두 번째 파라미터에 넣으면 자동으로 JSON 형태로 변환
    • 세 번째 파라미터: 전달 받을 데이터 클래스의 타입
public ItemDto postCall(String query) {
    // 요청 URL 만들기
    URI uri = UriComponentsBuilder
            .fromUriString("http://localhost:7070")
            .path("/api/server/post-call/{query}")
            .encode()
            .build()
            .expand(query)
            .toUri();
    log.info("uri = " + uri);

    User user = new User("Robbie", "1234");

    ResponseEntity<ItemDto> responseEntity = restTemplate.postForEntity(uri, user, ItemDto.class);

    log.info("statusCode = " + responseEntity.getStatusCode());

    return responseEntity.getBody();
}

Server 입장 서버

itemList를 조회하여 요청받은 검색어에 맞는 Item 반환

public Item postCall(String query, UserRequestDto userRequestDto) {
    System.out.println("userRequestDto.getUsername() = " + userRequestDto.getUsername());
    System.out.println("userRequestDto.getPassword() = " + userRequestDto.getPassword());

    return getCallObject(query);
}

요청 Header에 정보를 추가: exchange()

Client 입장 서버

  • restTemplate.exchange(requestEntity, String.class);: RequestEntity를 사용해 서버에 요청을 진행
    • 첫 번째 파라미터: RequestEntity 객체
      • uri, header, body의 정보를 한번에 전달 가능
    • 두 번째 파라미터: 전달 받을 데이터 클래스 타입
public List<ItemDto> exchangeCall(String token) {
    // 요청 URL 만들기
    URI uri = UriComponentsBuilder
            .fromUriString("http://localhost:7070")
            .path("/api/server/exchange-call")
            .encode()
            .build()
            .toUri();
    log.info("uri = " + uri);

    User user = new User("Robbie", "1234");

    RequestEntity<User> requestEntity = RequestEntity
            .post(uri)
            .header("X-Authorization", token)
            .body(user);

    ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);

    return fromJSONtoItems(responseEntity.getBody());
}

Server 입장 서버

  • @RequestHeader("X-Authorization"): 헤더에서 주어진 key값을 반환
@PostMapping("/exchange-call")
    public ItemResponseDto exchangeCall(@RequestHeader("X-Authorization") String token, @RequestBody UserRequestDto requestDto) {
        return itemService.exchangeCall(token, requestDto);
    }
  • 전달된 header와 body의 정보를 확인 가능
public ItemResponseDto exchangeCall(String token, UserRequestDto requestDto) {
    System.out.println("token = " + token);
    System.out.println("requestDto.getUsername() = " + requestDto.getUsername());
    System.out.println("requestDto.getPassword() = " + requestDto.getPassword());

    return getCallList();
}
profile
공부한 내용은 바로바로 기록하자!

0개의 댓글