[Spring] RestTemplate 사용하기

WOOK JONG KIM·2022년 11월 8일
1
post-thumbnail
post-custom-banner

서버 용도로 프로젝트 한개 만들고 다른 프로젝트에서 Resttemplate을 통해 요청을 보내는 방식으로 진행

서버 프로젝트 생성하기

실습 환경에서는 컴퓨터안에 두개의 프로젝트 가동시키기에 톰캣의 포트를 변경해야 함

서버 프로젝트의 포트 번호는 9090으로 설정

Member Dto

public class MemberDto {
    
    private String name;
    private String email;
    private String organization;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getOrganization() {
        return organization;
    }

    public void setOrganization(String organization) {
        this.organization = organization;
    }

    @Override
    public String toString() {
        return "MemberDto{" +
                "name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", organization='" + organization + '\'' +
                '}';
    }
}

컨트롤러

@RestController
@RequestMapping("/api/v1/crud-api")
public class CrudController {

    // 아무 파라미터가 없는 경우
    @GetMapping
    public String getName(){
        return "Flature";
    }

    // PathVariable
    @GetMapping(value = "/{variable}")
    public String getVariable(@PathVariable String variable){
        return variable;
    }

    // RequestParam 사용 경우
    @GetMapping("/param")
    public String getNameWithParam(@RequestParam String name){
        return "Hello. " + name + "!";
    }

    // 요청 파라미터와 요청 바디를 같이 받는 경우
    @PostMapping
    public ResponseEntity<MemberDto> getMember(
            @RequestBody MemberDto request,
            @RequestParam String name,
            @RequestParam String email,
            @RequestParam String organization
    ){
        System.out.println(request.getName());
        System.out.println(request.getEmail());
        System.out.println(request.getOrganization());

        MemberDto memberDto = new MemberDto();
        memberDto.setName(name);
        memberDto.setEmail(email);
        memberDto.setOrganization(organization);

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

    // 임의의 HTTP 헤더를 받도록 함
    @PostMapping(value = "/add-header")
    public ResponseEntity<MemberDto> addHeader(@RequestHeader("my-header") String header,
                                               @RequestBody MemberDto memberDto){
        System.out.println(header);
        return ResponseEntity.status(HttpStatus.OK).body(memberDto);
    }
}

RestTemplate 구현하기

RestTemplate는 별도의 유틸리티 클래스 생성하거나, 서비스 or 비즈니스 계층에서 구현됨

앞 서 생성한 서버 프로젝트에 요청을 날리기 위해 서버의 역할을 수행하면서 다른 서버로 요청을 보내는 클라이언트의 역할도 수행하는 새로운 프로젝트 생성

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

구조 : 클라이언트로 요청을 받는 컨트롤러 + RestTemplate를 활용해 다른 서버에 통신 요청을 하는 서비스 계층

GET 형식의 RestTemplate 작성하기

@Service
public class RestTemplateService {

    public String getName(){
        URI uri = UriComponentsBuilder
                .fromUriString("http://localhost:9090")
                .path("/api/v1/crud-api")
                .encode()
                .build()
                .toUri();

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

        return responseEntity.getBody();
    }
    
    public String getNameWithPathVariable(){
        URI uri = UriComponentsBuilder
                .fromUriString("http://localhost:9090")
                .path("/api/v1/crud-api/{name}")
                .encode()
                .build()
                .expand("Flature") // 복수의 값을 넣어야 할 경우 ,를 추가하여 구분
                .toUri();
        
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
        
        return responseEntity.getBody();
    }
    
