0. 개요
게시판 등 다양한 웹서비스에서 제공하는 기능인 파일 업로드 기능을 구현하는 것을 목표로 한다.
다양한 파일 업로드 중 '이미지' 파일 업로드를 첫 대상으로 한다.
기존에 제작했던 게시판 서비스에서는 '이미지', '동영상', '텍스트 파일' 등 다양한 종류의 파일을 게시글에 포함하여 저장하는 기능을 포함하지 않았다.
이미지 파일을 처리해야 하는 수요가 지속적으로 생겨, 클라이언트로 부터 저장을 요구받는 이미지 파일을 어떠한 방식으로 저장을 해야 하는가에 대한 고민이 생겨 이 테스트 프로젝트를 구현하게 되었다.
이 프로젝트가 해결해야 하는 궁금증이자 달성 목표는 다음과 같다.
첫째, 이미지 파일을 어떠한 방식으로 저장하는 것이 효율적인가?
둘째, 이미지 파일을 게시판의 게시글을 처리하는 것 처럼, DB를 통해 저장할 수 있는가?
셋째, 이미지 뿐만 아니라 동영상 파일, gif, txt, 엑셀, ppt 등 다양한 파일을 처리할 수 있는가?
위 목표에 달성하기 위해서 앞으로 프로젝트를 진행 할 것이다.
이를 위한 첫 포스팅 주제는 다음과 같다.
" 서버의 로컬 저장소를 이용한 이미지 업로드 방식 구현"
1. 업로드 방식
1) 클라이언트가 '이미지 파일'을 파일 업로드 한다.
2) 업로드된 '이미지 파일'은 서버의 물리적 저장장치에 저장된다.
3) 데이터베이스는 '이미지 파일'이 저장된 서버의 물리적 저장장치의 주소를 저장한다.
클라이언트가 업로드한 이미지 파일은 서버의 물리적 저장소(로컬)에 저장되고, DB에는 저장된 주소를 기록하는 방식이다.
2. 구현
1. 'application.yml'
- 환경 설정(파일 업로드 경로)
파일 업로드 경로를 "C:\SpringBoot\upload" 로 설정한다.
2. 'Files.java'
- 파일 엔티티
package study.imageHandlerTest.entity;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import java.sql.Timestamp;
@Entity
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class SaveFiles {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String title;
private String imageUrl;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "posts_id")
private Posts posts;
@CreationTimestamp
private Timestamp createDate;
}
+) 'FilesUploadDto.java'
- 파일 업로드 DTO
package study.imageHandlerTest.dto;
import lombok.Data;
import org.springframework.web.multipart.MultipartFile;
import study.imageHandlerTest.entity.SaveFiles;
@Data
public class FilesUploadDto {
private MultipartFile file;
private String title;
//DTO -> Entity
public SaveFiles toEntity(String imageUrl) {
return SaveFiles.builder()
.imageUrl(imageUrl)
.title(title)
.build();
}
}
3. 'FilesRepository.java'
- JPA로 구현
4. 'ImageService.java'
package study.imageHandlerTest.service;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import study.imageHandlerTest.dto.FilesUploadDto;
import study.imageHandlerTest.entity.SaveFiles;
import study.imageHandlerTest.repository.FilesRepository;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
@Service
@RequiredArgsConstructor
public class ImageService {
private final FilesRepository filesRepository;
//파일 업로드 경로 지정
@Value("${file.path}")
private String uploadFolder;
@Transactional
public void imageUpload(FilesUploadDto filesUploadDto) {
UUID uuid = UUID.randomUUID();
String imageFileName = uuid + "_" + filesUploadDto.getFile().getOriginalFilename();
System.out.println("이미지 이름: " + imageFileName);
Path imageFilePath = Paths.get(uploadFolder, imageFileName);
try {
Files.write(imageFilePath, filesUploadDto.getFile().getBytes());
} catch (Exception e) {
e.printStackTrace();
}
SaveFiles saveFiles = filesUploadDto.toEntity(imageFileName);
filesRepository.save(saveFiles);
}
}
- 'uploadFolder' 문자열 변수
: '파일 업로드 경로'를 의미한다.
'applicaion.yml'에 설정한 그 경로를 지칭한다.
- UUID란? / 사용이유
: 128비트 고유식별자로서, 36자리 문자열 형태이다.
: 파일명을 저장하기 위해서, 랜덤으로 UUID를 생성하여
"UUID" + "_" + "파일명" 의 형태로 업로드 파일을 저장한다.
UUID를 단독으로 사용해도 거의 문제가 발생하지 않지만, 희박하게 공통의 UUID가 생성되어 문제가 발생할 수도 있기에 파일명과 함께 조합하여 업로드 파일명을 관리한다.
5. MainController.java
package study.imageHandlerTest.controller;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import study.imageHandlerTest.dto.FilesUploadDto;
import study.imageHandlerTest.service.ImageService;
@Controller
@RequiredArgsConstructor
public class MainController {
private final ImageService imageService;
@GetMapping("/")
public String index() {
return "index";
}
@PostMapping("/")
public String coverImageUpload(FilesUploadDto filesUploadDto) {
if(filesUploadDto.getFile().isEmpty()) {
throw new RuntimeException("File is empty");
}
imageService.imageUpload(filesUploadDto);
return "redirect:/";
}
}
6. HTML (index.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>File Upload</title>
</head>
<body>
<form action="/" method="POST" enctype="multipart/form-data">
<div class="mb-3">
<label for="imageTitle" class="form-label">이미지 제목</label>
<input type="text" class="form-control" id="imageTitle" name="title" required>
</div>
<div class="mb-3">
<label for="imageFile" class="form-label">이미지 파일</label>
<input type="file" class="form-control" id="imageFile" name="file" required>
</div>
<button type="submit" class="btn btn-primary">업로드</button>
</form>
</body>
</html>
- <form> 태그의 enctype="multipart/form-data" 속성 설정
: 폼 데이터가 파일이나 이미지와 같은 속성을 포함하게 해줄 수 있게 한다.
- <input> 태그의 type="file" 속성 설정
: 파일을 입력받기 위한 속성
+) 프로젝트 트리
3. 실제 작동 모습
- 사전 설명 -
클라이언트는 이미지 파일을 '파일 업로드' 기능을 이용해서 업로드를 진행한다.
1) 업로드된 이미지 파일들은 "서버의 로컬 저장소"에 저장된다.
2) "서버의 로컬 저장소"에 저장된 파일 경로(주소)를 DB에 저장한다.
[초기 DB의 테이블 모습]
1. '클라이언트'의 파일 업로드
'파일 선택' 을 눌러 업로드 하고자 하는 이미지 파일을 업로드 한다.
'tiger.jpg' 파일을 선택한다.
'이미지 제목'을 "animal1"으로 입력하고 '업로드' 버튼을 눌러 파일 업로드 기능을 수행한다.
2. 서버의 로컬 저장소에 저장되었는지 확인
저장소 경로 : "C:\SpringBoot\upload" 에 업로드된 파일이 저장된 것을 확인 할 수 있다.
1) 업로드된 이미지 파일들은 "서버의 로컬 저장소"에 저장된다.
위 1번 목표를 달성했다.
3. DB에 저장된 파일 주소가 기록되었는지 확인
DB에 파일 주소가 기록된 것을 확인할 수 있다.
더불어 title에 파일명으로 입력한 "animal1"이 기록된 것을 확인할 수 있다.
2) "서버의 로컬 저장소"에 저장된 파일 경로(주소)를 DB에 저장한다.
위 2번 목표를 달성했다.
- 포스팅 마무리
"서버의 로컬 저장소를 이용하여 이미지 파일 업로드 기능을 구현하였다."
- 이어지는 포스팅 확인하기
[SpringBoot - 파일 다루기] 2. 업로드한 이미지 파일 웹에서 확인하기
https://notorious.tistory.com/423
[SpringBoot - 파일 다루기] 2. 업로드한 이미지 파일 웹에서 확인하기
0. 개요- 이전 포스팅에서 클라이언트가 '이미지 파일'을 업로드 하여, 서버에 저장하는 기능을 구현하였다.저장된 이미지를 클라이언트가 확인하는 기능이 필요하다는 것을 느꼈다.따라서, 클
notorious.tistory.com
[SpringBoot - 파일 다루기] 3. 동영상 파일(MP4) 다루기
https://notorious.tistory.com/424
[SpringBoot - 파일 다루기] 3. 동영상 파일(MP4) 다루기
0. 개요- 이전 포스팅은 '이미지 파일'을 다루는 것에 초점을 두었다.이번 포스팅은 동영상 파일(MP4)를 업로드 기능을 구현하고자 한다. [현 상태에서 동영상(MP4) 파일 업로드 한다면...?] 1. '동영
notorious.tistory.com
[SpringBoot - 파일 다루기] 4. 기존 게시판 프로젝트에 '파일 업로드' 기능 추가하기 (완)
https://notorious.tistory.com/425
'Spring' 카테고리의 다른 글
[SpringBoot - 파일 다루기] 3. 동영상 파일(MP4) 다루기 (0) | 2025.01.25 |
---|---|
[SpringBoot - 파일 다루기] 2. 업로드한 이미지 파일 웹에서 확인하기 (1) | 2025.01.23 |
[SpringBoot - 파일 다루기] 0. 프로젝스 생성 및 설정 (0) | 2025.01.19 |
[JUnit] 스프링 부트 테스트와 JUnit (0) | 2024.05.14 |
[Spring + IntelliJ] Generated source files should not be edited 경고 메시지 (0) | 2024.01.25 |