본문 바로가기

팀프로젝트 - TailsRoute

TEAM Project (11.26)

Flask와 Spring Boot를 활용한 비디오 업로드 및 분석 시스템 구현

흐름

  1. 사용자 업로드 -> 사용자가 브라우저에서 비디오 파일을 업로드
  2. Spring Boot 처리
    -> 업로드된 비디오 파일을 Flask 서버로 전달
    -> Flask 서버가 비디오를 분석하고 결과를 반환
  3. 결과 표시
    -> Spring Boot가 분석 결과를 HTML로 렌더링하여 사용자에게 같은 페이지에서 결과 표시

 

해당 페이지의 Spring Boot 디렉터리 구조

 

com
└── project
└── tailsroute
├── api
│ └── RestTemplateConfig.java // RestTemplate 설정
├── controller
│ └── BehaviorController.java // 요청 처리 컨트롤러
├── service
│ └── BehaviorService.java // Flask 서버와 통신
├── util
│ └── MultipartFileResource.java // 파일 처리 유틸리티
└── templates
└── videoAnalysis.html // 업로드와 결과 HTML

 

  1. RestTemplate 설정
  • Flask 서버와 HTTP 통신을 위해 RestTemplate을 설정
package com.project.tailsroute.api;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

 

RestTemplate는 스프링 프레임워크에서 제공하는 클래스로, 다른 프로그램(또는 서버)에 HTTP 요청을 보낼 때 사용된다. 주로, RESTful 웹 서비스와 통신할 때 사용하며, 클라이언트 역할을 한다. 이를 통하여 GET, POST, PUT, DELETE 등의 HTTP 요청을 보냄

  • 클라이언트 측에서 다른 서버에 요청을 보내고, 응답을 받을 수 있으며, JSON, XML 같은 데이터를 요청하거나 받을 수 있음
  • 요청을 보내고, 응답이 돌아올 때까지 기다리는 동기적인 작업 흐름을 작동
  • HTTP 요청을 위한 코드를 단순화하고, 예외 처리를 쉽게 할 수 있도록 도와준다.

 

package com.project.tailsroute.util;

import org.springframework.core.io.ByteArrayResource;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

public class MultipartFileResource extends ByteArrayResource {

    private final String filename;

    public MultipartFileResource(MultipartFile file) throws IOException {
        super(file.getBytes());
        this.filename = file.getOriginalFilename();
    }

    @Override
    public String getFilename() {
        return this.filename;
    }
}
package com.project.tailsroute.service;

import com.project.tailsroute.util.MultipartFileResource;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

@Service
public class BehaviorService {

    private final RestTemplate restTemplate;

    public BehaviorService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public String analyzeVideo(MultipartFile file) throws IOException {
        String url = "http://localhost:5000/analyze"; // Flask 서버 URL

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);

        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("file", new MultipartFileResource(file));

        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);

        ResponseEntity<String> response = restTemplate.postForEntity(url, requestEntity, String.class);

        if (response.getStatusCode() == HttpStatus.OK) {
            return response.getBody();
        } else {
            throw new RuntimeException("Flask 서버에서 오류 발생: " + response.getStatusCode());
        }
    }
}
package com.project.tailsroute.controller;

import com.project.tailsroute.service.BehaviorService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

@Controller
@RequestMapping("/usr/behaviorAnalysis")
public class BehaviorController {

    private final BehaviorService behaviorService;

    public BehaviorController(BehaviorService behaviorService) {
        this.behaviorService = behaviorService;
    }

    @GetMapping("/videoAnalysis")
    public String videoAnalysisPage(Model model) {
        model.addAttribute("result", null);
        return "videoAnalysis";
    }

    @PostMapping("/videoAnalysis")
    public String analyzeVideo(@RequestParam("file") MultipartFile file, Model model) {
        try {
            String result = behaviorService.analyzeVideo(file);
            model.addAttribute("result", result);
        } catch (Exception e) {
            model.addAttribute("result", "오류 발생: " + e.getMessage());
        }
        return "videoAnalysis";
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>비디오 분석</title>
</head>
<body>
    <h1>비디오 업로드 및 분석</h1>

    <form action="/usr/behaviorAnalysis/videoAnalysis" method="post" enctype="multipart/form-data">
        <label for="video">비디오 파일 선택:</label>
        <input type="file" id="video" name="file" accept="video/*" required>
        <br><br>
        <button type="submit">업로드 및 분석</button>
    </form>

    <hr>

    <h2>분석 결과</h2>
    <div>
        <pre>
            <p th:text="${result} != null ? result : '분석 결과가 여기에 표시됩니다.'"></p>
        </pre>
    </div>
</body>
</html>