[Spring] 서블릿 파일 업로드와 스프링 파일 업로드

728x90

 

HTML 폼 전송 방식

application/x-www-form-urlencoded

  : Form 태그에 enctype 옵션이 없으면 웹 브라우저가 요청 HTTP 메시지 헤더에 Content-Type 으로 추가

  : 입력한 폼 데이터를 HTTP Body 에 & 로 구분하여 전송

  : 파일 전송 불가

multipart/form-data

  : Form 태그에 enctype 옵션을 지정해야 함

  : 다른 종류의 여러 파일과 폼 내용 동시에 전송 가능

  : 각각의 전송 항목이 구분되어 한 번에 전송됨

 

멀티파트 사용 옵션

spring.servlet.multipart.max-file-size=1MB
spring.servlet.multipart.max-request-size=10MB

max-file-size : 파일 하나의 최대 사이즈

max-request-size : 요청 전체의 최대 사이즈

 

파일 경로 설정

file.dir=\\C:\\Users\\{경로}\\  (윈도우)
file.dir=/Users/{경로}/         (맥)

파일이 저장되는 경로를 설정한다.

@Value("${file.dir}")
private String fileDir;

저장할 file.dir 값을 주입한다.

 

서블릿 파일 업로드

@PostMapping("/upload")
public String saveFileV1(HttpServletRequest request) throws ServletException, IOException {
  String itemName = request.getParameter("itemName");
  
  Collection<Part> parts = request.getParts();
  for (Part part : parts) {
    Collection<String> headerNames = part.getHeaderNames();
    for (String headerName : headerNames) {
    }
    
    InputStream inputStream = part.getInputStream();
    String body = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
    
    if (StringUtils.hasText(part.getSubmittedFileName())) {
      String fullPath = fileDir + part.getSubmittedFileName();
      part.write(fullPath);
    }
  }
  
  return "upload-form";
}

part.getSubmittedFileName() : 클라이언트가 전달한 파일명

part.getInputStream() : Part 의 전송 데이터를 읽을 수 있음

part.write(...) :  Part 를 통해 전송된 데이터를 저장

 

스프링 파일 업로드

@PostMapping("/upload")
public String saveFile(@RequestParam String itemName, @RequestParam MultipartFile file, 
                       HttpServletRequestrequest) throws IOException {

  if (!file.isEmpty()) {
    String fullPath = fileDir + file.getOriginalFilename();
    file.transferTo(new File(fullPath));
  }
  
  return "upload-form";
 }

@RequestParam MultipartFile file

  : 업로드하는 HTML Form 의 name 에 맞추어 @RequestParam 을 적용

  : @ModelAttribute 에서 MultipartFile 동일하게 사용 가능

file.getOriginalFilename() : 클라이언트가 전달한 파일명

file.transferTo(...) : 파일 저장

 

예시

String uploadFileName = file.getOriginalFilename();
String uuid = UUID.randomUUID().toString();
String storeFileName = uuid + "." + extractExt(uploadFileName);

uploadFileName : 고객이 업로드한 파일명

storeFileName : 서버 내부에서 관리하는 파일명 (uuid + . + 확장자)

(다른 고객과 파일이 겹칠 수도 있기 때문에)

 

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

<img src="/images/파일명"> 과 같이 img 태그로 이미지 조회할 때 사용한다.

UrlResource 로 이미지 파일을 읽어와

Resource 객체를 @ResponseBody 로 이미지 바이너리로 변환하여 이미지 응답을 반환한다.

 

@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));
  
  String encodedUploadFileName = UriUtils.encode(uploadFileName, StandardCharsets.UTF_8);
  String contentDisposition = "attachment; filename=\"" + encodedUploadFileName + "\"";
  
  return ResponseEntity.ok()
                       .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition)
                       .body(resource);
 }

파일을 다운로드할 때 실행한다.

파일 다운로드 시 권한 체크를 한다고 가정하고, 이미지 id 를 요청하도록 한다.

 

고객이 업로드한 파일 이름으로 다운로드 하도록 한다.

Content-Disposition 헤더에

attachment; filename="업로드 파일명" 을 설정하여 브라우저에서 자동으로 다운로드를 처리할 수 있도록 한다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

출처 | 스프링 MVC 2(김영한) - 인프런

728x90