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);
}
}
}
- Request를 요청할 RestTemplate를 선언한다
- 요청할 URL을 지정한다.
- 이미지 파일명이 없을 경우를 예외처리한다.
- body에 이미지와 메세지를 담는다.
- 헤더를 담고, Request객체에 담아서 전송한다.
- 요청결과를 받는다.
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에 올려서 사용해보았다.

반응형