본문 바로가기

Spring

[Spring boot] thymeleaf를 이용한 file upload & download

 

<form action="#" enctype="multipart/form-data" th:action="@{/fileupload}" method="post">
    File : <input type="file" name="file">
    <input type="submit" value="upload">
</form>

 

  • form 태그의 enctype 속성은 form의 data가 server로 submit 될 때 인코딩되는 방법을 의미

 

인코딩 방법은 3가지의 방법이 있음

 

* 인코딩(encoding)이란? 파일에 저장된 정보의 형태나 형식을 데이터 표준화, 보안, 처리 속도 향상, 저장 공간 절약 등을 위해서 다른 형태로 변환하는 처리 혹은 그 처리 방식

 

  1. application/x-www-form-urlencoded : 기본값으로 모든 문자들은 서버로 보내기 전에 인코딩됨을 명시 (defalut)
  2. multipart/form-data : 모든 문자를 인코딩하지 않음을 명시, form 태그에서 파일이나 이미지를 전송할 때 주로 사용
  3. text/plain : 공백 문자(space)는 "+" 기호로 변환하지만 나머지 문자는 모두 인코딩되지 않음을 명시

 

  • multipart/form-data 사용 이유: 기본 값으로 사용되는 application/x-www-form-urlencoded 방식은 문자열로만 데이터를 보내기 때문에 파일을 보낼 수 없음 하지만 multipart/form-data를 사용하면 바이너리 데이터를 보낼 수 있기 때문에 파일을 전송할 수 있음

 

 

 

@PostMapping("/fileupload")
    public String fileUpload(@RequestParam MultipartFile file, RedirectAttributes redirectAttributes) throws IOException {
        log.info(file.getOriginalFilename());
        File converFile = new File(file.getOriginalFilename());

        file.transferTo(converFile);
//        file.transferTo(new File(file.getOriginalFilename()));

        String filename_url = file.getOriginalFilename();
        String message = file.getOriginalFilename()+ " 파일이 저장되었습니다.";

        redirectAttributes.addFlashAttribute("message",message);
        redirectAttributes.addFlashAttribute("filename_url",filename_url);

        return "redirect:/upload";
    }

 

 

  • @RequestParam 을 이용하여 MultipartFile을 받고 transferto를 이용해 파일로 변환하여 지정한 경로에 저장하는 방식으로 구현
  • RedirectAttributes 클래스를 이용하여 String 형태로 업로드 메세지 전달 (addFlashAttribute - 데이터가 post 형식으로 전달, 세션을 활용해 필요한 데이터만 일회성으로 값을 넘겨줌)

 

 

 

    @GetMapping("/download/{filename}")
    public ResponseEntity<Resource> fileDownload(@PathVariable String filename) throws IOException {
//      log.info(filename);
        Resource resource = resourceLoader.getResource("classpath:" + filename);
        log.info(String.valueOf(resource.exists()));
        
        File file = resource.getFile();
        Tika tika = new Tika();
        
        String mediaType = tika.detect(file);
        
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachement; filename=\"" + resource.getFilename() +"\"")
                .header(HttpHeaders.CONTENT_TYPE, mediaType)
                .header(HttpHeaders.CONTENT_LENGTH, file.length()+"")
                .body(resource);
    }​

 

 

  • ResponseEntity는 사용자의 HttpResquest에 대한 응답 데이터를 포함하는 클래스이므로 응답 header , body를 같이 리턴할 수 있는 타입
  • PathVariable을 이용하여 URL 경로에 변수를 넣을 수 있음 
  • Resource는 classpath 기준으로 리소스를 읽어올 수 있음, getResource 메소드로 경로의 리소스를 불러올 수 있음
  • Tika 라이브러리 : PPT, CSV ,PDF 등 다양한 형태의, 파일의 메타 데이터와 텍스트를 감지하고 추출하는 라이브러리
  • Content-Disposition에 attachment를 주는 경우로, 이때 filename과 함께 주게 되면 body에 오는 값을 다운로드 받으라는 의미 

-----------------------------------------------------------------------------------------------------------------------------------

 

getFile 메소드는 기존(빌드 전)에 classpath 경로에 있는 파일은 읽어들여 다운로드할 수 있지만 새롭게 업로드 하는 파일은 읽어들이지 못해 다운로드가 안되는 에러가 발생하였음. -> 구글링을 통해 알아보니 getFile의 사용을 지양하는듯

 

그래서 코드를 변경하게 되었다.

 

@Value("${spring.servlet.multipart.location}")
private String path


@GetMapping("/download/{filename}")
    public ResponseEntity<Resource> fileDownload(@PathVariable String filename) throws IOException {
//        Resource resource = resourceLoader.getResource("classpath:"+filename);
//        Resource resource = new ClassPathResource(filename);
//        File file = resource.getFile(); // 수정 전 코드

        Path path1 = Paths.get(path + "/" + filename); // 다운로드 할 파일의 최종 경로
        String contentType = Files.probeContentType(path1); // 타입 받아오기

        Resource resource = new InputStreamResource(Files.newInputStream(path1)); // path1의 

        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachement; filename=\"" + filename +"\"")
                .header(HttpHeaders.CONTENT_TYPE, contentType)
                .body(resource);
    }

'Spring' 카테고리의 다른 글

Spring layer architechture 3 layer 정리  (0) 2021.12.01