본문 바로가기
개발/Springboot

Springboot_ 이미지 보여주기

by JunsC 2024. 8. 26.
728x90

스프링부트에서 정적 파일인 이미지를 어떻게 보여주는지 다시한번 구글링해보았다.

여러가지 방법이 있었던것 같은데 나는 정적인 이미지 파일이니까 해당 파일이 있는 위치에서 바로 불러오고 싶었다.

그래서 한번 찾아보았다..

    @GetMapping("/{imageName}")
    public ResponseEntity<byte[]> getImage(@PathVariable String imageName) throws IOException {
        // 여기서는 예를 들어 images 디렉토리에서 이미지를 로드합니다
        Resource imgFile = new ClassPathResource("static/images/" + imageName);
        
        InputStream in = imgFile.getInputStream();
        byte[] imageBytes = StreamUtils.copyToByteArray(in);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.IMAGE_JPEG);  // 이미지 타입에 따라 MediaType 설정
        headers.setContentLength(imageBytes.length);

        return new ResponseEntity<>(imageBytes, headers, HttpStatus.OK);
    }

이 코드를 사용하면 바로 해당 위치의 파일 바이트를 복사해서 보여주는 기능을 할 수 있다.!!

 

우선 위의 코드들을 상세히 살펴보도록 해보자.

@GetMapping("/{imageName}")
public ResponseEntity<byte[]> getImage(@PathVariable String imageName) throws IOException


위의 코드는 기본적인 선언문이다. 그럼 throws IOException 하는 이유가 무엇일까?

 

throws IOException를 사용하는 이유

java
복사편집
@GetMapping("/{imageName}") public ResponseEntity<byte[]> getImage(@PathVariable String imageName) throws IOException {

위 코드에서 throws IOException을 선언하는 이유는 이미지 파일을 읽는 과정에서 발생할 수 있는 예외(오류)를 처리하기 위해서입니다.


1. IOException이 발생할 수 있는 상황

아래 코드를 보면 이미지 파일을 불러오는 과정에서 IOException이 발생할 가능성이 있습니다.

Resource imgFile = new ClassPathResource("static/images/" + imageName);
InputStream in = imgFile.getInputStream();  // IOException 가능
byte[] imageBytes = StreamUtils.copyToByteArray(in);
 
  • getInputStream() 메서드는 파일을 찾을 수 없거나 접근할 수 없는 경우 IOException을 던짐
    • 예: 파일이 존재하지 않음 (FileNotFoundException 포함)
    • 예: 파일을 읽을 권한이 없음
    • 예: 파일이 손상되어 읽을 수 없음

2. throws IOException를 선언하지 않으면?

  • 예외가 발생하면 컴파일 오류가 발생합니다.
  • IOException은 Checked Exception이기 때문에, 반드시 처리해야 합니다.

✅ 해결 방법

  1. throws IOException을 선언하여 예외를 호출한 곳에서 처리하도록 위임
  2. try-catch로 감싸서 예외를 직접 처리
@GetMapping("/{imageName}")
public ResponseEntity<byte[]> getImage(@PathVariable String imageName) {
    try {
        Resource imgFile = new ClassPathResource("static/images/" + imageName);
        InputStream in = imgFile.getInputStream();
        byte[] imageBytes = StreamUtils.copyToByteArray(in);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.IMAGE_JPEG);
        headers.setContentLength(imageBytes.length);

        return new ResponseEntity<>(imageBytes, headers, HttpStatus.OK);
    } catch (IOException e) {
        return new ResponseEntity<>(HttpStatus.NOT_FOUND); // 404 에러 반환
    }
}
  • try-catch를 사용하면 파일을 찾을 수 없을 때 404 오류를 반환할 수 있음
  • throws IOException 없이도 정상적으로 동작

그럼 다음 이미지를 보여주기 위한 코드를 살펴보자 .

Resource imgFile = new ClassPathResource("static/images/" + imageName);

 

✅ ClassPathResource("static/images/" + imageName)

  • Spring Boot 프로젝트 내부의 static/images/ 디렉토리에서 파일을 찾음
  • 예: imageName = "sample.jpg" → "static/images/sample.jpg" 파일을 찾음
  • ClassPathResource는 resources 폴더 내의 정적 파일을 불러오는 역할을 합니다.

한계점

  • ClassPathResource는 JAR 파일로 패키징되면 내부 파일을 수정할 수 없음
    • 즉, 실행 중에는 새로운 이미지를 저장할 수 없습니다.
  • 동적으로 업로드한 이미지는 보통 ClassPathResource가 아닌, 외부 디렉토리(예: /uploads/)에서 불러오는 것이 좋습니다.

그리고 다음 코드는

InputStream in = imgFile.getInputStream();
byte[] imageBytes = StreamUtils.copyToByteArray(in);

 

 

✅ InputStream in = imgFile.getInputStream();

  • ClassPathResource에서 찾은 이미지 파일을 읽을 준비를 합니다.

✅ StreamUtils.copyToByteArray(in);

  • 이미지 파일을 바이트 배열 (byte[]) 로 변환
  • HTTP 응답으로 보내기 위해 파일을 이진 데이터 (Binary) 로 변환하는 과정

그리고 마지막 리턴값의 내용은

return new ResponseEntity<>(imageBytes, headers, HttpStatus.OK);

 

✅ new ResponseEntity<>(imageBytes, headers, HttpStatus.OK);

  • ResponseEntity<byte[]> 타입으로 바이트 데이터를 HTTP 응답으로 반환
  • HttpStatus.OK (200) → 요청이 성공했음을 의미

 

위와 같은 구조대로 이루어진다. 

 

근데 좀더 개선해야할 점을 찾아보자면,

 

개선할 점

1️⃣ JAR 패키징 후에도 사용 가능하도록 ClassPathResource 대신 파일 시스템을 사용

 

File imgFile = new File("/uploads/" + imageName);
InputStream in = new FileInputStream(imgFile);
 
  • 이렇게 하면 외부 폴더에서 이미지를 관리 가능 (업로드도 가능)
  • /uploads/ 폴더를 Nginx 같은 웹 서버와 연동하여 정적 파일로 제공하는 것이 더 효율적

2️⃣ 이미지 타입 자동 감지 현재 MediaType.IMAGE_JPEG로 고정되어 있는데, 이미지 확장자에 따라 타입을 자동 설정할 수 있음.

String contentType = Files.probeContentType(imgFile.toPath());
headers.setContentType(MediaType.parseMediaType(contentType));
 
  • 이렇게 하면 PNG, JPG, GIF 등 다양한 포맷을 자동 감지하여 설정 가능

 

이렇게 한번 이미지를 보여주는 방식을 알아보았다 . 혹시 좀 더 자세하거나 구체적이며 효율적인 코드가 있으면 언제든 댓글 부탁!!!!

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."