[Spring] 파일 업로드

[Spring] 파일 업로드

파일 업로드를 위한 설정 후 파일 업로드를 해봅시다.


파일 업로드 작업을 수행하기 위해 먼저 해야할 설정이 있습니다. 스프링 부트로 파일을 업로드하는 것은 단순한 설정으로 가능합니다. 스프링 부트의 파일 업로드 설정은

  1. 별도의 파일 업로드 라이브러리를 이용
  2. Servlet 3버전부터 추가된 자체적인 파일 업로드 라이브러리를 이용
    두 가지 설정이 존재합니다.


1. application.properties 수정



1

스프링 부트 프로젝트를 내장된 Tomcat을 이용해 실행한다면 별도의 추가적인 라이브러리 없이 application.properties 파일을 수정하는 것만으로 충분합니다.
application.properties 파일을 위의 그림과 같이 수정합니다.

2. UploadController - uploadFile() 작성



2

이번 프로젝트에서 파일 업로드와 관련된 모든 작업은 Ajax 방식으로 처리합니다. 위의 그림과 같은 경로의 패키지를 생성하고 UploadController 클래스를 추가합니다
uploadFile() 메소드는 파라미터로 MultipartFile 배열을 받도록 설계합니다. 배열을 활용하면 동시에 여러 개의 파일을 처리할 수 있습니다.
업로드하는 파일의 이름은 IE계열에서는 전체 경로가 들어오고 크롬 브라우저에서는 단순한 파일의 이름만 들어오기 때문에 originalName과 orignalName에서 경로를 제거한 다음 파일 이름만을 취하는 fileName을 선언해둡니다.

3. UploadTestController - uploadEx() 작성



3

실제 업로드는 브라우저상에서 jQuery로 처리할 것이므로 위의 그림의 경로로 UploadTestsController를 추가하고 GET 방식으로 화면을 보도록 작성합니다.

4. uploadEx.html 생성



4

업로드 테스트를 위한 화면 내용을 uploadEx.html을 추가해 구성합니다.
Ajax로 파일 업로드를 하기 위해서 가상의 Form 객체를 만들어서 사용합니다.

5. jQuery cdn



5

uploadeEX의 중간 <script>문의 경우 위 그림의 사이트에서 버전에 맞는 코드를 가져와야 합니다.

6. uploadEx.html 결과



6

브라우저에서 uploadeEx를 살펴보면 파일선택 버튼과 업로드 버튼이 보이는 것을 확인할 수 있습니다.

7. uploadeEx.html - 업로드 결과



7

uploadeEx에 사진을 등록한 뒤 업로드 버튼을 클릭한 후 개발자 도구를 통해 살펴보면 선택한 파일의 정보가 콘솔창을 통해 출력되는 것을 확인할 수 있습니다.

8. uploadEx - Ajax 업로드 처리 작성



8

업로드 버튼을 눌렀을 때의 함수를 작성합니다.
AJax로 업로드를 처리하는 부분은 몇 가지 속성을 지정하기 때문에 $.ajax()를 이용해 처리합니다.
파일 업로드를 위해서는 contentType 속성을 반드시 false로 저징하는데 파일 업로드는 ‘multipart/form-data’ 타입을 사용하기 위함입니다. dataType 속성으로 ‘json’을 지정하였지만 아직은 컨트롤러의 메서드에서 어떠한 데이터도 반환하지 않는 상태입니다.

9. uploadeEx.html - 서버에 업로드 결과



9

uploadeEx에서 다시 업로드를 수행한 뒤 스택트레이스를 살펴보면 업로드된 파일의 이름들이 출력됩니다.

10. application.properties - 파일 업로드 설정 작성



10

업로드된 파일을 저장하기 위한 설정을 작성합니다.
파일을 저장할 때 경로는 설정 파일을 통해서 저장하고 사용할 수 있도록 application.properties에 별도의 설정값을 추가하고 이를 UploadeController에서 사용하도록 작성합니다.

11. UploadController - uploadPath 작성



11

application.properties에서 작성한 경로를 @Value를 통해 사용합니다.

