본문 바로가기

Backend/Spring

Spring Boot 파일 다운로드 (Controller)

스프링부트에서 컨트롤러를 만들어서 이미지를 다운로드하는 코드에요.

부트 환경이 아니여도 스프링 프레임워크를 사용하고 있다면 어디에나 적용 가능합니다.

 

코드를 간단하게 설명드리자면

파일 데이터에서 직접 Content-Type을 조사하여 Response Header에 세팅하고

InputStream으로 Resource를 생성하고 body에 세팅하여 전송합니다.

Content-Disposition 값을 inline으로 하거나 헤더를 설정하지 않으면 웹 브라우저 내에서 이미지 확인이 가능합니다.

(default가 inline)

 

@GetMapping("download")
public ResponseEntity<Resource> download() throws IOException {
	Path path = Paths.get("C:/Users/001/Pictures/anise-4623554_1280.png");
	String contentType = Files.probeContentType(path);
	
	HttpHeaders headers = new HttpHeaders();
	headers.add(HttpHeaders.CONTENT_TYPE, contentType);

	Resource resource = new InputStreamResource(Files.newInputStream(path));
	return new ResponseEntity<>(resource, headers, HttpStatus.OK);
}

 

크롬 브라우저에서 호출해보면 이미지가 화면 상에 제대로 나오는 것을 확인할 수 있어요.

 

 

자 그럼 위의 코드에서 Content-Disposition 값을 attachment로 변경해볼게요.

Content-Disposition 헤더는 HTTP 표준이 아니지만 널리 사용되어 HTTP 스펙 문서에 포함되었어요.

아래 코드는 한글 이름도 깨지지 않고 정상적으로 출력이 될 거에요.

그리고 동일하게 브라우저에서 URL을 호출해보세요.

 

headers.setContentDisposition(ContentDisposition.builder("attachment")
        .filename("anise-4623554_1280.png", StandardCharsets.UTF_8)
        .build())

 

사실, 파일을 누구에게나 공개하고 빠르게 응답해야 하는 시스템에서는 직접 WAS에서 다운로드할 필요는 없습니다. (요구사항에 따라 다르겠지만...)

WAS에서 파일 다운로드를 구현할 때에는 보안이 필요한 파일을 다루는 경우가 많고, 파일명을 파라미터로 받아서 접근하는 경우도 있죠.

이 때 클라이언트에서 파일명에 경로도 넣고 이름도 임의로 조작하여 다른 서버 파일에 마음대로 접근할 수 있음을 인지하고 계셔야 합니다.

파일에 철저한 보안이 필요하다면 경로 문자열을 직접 서버에서 관리하고 파일에 대한 권한 기능을 도입해야 합니다.

 

  • 땡큐맨 2020.12.12 19:47

    감사합니다. 간단하게 배울 수 있었습니다~

  • EpicArts 2021.01.27 00:58 신고

    감사합니다 ~

  • MAKERJ 2021.01.31 15:18

    자 그럼 위의 코드에서 Content-Disposition 값을 attachment로 변경해볼게요.
    그리고 동일하게 브라우저에서 URL을 호출해보세요.
    headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + path.getFileName().toString());


    위 방식 보안에 취약한 방법입니다.
    이 글이 구글 검색 결과 상위에 나오네요. 많은 분들이 보실 것 같아 코멘트 남깁니다.
    Stackoverflow 관련 링크 참조하세요. https://stackoverflow.com/a/22243867/2050087

  • 재량 2021.03.08 10:13

    안녕하세요?
    다운로드할 파일이 없을 경우의 예외처리는 어떻게 처리하셨나요?

    • 홍아지 2021.03.16 18:28 신고

      해당 코드에는 예외처리는 별도로 처리하지 않았습니다! 없는 파일이 요청들어오면 500 오류 발생할거에요.

      파일이 없을 경우에도 IOException 발생하기 때문에 @ExceptionHandler에서 예외처리를 구현하시면 됩니다. 혹은 Controller에서 throws IOException하지 않고 catch문을 써서 처리하실 수도 있습니다.

      파일이 없을 때 정확히는 NoSuchFileException가 발생하네요.
      NoSuchFileException은 FileSystemException을 상속받았구, FileSystemException은 IOException을 상속받았습니다.