HTTP 통신을 위한 RestTemplate 사용방법

이경영·2022년 10월 20일
0

스프링부트2

목록 보기
18/19
post-custom-banner

RestTemplate 이란?

스프링에서 제공하는 HTTP 통신 기능을 쉽게 사용할 수 있게 설계되어 있는 템플릿
HTTP 서버와의 통신을 단순화하고 RESTful 원칙을 지킴
동기 방식으로 처리되며, 비동기 방식으로는 AsyncRestTemplate이 있음
RestTemplate 클래스는 REST 서비스를 호출하도록 설계되어 HTTP 프로토콜의 메소드에 맞게 여러 메소드를 제공


클라이언트 부분

MemberDTO.java

package com.example.testproject.data.dto;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;


@Getter
@Setter
@ToString
public class MemberDTO {
    private String name;
    private String email;
    private String organization;

}

RestTemplateService.java

package com.example.testproject.data.service;

import com.example.testproject.data.dto.MemberDTO;
import org.springframework.http.ResponseEntity;

import java.lang.reflect.Member;

public interface RestTemplateService {

    public String getAroundHub();
    public String getName();
    public String getName2();
    public ResponseEntity<MemberDTO> postDto();
    public ResponseEntity<MemberDTO> addHeader();

}

RestTemplateServiceImpl.java

package com.example.testproject.data.service.Impl;

import com.example.testproject.data.dto.MemberDTO;
import com.example.testproject.data.service.RestTemplateService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 RestTemplateServiceImpl implements RestTemplateService {

    private final Logger LOGGER = LoggerFactory.getLogger(RestTemplateServiceImpl.class);

    @Override
    public String getAroundHub() {
        //uri는 어떤경로로 요청을 할건지해서 사용하는 클래스
        URI uri= UriComponentsBuilder
                .fromUriString("httpL//localhost:8081")
                .path("/api/server/around-hub")
                .encode() //기본적 utf-8로
                .build() //return 값 uricomponent 이기때문에
                .toUri(); //uri로 바꿔줌

        RestTemplate restTemplate=new RestTemplate();
        // 응답을 ResponseEntity 객체로 받는다. getForObject()와 달리 HTTP 응답에대한
        // 추가 정보를 담고 있어서 GET 요청에 대한 응답 코드, 실제 데이터를 확인할 수 있다.
        // 또한 ResponseEntity<T> 제네릭 타입에 따라서 응답을 String이나 Object 객체로 받을 수 있다.
        ResponseEntity<String> responseEntity=restTemplate.getForEntity(uri, String.class); //만들어진 uri값과 그 타입과 맞춘 클래스

        LOGGER.info("status code: {}", responseEntity.getStatusCode());
        LOGGER.info("body : {}", responseEntity.getBody());

        return responseEntity.getBody();
    }

    @Override
    public String getName() {
        URI uri = UriComponentsBuilder
                .fromUriString("http://localhost:8081")
                .path("/api/server/name") //위의 getAroundHub와 경로 다름
                .queryParam("name", "Flature") //requestparam 넣음
                .encode()
                .build()
                .toUri();

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

        LOGGER.info("status code : {}", responseEntity.getStatusCode());
        LOGGER.info("body : {}", responseEntity.getBody());

        return responseEntity.getBody();
    }

    @Override
    public String getName2() {
        URI uri = UriComponentsBuilder
                .fromUriString("http://localhost:8081")
                .path("/api/server/path-variable/{name}") // expand를 넣어줘서 값을 넣음.
                .encode()
                .build()
                .expand("Flature") // 복수의 값을 넣어야할 경우 , 를 추가하여 구분
                .toUri();

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

        LOGGER.info("status code : {}", responseEntity.getStatusCode());
        LOGGER.info("body : {}", responseEntity.getBody());

        return responseEntity.getBody();
    }

    @Override
    public ResponseEntity<MemberDTO> postDto() {
        URI uri = UriComponentsBuilder
                .fromUriString("http://localhost:8081")
                .path("/api/server/member")
                .queryParam("name", "Flature")
                .queryParam("email", "jjj@jjj.com")
                .queryParam("organization", "Around Hub Studio")
                .encode()
                .build()
                .toUri();

        //request값에 값을 넣기 위해 사용됨.
        MemberDTO memberDTO = new MemberDTO();
        memberDTO.setName("flature!!");
        memberDTO.setEmail("aaa@aaa.com");
        memberDTO.setOrganization("Around Hub Studio!!");

        RestTemplate restTemplate = new RestTemplate();
        //memberDTO가 들어가게 되고 requestBody로 인식
        ResponseEntity<MemberDTO> responseEntity = restTemplate.postForEntity(uri, memberDTO,
                MemberDTO.class);

        LOGGER.info("status code : {}", responseEntity.getStatusCode());
        LOGGER.info("body : {}", responseEntity.getBody());

        return responseEntity;
    }

    @Override
    public ResponseEntity<MemberDTO> addHeader() {
        URI uri = UriComponentsBuilder
                .fromUriString("http://localhost:9090")
                .path("/api/server/add-header")
                .encode()
                .build()
                .toUri();

        MemberDTO memberDTO = new MemberDTO();
        memberDTO.setName("flature");
        memberDTO.setEmail("jjj@jjj.com");
        memberDTO.setOrganization("Around Hub Studio");

        //requestEntity.get .delete .put. patch 다 있음.
        RequestEntity<MemberDTO> requestEntity = RequestEntity
                .post(uri)
                .header("around-header", "Around Hub Studio")
                .body(memberDTO);

        RestTemplate restTemplate = new RestTemplate();
        //header와 body값이 다 들어가있기 때문에 requestEntity만 넣어줌
        ResponseEntity<MemberDTO> responseEntity = restTemplate.exchange(requestEntity,
                MemberDTO.class);

        LOGGER.info("status code : {}", responseEntity.getStatusCode());
        LOGGER.info("body : {}", responseEntity.getBody());

        return responseEntity;
    }
}
package com.example.testproject.controller;

