본문 바로가기
Spring

Rest template란 무엇인가?

by 다오__ 2023. 6. 21.

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

 

예를 들어 회원가입을 진행할때 사용자의 주소를 받아야한다면?

  • 주소를 검색할 수 있는 기능을 구현해야 하는데 많은 시간과 비용이 들어간다

이때 카카오에서 만든 주소검색 API를 사용한다면 기능을 간편하게 구현할 수 있다.

  • 이럴 때 우리의 서버는 클라이언트의 입장이 되어 카카오 서버에 요청을 진행해야한다.
  • Spring에서는 서버에서 다른 서버로 간편하게 요청할 수 있도록 RestTemplate를 제공하고 있다.

 

RestTemplate의 GET요청

클라이언트용 서버와 서버용 서버 총 두개의 프로젝트를 만들어 직접 요청을 보내고 받아보자.

 

클라이언트용 서버를 먼저 보자

1. 클라이언트용 서버의 Service에서 RestTemplate을 주입받는다.

private final RestTemplate restTemplate;

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

RestTemplate는 RestTemplateBuilder를 통해 주입받을 수 있다.

 

2. 요청받은 검색어를 Query String 방식으로 서버용 서버로 RestTemplate을 사용하여 요청한다.

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> reponseEntity = restTemplate.getForEntity(uri, ItemDto.class);
    
    log.info("statusCode = "+ responseEntity.getStatusCode());
    
    return responseEntity.getBody();
    }
  • UriComponentsBuilder를 통해 URI를 쉽게 만들 수 있다.
  • RestTemplate의 getForEntity메서드는 Get방식으로 해당 URI의 서버에 요청을 진행한다.
    • 첫번째 파라미터에는 URI를 두번째 파라미터에는 전달받은 데이터와 매핑하여 인스턴스화할 클래스의 타입을 준다.
  • 요청한 결과값에 대해 직접 JSON TO Object를 구현할 필요없이 RestTemplate을 사용하면 자동으로 처리해준다.
    • 따라서 Response.getBody()를 사용하여 두번째 파라미터로 전달한 클래스 타입으로 자동 변환된 객체를 가져올 수 있다.

 

서버용 서버

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

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

이렇게 하면 한개의 Item에 대해서 ItemDto객체타입으로 변환하여 데이터를 얻을 수 있다.

 

그런데 요청한 Item이 여러 개라면 어떻게 해야할까?

 

build.gradle에 json 처리를 도와주는 라이브러리를 초가하자

// json
implementation 'org.json:json:20230227'

1. Item List (다중) 조회

 

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

요청한 Item이 여러개이기 때문에 다중 JSON으로 넘어온다. JSON To Object를 사용하지 않고 일단 String값 그대로를 가져온다.

 

String.class로 받아온 responseEntity를 직접 정의한 fromJSONtoItems로 보낸다.

  • +서버용 서버에서 담겨오는 데이터는 아래와 같다. (예시)
{
"items":[
		{"title":"Mac","price":3888000},
		{"title":"iPad","price":1230000},
		{"title":"iPhone","price":1550000},
		{"title":"Watch","price":450000},
		{"title":"AirPods","price":350000}
	]
}

fromJSONtoItems메서드 코드

public List<ItemDto> fromJSONtoItems(String responseEntity){
	
    //문자열 정보를 JSONObject로 바꾸기
    JSONObject jsonObject = new JSONObject(responseEntity);
    
    //JSONObject에서 item배열 꺼내 JSONArray타입으로 저장
    JSONArray items = jsonObject.getJSONArray("items");
    
    //JSONArray로 for문을 돌면서 상품 하나씩 ItemDto로 변환하기
    List<ItemDto> itemDtoList = new ArrayList<>();
    for(Object item : items){
    	ItemDto itemDto = new ItemDto((JSONObject) item);
        itemList.add(itemDto);
    }
}

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

 

서버용 서버

Service단에서 아래와 같이 작성한다.

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

 

 

지금까지 GET요청방법을 알아보았다.  이제 POST요청방법을 알아보자

클라이언트용 서버

 

Service단의 postCall메서드를 작성하자.

public ItemDto postCall(String query) {
	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();
}
  • UriComponentsBuilder의 expand를 통하여 {query}안의 값을 동적으로 처리할 수 있다.
  • RestTemplate의 postForEntity는 Post 방식으로 해당 URI의 서버에 요청을 진행한다.
    • 첫번째 파라미터 : URI
    • 두번째 파라미터 : HTTP Body에 넣어줄 데이터 (Java 객체를 두 번째 파라미터에 넣으면 자동으로 JSON형태로 변환된다.)
    • 세번째 파라미터에는 전달받은 데이터와 매핑하여 인스턴스화할 클래스 타입을 준다.

서버용 서버

  • Service단에서 itemList를 조회하여 요청받은 검색어에 맞는 Item을 반환한다.
public Item postCall(String query, UserRequestDto userReqeustDto) {
	System.out.println("userRequestDto.getUsername() = "+ userRequestDto.getUsername();
    System.out.println("userRequestDto.getPassword() = "+ userRequestDto.getPassword();
    
    return getCallObject(query);
}

 

이로써 GET 요청과 POST 요청방법에 대해 알아보았다.

 

한가지 더, RestTemplate로 요청을 보낼 때  Header에 정보를 추가하고 싶다면?

 

클라이언트용 서버

   RestTemplate의 exchange메서드 를 사용한다.

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());
}
  • exchange 메서드의 첫 번째 파라미터에 RequestEntity 객체를 만들어 전달해주면 uri, 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();
}

전달된 header(token)와 body정보를 확인할 수 있다.

'Spring' 카테고리의 다른 글

객체 지향 프로그래밍  (1) 2023.10.23
스프링의 탄생과 하이버네이트  (1) 2023.10.23
같은 타입의 bean이 2개 이상일 때  (0) 2023.06.19
MVC란 무엇일까?  (1) 2023.06.16
스프링 IoC 와 DI  (0) 2023.06.14