프로그래밍/spring

[스프링 부트] 파일 다운로드 - 18

승민아 2023. 8. 4. 20:08

PosterController

@GetMapping("/download/{id}")
public ResponseEntity<Resource> downloadAttach(@PathVariable Long fileId) throws MalformedURLException {

    UploadFile file = uploadFileRepository.findById(fileId).get();
    String uploadFileName = file.getUploadFileName();
    String storeFileName = file.getStoreFileName();
    UrlResource urlResource = new UrlResource("file:" + fileStore.getFullPath(storeFileName));

    String encodeUploadFileName = UriUtils.encode(uploadFileName, StandardCharsets.UTF_8);
    String contentDisposition = "attachment; filename=\"" + encodeUploadFileName + "\"";
    return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition)
            .body(urlResource);
}

 

@PathVariable?

GetMapping에 변수명으로 {id}가 있다. 여기에 작성된 변수명은

메서드 파라미터로 써놓은 @PathVariable("id")와 매핑이 된다.

보통 @RequestParam으로 쿼리 스트링 요청이 들어오는 /upload?id=2와 달리

/upload/2 를 처리할 때 사용한다.

 

Resource, UrlResource?

Resource resource = new UrlResource("file:{절대경로}");

Resource는 스프링에서 리소스(파일)에 접근하는데 사용되는 인터페이스이다.

구현체로 UrlResource가 있다. file: http:처럼 Prefix로 프로토콜을 명시하고 해당 리소스의 URL을 붙여 사용한다.

 

 

@ResponseEntity?

public class ResponseEntity<T> extends HttpEntity<T> {...}
Extension of HttpEntity that adds an HttpStatusCode status code. Used in RestTemplate as well as in @Controller methods.

HttpEntity의 확장으로 HTTP상태코드를 추가한것이다.

HttpEntity는 뭐고 어디 쓰는데? 산넘어 산이다.

 

HttpEntity

Represents an HTTP request or response entity, consisting of headers and body

헤더와 바디로 구성되어 HTTP 요청 응답 엔티티를 나타낸다.

헤더와 바디를 구성할 수 있는 클래스이다.

이제 아래의 코드를 보자.

return ResponseEntity.ok()
        .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition)
        .body(urlResource);

상태코드 HttpStatus.OK로 200을 설정하고 헤더와 바디를 설정해

응답으로 Resource를(ResponseEntity<Resource>) 반환하는 로직이다.

 

헤더에 Content-Disposition은 뭐하는 헤더 정보일까?

이 헤더는 서버가 클라이언트에게 전송하는 컨텐츠를 어떻게 처리하는지 지시하는데 사용한다.

 

이 헤더의 값으로 inline과 attachment가 있다. 

inline: 컨텐츠를 웹 브라우저에 표시한다.

attachment: 컨텐츠를 첨부파일로 처리하여 다운로드하게 한다.

inline 결과 (png 파일을 그냥 뿌려버림)

 

각각 inline과 attachment 값은 아래와 값이 사용한다.

Content-Disposition: inline
Content-Disposition: attachment; filename="클라이언트에게 보여질 이름.확장자"

 

posterView.html

    <table class="table">
        <tr>
            <th>제목</th>
            <td th:text="${poster.title}"></td>
        </tr>
        ...
        <tr th:if="${poster.getImgFiles().size} != 0">
            <th>첨부파일</th>
            <td>
                <a class="d-block" th:each="file : ${poster.imgFiles}" th:text="${file.getUploadFileName()}" th:href="|/download/${file.getId()}|"></a>
            </td>
        </tr>
    </table>

<a> 태그로 /download/파일PK 로 요청을 보내게하여 클릭하면 다운로드가 진행되게 하자.

 

 

동작 결과