import com.example.testproject.data.dto.MemberDTO;
import com.example.testproject.data.service.RestTemplateService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/server")
public class RestTemplateController {
    private final Logger LOGGER= LoggerFactory.getLogger(RestController.class);
    private final RestTemplateService restTemplateService;

    public RestTemplateController(RestTemplateService restTemplateService){
        this.restTemplateService=restTemplateService;
    }

    @GetMapping(value = "/around-hub")
    public String getAroundHub() {
        return restTemplateService.getAroundHub();
    }

    @GetMapping(value = "/name")
    public String getName() {
        return restTemplateService.getName();
    }

    @GetMapping(value = "/name2")
    public String getName2() {
        return restTemplateService.getName2();
    }

    @PostMapping(value = "/dto")
    public ResponseEntity<MemberDTO> postDto() {
        return restTemplateService.postDto();
    }

    @PostMapping(value = "/add-header")
    public ResponseEntity<MemberDTO> addHeader() {
        return restTemplateService.addHeader();
    }


서버 부분

TestController.java

package controller;

import dto.MemberDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/server")
public class TestController {

    private final Logger LOGGER= LoggerFactory.getLogger(TestController.class);


    @GetMapping(value="/around-hub")
    public String getTest1(){
        LOGGER.info("getTest1 호출!");
        return "Hello, Around Hub Studio!";
    }

    @GetMapping(value="/name")
    public String getTest2(@RequestParam String name){
        LOGGER.info("getTest2 호출");
        return "Hello. "+name+"!";
    }

    @GetMapping(value="/path-variable/{name}")
    public String getTest3(@PathVariable String name){
        LOGGER.info("getTest3 호출");
        return "Hello. "+name+"!";
    }

    @PostMapping(value="/member")
    public ResponseEntity<MemberDTO> getMember(
            @RequestBody MemberDTO memberDTO,
            @RequestParam String name,
            @RequestParam String email,
            @RequestParam String organization){
        LOGGER.info("getMember 호출!");

//        MemberDTO memberDTO1=new MemberDTO();
//        memberDTO1.setName(name);
//        memberDTO1.setEmail(email);
//        memberDTO1.setOrganization(organization);

        return ResponseEntity.status(HttpStatus.OK).body(memberDTO);
    }

