Spring으로 이미지 업로드

Legday_Dev·2023년 9월 12일
0

Spring

목록 보기
10/14
post-thumbnail

클라이언트가 이미지를 업로드하면 서버는 프로젝트 외부에 있는 폴더에 사진을 저장하고 DB 에는 사진의 경로와 사진이름으로 조합된 문자열을 DB 에 저장한다 !

ImageController 구현


  • 사용자로부터 이미지파일과 이미지설명을 받아오는 DTO 를 구현한다.
  • Spring에서 지원하는 MultipartFile 를 이용한다.
@Data
public class ImageUploadDto {
    private MultipartFile file;
    private String caption;
}
  • 컨트롤러에서는 DTO 와 누가 업로드했는지 알아야 하기 때문에 Session 에서 사용자 정보를 갖고오는 @AuthenticationPrincipal 를 사용해서 갖고온다.
    • PrincipalDetailsSpringSecurityUserDetails 인터페이스를 구체화 한 클래스이다.
@PostMapping("/image")
public String imageUpload(@ModelAttribute ImageUploadDto imageUploadDto,
                          @AuthenticationPrincipal PrincipalDetails principalDetails) {
    imageService.사진업로드(imageUploadDto,principalDetails);

    return "redirect:/user/"+principalDetails.getUser().getId();
}

ImageService 구현


실제 이미지 업로드가 구현되는 로직이다.

  • 우선 application.yml 에서 설정이 필요하다.
  • spring.servlet.multipart.enabled 옵션을 true 로 설정해준다.
  • file 옵션은 spring에서 지원하는게 아닌 따로 만든 키이다.
  • file.path 에는 프로젝트 외부에 upload 파일의 경로를 적어준다.

spring:
	# 생략 ...
  servlet:
    multipart:
      enabled: true
      max-file-size: 2MB
  # 생략 ...

file:
  path: /Users/jaeyoung/Desktop/workspaces/upload/
  • uploadFolder 변수는 application.yml 파일에 지정했던 file.path 의 경로를 가져와서 저장하는 변수다.
  • @Value 어노테이션은 lombok 이 아닌 spring 에서 제공하는 어노테이션이다.
    • ${file.path} 는 application.yml 에 지정했던 키를 그대로 가져오면 된다. 그러면 이미지 저장폴더가 있는 경로를 uploadFolder 에 지정한다.
  • UUID 를 사용하는 이유는 사용자는 똑같은 이미지 파일을 업로드할 수 있다. 계속하게 되면 서버에서는 똑같은 사진을 구별할 필요가 있다. UUID 의 고유 식별자를 이용하여 서버에서 똑같은 사진을 구분하기 위해 사용한다.
  • DTO 에서 넘어온 이미지의 이름을 알기 위해서는 getOriginalFilename() 메서드를 이용하면 된다.
  • 그리고 nio 패키지가 지원하는 Path 클래스를 이용하여 파일이 저장되는 위치 + uuid + 이미지이름 을 저장한다. 이 Path 클래스의 변수가 DB에 저장된다.
  • 이미지를 upload 파일에 저장하기 위해 Files.write() 메서드를 실행한다.
    • write() 는 첫번째 파라미터로 Path 객체를 넣고 두번째에는 실제 파일을 byte로 변환해서 받고 세번째에는 옵션값이 들어오는데 비워둬도 된다.
  • 최종적으로 DTO 를 Entity 로 변환해서 save 하면 끝이다 !
@RequiredArgsConstructor
@Service
public class ImageService {

    private final ImageRepository imageRepository;

    @Value("${file.path}")
    private String uploadFolder;

    @Transactional
    public void 사진업로드(ImageUploadDto imageUploadDto, PrincipalDetails principalDetails){
        
        UUID uuid = UUID.randomUUID();

        String imageFileName = uuid + "_" + imageUploadDto.getFile().getOriginalFilename();

        Path imageFilePath = Paths.get(uploadFolder + imageFileName);

        try{
            Files.write( imageFilePath,imageUploadDto.getFile().getBytes());
        } catch (Exception e){
            e.printStackTrace();
        }
        Image imageEntity = imageRepository.save(imageUploadDto.toEntity(imageFileName,principalDetails.getUser()));
    }
}

💡 중요포인트!!
1. application.yml 설정파일을 수정해서 multipart 옵션을 활성화하고, 이미지저장되는 경로설정
2. UUID 와 이미지파일 이름을 이용하여 고유한 식별자 생성해서 DB 에 저장
3. 실제 이미지를 저장하는 Files.write() 에서는 이미지를 Byte 로 변환하는것!

profile
백엔드개발자

0개의 댓글