https://ssdragon.tistory.com/99?category=1008700
파일을 저장했으니 다운로드를 만들어보자.
우선 파일을 어떻게 저장했는지 살펴보자.
저번 게시글에서는 파일을 저장하는 것까지 했었는데 여기서 우리는 경로를 알고 있다.
따라서 이름이 중복되지 않게 저장할 파일명을 만들어주고, 사용자가 업로드 했을 당시의 파일명을 기억해야한다.
(둘 다 섞어도 되지만 여기서는 분리하여 저장했음)
- FILE_ID : 파일 테이블의 PK값 (시퀀스이고, 1부터 시작하여 자동 저장)
- STORE_FILE_NAME : 저장한 파일이름 (중복을 제거하기 위해 UUID 사용)
- UPLOAD_FILE_NAME : 사용자가 업로드한 파일명
이렇게 구성했다. 나머지 컬럼들은 신경안써도 된다.
자, 그럼 DB에도 파일 정보들이 저장되어 있고, 실제로 우리가 지정한 경로에도 파일이 저장되었다면 다운로드하는 법을 살펴보자.
참고로 SpringBoot + JPA + Spring Data Jpa를 사용하고 있습니다.
1. 컨트롤러 (Controller)
RestController는 위와같이 구성되어 있다.
/api/images/{fileId}/attach 로 GET 요청이 오면 fileService의 downloadImage() 함수가 실행된다.
그 함수의 인자로는 주소에 적힌 fileId가 들어간다.
📝 매개변수(parameter)와 인자(argument)는 서로 다릅니다!!
매개변수는 함수가 정의한 변수를 뜻하는것이고, 인자는 그 함수를 사용할 때 들어가는 실제 값을 의미합니다.
즉, 위에서는 downloadImage() 함수를 사용하기 위해 들어가는 실제 값인 fileId는 인자를 뜻합니다.
downloadImage(Long id) 라고 함수를 정의할 때 Long 타입의 변수인 id가 매개변수를 뜻합니다.
2. 서비스 (Service)
컨트롤러에 정의한 요청대로 온다면 FileService에서 downloadImage(Long fileId) 함수를 실행하게 됩니다.
1번은 아까 정의한 File 테이블에서 fileId 값과 동일한 pk 정보를 가지고 와서 검증하는 단계입니다.
2번은 File 테이블에서 가져온 값에서 서버에 저장한 파일명과 업로드 했을 당시의 파일명을 변수에 저장했습니다.
3번에서 header에 Content-Disposition의 값을 넣어주기위해 contentDisposition이라는 변수를 만들어서 값을 적어줍니다.
🧐 Content-Disposition이란?
HTTP Response Header (HTTP 응답 헤더) 속성으로 HTTP Response Body에 담겨져 있는 값이 무엇인지 설정해주는 것이다.
기본값은 inline으로 브라우저에 그냥 표시된다. 즉, 브라우저에 표시되는지 첨부파일로 표시되어 다운로드할 것인지 정하는 속성이다.
attachment를 filename과 함께 준다면 Body에 담긴 값을 filename으로 다운로드하라는 의미이다.
ex) Content-Disposition : attachment; filename="파일명.png"
이제 Body에 담아줄 파일값을 가져와야하므로 파일을 접근하기위해 Resource 인터페이스를 활용한다.
Spring은 Resource 구현체를 여러개 포함하는데 우리는 이 UrlResource란 구현체를 사용할 것이다.
🧐 UrlResource란?
Spring이 제공하는 Resource 구현체 중 하나이다. "file :" 또는 "http: " 프로토콜을 먼저 명시후 해당 리소스의 위치를 적으면 URL 방식으로 리소스를 읽는다.
지원하는 프로토콜 : http, https, ftp, file, jar
따라서 파일을 UrlResource 객체 형태로 반환받아서 HTTP 응답 바디에 보내주게 된다.
아 참고로 현재 코드에서 new UrlResource()안에 fileStoreUtil 클래스의 getFullPath() 함수를 사용하고 있는데 이건 내가 지정한 경로를 반환받는 값이라서 혹시 사용하실 분들은 저기에 파일경로와 파일 이름을 적으면 된다.
ex) new UrlResource("file: /파일경로/.../파일명");
🖥 만약 파일명을 한글로 했다면 다운받을 시 파일명이 깨지므로 인코딩을 해야한다.
아까 코드에서 현재 선택한 부분이 변경 및 추가되었다.
파일을 업로드 했을 당시에는 한글도 잘받아지고, DB에도 잘 저장되지만 사용자가 다운로드 받을 때에는 인코딩을 해야한다.
파일을 다운로드할 때 파일명을 설정할 수 있는 filename에는 US-ASCII, UTF-8 등 허용되는 것이 제한되어 있다.
따라서 허용되는 UTF-8로 한글명을 인코딩하여 넣어주면 된다.
UriUtils.encode(String source, Charset charset) 함수를 사용해서 우리가 설정한 UTF-8로 인코딩된 값을 받게된다.
이 함수는 RFC 3986에 정의된 대로 URI 내의 어느 곳에서나 잘못되었거나 예약된 의미를 갖는 모든 문자를 인코딩하는 함수이다.
따라서 URI의 구조나 의미에 영향을 미치지 않도록 하는데 유용한 함수이다.
'Spring > Spring' 카테고리의 다른 글
스프링 부트 의존관계 주입 에러 (0) | 2023.02.13 |
---|---|
스프링부트 - 하루에 한 번 쿠키 기반 조회수 증가 구현 (1) | 2022.10.03 |
[스프링시큐리티] Spring Security 5.7 (WebSecurityConfigurerAdapter 에러해결방법) (0) | 2022.07.03 |
스프링에서 파일저장하기 (0) | 2022.05.11 |
[Lombok] @NoArgsConstructor, @ToString (0) | 2022.04.11 |