    public String getNameWithParameter(){
        URI uri = UriComponentsBuilder
                .fromUriString("http://localhost:9090")
                .path("/api/v1/crud-api/param")
                .queryParam("name", "Flature")
                .encode()
                .build()
                .toUri();
        
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
        
        return responseEntity.getBody();
    }
}

RestTemplate 생성 시 보통 UriComponenetsBuilder를 사용함
-> 파라미터를 연결하여 URI를 만듬

fromUriString 에서는 호출부의 URL 입력

path() 메서드에는 세부 경로 입력

encode()에는 인코딩 문자셋 설정하는데 디폴트 값은 UTF-8

build를 통해 빌더 생성 종료하고 UriComponent 타입이 리턴
-> 이것을 toURI 메서드를 통해 URI 타입으로 리턴 받음

생성한 uri는 외부 API를 요청하는데 사용됨
-> getForEntity() 의 파라미터로 사용하였음

path()내에 중괄호로 변수명을 입력한 후, expand에서 순서대로 값 입력 하면 됨(여러개 나열 가능)

queyrParam메서드를 통해 (키,값) 형식으로 파라미터 추가 가능

POST 형식의 RestTemplate 작성

public ResponseEntity<MemberDto> postwithParamAndBody(){
        URI uri = UriComponentsBuilder
                .fromUriString("http://localhost:9090")
                .path("/api/v1/crud-api")
                .queryParam("name", "Flature")
                .queryParam("email", "flature@wikibooks.co.kr")
                .queryParam("organization", "WikiBooks")
                .encode()
                .build()
                .toUri();

        MemberDto memberDto = new MemberDto();
        memberDto.setName("flature!!");
        memberDto.setEmail("flature@gmail.com");
        memberDto.setOrganization("Around Hub Studio");

        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<MemberDto> responseEntity = restTemplate.postForEntity(
                uri, memberDto, MemberDto.class
        );

        return responseEntity;
    }

    public ResponseEntity<MemberDto> postWithHeader(){
        URI uri = UriComponentsBuilder
                .fromUriString("http://localhost:9090")
                .path("/api/v1/crud-api/add-header")
                .encode()
                .build()
                .toUri();

        MemberDto memberDto = new MemberDto();
        memberDto.setName("flature");
        memberDto.setEmail("flature@wikibooks.co.kr");
        memberDto.setOrganization("Around Hub Studio");

        RequestEntity<MemberDto> requestEntity = RequestEntity
                .post(uri)
                .header("my-header", "wikibooks API")
                .body(memberDto);

        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<MemberDto> responseEntity = restTemplate.exchange(
                requestEntity, MemberDto.class
        );

        return responseEntity;
    }

첫 메서드는 외부 API에 요청할 때 Body값과 파라미터 값을 담는 방법

두번째 메서드는 헤더를 추가하는 예제
-> 대부분의 외부 API는 토큰키를 받아 서비스 접근을 인증하는 방식으로 작동
-> 이때 토큰값을 보통 헤더에 담음

헤더 설정을 위해선 보통 RequestEntity를 정의해서 사용하는 방법이 가장 편리

post()로 URI 설정
header() 메서드에서 키 이름과 값을 설정

exchange() 메서드는 모든 형식의 HTTP 요청 생성 가능
-> post() 메서드 대신 다른 형식의 메서드로 정의만 하면 exchange() 메서드로 쉽게 사용할 수 있기에 대부분 사용함

Swagger 설정

@Configuration
@EnableSwagger2
public class SwaggerConfiguration {

    @Bean
    public Docket api(){
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.springboot.rest"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo(){
        return new ApiInfoBuilder()
                .title("Spring Boot Open API Test with Swagger")
                .description("설명 부분")
                .version("1.0.0")
                .build();
    }
}

컨트롤러 작성

앞서 작성한 서비스 코드를 연결하는 컨트롤러 코드 작성

@RestController
@RequestMapping("/rest-template")
public class RestTemplateController {

    private final RestTemplateService restTemplateService;

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

    @GetMapping
    public String getName(){
        return restTemplateService.getName();
    }

    @GetMapping("/path-variable")
    public String getNameWithPathVariable(){
        return restTemplateService.getNameWithPathVariable();
    }

    @GetMapping("/parameter")
    public String getNameWithParameter(){
        return restTemplateService.getNameWithParameter();
    }

    @PostMapping
    public ResponseEntity<MemberDto> postDto(){
        return restTemplateService.postWithParamAndBody();
    }

    @PostMapping("/header")
    public ResponseEntity<MemberDto> postWithHeader(){
        return restTemplateService.postWithHeader();
    }

}

POST 호출 결과

profile
Journey for Backend Developer
post-custom-banner

0개의 댓글