오늘은 협업 프로젝트를 하던 도중 Spring Boot에서 필요한 데이터를 Flask 서버로 전달하기 위해서 RestTemplate을 사용한 데이터 전송에 대해서 알아보겠습니다.
스프링 부트와 플라스크는 둘 다 로컬 환경에서 설정하였으며 macOS 기반으로 실습을 하였습니다.
RestTemplate 이란 Spring에서 지원하는 객체로 REST API를 호출할 수 있습니다.
Spring 3 이상부터 사용할 수 있으며 동기 , 비동기 REST Client을 제공합니다.

위에 있는 메서드들을 활용하여 필요한 상황에 따라 사용할 수 있습니다.
이번에 데이터를 전송하기 위해서는 저는 postForObject 메서드를 사용하였습니다.
Spring boot : 2.7.17 Gradle 버전을 사용중입니다.
이미 IntelliJ나 VSCode같은 개발 환경은 있다고 생각하고 진행하겠습니다.
implementation 'org.springframework.boot:spring-boot-starter-web' 을 build.gradle에 추가하고 진행해야 합니다.
만약, 진행하시다가 제대로 코드가 진행되지 않는 경우 아래 링크로 이동하시면 현재 사용하고 있는 build.gradle 에 대한 정보를 볼 수 있습니다.
<링크>

Flask는 파이썬을 기반으로 사용되는 프레임워크이며
특별한 도구나 라이브러리 없이 사용할 수 있어 마이크로 프레임워크라도 불립니다.
Flask를 설치하기 위해서는 우선 macOS에 HomeBrew 가 설치되어 있어야 합니다.
HomeBrew 설치 및 Flask 설치는 아래 있는 티스토리에서 잘 설명이 되어 있으므로 참고 부탁드립니다.
Flask를 설치하기 위해서는 Python이 필요하기 때문에 HomeBrew를 통해서 진행하도록 하겠습니다.
Python3 설치
$ brew install python3
$ python3 --version

위에 명령어를 잘 실행했다면 파이썬 버전이 터미널에 뜨게 됩니다.
Python3을 설치하게 되면 pip 명령어를 사용할 수 있게 되어서 추가적인 환경을 구축해보도록 하겠습니다.
가상환경 설치
$ sudo pip3 install virtualenv
가상 환경이 설치가 완료되었다면 가상환경을 설정하여 적용해보도록 하겠습니다.
$ virtualenv venv
$ source venv/bin/activate
이렇게 하면 터미널 안에서 프롬프트 맨 앞을 보게 되면 가상환경을 사용할 수 있게 되며 deactivate를 하면 가상환경을 종료할 수 있습니다.
이제부터 실제로 Spring Boot 서버에서 Flask 서버로 데이터 전송을 해보도록 하겠습니다.
데이터 전송을 할 때 진행되는 순서를 적고 따라가보도록 하겠습니다.
import Byulha.project.domain.flask.model.dto.request.RequestSendToFlaskDto;
import Byulha.project.domain.flask.service.FlaskService;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
@Tag(name = "Flask 관련 컨트롤러", description = "Flask 관련 기능 컨트롤러")
public class FlaskController {
private final FlaskService flaskService;
/**
* Flask로 데이터 전송
*/
@PostMapping("/flask")
public String sendToFlask(@RequestBody RequestSendToFlaskDto dto) throws JsonProcessingException {
return flaskService.sendToFlask(dto);
}
}
컨트롤러에서는 사용자로부터 받은 데이터를 RequestSendToFlaskDto로 감싸서 service에 전달해주도록 하였습니다.
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public class RequestSendToFlaskDto {
private final String nickname;
private final String fileId;
}
사용자로부터 데이터를 입력받을 Dto에 사용자 닉네임과 S3에 올라가 있는 이미지에 대한 파일 이름을 Flask 서버로 던져주기 위해서 위와 같이 작성하였습니다.
DTO 안에 변수는 필요한 데이터 값으로 변경하여 사용하시면 됩니다 !!
import Byulha.project.domain.flask.model.dto.request.RequestSendToFlaskDto;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
@Service
@RequiredArgsConstructor
public class FlaskService {
//데이터를 JSON 객체로 변환하기 위해서 사용
private final ObjectMapper objectMapper;
@Transactional
public String sendToFlask(RequestSendToFlaskDto dto) throws JsonProcessingException {
RestTemplate restTemplate = new RestTemplate();
//헤더를 JSON으로 설정함
HttpHeaders headers = new HttpHeaders();
//파라미터로 들어온 dto를 JSON 객체로 변환
headers.setContentType(MediaType.APPLICATION_JSON);
String param = objectMapper.writeValueAsString(dto);
HttpEntity<String> entity = new HttpEntity<String>(param , headers);
//실제 Flask 서버랑 연결하기 위한 URL
String url = "http://127.0.0.1:8082/receive_string";
//Flask 서버로 데이터를 전송하고 받은 응답 값을 return
return restTemplate.postForObject(url, entity, String.class);
}
}
이제 flask 코드에 대해서 설명하겠습니다.
먼저, 위에서 설명드린 내용으로 제대로 flask가 설치가 되지 않았다면 설치를 다시 진행하지 못하여 간략하게 설명드린 점 양해 부탁드립니다..
추후에 AWS 인스턴스에 스프링 서버와 함께 올려 두 개의 백엔드 서버로 사용하기 위해서 포트를 8082로 설정하였는데 기본 디폴트 포트는 5000입니다.
from flask import Flask, request, render_template
import boto3, json
from werkzeug.utils import secure_filename
from socket import *
app = Flask(__name__)
# !! 주의 route 뒤에 경로는 위에 Spring에서 적은 경로와 같아야함 !!
@app.route('/receive_string', methods=['POST'])
def receive_string():
#Spring으로부터 JSON 객체를 전달받음
dto_json = request.get_json()
#dto_json을 dumps 메서드를 사용하여 response에 저장
response = json.dumps(dto_json, ensure_ascii=False)
#Spring에서 받은 데이터를 출력해서 확인
print(dto_json)
#Spring으로 response 전달
return response
# 0.0.0.0 으로 모든 IP에 대한 연결을 허용해놓고 포트는 8082로 설정
if __name__ == '__main__':
app.run('0.0.0.0', port=8082, debug=True)
터미널에서 flask 서버를 실행합니다.
$ python3 test.py 0.0.0.0:8082

