Spring

Server to Server - RestTemplate

테니드2 2025. 4. 16. 14:40

지금까지 살펴본 부분은 항상 Server의 입장에서 API를 제공하는 방법에 대하여 학습

Back-end에서 Client로 다른 Server와의 연결은 필수!!!

Port 설정은 resource 하위의 application.properties 파일에서

server.port = {사용할 포트 번호} 로 변경할 수 있다.

1. Server to Server - GET

Client

package com.example.client.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserResponse {
    private String name;
    private int age;
}

package com.example.client.service;

import com.example.client.dto.UserResponse;
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 RestTemplateService {

    // <http://localhost/api/server/hello>
    // response
    public UserResponse hello(){
        URI uri = UriComponentsBuilder
                .fromUriString("<http://localhost:9090>")
                .path("/api/server/hello")
                .queryParam("name","jun")
                .queryParam("age",30)
                .encode()
                .build()
                .toUri();

        System.out.println(uri.toString());

        RestTemplate restTemplate = new RestTemplate();

        ResponseEntity<UserResponse> result = restTemplate.getForEntity(uri, UserResponse.class);
        System.out.println("getStatusCode : "+ result.getStatusCode());
        System.out.println("getBody : "+ result.getBody());

        return result.getBody();
    }
}

RestTemplate 클래스를 이용하여 다른 서버로 요청(GET, POST, DELETE, …) 을 보낼 수 있다.

서버와 API 표준 스펙을 정하여 DTO 클래스를 설계하여 응답을 받을 때 사용한다.

Server

package com.example.server.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private String name;
    private int age;
}

package com.example.server.controller;

import com.example.server.dto.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

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

    @GetMapping("/hello")
    public User hello(@RequestParam String name ,@RequestParam int age){
        User user = new User();
        user.setName(name);
        user.setAge(age);

        return user;
    }
}

 

 

2. Server to Server - POST

Client

package com.example.client.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserRequest {
    private String name;
    private int age;
}
package com.example.client.service;

import com.example.client.dto.UserRequest;
import com.example.client.dto.UserResponse;
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 RestTemplateService {

    public UserResponse post(){
        // <http://localhost:9090/api/server/user/{userId}/name/{userName}>

        URI uri = UriComponentsBuilder
                .fromUriString("<http://localhost:9090>")
                .path("/api/server/user/{userId}/name/{userName}")
                .encode()
                .build()
                .expand(100,"jun")
                .toUri();

        System.out.println(uri);

        // http body -> object -> object mapper -> json -> rest template -> http body json
        UserRequest req = new UserRequest();
        req.setAge(30);
        req.setName("jun");

        RestTemplate restTemplate = new RestTemplate();

        ResponseEntity<UserResponse> response = restTemplate.postForEntity(uri, req, UserResponse.class);

        System.out.println("getStatusCode : "+ response.getStatusCode());
        System.out.println("getHeaders : "+ response.getHeaders());
        System.out.println("getBody : "+ response.getBody());

        return response.getBody();

    }
}

RestTemplate의 postForEntity 함수를 이용하여 requstBody의 내용을 추가하여 다른 서버로 요청할 수 있다.

Server

package com.example.server.controller;

import com.example.server.dto.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

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

    @PostMapping("/user/{userId}/name/{userName}")
    public User post(@RequestBody User user, @PathVariable int userId, @PathVariable String userName){
        log.info("userId : {} , userName : {}",userId,userName);
        log.info("user : {}",user);

        return user;
    }
}

 

 

3. Server to Server - exchange

Client

package com.example.client.service;

import com.example.client.dto.Req;
import com.example.client.dto.UserRequest;
import com.example.client.dto.UserResponse;
import org.springframework.core.ParameterizedTypeReference;
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 RestTemplateService {

    public UserResponse exchange(){
        // <http://localhost:9090/api/server/user/{userId}/name/{userName}>

        URI uri = UriComponentsBuilder
                .fromUriString("<http://localhost:9090>")
                .path("/api/server/user/{userId}/name/{userName}")
                .encode()
                .build()
                .expand(100,"jun")
                .toUri();

        System.out.println(uri);

        // http body -> object -> object mapper -> json -> rest template -> http body json
        UserRequest req = new UserRequest();
        req.setAge(30);
        req.setName("jun");

        RequestEntity<UserRequest> requestEntity = RequestEntity
                                                .post(uri)
                                                .header("x-authorization","asdf")
                                                .header("custom-header","112233")
                                                .body(req);

        RestTemplate restTemplate = new RestTemplate();

        ResponseEntity<UserResponse> response = restTemplate.exchange(requestEntity,UserResponse.class);

        System.out.println("getStatusCode : "+ response.getStatusCode());
        System.out.println("getHeaders : "+ response.getHeaders());
        System.out.println("getBody : "+ response.getBody());

        return response.getBody();

    }

}