    @PostMapping(value="/add-header")
    public ResponseEntity<MemberDTO> addHeader(@RequestHeader("around-header") String header, @RequestBody MemberDTO memberDTO){
        LOGGER.info("add-header 호출!");
        LOGGER.info("header 값 : {}", header);

        return ResponseEntity.status(HttpStatus.OK).body(memberDTO);
    }
}

MemberDTO.java

package dto;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class MemberDTO {

    private String name;
    private String email;
    private String organization;
}

클라이언트(포트8080)의 컨트롤러에서 리턴값으로 @Service의 메소드를 불러냄. 그 메소드들은 localhost:9090에 restapi를 호출하게끔 설계되어있음

서버(포트:9090)는 컨트롤러에서 정의해놓은 로거들을 실행하면서 (EX. getTest1호출!) 정해진 리턴값을 보내줌
그럼 클라이언트의 RestTemplateServiceImpl에서 응답을 ResponseEntity 객체로 받아 바디에 넣어서 리턴해줌

/api/rest-template/around-hub

  • 클라이언트

  • 서버

/api/rest-template/name

  • 클라이언트
[2022-10-21 02:24:09.943] [INFO ] [http-nio-8080-exec-3] c.e.t.d.s.I.RestTemplateServiceImpl status code : 200 OK
[2022-10-21 02:24:09.943] [INFO ] [http-nio-8080-exec-3] c.e.t.d.s.I.RestTemplateServiceImpl body : Hello. Flature!
  • 서버
2022-10-21 02:24:09.941  INFO 51196 --- [nio-9090-exec-3] c.e.r.controller.TestController          : getTest2 호출


❤❤ 중요! /api/rest-template/dto

RestTemplateServiceImpl.java
부분 postDto 실행될때

    public ResponseEntity<MemberDTO> postDto() {
        URI uri = UriComponentsBuilder
                .fromUriString("http://localhost:9090")
                .path("/api/server/member")
                .queryParam("name", "Flature")
                .queryParam("email", "jjj@jjj.com")
                .queryParam("organization", "Around Hub Studio")
                .encode()
                .build()
                .toUri();

        //request값에 값을 넣기 위해 사용됨.
        MemberDTO memberDTO = new MemberDTO();
        memberDTO.setName("flature!");
        memberDTO.setEmail("aaa@aaa.com");
        memberDTO.setOrganization("Around Hub Studio!!");

        RestTemplate restTemplate = new RestTemplate();
        //memberDTO가 들어가게 되고 requestBody로 인식
        ResponseEntity<MemberDTO> responseEntity = restTemplate.postForEntity(uri, memberDTO,
                MemberDTO.class);

        LOGGER.info("status code : {}", responseEntity.getStatusCode());
        LOGGER.info("body : {}", responseEntity.getBody());

        return responseEntity;
    }

: MemberDTO의 값이 반영되서 리턴됨을 알 수 있음

왜일까?

