스프링 게시판 만들기 - 6(파일 다운로드 링크)
1.html
read.html 부분에 다운로드 링크를 달자
<tr>
<td>
<a th:href="@{/api/board/download/(boardNo=*{boardNo}}"> 다운로드 </a>
</td>
</tr>
http 에 표시되는 것
api/board/download/?boardNo=boaradNo**
2.service
1.ResponseEntity 클라스 타입 가져오기
public ResponseEntity<Resource> getDownloadResponse(Map<String,Object> param) throws Exception{
HttpHeaders header = new HttpHeaders();
Resource res = null;
BoardVO.Response board = mapper.getBoard(param);
}
보통 @RestApi 프로젝트 코드들의 반환 값은 대부분 Object였다. 예를 들어서, 게시판 보여주기의 경우 , 이처럼 반환값은 list에 들어있는 BoardVO 객체였다.
public List<BoardVO.Response> getList(PagingVO page) throws Exception{
return mapper.getList(page);
}
하지만 파일 다운로드의 경우, get방식을 통해 url을 소환한다. 이때 이 url에 있는 것은 내가 만든 객체가 아니라, http상에 저장되어 있는 컨텐츠이다 (바이너리 컴퓨터 언어로 되어있음). 이러한 것들은 http의 response header에 저장되어있으며, 이것을 쓰기 위해 HttpHeaders header = new HttpHeaders()로 header도 같이 소환해준다.
일단 Resource를 null로 셋팅하고 , 파일 정보를 얻기 위해, 게시판 글을 가져온다. (BoardVO.Response board = maper.getBoard(param);
2.파일 경로 및 파일 객체 생성
String fullPath = filePath + board.GetStoredFileName();
String originFileName = board.getOriginFileName();
File file = new File(fullPath);
fullPath는 파일 전체 저장경로인데 (db까지 왔을때 로컬파일에 저장되는 경로) 이건 로컬파일경로(filePath)+로컬파일에 저장될때의 이름을 합친걸로 만들어준다.
originFileName은 원본 파일 저장이름이다.
전체 저장 경로를 가진 파일 객체를 만들어준다. 파일객체는 사실 실제 파일이 아니라, 단순한 프로그램과 실제 파일 조작을 수행하는 운영 체제의 기능 사이의 인터페이스처럼 동작한다. (근데 class임 , 그래서 new File할 수 있음)
new File(전체 경로)를 함으로서 전체 경로를 가진 , file인스턴스를 하나 만든거임
3.밈타입 설정
if(file.exists()){
String mimeType = Files.probeContentType(Paths.get(file.getAbsolutePath()));
if(mimeType == null){
mimeType = "application/octet-stream";
}
}
mimeType이란 바이너리 언어(ascii코드가 아니라, 이미지나 소리 등등)으로 되어있는 데이터를 주고 받을 때 쓰는 타입이다. mime타입을 쓰면 바이너리 언어로 되어있는 컨텐츠를 규칙에 맞게 ascii코드로 변형해서 읽을 수 있으며, 주고 받을 수 있다. mime타입이 없으면 전송할 때 파일이 깨지거나 파일이 텍스트 값으로 저장될 수 있다. Paths.get 은 그냥 경로를 리턴하며, 여기에 file.getAbsolutePath()를 하면 절대 경로를 리턴한다 (더 자세한 경로) 이건 파일에 타입을 가져오는 과정이다.만약 파일에 타입이 없으면 "application/oct-stream"으로 설정해준다. 이는 mime타입 중 application에 속하는 타입인데 이진데이터를 표시한다. 규칙이 정해져 있으며 이미지의 경우 image.png 이런식으로 저장되게 해준다.
4.리소스 객체에 파일 데이터 집어넣기
res = new UrlResource(file.toUrl());
아까 resource 타입의 res라는 것을 만들었다. 여기서 resource란 무엇일까?
Resource 인터페이스는 소리,이미지 등등 독립적인 방식으로 접근해야하는 데이터들을 말한다. 이때 Resource인터페이스는 이러한 데이터들에 접근하기 위한 여러가지 구현체를 만들어준다.
그 중에 하나다 UrlResource이다. UrlResouce 객체는 url데이터를 새로운 url이 있는 Resource 객체로 만들어준다.
따라서 메소드 안에는 url을 넣어줘야하는데 toUrl()은 받은 파일을 url형식으로 만들어주는 메소드이다.
즉, file url을 urlResource객체로 만들어준 과정이다.
---자, 여기까지 사용자가 등록한 이미지를 url로 등록하는 과정이였다
---이제 사용자에게 이미지를 다운로드 하라고 알려주자
5.인코딩 설정
String encodingFileName = URLEncoder.encode(originFileName,"UTF-8").replace("+","%20");
originFileName 은 client에 가는 파일을 말함.
파일 전송시 문자열 깨짐 방지를 위한 인코딩이다. URLEncoder를 사용할 때는 replaceAll 정규식이 들어간다. 이는 어떤 문자를 패턴화해서 찾는다. 인코딩할 때 , +로 바뀌는 부분이 있는데 이를 %20으로 바꾸라는 내용이다.
6.헤더 셋팅, 다운로드할 부분 셋팅
header.set("Content-Disposition",
"attachement;filename*=UTF-8''"+encodingFileName);
//파일이 크거나 임시 저장공간이용량을 많이 먹기 때문에 캐시 사용하지 말라하는거
//용량이 클 때 늦게 다운될 수 있음 ... 캐시에서 보조 메모리를 안써서
//캐시를 안쓰면 , 브라우저 속도가 늦음
header.setCacheControl("no-cache");
header.setContentType(MediaType.parseMediaType(mimeType));
}
//오른쪽 generic은 없어도 괜찮음
return new ResponseEntity<>(res, header, HttpStatus.OK);
}