RestTemplate의 exchange함수를 이용하여 RequestEntity를 추가할 수 있다.

→ RequestEntity 클래스에서 httpMethod, URI, Header, Body를 설정

Server

package com.example.server.controller;

import com.example.server.dto.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

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

    @GetMapping("/hello")
    public User hello(@RequestParam String name ,@RequestParam int age){
        User user = new User();
        user.setName(name);
        user.setAge(age);

        return user;
    }

    @PostMapping("/user/{userId}/name/{userName}")
    public User post(@RequestBody User user,
                     @PathVariable int userId,
                     @PathVariable String userName,
                     @RequestHeader(name ="x-authorization") String authorization ,
                     @RequestHeader(name ="custom-header") String customHeader){
        log.info("userId : {} , userName : {}",userId,userName);
        log.info("x-authorization : {} , custom-header: {}",authorization,customHeader);
        log.info("user : {}",user);

        return user;
    }
}

 

4. Server to Server - GenericExchange

{
	"header": {
		"response_code" : ""
	},
	"body" : {
		"name" : "jun",
		"age" : 30

	}

위 처럼 JSON 내용이 header,body 2가지로 나뉘고 상황에 따라 body의 내용만 바뀌는 상황이 있을 수 있다.

제네릭 dto클래스를 이용하여 간단하게 구현할 수 있다.

Client

package com.example.client.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Req<T> {
    private Header header;
    private T resBody;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Header{
        private String responseCode;
    }
}

package com.example.client.service;

import com.example.client.dto.Req;
import com.example.client.dto.UserRequest;
import com.example.client.dto.UserResponse;
import org.springframework.core.ParameterizedTypeReference;
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 RestTemplateService {

    public Req<UserResponse> genericExchange(){
        // <http://localhost:9090/api/server/user/{userId}/name/{userName}>

        URI uri = UriComponentsBuilder
                .fromUriString("<http://localhost:9090>")
                .path("/api/server/user/{userId}/name/{userName}")
                .encode()
                .build()
                .expand(100,"jun")
                .toUri();

        System.out.println(uri);

        // http body -> object -> object mapper -> json -> rest template -> http body json
        UserRequest userRequest = new UserRequest();
        userRequest.setAge(30);
        userRequest.setName("jun");

        Req<UserRequest> req = new Req<>();
        req.setHeader(new Req.Header());
        req.setResBody(userRequest);

        RequestEntity<Req<UserRequest>> requestEntity = RequestEntity
                .post(uri)
                .header("x-authorization","asdf")
                .header("custom-header","112233")
                .body(req);

        RestTemplate restTemplate = new RestTemplate();

        ResponseEntity<Req<UserResponse>> response = restTemplate
                                                    .exchange(requestEntity, new ParameterizedTypeReference<Req<UserResponse>>() {});

        System.out.println("getStatusCode : "+ response.getStatusCode());
        System.out.println("getHeaders : "+ response.getHeaders());
        System.out.println("getBody : "+ response.getBody());

        return response.getBody();

    }

}

Server

package com.example.server.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Req<T> {
    private Header header;
    private T resBody;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Header{
        private String responseCode;
    }
}
package com.example.server.controller;

import com.example.server.dto.Req;
import com.example.server.dto.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController
@RequestMapping("/api/server")
public class ServerApiController {
    @PostMapping("/user/{userId}/name/{userName}")
    public Req<User> post(
                     @RequestBody Req<User> req,
                     @PathVariable int userId,
                     @PathVariable String userName,
                     @RequestHeader(name ="x-authorization") String authorization ,
                     @RequestHeader(name ="custom-header") String customHeader){
                     
        log.info("userId : {} , userName : {}",userId,userName);
        log.info("x-authorization : {} , custom-header: {}",authorization,customHeader);
        log.info("user : {}",req.getResBody());

        Req<User> response = new Req<>();
        response.setHeader(new Req.Header());
        response.setResBody(req.getResBody());

        return response;
    }
}