AI

태태개발일지 - 객체탐지 서비스 Springboot로 서빙하기 AI API 사용하기

태태코 2025. 10. 8. 12:14
반응형

JSP

우선 JSP를 통해서 사진을 받을 코드를 작성한다.

 

 

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>사진 업로드</title>
</head>
<body>
<h1>사진 업로드</h1>

<!-- enctype은 반드시 multipart/form-data -->
<form action="/upload" method="post" enctype="multipart/form-data">
    <label for="file">사진 선택</label>
    <input type="file" id="file" name="file" accept="image/*" required><br><br>

    <button type="submit">업로드</button>
</form>
</body>
</html>

 

사진을 넣으면 /upload로 multipart/form-data로 image가 전달된다.

 

Springboot에서 JSP를 사용하려면 설정이필요하다.

https://taetaecoding.tistory.com/347

 

태태개발일지 - SpringBoot에서 JSP사용하는 방법

문제 springboot에서 jsp를 사용하려고 하니깐, 문제가 생겼다. 해결 1. /src/main/webapp/WEB-INF/views/**.jsp 이와같은 경로 아래 jsp 파일들을 둔다.2. build.gradle file에 jasper 의존성을 둔다.implementation 'org.apache.

taetaecoding.tistory.com

 

 

SpringBoot

@RestController
@RequestMapping("/upload")
@RequiredArgsConstructor
public class UploadController {

    private final UploadService uploadService;

    @PostMapping()
    public String upload(@RequestBody  MultipartFile file, Model model) {
       return uploadService.uploadImage(file); // message, image(base64)

    }
}

 

@Service
@RequiredArgsConstructor
public class UploadService {

    final RestTemplate restTemplate = new RestTemplate();
    private static final String DETECT_URL = "http://127.0.0.1:8000/detect"; // 필요 시 환경변수/설정으로 분리

    public String uploadImage(MultipartFile file) {
        try {
            // Multipart 본문 구성: key 이름은 상대 서버의 파라미터명과 일치해야 함(예: "file")
            ByteArrayResource filePart = new ByteArrayResource(file.getBytes()) {
                @Override
                public String getFilename() {
                    // 원본 파일명이 없을 수도 있으므로 기본값 처리
                    String name = file.getOriginalFilename();
                    return (name == null || name.isBlank()) ? "upload.jpg" : name;
                }
            };

            MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
            body.add("file", filePart);
            body.add("message", "Test message");
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.MULTIPART_FORM_DATA);

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

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

            return response.getBody();
        } catch (Exception e) {
            throw new RuntimeException("detect 호출 실패: " + e.getMessage(), e);
        }
    }

}

 

  1. Request를 요청할  RestTemplate를 선언한다
  2. 요청할 URL을 지정한다.
  3. 이미지 파일명이 없을 경우를 예외처리한다. 
  4. body에 이미지와 메세지를 담는다.
  5. 헤더를 담고, Request객체에 담아서 전송한다.
  6. 요청결과를 받는다.

Python

yolo모델을 가져와서 /detect 로 받은 image를 yolo모델로 실행하여 결과값을 반환한다.

from fastapi import FastAPI, UploadFile, File, Form
from fastapi.responses import JSONResponse
from pydantic import BaseModel
import io
import base64
from PIL import Image
import numpy as np
from ultralytics import YOLO
import cv2

app = FastAPI()

model = YOLO('yolov8n.pt')


class DetectionResult(BaseModel):
    message: str
    image: str


def detect_objects(image: Image.Image):
    img = np.array(image)
    results = model(img)
    class_names = model.names

    for result in results:
        boxes = result.boxes.xyxy
        confidences = result.boxes.conf
        class_ids = result.boxes.cls
        for box, confidence, class_id in zip(boxes, confidences, class_ids):
            x1, y1, x2, y2 = map(int, box)
            label = class_names[int(class_id)]
            cv2.rectangle(img, (x1,y1), (x2,y2), (255,0,0), 2)
            cv2.putText(img, f'{label} {confidence:.2f}', (x1,y1),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.9, (255,0,0), 2)
    result_image = Image.fromarray(img)
    return result_image


@app.get("/")
async def read_root():
    return {"message": "Hello FastAPI"}


@app.post("/detect")
async def detect_service(message: str = Form(...), file: UploadFile = Form(...)):
    image = Image.open(io.BytesIO(await file.read()))

    if image.mode == 'RGBA':
        image = image.convert('RGB')
    elif image.mode == 'RGB':
        image = image.convert('RGB')

    result_image = detect_objects(image)

    buffered = io.BytesIO()
    result_image.save(buffered, format='JPEG')
    img_str = base64.b64encode(buffered.getvalue()).decode('utf-8')
    return DetectionResult(message=message, image=img_str)


if __name__=="__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

 

가장 기본적인 방법을 통해 AI service를 Springboot에 올려서 사용해보았다.

 

반응형