본문 바로가기
컴퓨터 프로그래밍/Spring

[Spring] RestTemplate

by 한33 2024. 9. 17.

RestTemplate 을 이용하면 내 서버에서 카카오에서 만든 주소검색 API 라든지 로그인이라든지 기능을 가져와서 간편하게 구현할 수 있다.

 

이럴 때 우리의 Client 의 입장이 되어서 Kakao 서버에 요청을 진행해야한다.


프로젝트 하나는 8080 포트, 하나는 7070 포트로 서버 코드를 만들어서 진행.


RestTemplate 의 Get 요청 (단건 Get)

client-controller

@GetMapping("/get-call-obj")
public ItemDto getCallObject(String query) {
    return restTemplateService.getCallObject(query);
}

client-service

public class RestTemplateService {

    private final RestTemplate restTemplate;

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

 

RestTemplate 을 주입 받는다.

 

client-service

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

UriComponentsBuider 를 사용해서 URI 를 손쉽게 만들 수 있다.

 

RestTemplate의 getForEntity는 Get 방식으로 해당 URI의 서버에 요청을 진행

 

uri 에 저장된 값을 ItemDto 에 담아서 반환한다.

 

첫 번째 파라미터에는 URI, 두 번째 파라미터에는 전달 받은 데이터와 매핑하여 인스턴스화할 클래스의 타입을 주면됨.

 

자동으로 object 에서 Json 으로 변환시켜준다.

 

server-controller

@GetMapping("/get-call-obj")
public Item getCallObject(@RequestParam String query) {
    return itemService.getCallObject(query);
}

server-service

public class ItemService {

    private final List<Item> itemList = Arrays.asList(
            new Item("Mac", 3_888_000),
            new Item("iPad", 1_230_000),
            new Item("iPhone", 1_550_000),
            new Item("Watch", 450_000),
            new Item("AirPods", 350_000)
    );

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

 

서버측 코드에서는 /get-call-obj 에서 전달받은 query 를 미리 만들어놓은 Dummy Data 와 비교해서 일치하는 게 있으면 return 시킨다. 

 

그럼 그 item 이 컨트롤러로 반환되고 이게 client 측 서버에서 가져가지는 것.


RestTemplate 의 Get 요청 (다건 Get)

build.gradle 에 json 세팅을 해주고

 

client-controller

@GetMapping("/get-call-list")
public List<ItemDto> getCallList() {
    return restTemplateService.getCallList();
}

client-service

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 To Object를 사용하지 않고 일단 String 값 그대로를 가져옴.
    • Server 입장 서버의 ItemResponseDto는 아래의 JSON 형태로 변환되어 전달됨.

 

그래서 JSON 처리를 도와주는 라이브러리를 추가하여 받아온 JSON 형태의 String 을 처리

client-service

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 Object, JSON Array 이해하기

server-service

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

Server 입장의 서버에서 itemList를 ItemResponseDto에 담아 반환


RestTemplate 의 Post 요청

client-controller

@GetMapping("/get-call-obj")
public ItemDto getCallObject(String query) {
    return restTemplateService.getCallObject(query);
}

client-service

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

 

UriComponentsBuilder의 expand를 사용하여 {query} 안의 값을 동적으로 처리할 수 있음

 

  • RestTemplate의 postForEntity는 Post 방식으로 해당 URI의 서버에 요청을 진행.
    • 첫 번째 파라미터에는 URI, 두 번째 파라미터에는 HTTP Body에 넣어줄 데이터를 넣음.
      • Java 객체를 두 번째 파라미터에 넣으면 자동으로 JSON 형태로 변환됨.
    • 세 번째 파라미터에는 전달 받은 데이터와 매핑하여 인스턴스화할 클래스의 타입을 주면됨.

server-controller

@PostMapping("/post-call/{query}")
public Item postCall(@PathVariable String query, @RequestBody UserRequestDto requestDto) {
    return itemService.postCall(query, requestDto);
}

server-service

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

    return getCallObject(query);
}

RestTemplate 의 exchange 요청

client-controller

@GetMapping("/exchange-call")
public List<ItemDto> exchangeCall(@RequestHeader("Authorization") String token) {
    return restTemplateService.exchangeCall(token);
}

client-service

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의 정보를 한번에 전달할 수 있음

 

server-controller

@PostMapping("/exchange-call")
public ItemResponseDto exchangeCall(@RequestHeader("X-Authorization") String token, @RequestBody UserRequestDto requestDto) {
    return itemService.exchangeCall(token, requestDto);
}

server-service

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

 

 

 

Authorization 이름으로 Header 로 전달을 하면 server 측 코드에서도 헤더로 원하는 값이 전달이 된다.

'컴퓨터 프로그래밍 > Spring' 카테고리의 다른 글

[Spring] JwtUtil 예시 코드 분석  (0) 2024.09.21
[Spring] Naver Open API  (0) 2024.09.18
[Spring] Service Test Code 작성  (0) 2024.09.14
[Spring] Controller Test Code 작성  (0) 2024.09.14
[Spring] AOP  (0) 2024.09.10