스프링개발자/301 - 아키텍처

3. 그레이들 멀티프로젝트 - RestTemplate

2ndPrince 2020. 8. 30. 04:29

[배경]

앞서 구현한 두개의 어플리케이션 간의 호출이 일어나게 하자.

 


1. RestController 만들기

weather-application내에 비가 오는 확율을 계산해주는 ForecastController를 만든다.

package com.example.monorepo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping(value = "/weather")
public class ForecastController {

    @Autowired
    ForecastService forecastService;

    @GetMapping(value = "/forecast/{days}")
    public List<Double> forecast(@PathVariable int days) {
        return forecastService.predict(days);
    }
}

 Autowired로 주입받는 ForecastService는 다음과 같다;

package com.example.monorepo;

import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class ForecastService {

    public List<Double> predict(int days) {
        List<Double> rainProbabilityList = new ArrayList<>();
        for (int i = 1; i <= days; i++) {
            if (i == 5) {
                rainProbabilityList.add(1.0);
            } else if (i % 2 == 0) {
                rainProbabilityList.add(0.5);
            } else{
                rainProbabilityList.add(0.1);
            }
        }
        return rainProbabilityList;
    }
}

오늘부터 5일 후의 비가 올 확율이 100%, 오늘부터 짝수만큼의 날들은 비올 확율 50%, 그 외엔 10%라고 임시 설정. 

 

2. RestController 동작 확인

WeatherApplication을 구동시킨다.

http://localhost:8081/weather/forecast/7

 

[
0.1,
0.5,
0.1,
0.5,
1,
0.5,
0.1
]

 

3. 어플리케이션간의 호출

main-application의 MainController에서 weather-application의 ForecastController호출해보자.

RestTemplate을 이용한다.

 

앞으로 1주일의 야외수업 여부를 알아보는 api endpoint 이다.

임의의 임계치인 0.4보다 같거나 높은 비 올 확률이면, 야외수업을 가지 않고, 0.4보다 낮으면 야외수업을 간다고 알려준다.

 

main-application에 PlanService를 만든다.

package com.example.monorepo;

import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Service
public class PlanService {

    public List<Boolean> canGoOutsideForWeek(double threshold) {
        RestTemplate restTemplate = new RestTemplate();

        // create headers
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        // send POST request
        String url = "http://localhost:8081/weather/forecast/7";
        ResponseEntity<Object[]> response = restTemplate.getForEntity(url, Object[].class);
        ArrayList<Double> body = new ArrayList(Arrays.asList(response.getBody()));
        ArrayList<Boolean> yesno = new ArrayList<>();
        for (Double d : body) {
            if (d < threshold) {
                yesno.add(true);
            } else {
                yesno.add(false);
            }
        }
        return yesno;
    }
}

RestTemplate call에 대한 자세한 내용은 이전 글(https://2ndprince.tistory.com/12) 참고

 

MainController에도 PlanService를 주입받고, endpoint 하나를 더 추가했다.

package com.example.monorepo;

import com.example.monorepo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping(value = "/main")
public class MainController {

    @Autowired
    PlanService planService;

    @GetMapping(value = "/demo")
    public User demo(){
        User myUser = new User();
        myUser.setAge(10);
        myUser.setName("2nd prince");
        myUser.setId("1");
        return myUser;
    }

    @GetMapping("/weekly")
    public String makeWeeklyPlan(){
        List<Boolean> booleans = planService.canGoOutsideForWeek(0.4);
        return booleans.toString();
    }
}

http://localhost:8080/main/weekly를 get으로 실행해본다.

[true, false, true, false, false, false, true]

WeatherApplication을 호출하여 받은 비올 확율 값을 이용하여 야외수업을 나갈지 여부를 결정해주는 endpoint를 만들었다.

 

Client Request -> MainController -> PlanService -> ForestController -> ForecastService -> ForecastController -> PlanService -> MainController -> Client Response 의 흐름이다.

 

소스코드

https://github.com/2ndPrince/monorepo/tree/monorepo_restTemplate


[TroubleShooting]

1. restTemplate call으로 List<Double>을 받아온다. Object[].class으로 하였다. type safe하지 못한 좋지 않은 방법인데, 이것을 해결하려면 ParameterizedTypeReference 을 사용하면 되지만, Double에 막혀서 못 구현했다.