티스토리 뷰
이어서 이미지 불러오기에 대해 설명해보겠다.
이미지 저장에서 설명한 FileUtil 클래스를 이용하며, 전체적으로 코드가 간단하므로 먼저 코드부터 나열하겠다.
@RestController
@RequiredArgsConstructor
public class ImageLoadController {
private final ImageLoadService imageLoadService;
@GetMapping("/uploads/images/{imageName}")
public ResponseEntity<byte[]> load(@PathVariable String imageName) {
ImageResponse image = imageLoadService.load(imageName);
return ResponseEntity.ok()
.contentType(image.getContentType())
.body(image.getContent());
}
}
@Service
@RequiredArgsConstructor
public class ImageLoadService {
private static final String PNG = "PNG";
private final FileUtil fileUtil;
public ImageResponse load(String imageName) {
return ImageResponse.builder()
.contentType(getContentType(imageName))
.content(getFileContent(imageName))
.build();
}
private byte[] getFileContent(String imageName) {
File file = fileUtil.find(imageName);
try (FileInputStream fis = new FileInputStream(file)) {
return fis.readAllBytes();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private MediaType getContentType(String imageName) {
String extension = StringUtils.getFilenameExtension(imageName);
return Objects.requireNonNull(extension).equalsIgnoreCase(PNG) ? MediaType.IMAGE_PNG : MediaType.IMAGE_JPEG;
}
}
로직은 간단하다.
이미지 이름을 PathVariable로 받아서 FileUtil 클래스를 통해 파일을 찾는다.
그 파일을 readAllBytes로 읽는데, 대용량에 문제가 생길 수 있지만 파일을 저장할 때 최대 크기가 지금은 작기 때문에 괜찮다고 판단했다. Response에 content type과 파일을 읽은 byte를 content에 담아 보내면 된다.
이미지 불러오는 설명은 여기서 끝이지만 저번 편에 이어서 FileUtil 클래스에 대해서 더 얘기해보도록 하겠다.
저번 글에서 파일을 저장한 후에 클라이언트에게 응답으로 url과 파일 이름을 전달했는데, 게시글을 등록하거나 업데이트할 때 나는 해당 게시글에서 사용되는 이미지의 url과 파일 이름을 받고 있다. 왜냐하면 실제로 이 파일이 존재하는지 확인을 해야하기 때문이다. 그래서 FileUtil 클래스에서 find라는 메소드 하나를 가지고 이미지를 불러오는 서비스, 게시글 등록/업데이트 서비스에서 파일을 찾아서 존재하는지 확인할 수 있었다.
find 메소드 대신 exists 처럼 직접 밖에서 파일이 존재하는지 확인하고 에러 처리를 해야 하나 고민했지만, 파일이 존재하지 않는 상황에서의 로직은 존재하지 않았기 때문에 find 메소드 내에서 에러 처리하고 파일을 리턴했다.
사실 불러오기를 구현하면서 여러 가지 실수를 저질렀다.
resource/uploads 폴더에 이미지를 저장하고 있었는데, 사용자들이 실시간으로 업로드하는 이미지 파일인데도 불구하고 css/js와 같은 정적 파일과 동일시 해버렸다. 그래서 환경에 상관없이 정적 파일에 접근하는 방법을 찾아보게 되었고 getResources() 해서 resource 배열을 받아 그 안에서 파일을 찾았었다.
이렇게 구현하면 가장 큰 문제는 방금 등록한 파일을 불러오기 요청을 보내면 불러와지지가 않는다.
런타임에 build 폴더에 resource가 최신화되지 않기 때문이다. 처음에 빌드할 때 정적파일이 올라간 후 변화가 없는 것이 당연하다. 그래서 Resource를 이용하지 않고 Path를 통해 직접 파일을 찾으니 즉시 불러오기가 되면서 런타임에 등록한 이미지가 불러와지지 않는 문제가 해결이 되었다.
'spring' 카테고리의 다른 글
jackson 일급 컬렉션 직렬화 역직렬화 (0) | 2023.08.17 |
---|---|
Spring 이미지 저장/불러오기 (저장편) (0) | 2023.07.06 |