Spring boot - 파일 업로드 서비스 구현하기

목차

DTO 생성하기

@Data
public class Item {
private Long id;
private String itemName;
private UploadFile attachFile;

// 여러개의 이미지 파일을 입력하기 위한 List
private List<UploadFile> imageFiles;
}

파일을 업로드 할때 중복된 이름을 가진 파일이 있을 경우 해당 파일로 업데이트 되는 문제가 발생합니다. 이를 해결하기 위해 파일을 저장할때는 다름 이름으로 저장하고 원래 파일이름을 별도로 저장합니다.

저장된 파일이름과 매핑되는 원래 파일 이름을 가져올 수 있도록 UploadFile 객체를 생성합니다.

@Data
public class UploadFile {

private String uploadFileName;
private String storeFileName;

public UploadFile(String uploadFileName, String storeFileName) {
this.uploadFileName = uploadFileName;
this.storeFileName = storeFileName;
}
}

파일 저장 - 서비스 구현

파일에서 확장자 추출하기

String 객체에서 lastIndexOf 메소드를 이용해 확장자명이 시작되는 위치를 가져온 후 substring 메소드를 이용해 추출한다.

private String extractExt(String originalFilename) {
int pos = originalFilename.lastIndexOf(".");
return originalFilename.substring(pos + 1);
}

UUID에 파일 확장자 추가

전송된 파일명을 사용할 경우 중복이 일어날시 파일이 업데이트가 되는 문제가 발생하기 때문에 파일마다 고유한 이름 값을 가질 수 있도록 UUID 를 사용해 유니크한 값을 갖도록 변경한 후 extractExt 메소드를 통해 추출된 확장자를 붙여준다.

private String createStoreFileName(String originalFilename) {
String ext = extractExt(originalFilename);
String uuid = UUID.randomUUID().toString();
return uuid + "." + ext;
}

MultipartFile 객체를 이용한 파일 저장

MultipartFile 객체를 이용해 파일을 저장하기 위해서는 다음과 같은 메소드를 사용합니다.

  • getOriginalFilename()
    • 파일 명을 가져오는 메소드
  • transferTo(File file)
    • MultipartFile 내 데이터를 전달받은 File 객체에 저장한다.
public UploadFile storeFile(MultipartFile multipartFile) throws IOException {
if (multipartFile.isEmpty()) {
return null;
}

String originalFilename = multipartFile.getOriginalFilename();
String storeFileName = createStoreFileName(originalFilename);
multipartFile.transferTo(new File(getFullPath(storeFileName)));
return new UploadFile(originalFilename, storeFileName);
}

여러개 파일 저장하기

여러개의 파일을 저장하기 위해서는 List 객체를 이용해 MultipartFile 객체들을 받아온 후 반복문을 통해 파일을 저장합니다.

public List<UploadFile> storeFiles(List<MultipartFile> multipartFiles) throws IOException {
List<UploadFile> storeFileResult = new ArrayList<>();
for (MultipartFile multipartFile : multipartFiles) {
if (!multipartFile.isEmpty()) {
storeFileResult.add(storeFile(multipartFile));
}
}
return storeFileResult;
}

전체 소스 코드

@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> storeFileResult = new ArrayList<>();
for (MultipartFile multipartFile : multipartFiles) {
if (!multipartFile.isEmpty()) {
storeFileResult.add(storeFile(multipartFile));
}
}
return storeFileResult;
}

public UploadFile storeFile(MultipartFile multipartFile) throws IOException {
if (multipartFile.isEmpty()) {
return null;
}

String originalFilename = multipartFile.getOriginalFilename();
String storeFileName = createStoreFileName(originalFilename);
multipartFile.transferTo(new File(getFullPath(storeFileName)));
return new UploadFile(originalFilename, storeFileName);
}

private String createStoreFileName(String originalFilename) {
String ext = extractExt(originalFilename);
String uuid = UUID.randomUUID().toString();
return uuid + "." + ext;
}

private String extractExt(String originalFilename) {
int pos = originalFilename.lastIndexOf(".");
return originalFilename.substring(pos + 1);
}
}

Controller 구현

DTO 생성

@Data
public class ItemForm {

private Long itemId;
private String itemName;
private MultipartFile attachFile;
private List<MultipartFile> imageFiles;
}

파일 저장

@PostMapping("/items/new")
public String saveItem(@ModelAttribute ItemForm form, RedirectAttributes redirectAttributes) throws IOException {
UploadFile attachFile = fileStore.storeFile(form.getAttachFile());
// Request 객체에서 받아온 MultipartFile 객체들을 가져와 저장한다.
List<UploadFile> storeImageFiles = fileStore.storeFiles(form.getImageFiles());

//데이터베이스에 저장
Item item = new Item();
item.setItemName(form.getItemName());
item.setAttachFile(attachFile);
item.setImageFiles(storeImageFiles);
itemRepository.save(item);

redirectAttributes.addAttribute("itemId", item.getId());

return "redirect:/items/{itemId}";
}

저장된 파일들 보여주기 위한 Controller

@GetMapping("/items/{id}")
public String items(@PathVariable Long id, Model model) {
Item item = itemRepository.findById(id);
model.addAttribute("item", item);
return "item-view";
}

UrlResource 를 통해 서버에 저장된 파일 보여주기

@ResponseBody
@GetMapping("/images/{filename}")
public Resource downloadImage(@PathVariable String filename) throws MalformedURLException {
return new UrlResource("file:" + fileStore.getFullPath(filename));
}
Share