정상적으로 실행이 되면 위와 같은 화면으로 서버가 실행된다.
이제 스프링에서 원하는 데이터를 입력하여 Flask 서버로 정확히 전달되는지 확인해볼 시간이다.
Swagger 에서 API를 호출하여 확인해보도록 하겠습니다.

RequestBody에 아래와 같은 데이터를 입력하고 실행해보도록 하겠습니다.
{
"nickname" : "cha_hammin",
"fileId" : "image.png"
}
Postman을 사용하시는 분들은 아래처럼 데이터를 넣고 확인할 수 있습니다.

터미널에서 Flask 서버에 바로 아래와 같이 원하는 데이터가 정상적으로 전달된 걸 확인할 수 있습니다.

이 과정을 진행한 이유는 스프링 서버에서는 로그인을 구현하였고 Flask에는 이후에 AI 모델을 사용하여 이미지 분석을 진행하려고 합니다. AWS S3에 이미지를 올려 Flask 서버에서 가져오려고 하였는데 어떤 유저가 언제 업로드 하였는지를 알아내는 것이 어렵다고 판단하였고 그리하여 사용자가 이미지를 업로드하는 즉시 필요한 데이터를 Flask 서버로 전달하여 이후에 과정을 원활하게 처리하도록 하기 위해서 데이터 전송을 시도하였습니다.
이때까지, Spring Boot에서 원하는 데이터를 JSON 객체로 변환하여 Flask 서버로 전달하는 과정에 대해서 글을 작성했습니다. 사실, 여러 블로그를 찾아보고 많은 시도와 오랜 시간을 투자하여 성공한 경험이라 머리 속에 오랫동안 남아있을 것 같습니다.
아직 Rest API에 대한 사용이 완벽하지 않고 어색하지만 앞으로 채팅 기능도 도전해보고 여러가지 시도를 해보면서 좀 더 성장하는 개발자가 되도록 노력하겠습니다.
p.s. 진행 중 오류가 나거나 문제가 발생 시 댓글로 피드백 부탁드립니다 !
안녕하세요! 문의드릴게 있어서 메일 드렸는데 확인해주시면 감사하겠습니다!