  • 서버의 TestController를 보자
    @PostMapping(value="/member")
    public ResponseEntity<MemberDTO> getMember(
            @RequestBody MemberDTO memberDTO,
            @RequestParam String name,
            @RequestParam String email,
            @RequestParam String organization){
        LOGGER.info("getMember 호출!");

//        MemberDTO memberDTO1=new MemberDTO();
//        memberDTO1.setName(name);
//        memberDTO1.setEmail(email);
//        memberDTO1.setOrganization(organization);

        return ResponseEntity.status(HttpStatus.OK).body(memberDTO);

return 값을 보면 body에 memberDTO가 들어가있음을 알 수 있다. 그러면 주석을 해제하고 memberDTO1값을 body에 담으면 어떻게 될까?

  • 수정후 서버의 TestController.java
    @PostMapping(value="/member")
    public ResponseEntity<MemberDTO> getMember(
            @RequestBody MemberDTO memberDTO,
            @RequestParam String name,
            @RequestParam String email,
            @RequestParam String organization){
        LOGGER.info("getMember 호출!");

        MemberDTO memberDTO1=new MemberDTO();
        memberDTO1.setName(name);
        memberDTO1.setEmail(email);
        memberDTO1.setOrganization(organization);

        return ResponseEntity.status(HttpStatus.OK).body(memberDTO1);
    }

  • 전혀 다른 결과가 나타남

수정 전

클라이언트의 RestTemplateServiceImpl.java의 메소드 postDto에서 memberDTO객체를 생성해서 보낸 값들은

ResponseEntity<MemberDTO> responseEntity = restTemplate.postForEntity(uri, memberDTO,
                MemberDTO.class);

에서 request(memberDTO)에 담기게 된다
이부분은 서버(TestController.java)에서 @RequestBody 로 불러오는것이 가능해진다.

  • 클라이언트
[2022-10-21 02:29:04.927] [INFO ] [http-nio-8080-exec-5] c.e.t.d.s.I.RestTemplateServiceImpl body : MemberDTO(name=flature!!, email=aaa@aaa.com, organization=Around Hub Studio!!)
[2022-10-21 02:34:55.101] [INFO ] [http-nio-8080-exec-4] c.e.t.d.s.I.RestTemplateServiceImpl status code : 200 OK
  • 서버
2022-10-21 02:34:55.064  INFO 26268 --- [nio-9090-exec-1] c.e.r.controller.TestController          : getMember 호출!

수정 후

클라이언트의 RestTemplateServiceImpl.java의 메소드 postDto에서 쿼리파라미터(.queryParam)으로 담아준 값(uri에 담김)들은

ResponseEntity<MemberDTO> responseEntity = restTemplate.postForEntity(uri, memberDTO,
                MemberDTO.class);

서버에서 @RequestParam으로 받아와져서 객체를 생성(memberDTO1), 넣어준 뒤에 바디값으로 보내기 때문에

        MemberDTO memberDTO1=new MemberDTO();
        memberDTO1.setName(name);
        memberDTO1.setEmail(email);
        memberDTO1.setOrganization(organization);
        return ResponseEntity.status(HttpStatus.OK).body(memberDTO1);

응답값으로 받아와진다.

  • 클라이언트
[2022-10-21 02:34:55.101] [INFO ] [http-nio-8080-exec-4] c.e.t.d.s.I.RestTemplateServiceImpl body : MemberDTO(name=Flature, email=jjj@jjj.com, organization=Around Hub Studio)
[2022-10-21 02:53:47.056] [INFO ] [http-nio-8080-exec-8] c.e.t.d.s.I.RestTemplateServiceImpl status code : 200 OK
  • 서버
2022-10-21 02:34:55.064  INFO 26268 --- [nio-9090-exec-1] c.e.r.controller.TestController          : getMember 호출!


/api/rest-template/add-header

key : header - value : around hub studio 값을 넣어서 보냄

RestTemplateServiceImpl.java

 @Override
    public ResponseEntity<MemberDTO> addHeader() {
        URI uri = UriComponentsBuilder
                .fromUriString("http://localhost:9090")
                .path("/api/server/add-header")
                .encode()
                .build()
                .toUri();

        MemberDTO memberDTO = new MemberDTO();
        memberDTO.setName("flature");
        memberDTO.setEmail("jjj@jjj.com");
        memberDTO.setOrganization("Around Hub Studio");

        //requestEntity.get .delete .put. patch 다 있음.
        RequestEntity<MemberDTO> requestEntity = RequestEntity
                .post(uri)
                .header("around-header", "Around Hub Studio")
                .body(memberDTO);

        RestTemplate restTemplate = new RestTemplate();
        //header와 body값이 다 들어가있기 때문에 requestEntity만 넣어줌
        ResponseEntity<MemberDTO> responseEntity = restTemplate.exchange(requestEntity,
                MemberDTO.class);

        LOGGER.info("status code : {}", responseEntity.getStatusCode());
        LOGGER.info("body : {}", responseEntity.getBody());

        return responseEntity;
    }
  • 서버 : @RequestHeader로 받아서 전달됨.
    @PostMapping(value="/add-header")
    public ResponseEntity<MemberDTO> addHeader(@RequestHeader("around-header") String header, @RequestBody MemberDTO memberDTO){
        LOGGER.info("add-header 호출!");
        LOGGER.info("header 값 : {}", header);

        return ResponseEntity.status(HttpStatus.OK).body(memberDTO);
    }


결과

  • 클라이언트
[2022-10-21 02:53:47.056] [INFO ] [http-nio-8080-exec-8] c.e.t.d.s.I.RestTemplateServiceImpl status code : 200 OK
[2022-10-21 02:53:47.057] [INFO ] [http-nio-8080-exec-8] c.e.t.d.s.I.RestTemplateServiceImpl body : MemberDTO(name=flature, email=jjj@jjj.com, organization=Around Hub Studio)
  • 서버 ❤❤ 여기서 결과값 확인
2022-10-21 02:53:47.051  INFO 26268 --- [nio-9090-exec-3] c.e.r.controller.TestController          : add-header 호출!
2022-10-21 02:53:47.052  INFO 26268 --- [nio-9090-exec-3] c.e.r.controller.TestController          : header 값 : Around Hub Studio

인증(authentication)은 헤더값을 통해 많이 사용됨.

profile
꾸준히
post-custom-banner

0개의 댓글