스프링부트 이미지 저장, 전송

dragonappear·2021년 12월 20일
5

Spring & SpringBoot

목록 보기
3/11

이미지 클래스

예를 들어, 사용자의 프로필 사진을 저장해야 한다고 했을때 사진 자체를 DB에 저장하는 것은 용량도 크고 장점보다 단점이 많다.
그래서 이미지 정보를 DB에 저장하였다. 또한, 이미지는 사용자 프로필 뿐만 아니라 다른 여러 곳에서 사용할 수 있기 때문에 임베디드 클래스로 뽑아서 사용하였다.

@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Entity
public class UserImage extends JpaBaseTimeEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_image_id")
    private Long id;

    @Embedded
    private Image image;
    
    ...

}

Image 클래스

@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Embeddable
public class Image {
    @Column(nullable = false)
    private String fileName;

    @Column(nullable = false)
    private String fileOriName;

    @Column(nullable = false)
    private String fileUrl;
}

이미지 저장

Controller 클래스

@PostMapping("/api/v1/users/images/{userId}")
    public Map<String, Object> updateUserProfile(@PathVariable("userId") Long userId, @RequestBody MultipartFile file)  {
        ImageDto imageDto = updateProfile(file);
        if(imageDto.getContent()==null) {
            return imageDto.getMap();
        }
        userImageService.update(userService.findOneById(userId), (Image) imageDto.getContent());
        return imageDto.getMap();
    }

저장 로직

 public ImageDto updateProfile(MultipartFile file)  {
        try {
            String sourceFileName = file.getOriginalFilename();
            String sourceFileNameExtension = FilenameUtils.getExtension(sourceFileName).toLowerCase();
            String fileUrl = "이미지 저장 주소";
            String destinationFileName = RandomStringUtils.randomAlphabetic(32) + "." + sourceFileNameExtension;
            File destinationFile = new File(fileUrl + destinationFileName);
            destinationFile.getParentFile().mkdirs();
            file.transferTo(destinationFile);
            Image image = new Image(destinationFileName, sourceFileName, fileUrl);
            return ImageDto.builder()
                    .map(getDto("isFileInserted", true, "uploadStatus", "AllSuccess"))
                    .content(image)
                    .build();
        } catch (Exception e) {
            return ImageDto.builder()
                    .map(getDto("isFileInserted", false, "uploadStatus", "FileIsNotUploaded"))
                    .content(null)
                    .build();
        }
    }
destinationFile.getParentFile().mkdirs();
file.transferTo(destinationFile);

만약 파일을 잘못 읽어오면 위 코드 부분이나 파일 이름을 설정하는 코드 부분에서 exception이 터질것이다.
exception을 잡아서 클라이언트에게 서버에 파일 업로드가 되지 않았다고 메시지를 날린다.


이미지 전송

@GetMapping(value = "/api/v1/items/images/{fileOriginName}")
    public ResponseEntity<Resource> getItemImageByName(@PathVariable("fileOriginName") String fileName) {
        try {
            String path = "실제 이미지가 있는 위치";
            FileSystemResource resource = new FileSystemResource(path+fileName);
            if (!resource.exists()) {
                throw new NotFoundImageException();
            }
            HttpHeaders header = new HttpHeaders();
            Path filePath = null;
            filePath = Paths.get(path+fileName);
            header.add("Content-Type", Files.probeContentType(filePath));
            return new ResponseEntity<Resource>(resource, header, HttpStatus.OK);
        } catch (Exception e) {
            throw new NotFoundImageException();
        }
    }

Files.probeContentType

  • 자바 7부터 지원하는 메소드로, 마임타입을 확인하지 못하면 Null을 반환한다.
  • 실제 파일의 내용이 아니라 파일의 확장자를 이용하여 마임타입을 판단한다.
  • 그러므로 확장자가 없는 파일은 null을 반환하고, 실제 파일이 존재 하지 않아도 확장자로 마임타입을 반환한다.

참고

https://2ham-s.tistory.com/283
https://server-talk.tistory.com/183

0개의 댓글