쌓고 쌓다
[스프링 부트] 파일 업로드 - 17 본문
upload_file 테이블
create table upload_file (
id bigint auto_increment,
pno bigint,
upload_file_name VARCHAR(255),
store_file_name VARCHAR(255),
PRIMARY KEY (id),
FOREIGN KEY (pno) REFERENCES poster(id)
);
파일명 중복을 방지하고자 시스템상 저장하는 파일명 store_file_name이 존재한다.
UploadFile
@Entity
@NoArgsConstructor
@Getter
@Setter
public class UploadFile {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long pno;
private String uploadFileName; // 업로드한 파일명
private String storeFileName; // 시스템에 저장한 파일명
public UploadFile(String uploadFileName, String storeFileName) {
this.uploadFileName = uploadFileName;
this.storeFileName = storeFileName;
}
}
DB에서 저장할 파일에 대한 클래스이다.
파일명을 두개로 나눈 이유는 서버에 저장될 파일이름이 중복되는경우 문제가 발생하기에
시스템에 저장할 파일명을 따로 저장해두는것이다.
Poster
public class Poster {
@OneToMany
@JoinColumn(name="pno")
private List<UploadFile> imgFiles;
}
게시글에서 이제 일대다 단방향으로 연관관계를 맺었다.
외래 키 관리는 Poster가 한다.
@JoinColumn의 name 속성의 값을 상대 테이블의 컬럼명으로 해주어 외래 키를 Poster가 관리하게 한다.
UploadFileRepository
public interface UploadFileRepository extends JpaRepository<UploadFile, Long> {
}
application.properties
file.dir = /Users/lsm/Desktop/imgFolder/
@Value 어노테이션으로 프로퍼티를 읽어 파일 저장 경로를 읽을 예정이다.
FileStore
@Component
public class FileStore {
@Value("${file.dir}")
private String fileDir;
public String getFullPath(String fileName) {
return fileDir + fileName;
}
public List<UploadFile> storeFiles(List<MultipartFile> multipartFiles) throws IOException {
List<UploadFile> storeResult = new ArrayList<>();
for(MultipartFile multipartFile : multipartFiles) {
String uploadFileName = multipartFile.getOriginalFilename();
String uuid = UUID.randomUUID().toString();
int pos = uploadFileName.indexOf(".");
String ext = uploadFileName.substring(pos + 1);
String storeFileName = uuid + "." + ext;
multipartFile.transferTo(new File(getFullPath(storeFileName)));
storeResult.add(new UploadFile(uploadFileName, storeFileName));
}
return storeResult;
}
}
파일 경로 필드와 메서드 기능 두개를 가진다.
getFullPath : 파일 경로와 파일 이름을 합쳐 저정할 경로와 파일명까지 전체경로를 반환한다.
storeFiles : List<MultipartFile>을 받아 파일들을 전체경로로 저장하고 List<UploadFile>로 변환하여 반환한다
storeFiles 메서드에서 UUID를 통해 시스템 저장 파일명과 원래 파일명을 저장한다.
createPosterForm.html
<form action="/poster/write" method="post" enctype="multipart/form-data">
...
<input type="file" name="files" multiple="multiple">
</form>
enctype="multipart/form-data": 여러 종류의 데이터를 여러 부분으로 나눠 전송할 때 사용한다.
boundary로 메시지 파트를 나눈다.
PosterController
@Controller
public class PosterController {
private FileStore fileStore;
private UploadFileRepository uploadFileRepository;
@PostMapping("/poster/write")
public String write(@RequestParam(required = false) List<MultipartFile> files, @Valid Poster poster ,Errors errors) throws IOException {
if(errors.hasErrors()) {
return "posters/createPosterForm";
}
List<UploadFile> uploadFiles = fileStore.storeFiles(files);
uploadFileRepository.saveAll(uploadFiles);
poster.setImgFiles(uploadFiles);
posterService.write(poster);
return "redirect:/";
}
}
form을 통해 넘어온 files를
storeFiles 메서드를 통해 서버 폴더에 파일을 저장하고 반한된 List<UploadFile>를 DB에 저장하고 (아직 외래키는 NULL인 상태)
poster의 ImgFIles를 List<UploadFile>로하여 poster를 DB에 저장하면
poster의 ImgFiles들의 외래 키를 설정해주는 UPDATE 쿼리가 날아간다.
구현 결과
+ 파일 선택 없이 제출시 빈 파일이 들어가있다 => https://non-stop.tistory.com/528
'프로그래밍 > spring' 카테고리의 다른 글
[스프링 부트] 파일 다운로드 - 18 (0) | 2023.08.04 |
---|---|
List<MultipartFile> 빈 파일 문제, MultipartFile null 체크 (0) | 2023.08.03 |
@Valid 400 에러, 메서드 파라미터 건들였더니 에러 (0) | 2023.08.01 |
[스프링 부트] 대댓글 작성 및 더보기 기능 - 16 (0) | 2023.07.28 |
스프링 JSON 응답에 추가 정보(데이터) 추가하기 (0) | 2023.07.27 |