728x90
이전 포스팅에서는 게시글 상세페이지에서 파일을 다운로드 하기 위해
게시글에 해당하는 파일 정보를 불러오는 기능을 추가하였다.
오늘은 드디어 핵심기능인
게시글 상세페이지 내 파일을 클릭하면 다운로드를 할 수 있는 예제를 진행해보자.
이전 포스팅 참고
https://just-joat.tistory.com/36
[Spring Boot] 스프링부트 & MyBatis 게시판 파일 다운로드 예제 (1/2)
이전 포스팅인 게시판 파일 업로드 예제에 이어서이번에는 파일을 다운로드 하는 예제를 진행해보겠다. 따라서 DB 내에 게시글 테이블 및 파일 정보 테이블이 존재하고,파일 업로드 예제의 소
just-joat.tistory.com
전체적인 흐름은 다음과 같다.
- 상세 페이지에서 파일을 클릭하면 해당 파일의 seq 값을 서버에 요청
- 요청된 서버의 seq 값을 가지고 파일 테이블에서 파일의 정보 조회
- 조회된 파일의 정보를 이용해 자바의 Resource 인터페이스 구현체를 생성하여 리턴
* Resource 인터페이스: 컴퓨터 내 물리적으로 저장된 파일을 읽을 수 있는 인터페이스. 해당 인터페스의 구현체를 클라이언트에게 반환하면 파일을 다운로드 받을 수 있음.
1. FileMapper 인터페이스 수정 - 게시글 내 클릭한 파일의 상세정보 조회 메서드 추가
FileResponse getFileBySeq(int seq); // 파일 상세정보 조회
- DB 내 파일 테이블에서 파일의 상세정보를 조회 할 수 있도록 메서드를 추가한다.
- 리턴 타입은 당연히 FileResponse 이다.
2. FileMapper XML 수정 - 파일 SEQ 값을 참조하여 파일의 정보를 조회하는 쿼리 추가
<select id="getFileBySeq" resultMap="fileResponse">
SELECT
SEQ,
<include refid="fileColumns"></include>
FROM
BOARD_FILE
WHERE
DELETE_YN = 'N'
AND SEQ = #{seq}
</select>
- 요청된 파일의 seq 값을 이용해 해당 seq의 파일 정보를 조회하는 쿼리를 추가한다.
- FileResponse 로 변환하기 위해 resultMap 설정하는거 잊지말자.
3. FileService 클래스 수정 - 메서드 추가
public FileResponse getFileBySeq(int seq) {
return fileMapper.getFileBySeq(seq);
}
- 파일 조회 메서드를 서비스에도 추가해준다.
4. FileUtils 클래스 수정 - 클라이언트에게 제공할 Resource 구현체 생성
//파일 Resource 객체 생성
public Resource readFileAsResource(final FileResponse file) {
String uploadedDate = file.getCreatedDate().toLocalDateTime().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());
}
}
- 앞서 말했던 이번 예제에서 가장 중요한 Resource 구현체를 생성해주는 메서드이다.
- Path filePath = Paths.get(uploadPath, uploadedDate, filename): 앞선 과정 중 DB에서 조회하여 파라미터로 넘어온 파일의 정보를 이용해 해당 파일이 저장되어 있는 파일의 경로
- Resource resource = new UrlResource(filePath.toUri()): 위에서 만든 파일의 경로를 Resource 인터페이스의 구현체인 UrlResource 객체 생성자에 집어넣어 결국 클라이언트에게 제공할 수 있는 Resource 객체를 만들게 된다.
- 생성한 Resource가 존재하지 않거나 파일이 아닐 경우에 인지할 수 있는 간단한 예외처리를 한다.
5. FileRestController 클래스 수정 - 파일 다운로드 매핑 메소드 추가
// 파일 다운로드
@GetMapping("fileDownload")
public ResponseEntity<Resource> downloadFile(@RequestParam("seq") int seq) {
FileResponse file = fileService.getFileBySeq(seq);
Resource resource = fileUtils.readFileAsResource(file);
try {
String filename = URLEncoder.encode(file.getOriginalName(), "UTF-8"); // 다운로드 시 파일명
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM) // HTTP MIME 타입 설정
.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());
}
}
- 다운로드 요청을 받고 앞서 추가한 메서드들을 호출해서 파일의 정보를 조회하고, 조회된 파일 정보를 가지고 Resource 객체를 만들어서 클라이언트에게 반환한다.
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM) // HTTP MIME 타입 설정
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; fileName=\""+filename+"\";") // 이 응답은 파일 다운로드
.header(HttpHeaders.CONTENT_LENGTH, file.getSize() + "") // 헤더에 파일크기 설정
.body(resource);
- 클라이언트에게 반환되는 이 응답은 파일 다운로드이다. 라는 것을 알려주기 위한 HTTP 헤더 설정 방법이다.
- HttpHeaders.CONTENT_DISPOSITION: 이 값을 HTTP 헤더에 설정해주어야 클라이언트가 파일을 다운로드 받을 수 있다.
- HTTP 바디에는 우리가 만든 Resource를 넣어준다.
※ 결과
728x90
'웹개발 > Java, Spring' 카테고리의 다른 글
[Spring] 스프링 시큐리티 PasswordEncoder 간단하게 사용하기 (0) | 2024.07.10 |
---|---|
[Java] 자바의 접근 제어자 종류 간단 정리 (0) | 2024.07.10 |
[Spring Boot] 스프링부트 & MyBatis 게시판 파일 다운로드 예제 (1/2) (0) | 2024.07.07 |
[Spring Boot] 스프링부트 & MyBatis 게시판 파일 업로드 예제 (0) | 2024.07.06 |
[MyBatis] Mapper XML 내 ResultMap 사용법 (0) | 2024.06.29 |