우선,
가상 폴더(경로)와 실제 폴더(경로)가 무엇일까?
가상 폴더는 외부에 노출해도 되는 폴더 경로이다. 실제 파일이 저장되는 위치와 다르다.
프로젝트에서 API를 설계할 때, /page/index로 하는 것도 일종의 가상 경로이다.
실제 index.html 파일의 경로가 아니다.
가상 폴더의 위치에는 파일이 저장되지 않고, 실제(realPath) 폴더 경로에 저장이 된다.
즉, 가상 폴더에는 이미지 파일이 존재하지 않으며, 실제 폴더 경로에 이미지가 존재한다.
왜 이런 방식을 쓸까? 이미지가 있는 폴더를 직접적으로 노출하면 위험하니 보안상의 이유이다.
jsp , html 파일의 위치를 노출하지 않고, 서블릿을 통해 API 요청으로 불러오도록 하는 것과 동일한 이유
이미지를 요청하는 클라이언트는 실제 위치를 알 수 없다!
그러면 위의 경우에, (webapp) /storage는 가상 경로이고,
getRealPath로 ~~/workspace/.metadata/~~~ 실제 경로를 얻어올 것이다.
그리고,
이렇게 MultipartRequest 객체를 생성만 해주면
html에 <form> 에서 submit으로 넘어온 request 객체 안에서 이미지 파일만 실제 경로(realFolder)에 저장된다.
그렇다면, 클라이언트가 보낸 파일 이름이 hello.jpg 라고 한다면,
중복된 파일 이름은 어떻게 처리될까?
new DefaultFileRenamePolicy() 기본 정책은
파일 이름이 중복되면 실제 경로에 파일 이름 + 번호로 저장한다.
가령, 원본 파일 이름이 hello.jpg ---------> realFolder에 저장되는 파일 이름은
실제 폴더(realFolder 경로에) hello.jpg hello1.jpg hello2.jpg hello3.jpg hello4.jpg ... 로 저장 된다.
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ데이터베이스에 저장 방식 ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
데이터베이스에 저장은 일반적으로
원본 파일 이름 = originalFileName,
실제 폴더(realFolder)에 저장되는 파일 이름 = fileSystemName
원본, 실제 파일 이름 둘다 (폴더 경로는 이미 알고 있으므로) 파일 이름만 저장한다.
DB에 꼭 원본 파일 이름은 없어도 되지만,
실제 파일 이름(fileSystemName)은 반드시 있어야 이미지 파일 위치를 특정할 수 있다.
원본 파일 이름 저장 = 선택,
실제 파일 이름 저장 = 필수
DB에 원본 파일 이름 = 중복 가능,
실제 파일 이름 = 중복 불가 unique 유일해야함
기본 정책을 따르면 위처럼 저장이 될 것이다.
만약, uuid 정책을 쓴다면?
즉, 파일이 서버에 저장 되는 방식을 정리하면
클라이언트는 원본 파일 이름, 이미지 파일을 서버에 전송하면
서버의 가상 경로의 실제 폴더 위치에 파일이 저장되고, 중복된 파일 이름은 정해둔 정책을 따른다.
그리고 DB에는 원본 파일 이름, 중복된 파일 이름 정책을 따른 실제 파일 이름만 저장해준다.
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ아래부터는 이제 파일을 불러오기 ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
들어가기 앞서,
<img src = "~~"> 에서 이것도 일종의 GET API 요청이다.
src에 적힌 서버 주소로 api 요청을 보내면 이미지 파일만 가져온다.
그럼, 이미지 목록을 불러오는 순서를 정해보면
1. ajax 요청으로 이미지 목록을 API 요청 /MamondeProject/api/product/list
2. 서버에서 DB 조회 후, 실제 폴더 (realFolder) 파일 이름(FileSystemName)을 ResponseBody에 JSON으로 담아서(return DTO) 클라이언트로 전송 (여기까지는 이미지가 아닌 텍스트 데이터만 이동)
3. ajax에서 요청 결과를 받아서 <img src = " ~~~/storage/${실제 폴더 파일 이름} 로 html 태그를 생성
(여기까지는 이미지가 아닌 텍스트 데이터만 이동)
4. img src에 get 요청으로 서버에 ~~/storage/${실제 폴더 파일이름} API 요청
5. 서버에서 /storage/${실제 폴더 파일 이름} API 요청을 받으면,
실제 폴더(realFolder)에서 실제 폴더 파일 이름(FileSystemName)을 찾아서 클라이언트로 이미지 전송한다.
즉,
/MamondeProject/api/product/list 요청으로 이미지 목록이 10개이면
img 태그를 10개 생성 후 src의 /storage/${실제 폴더 파일 이름}으로 GET 요청을 10번 보냄
그 결과로 이미지 10개를 받아서 html에 이미지를 삽입한다.
예시)
src = "/가상 폴더 위치/실제 파일 이름" 형식이여야 한다.
원본 파일 이름으로는 중복된 파일을 절대 특정할 수 없다.
<img src="/storage/123e4567-e89b-12d3-a456-426614174000.jpg" alt="Uploaded Image 1" />
<img src="/storage/123e4567-e89b-12d3-a456-426614174001.jpg" alt="Uploaded Image 2" />
<img src="/storage/123e4567-e89b-12d3-a456-426614174002.jpg" alt="Uploaded Image 3" />
<img src="/storage/홍길동1.jpg" alt="Uploaded Image 3" />
<img src="/storage/홍길동2.jpg" alt="Uploaded Image 3" />
결론적으로 정리하면
이미지 파일 업로드는
클라이언트(원본파일이름,이미지파일)이
서버 가상폴더 -> 실제 폴더 경로에 이미지파일이 저장되고,
DB에는 원본파일명(선택) + 실제 파일명(필수)
이미지 파일 조회는
DB에서 실제 파일명(텍스트)을 받아서, img src 태그를 생성하고
src에서 /가상폴더/실제파일명 위치로 이미지 파일 요청한다.
각각 모든 이미지마다 GET 요청으로 불러온다.