12. UploadController - uploadFile() 수정



12

파일을 저장할 때 다음과 같은 사항을 고려해야만 합니다.

  1. 업로드된 확장자가 이미지인지 유효성 검사.
  2. 동일한 이름의 파일이 업로드될 시 기존 파일을 덮어쓰는지.
  3. 업로드된 파일을 저장하는 폴더의 용량.
    이 세 가지의 사항을 고려해야 합니다.
    먼저 2번의 경우 첨부파일의 이름이 같을 때 새로운 파일로 덮어쓰기가 되는 문제가 생길 수 있고 이를 예방하기 위해 UUID를 사용해 저장하도록 합니다.
    3번의 경우 동일한 폴더에 모든 파일을 넣을 경우 성능이 저하되는 문제가 생길 수 있습니다. 이를 위해 년/월/일 폴더를 생성해 한 폴더에 너무 많은 파일이 쌓이지 않도록 합니다.
    1번의 경우 업로드하는 파일의 이미지를 검사하도록 해 쉘 스크립트 파일 등을 업로드해 공격하지 못하도록 합니다.

13. UploadController - makeFolder() 작성



13

12번에서 사용한 makeFolder()를 작성합니다.
LocalDate.now()를 통해 년/월/일을 가져온 뒤 파일이 존재하는지 확인한 후 없을 시 mkdirs()를 통해 폴더를 생성하도록 작성합니다.

14. uploadeEx.html - 서버에 업로드 결과



14

프로젝트를 시작한 후 uploadEx에서 파일을 업로드해보면 지정한 경로에 년/월/일 폴더가 생성된 뒤 파일들이 업로드된 것을 확인할 수 있습니다.

15. UploadResultDTO 생성



15

이제 업로드된 이미지를 브라우저에서 보여주기 위한 UploadResultDTO를 생성합니다.
UploadResultDTO는 실제 파일과 관련된 모든 정보를 가지는데 나중에 전체 경로가 필요한 경우를 대비해서 getImageURL()을 제공합니다.

16. UploadController - uploadFile() 수정



16

UploadController의 리턴 타입을 void에서 ResponseEntity<List<UploadResultDTO>>로 변경해 UploadResultDTO의 리스트를 반환하도록 수정합니다. 이미지가 아닌 파일의 경우 예외 처리 대신 403 Forbidden을 반환하도록 합니다

17. uploadEx.html - 서버에 업로드 결과



17

다시 프로젝트를 시작한 뒤 브라우저에서 업로드를 수행한 결과 업로드 처리 후에 JSON의 배열 형태로 결과를 전달받는 것을 확인할 수 있습니다.

18. UploadController - getFile() 작성



18

JSON으로 반환된 업로드 결과를 화면에서 확인하기 위해 브라우저에서 링크를 통해 <img> 태그를 추가하고 이미지 파일 데이터를 브라우저로 전송해야 합니다. display URL 호출 시 이미지가 전송되도록 getFile() 메소드를 작성합니다.
getFile()은 URL 인코딩된 파일 이름을 파라미터로 받아 byte[]로 만들어 브라우저로 전송합니다. 파일의 확장자에 따라서 브라우저에 전송하는 MIME 타입이 달라져야 하는 문제는 java.nio.file의 Files.probeContentType()을 이용해 처리하고, 파일 데이터의 처리는 스프링의 org.springframework.util.FileCopyUtils를 이용해 처리합니다.

19. uploadEx.html - uploadResult 추가



19

uploadEx에 업로드된 이미지들을 보여줄 수 있는 <div>를 추가합니다.

20. uploadEx.html - showUploadedImages() 작성



20

Ajax 업로드 이후 이미지를 호출하는 함수인 showUploadedImages()를 작성합니다.
이미지의 업로드에 성공할 경우 함수를 호출하도록 Ajax의 success: function에 showUploadedImages()를 작성합니다.

21. UploadeEx.html - showUploadedImages() 결과



21

브라우저에서 업로드한 결과 이미지가 정상적으로 출력된 것을 확인할 수 있습니다.


© 2022. All rights reserved.