Spring/팀스파르타

33. RestTemplate이란 무엇일까?

열심히 해 2024. 11. 25. 09:13

 

 

서비스 개발을 진행하다보면 라이브러리 사용만으로는 구현이 힘든 기능들이 무수히 많이 존재합니다.

  • 예를 들어 우리의 서비스에서 회원가입을 진행할 때 사용자의 주소를 받아야 한다면?
    >> 주소를 검색할 수 있는 기능을 구현해야하는데 직접 구현을 하게되면 많은 시간과 비용이 들어갑니다.
  • 이때 카카오에서 만든 주소 검색 API를 사용한다면 해당 기능을 간편하게 구현할 수 있습니다.

 

RestTemplate

 

  • 우리의 서버는 Client의 입장이 되어 Kakao 서버에 요청을 진행해야합니다.
  • Spring에서는 서버에서 다른 서버로 간편하게 요청할 수 있도록 RestTemplate 기능을 제공하고 있습니다.

 


 

 

Get 요청 방법

 

 

- Client 입장의 서버 -

 

  • RestTemplate을 주입 받습니다.
  • 요청 받은 검색어를 Query String 방식으로 Server 입장의 서버로 RestTemplate를 사용하여 요청합니다.

 

1. Server 입장의 서버에게 데이터 요청하기

private final RestTemplate restTemplate;

// RestTemplateBuilder의 build()를 사용하여 RestTemplate을 생성합니다.
public RestTemplateService(RestTemplateBuilder builder) {
    this.restTemplate = builder.build();
}

// ... 

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();
}

 

  • Spring의 UriComponentsBuilder를 사용해서 요청 URI를 손쉽게 만들 수 있습니다.
  • RestTemplate의 getForEntity는 Get 방식으로 위 URI의 서버에 요청을 진행합니다.
    • 첫 번째 파라미터에는 URI, 두 번째 파라미터에는 전달 받은 데이터와 매핑하여 인스턴스화할 클래스의 타입을 주면 됩니다.
  • 요청의 결과값에 대해서 직접 JSON TO Object를 구현할 필요없이 RestTemplate을 사용하면 자동으로 처리 해줍니다.
    • 따라서 response.getBody() 를 사용하여 두 번째 파라미터로 전달한 클래스 타입으로 자동 변환된 객체를 가져올 수 있습니다.
    • Server 입장의 서버에서 itemList를 조회하여 요청받은 검색어에 맞는 Item을 반환합니다.

 


 

 

2. 만약 요청하는 아이템이 여러 개라면 어떻게 할까요?

  • 결과 값이 다중 JSON으로 넘어오기 때문에 JSON To Object를 사용하지 않고 일단 String 값 그대로를 가져옵니다.
  • 아래 메서드를 통해 String 타입의 데이터에 들어있는, Json 형태의 데이터들을 ItemDto에 담습니다.

 

public List<ItemDto> getCallList() {
    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());
}

// ...

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;
}

 

Json 모양의 데이터를 다루기 위해 아래 의존성을 추가합니다.

implementation 'org.json:json:20230227'

 

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 입장의 서버 -

 

 

Server 입장의 서버에서 itemList를 조회하여 요청받은 검색어에 맞는 Item을 반환합니다.

 

1. Client 입장의 서버에게 데이터 요청 받기

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

 

 


 

 

 

2. 만약 요청받는 아이템이 여러 개라면 어떻게 할까요?

 

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

 

@Getter
public class ItemResponseDto {
    private final List<Item> items = new ArrayList<>();

    public void setItems(Item item) {
        items.add(item);
    }
}

 

 

 


참고

 

 

 

중첩 JSON 데이터

{
        "items":[
        {"title":"Mac","price":3888000},
        {"title":"iPad","price":1230000},
        {"title":"iPhone","price":1550000},
        {"title":"Watch","price":450000},
        {"title":"AirPods","price":350000}
        ]
}

'Spring > 팀스파르타' 카테고리의 다른 글

35. Entity 연관 관계 기초  (0) 2024.11.28
34. RestTemplate의 Post 요청, exchange  (0) 2024.11.27
31. Spring Security: JWT 로그인  (0) 2024.11.21
30. Spring Security 로그인  (1) 2024.11.20
28. 필터란 무엇일까?  (0) 2024.11.16