첨부파일을 다운로드 하는 기능을 구현할 것
-FileMapper 인터페이스 , 첨부파일 상세정보 조회 메서드 추가하기
첨부파일 다운로드는 게시글 상세 페이지에서 파일명을 클릭했을 때 실행된다. 이때 파일의 id(Pk)를 컨트롤러로 전달해 다운로드할 첨부파일의 상세정보를 DB에서 조회해야 한다.
DB에서 첨부파일 상세정보를 조회할 수 있도록 FileMapper 인터페이승[ 아래 메서드를 추가한다.
/**
* 파일 상세정보 조회
* @param id - PK
* @return 파일 상세정보
*/
FileResponse findById(Long id);
-FileMapper XML 첨부파일 상세정보 조회 SQL쿼리 작성
앞에서 추가한 메서드와 연결할 파일 상세정보 조회쿼리를 작성한다.
<!-- 파일 상세정보 조회 -->
<select id="findById" parameterType="long" resultType="com.study.domain.file.FileResponse">
SELECT
<include refid="fileColumns" />
FROM
tb_file
WHERE
delete_yn = 0
AND id = #{value}
</select>
-FileService 클래스 , 첨부파일 상세조회 메서드 추가하기
쿼리 실행 결과를 리턴해준다
/**
* 파일 상세정보 조회
* @param id - PK
* @return 파일 상세정보
*/
public FileResponse findFileById(final Long id) {
return fileMapper.findById(id);
}
-FileUtils클래스, 첨부파일(리소스) 조회 메서드 추가하기
Resource는 inputStreamSource를 상속하며 리소스에 대한 접근을 추상화하여 사용된다. 이 Resource를 사용해 파일 다운로드를 처리한다.
DB에서 조회한 첨부파일 정보를 이용해 디스크상에 업로드된 물리적 파일 객체를 읽어들이는 기능을 구현해야 한다.
FilesUtils에 아래 매서드를 추가한다.
/**
* 다운로드할 첨부파일(리소스) 조회 (as Resource)
* @param file - 첨부파일 상세정보
* @return 첨부파일(리소스)
*/
public Resource readFileAsResource(final FileResponse file) {
String uploadedDate = file.getCreatedDate().toLocalDate().format(DateTimeFormatter.ofPattern("yyMMdd"));
String filename = file.getSaveName();
Path filePath = Paths.get(uploadPath, uploadedDate, filename);
try {
Resource resource = new UrlResource(filePath.toUri());
if (resource.exists() == false || resource.isFile() == false) {
throw new RuntimeException("file not found : " + filePath.toString());
}
return resource;
} catch (MalformedURLException e) {
throw new RuntimeException("file not found : " + filePath.toString());
}
}
file : DB로 조회한 첨부파일의 상세 정보를 의미한다. 이를 통해 업로드된 첨부파일의 경로를 찾아낼 수 있다.
uploadDate: 첨부파일이 업로드된 날짜를 의미한다.
filename: 디스크에 업로드된 파일명을 의미
resource: 본 메서드에서 핵심이되는 객체이다. resource의 구현체인 UrlResource의 생성자 파라미터로 filePath에 담긴 첨부파일의 경로를 전달해 Resource객체를 생성한다.
만약 리소스가 없거나 리소스 타입의 파일이 아닌 경우 예외를 실행해 로직을 종료한다
-FileApiController클래스 - 첨부파일 다운로드 메서드 추가하기
FileApiController에 FileUtils를 멤버로 선언하고 downloadFile()메서드를 추가한다
package com.study.domain.file;
import com.study.common.file.FileUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
@RestController
@RequiredArgsConstructor
public class FileApiController {
private final FileService fileService;
private final FileUtils fileUtils;
// 파일 리스트 조회
@GetMapping("/posts/{postId}/files")
public List<FileResponse> findAllFileByPostId(@PathVariable final Long postId) {
return fileService.findAllFileByPostId(postId);
}
// 첨부파일 다운로드
@GetMapping("/posts/{postId}/files/{fileId}/download")
public ResponseEntity<Resource> downloadFile(@PathVariable final Long postId, @PathVariable final Long fileId) {
FileResponse file = fileService.findFileById(fileId);
Resource resource = fileUtils.readFileAsResource(file);
try {
String filename = URLEncoder.encode(file.getOriginalName(), "UTF-8");
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; fileName=\"" + filename + "\";")
.header(HttpHeaders.CONTENT_LENGTH, file.getSize() + "")
.body(resource);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("filename encoding failed : " + file.getOriginalName());
}
}
}
postid: 게시글 번호 PK를 의미
fileId: 첨부파일 번호PK를 의미한다
file: DB에서 조회한 첨부파일 상세정보를 의미한다
resource: FileUtils의 readFileResource()로 첨부파일 상세정보를 전달해 다운로드할 첨부파일을 리소스타입으로 조회한다
filename: 다운로드 할 첨부파일의 이름을 의미한다. 리소스를 읽어들일땐 실제로 디스크에 저장된 파일명 (saveName)을 통해 접근했지만 다운로드되는 첨부파일의 이름은 원본 파일명이되어야 한다.
ResponseEntity: REST API 방식에 사용되는 클래스로 이 클래를 이용하여 사용자의 HTTP요청에 대한 응답데이터를 개발자가 직접 제어할 수 있다.
-view.html - findAllFile() 함수에 파일 다운로드 링크 추가
// 전체 파일 조회
function findAllFile() {
...
...
...
// 3. 파일 영역 추가
let fileHtml = '<div class="file_down"><div class="cont">';
response.forEach(row => {
fileHtml += `<a href="/posts/${postId}/files/${row.id}/download"><span class="icons"><i class="fas fa-folder-open"></i></span>${row.originalName}</a>`;
})
fileHtml += '</div></div>';
// 4. 파일 HTML 렌더링
document.getElementById('files').innerHTML = fileHtml;
}
'JAVA > SpringBoot' 카테고리의 다른 글
REST API , URI 설계 (0) | 2024.04.09 |
---|---|
Spring Boot - 간단한 Web , HTTP, Get, Post, Put (0) | 2024.04.09 |
게시판 프로젝트 - 첨부파일 추가, 수정, 삭제 및 기존 파일 유지 (1) | 2023.11.15 |
게시판 프로젝트 - 다중 첨부 파일 업로드, 다운로드 구현 (0) | 2023.11.15 |
게시판 프로젝트 - 로그인/ 로그아웃/ 로그인 세션 체크 기능 (0) | 2023.11.15 |