이번에는 스프링 부트를 이용해서 파일(이미지) 업로드를 하는 방법에 대해 알아보려합니다.
파일을 업로드하는 방법은 대표적으로 BLOB 와 파일 경로저장 방법입니다.
BLOB (Binary Large Object)
BLOB 방법은 이진 형식의 데이터를 직접 데이터베이스에 저장하는 방법입니다.
파일 자체가 데이터베이스에 저장되므로 별도의 경로나 URL이 필요 없습니다.
장점 :
단점 :
저장방법
build.gradle
persistence.xml
이 외 설정 파일은 여기를 참고 해주시면 됩니다.
우선 큰틀에서 설명드리겠습니다.
1. html form태그에서 이미지(jpeg)파일을 업로드를 받으면
2. 데이터 베이스에 BLOB 형태로 저장이 되고
3. 이 데이터를 사용하기위해 서비스 객체에서 파싱을 하고
4. 타임리프를 이용해 html에 표시합니다.
이미지 업로드
h1>이미지 업로드</h1>
<form th:action="@{/upload}" method="post" enctype="multipart/form-data">
<input type="file" name="file" accept="image/*">
<br>
<button type="submit">업로드</button>
</form>
<a th:href="@{/image-list}">List로 가기</a>
컨트롤러
@Controller
@RequestMapping("/")
public class ImageController {
private final ImageService imageService;
@Autowired
public ImageController(ImageService imageService) {
this.imageService = imageService;
}
@GetMapping("/")
public String showUploadForm() {
return "image-test.html"; // upload.html 템플릿을 보여줍니다.
}
@PostMapping("/upload")
public String uploadImage(@RequestParam("file") MultipartFile file) throws IOException {
// 파일 이름을 파라미터로 받아서 이미지 서비스로 전달
String fileName = file.getOriginalFilename();
imageService.uploadImage(fileName, file);
return "image-test";
}
@GetMapping("/image-list")
public String listImages(Model model) {
List<Image> images = imageService.getAllImages();
model.addAttribute("images", images); // Thymeleaf에 이미지 목록을 전달
return "image-list"; // Thymeleaf 템플릿 이름 반환
}
@GetMapping("/image/{id}")
public ResponseEntity<byte[]> getImage(@PathVariable Long id) {
Optional<Image> image = imageService.getImageById(id);
if (image.isPresent()) {
byte[] imageData = image.get().getData();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG); // 이미지 유형에 맞게 수정
return new ResponseEntity<>(imageData, headers, HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
}
서비스객체
@Service
public class ImageService {
private final ImageRepository imageRepository;
@Autowired
public ImageService(ImageRepository imageRepository) {
this.imageRepository = imageRepository;
}
public void uploadImage(String fileName, MultipartFile file) throws IOException {
Image image = new Image();
image.setFileName(fileName);
image.setData(file.getBytes());
imageRepository.save(image);
}
public List<Image> getAllImages() {
return imageRepository.findAll();
}
// 이미지 조회 메서드
public Optional<Image> getImageById(Long id) {
return imageRepository.findById(id);
}
}
이미지 리스트
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>업로드된 이미지 목록</title>
</head>
<body>
<h1>업로드된 이미지 목록</h1>
<!-- 이미지 목록을 표시하는 반복문 -->
<div th:each="image : ${images}">
<h3 th:text="${image.fileName}"></h3>
<!-- 이미지를 표시 -->
<img th:src="@{'/image/' + ${image.id}}" width="300" height="200" alt="Uploaded Image">
</div>
<!-- 이미지 업로드 폼으로 이동하는 링크 -->
<br>
<a th:href="@{/}">이미지 업로드 페이지로 이동</a>
</body>
</html>
form 요소에서 다음과 같이 업로드를 한다.
그러면 컨트롤러에서
@PostMapping("/upload")
public String uploadImage(@RequestParam("file") MultipartFile file) throws IOException {
// 파일 이름을 파라미터로 받아서 이미지 서비스로 전달
String fileName = file.getOriginalFilename();
imageService.uploadImage(fileName, file);
return "image-test";
}
이 실행돼 서비스객체의 uploadImage 메서드로 데이터베이스에 BLOB 형태로 저장된다.
마지막으로 이미지 리스트를 업로드하기위해서 list버튼을 클릭하면 컨트롤로에서 서비스객체의 uploadImage메서드를 호출해 BLOB 형태의 데이터를 파싱하게 되면 화면에
이렇게 출력된다.