Search
Duplicate
📒

[Spring Study] 05-xx. 파일 업로드

상태
수정중
수업
Spring Study
주제
Converter
4 more properties
참고

파일 업로드 소개

NOTE

HTML 폼 전송 방식

1.
application/x-www-form-urlencoded
2.
multipart/form-data

application/x-www-form-urlencoded 방식

NOTE
HTML 폼 데이터를 서버로 전송하는 가장 기본적인 방법!
쿼리파라미터 방식으로 전송됨
Form 태그에 별도의 enctype옵션이 없다면, 요청 HTTP헤더에 자동으로 Content-Type: application/x-www-form-urlencoded를 추가한다.
하지만 파일 업로드는 문자가 아닌 바이너리 데이터를 전송해야 한다. 또한, 보통 폼을 전송할 때 파일만 전송하지 않는다는 점을 해결해야 한다.
문자와 바이너리를 동시에 전송 multipart/form-data 사용

multipart/form-data

NOTE
form의 enctype에 multipart/form-data 추가 (각 파트마다 헤더와 바디를 가진다.)
이 방식은 다른 종류의 여러 파일과 폼 내용을 함께 전달할 수 있다! (multipart)

content-Disposition

항목별 헤더, 여기에 부가 정보가 포함된다.
이렇게 항목을 구분해서 한 번에 전송이 가능하다!

스프링과 파일 업로드

NOTE
서블릿 방식도 같이 소개하지만, 사실 스프링방식만 알아도 상관없으므로 생략한다..

Form(MultipartFile 타입) 받기!

@Data public class ItemForm { private Long itemId; private String itemName; private MultipartFile attachFile; private List<MultipartFile> imageFiles; }
Java
복사
DTO 파일
@PostMapping("/items/new") public String saveItem(@ModelAttribute ItemForm form, RedirectAttributes redirectAttributes) throws IOException { UploadFile attachFile = fileStore.storeFile(form.getAttachFile()); List<UploadFile> storeImageFiles = fileStore.storeFiles(form.getImageFiles()); // 데이터베이스에 저장 // ... return "redirect:/items/{itemId}"; }
Java
복사
컨트롤러 파일
위와 같이 Form의 형식에 따라 DTO를 작성하고, 파일은 MultipartFile 타입으로 받는다.

MultipartFile 주요 메서드

file.getOriginalFilename() : 업로드 파일명
file.transferTo() : 파일 저장

예제로 구현하는 파일 업로드, 다운로드

NOTE
실제로 파일업로드 방식을 구현해보자!

요구사항

상품을 관리(상품 이름, 첨부파일 하나, 이미지파일 여러개)
첨부파일 업로드, 다운로드 기능
업로드한 이미지 웹 브라우저에서 확인

DTO

NOTE
@Data public class ItemForm { private Long itemId; private String itemName; private MultipartFile attachFile; private List<MultipartFile> imageFiles; }
Java
복사
파일은 MultipartFile로 받는다.

Entity

NOTE
@Data public class Item { private Long id; private String itemName; private UploadFile attachFile; private List<UploadFile> imageFiles; }
Java
복사
실제로 저장하는건 파일이름
@Data public class UploadFile { private String uploadFileName; private String storeFileName; public UploadFile(String uploadFileName, String storeFileName) { this.uploadFileName = uploadFileName; this.storeFileName = storeFileName; } }
Java
복사
데이터베이스에 저장되는 이름과, 업로드할때 이름은 달라야한다!

FileStore

NOTE
전체코드!

첨부파일 저장

// properties에 있는 경로값 @Value("${file.dir}") private String fileDir; // 파일을 어디다 저장할것인지 public String getFullPath(String filename) { return fileDir + filename; }
Java
복사
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); }
Java
복사

파일 리스트 저장

public List<UploadFile> storeFiles(List<MultipartFile> multipartFiles) throws IOException { List<UploadFile> storeFileResult = new ArrayList<>(); // 여러 파일 처리 for (MultipartFile multipartFile : multipartFiles) { if(!multipartFile.isEmpty()){ UploadFile uploadFile = storeFile(multipartFile); storeFileResult.add(uploadFile); } } return storeFileResult; }
Java
복사

업로드 파일명 → DB에 저장할 파일명 변경

// 저장할 파일이름 ex(UUID 랜덤값 + . + png ) private String createStoreFileName(String originalFilename) { String uuid = UUID.randomUUID().toString(); String ext = extracted(originalFilename); return uuid + "." + ext; } // .png 형식 살리기 private String extracted(String originalFilename) { int pos = originalFilename.lastIndexOf("."); return originalFilename.substring(pos + 1); }
Java
복사

Controller

NOTE
전체코드!

이미지 반환

@ResponseBody @GetMapping("/images/{filename}") public Resource downloadImage(@PathVariable String filename) throws MalformedURLException { return new UrlResource("file:" + fileStore.getFullPath(filename)); }
Java
복사
해당 컨트롤러가 있어야 이미지가 정상적으로 나옴

다운로드

@GetMapping("/attach/{itemId}") public ResponseEntity<Resource> downloadAttach(@PathVariable Long itemId) throws MalformedURLException { Item item = itemRepository.findById(itemId); String storeFileName = item.getAttachFile().getStoreFileName(); String uploadFileName = item.getAttachFile().getUploadFileName(); // 파일 다운로드 위한 생성 UrlResource resource = new UrlResource("file:" + fileStore.getFullPath(storeFileName)); log.info("uploadFileName={}", uploadFileName); // 파일명 인코딩 및 파일 다운로드 기능 추가 String encodedUploadFileName = UriUtils.encode(uploadFileName, StandardCharsets.UTF_8); String contentDisposition = "attach; filename=\"" + encodedUploadFileName + "\""; return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition) .body(resource); }
Java
복사

참고!

NOTE
MultipartFIle의 용량제한의 기본값은 1MB이다. 이 제한을 해제하려면 yaml에서 설정을 해주어야 한다.
spring: servlet: multipart: max-file-size: 10MB max-request-size: 10MB
YAML
복사