아주 아주 간단한 프로그램 작성 요청이었지만 gpt 는 매우 훌륭한 결과물을 보여주었다.
의뢰 내용은 다음과 같다.
html5 에서 사용자가 카메라를 오픈하고 사진을 촬영한 후 사진을 서버로 전송하는데 canvas에서 캡쳐된 프레임을 post 데이터 binary 형태로 서버로 보내고 이 데이터를 수신받아 처리하는 서버의 예제를 완전한 형태의 html 과 servlet 으로 알려줘
그리고 gpt의 답변은 다음과 같다.
아래는 사용자가 브라우저에서 카메라를 오픈하여 사진을 촬영한 후, 캡처된 이미지를 canvas로 처리하고 서버로 바이너리 데이터를 POST로 전송하며, 서버에서 이를 처리하여 저장하는 완전한 HTML과 Java Servlet 예제입니다.
HTML 코드 (카메라 + 캡처 + 전송)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Camera Capture and Upload</title>
</head>
<body>
<h1>Camera Capture and Upload</h1>
<video id="video" autoplay playsinline width="640" height="480" style="border:1px solid black;"></video>
<canvas id="canvas" width="640" height="480" style="display:none;"></canvas>
<button id="capture">Capture Photo</button>
<button id="upload" style="display:none;">Upload Photo</button>
<script>
const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const captureButton = document.getElementById('capture');
const uploadButton = document.getElementById('upload');
// 카메라 시작
navigator.mediaDevices.getUserMedia({ video: true })
.then(stream => {
video.srcObject = stream;
})
.catch(err => {
console.error("Error accessing the camera: ", err);
});
// 사진 캡처
captureButton.addEventListener('click', () => {
const ctx = canvas.getContext('2d');
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
uploadButton.style.display = 'inline';
});
// 서버로 바이너리 데이터 전송
uploadButton.addEventListener('click', () => {
canvas.toBlob(blob => {
const xhr = new XMLHttpRequest();
xhr.open('POST', '/upload', true); // 서버의 업로드 엔드포인트
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
alert('Image uploaded successfully!');
}
};
xhr.send(blob);
}, 'image/png'); // PNG 포맷으로 Blob 생성
});
</script>
</body>
</html>
Java Servlet 코드 (이미지 수신 및 저장)
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@WebServlet("/upload")
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 저장할 디렉토리 설정
String uploadDir = getServletContext().getRealPath("/") + "uploads";
File dir = new File(uploadDir);
if (!dir.exists()) {
dir.mkdirs(); // 디렉토리가 없으면 생성
}
// 파일 저장
File outputFile = new File(uploadDir, "captured_image.png");
try (InputStream inputStream = request.getInputStream();
FileOutputStream outputStream = new FileOutputStream(outputFile)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
// 응답
response.setContentType("text/plain");
response.getWriter().write("Image uploaded to: " + outputFile.getAbsolutePath());
}
}
구조
- HTML 페이지:
- video 태그로 실시간 카메라 뷰 제공.
- 캡처 버튼(capture)으로 현재 화면을 canvas에 저장.
- 업로드 버튼(upload)으로 캔버스 데이터를 바이너리 형태로 서버에 전송.
- 서블릿:
- HTTP POST 요청으로 받은 바이너리 데이터를 저장.
- 저장 경로는 uploads 디렉토리로 설정.
프로젝트 디렉토리 구조
bash
코드 복사
/webapp |-- index.html |-- /uploads (이미지 저장 디렉토리) /src |-- UploadServlet.java
주요 포인트
- 캔버스 데이터를 Blob으로 변환:
- canvas.toBlob()으로 캡처된 이미지를 바이너리 Blob 형태로 변환 후 POST 전송.
- 서버에서 바이너리 데이터 처리:
- HttpServletRequest.getInputStream()으로 수신 데이터를 읽어 파일로 저장.
- 저장 파일 경로:
- ServletContext의 getRealPath("/")를 사용해 애플리케이션 디렉토리 기반으로 파일 저장.
이 코드는 카메라 캡처, 데이터 전송, 서버 저장 과정을 포함한 완전한 예제입니다. 필요에 따라 업로드된 파일에 대한 추가 처리를 적용할 수 있습니다.
gpt 가 알려준 html 과 servlet 의 내용을 그대로 파일로 만들고
url pattern 정보만 수정해서 서버를 구동후 브라우저에서 html 페이지를 오픈하여 upload 버튼까지 눌렀는데
오류 하나없이 정확하게 동작하여 실제 파일 업로드까지 한번에 성공하였다.
gpt 가 없던 시절엔 naver 와 google 그리고 stackoverflow 와 git 까지
학습에 유용한 문서와 잘 돌아가는 샘플을 찾아 참 많이도 시간을 허비했는데...
이젠 내 생각에 이렇게 저렇게 돌아갈거야 하는 부분을 gpt 에게 자세히 설명해주고
샘플링을 해보라고하면 참 기특한 결과물을 만들어준다.
사실 위와 같이 간단한 로직의 프로그램이야 워낙 방대한 정보의 바다 어딘가에서 그대로 가져온 것이어서
운좋게 한번에 성공해서 내가 손수 성공적인 샘플을 찾는 수고와 시간을 완벽하게 세이브 한 것 일수도 있지만,
원래 내가 gpt 를 주로 활용하는 방법은 접해보지 못한 아키텍처에 대해 기획하고 상세 구상이 필요할때
gpt 에게 물어 물어 실마리를 찾고 학습하며 좀더 상세하게 질문을 던져서 구체적인 아키텍처를 그려가는 용도로 활용하고 있었다.
그런데 오늘은 아예 내 대신 간단한 프로그래밍을 맡겨서 코딩하는 수고까지 덜어내서
1인 프로젝트로 제대로된 솔루션 하나 만들어 보고 싶은 욕심마저 생겼다.
비단 나만 이러한 욕심을 부리는 것이 아닐텐데...
아마도 많은 개발자들이 gpt로 인해 자신들만의 아이디어를 다른이의 도움없이 구체화하고 실현해보려는 욕심에 과감하게 사표를 내고 있는건지도 모르겠다.