[spring] 스프링 파일업로드 방법

최혜원·2023년 7월 26일
1
post-thumbnail

HTML이 폼을 전송하는 방법

파일을 업로드 하려면 문자가 아닌 바이너리 데이터를 전송해야 한다.
또한 파일뿐 아니라 이름, 나이 등도 함께 전송해야 한다.
즉, 첨부파일은 바이너리로, 이름과 나이는 문자로 동시에 전송해야 한다.
그래서 사용하는게 multipart/form-data이다.

multipart/form-data

• 위와 같은 문제를 해결하기 위해 multipart/form-data라는 전송 방식을 제공한다.
• 방식을 사용하려면 Form 태그에 별도의 enctype="multipart/form-data" 를 지정해야 한다.

스프링이 지원하는 파일 업로드

• 스프링은 MultipartFile 이라는 인터페이스로 멀티파트 파일을 매우 편리하게 지원한다.
• @ModelAttribute으로도 받을 수 있다.

@PostMapping("/profile")
    public String modifyProfile(@AuthenticationPrincipal UserDetailsImpl userDetails, @ModelAttribute UserProfileRequestDto requestDto) throws IOException {
        Long userId = userDetails.getUser().getId(); // 사용자 id
        UserProfileResponseDto dto = userService.updateUserProfile(userId, requestDto);
        return "redirect:/kp3c/user/profile"; // 수정 후 조회 화면에서 데이터 보여주기
    }

• MultipartFile 주요 메서드
file.getOriginalFilename() : 업로드 파일 명
file.transferTo(new File("PATH")) : 파일 저장

UploadFile - 업로드 파일명과 서버저장 파일명은 분리

import lombok.Data;

@Data
public class UploadFile {

    private String uploadFileName;
    private String storeFileName;

    public UploadFile(String uploadFileName, String storeFileName) {
        this.uploadFileName = uploadFileName;
        this.storeFileName = storeFileName;
    }
}

• 고객이 업로드한 파일명으로 서버 내부에 파일을 저장하면 안 된다.
• 똑같은 파일명으로 업로드하면 파일을 덮어버리기 때문!
• 그러기 때문에 서버에서는 저장할 파일명이 겹치지 않도록 내부에서 저장하는 별도의 파일명이 필요하다. (예를 들면 UUID를 사용해서 저장)

FileStore - 파일 저장과 관련된 업무 처리

package hello.upload.file;

import hello.upload.domain.UploadFile;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Component
public class FileStore {

    @Value("${file.dir}") // application.properties에 사진 저장 경로 설정 (file.dir=/Users/choihyewon/Desktop/file/)
    private String fileDir;

    public String getFullPath(String filename) { //파일이름 받아서 fullpath를 반환
        return fileDir + filename; // 디렉토리에 파일이름이 합쳐짐
    }

		// 루프를 돌면서 multipartFile 이 비어있지 않으면 실행하여 storeFileResult 에 넣어서 결과 반환
    public List<UploadFile> storeFiles(List<MultipartFile> multipartFiles) throws IOException { // 여러 개 업로드
        List<UploadFile> storeFileResult = new ArrayList<>(); // 업로드 파일이 계속 생성이 되기 때문에 담아줘야 한다.
        for (MultipartFile multipartFile : multipartFiles) { 
            if (!multipartFile.isEmpty()) { // multipartFile 이 비어있지 않으면!
                storeFileResult.add(storeFile(multipartFile)); 
							// 위 코드를 두줄로 하면
								UploadFile uploadFile = storeFile(multipartFile);
								storeFileResult.add(uploadFile);
            }
        }
        return storeFileResult;
    }

		// MultipartFile을 받아서 파일을 저장한 다음에 UploadFile로 반환해줌
    public UploadFile storeFile(MultipartFile multipartFile) throws IOException { // 한 개 업로드
        if (multipartFile.isEmpty()) {
            return null;
        }

        String originalFilename = multipartFile.getOriginalFilename(); // 사용자가 업로드한 파일이름
        String storeFileName = createStoreFileName(originalFilename); // 서버에 저장하는 파일명(uu아이디+.+확장자명)

        multipartFile.transferTo(new File(getFullPath(storeFileName))); // 디렉토리에 파일이름이 합쳐진 것이 File로 만들어지고
        return new UploadFile(originalFilename, storeFileName); // UploadFile 반환
    }

    private String createStoreFileName(String originalFilename) {
        String ext = extractExt(originalFilename);
        String uuid = UUID.randomUUID().toString(); // 서버에 저장하는 파일명(uu아이디)
        return uuid + "." + ext; // ext : 확장자명
    }

    private String extractExt(String originalFilename) { // 확장자명 꺼내기
        int pos = originalFilename.lastIndexOf("."); // 위치를 가져온다.
        return originalFilename.substring(pos + 1); // . 다음에 있는 확장자명 꺼냄
    }


}

HTML에서 파일 업로드 코드

• multipart/form-data을 사용하려면 form태그에 enctype="multipart/form-data"가 들어가야된다.
• input태그 속성으로 multiple="multiple" 을 넣으면 파일을 여러개 선택할 수 있다.
• 이때 스프링에선 List로 @RequestParam이든 @ModelAttribute든 받으면 된다.

HTML의 img에 이미지 보여주는 법

• HTML에서 img src="/images/[파일이름]" 형식으로 쓰면 된다.
• UrlResource는 file: FULLPATH를 인자로 넘겨주면 실제 그곳에 있는 파일을 UrlResource형태로 리턴해준다. 그럼 HTML의 img에 보여지게 되는 것!

profile
어제보다 나은 오늘

1개의 댓글

comment-user-thumbnail
2023년 7월 27일

좋은 정보 얻어갑니다, 감사합니다.

답글 달기