티스토리 뷰

백엔드/Spring

이미지 파일 업로드

uijin-j 2023. 6. 16. 23:19

일단 AWS의 스토리지 서비스인 S3를 쓰지 않고 이미지를 서버에 저장해보자!

❕Spring Web이 파일 업로드 기능을 제공!

 

✔️ 이미지를 저장하기 위해선 프론트에서 요청 바디의 형식을 multipart/form-data로 보내야 함!

(일반적인 요청 방식인 application/x-www-form-urlencoded는 바디 내용을 문자로 보내는데, 파일은 문자가 아니라 바이너리 데이터이기 때문!)

 

❔ multipart/form-data

: 다른 종류의 여러 파일과 폼의 내용을 함께 전송O

: 각 항목별(Part)로 헤더가 추가

 

 

📌 코드 스니펫

1️⃣ application.properties에 실제 파일이 저장되는 경로 지정 ← 실제로 디렉토리 만들어 놓기!

file.dir=/Users/uijin/Spring/file/

❕ (참고) application.properties와 application.yml 변환해주는 사이트

https://mageddo.com/tools/yaml-converter

 

2️⃣ 이미지가 필요한 도메인에 파일을 멤버변수 넣어주기!

@Data
public class Item {

    private Long id;
    private String itemName;
    private UploadFile attachFile;
    private List<UploadFile> imageFiles;
}

 

2️⃣ File 도메인 만들기

@Data
public class UploadFile {
    
    private String uploadfileName;
    private String storeFileName; //서버 내부에서 관리하는 파일명
    
    public file(String uploadfileName, String storeFileName) {
        this.uploadFileName = uploadfileName;
        this.storeFileName = storeFileName;
    } 
}

 

3️⃣ (file > ) FileStore 생성 - 파일 저장과 관련된 업무 처리

@Component
public class FileStore {
    
    @Value("${file.dir}") //application.properties에 저장해 둔 파일 경로
    private String fileDir;
    
    public String getFullPath(String filename) {
        return fileDir + filename;
    }
    
    public List<UploadFile> storeFiles(List<MultipartFile> multipartFiles) throws IOException {
        List<UploadFile> storeFileResult = new ArrayList<>();
        for (MultipartFile multipartFile : multipartFiles) {
            if (!multipartFile.isEmpty()) {
                storeFileResult.add(storeFile(multipartFile));
            } 
        }
        return storeFileResult;
    }
    
    public UploadFile storeFile(MultipartFile multipartFile) throws IOException {
        
        if (multipartFile.isEmpty()) {
            return null;
        }
        
        String originalFilename = multipartFile.getOriginalFilename();
        String storeFileName = createStoreFileName(originalFilename);
        multipartFile.transferTo(new File(getFullPath(storeFileName)));
        return new UploadFile(originalFilename, storeFileName);
    }
    
    private String createStoreFileName(String originalFilename) { //uuid로 서버에 저장될 파일명 생성
        String ext = extractExt(originalFilename);
        String uuid = UUID.randomUUID().toString();
        return uuid + "." + ext;
    }
    
    private String extractExt(String originalFilename) { //png와 같은 확장자 추출!
        int pos = originalFilename.lastIndexOf(".");
        return originalFilename.substring(pos + 1);
    } 
}

 

4️⃣ 컨트롤러 작성!

@Slf4j
@Controller
@RequiredArgsConstructor
public class ItemController {
    
    private final ItemRepository itemRepository;
    private final FileStore fileStore;
    
    @PostMapping("/items/new")
    public SaveItemResponse saveItem(@RequestBody SaveItemRequest request) throws IOException {
        
        UploadFile attachFile = fileStore.storeFile(request.getAttachFile());
        List<UploadFile> storeImageFiles = fileStore.storeFiles(request.getImageFiles());
        
        //데이터베이스에 저장
        Item item = new Item(); 
        item.setItemName(form.getItemName()); 
        item.setAttachFile(attachFile); 
        item.setImageFiles(storeImageFiles); 
        itemRepository.save(item);
        
        return new SaveItemResponse(item);
    }
    
    // 이미지 파일 보기
    @ResponseBody
    @GetMapping("/images/{filename}")
    public Resource downloadImage(@PathVariable String filename) throws MalformedURLException {
        return new UrlResource("file:" + fileStore.getFullPath(filename));
    }
    
    // 첨부파일 다운로드
    @GetMapping("/attach/{itemId}")
    public ResponseEntity<Resource> downloadAttach(@PathVariable Long itemId) throws MalformedURLException {
        
        Item item = itemRepository.findById(itemId);
        String storeFileName = item.getAttachFile().getStoreFileName();
        String uploadFileName = item.getAttachFile().getUploadFileName();
        UrlResource resource = new UrlResource("file:" + fileStore.getFullPath(storeFileName));
        
        log.info("uploadFileName={}", uploadFileName);
        String encodedUploadFileName = UriUtils.encode(uploadFileName, StandardCharsets.UTF_8);
        String contentDisposition = "attachment; filename=\"" + encodedUploadFileName + "\"";
        
        return ResponseEntity.ok()
                  .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition)
                  .body(resource);
    }
    
    /**
     * DTO
     */
    @Data
    static class SaveItemRequest {
        // ...
        private MultipartFile attachFile;
        private List<MultipartFile> imageFiles;
    }
    
    @Data
    static class SaveItemResponse {...}
}

 

📚 추후 공부해보고 싶은 부분

✔️ AWS S3

'백엔드 > Spring' 카테고리의 다른 글

프로젝트 환경설정  (0) 2023.07.06
빌드하기  (0) 2023.07.04
권한 관리 - 스프링 인터셉터  (0) 2023.06.15
로그인 1 - 쿠키와 세션  (1) 2023.06.14
스프링 부트와 JPA 활용1  (0) 2023.05.17
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함