Framework/Spring Boot

로컬에 파일 업로드

잔망루피 2023. 11. 5. 20:59

🔧 환경

  • Spring Boot
  • gradle

 

🟠 application.properties

# file upload path : window
file.path=C:/board/upload/
file.path.upload-images=C:/board/upload/imageUpload
file.path.upload-files=C:/board/upload/fileUpload/
spring.servlet.multipart.location=C:/board/upload/

# file upload path : mac
# file.path=/Users/aa/Desktop/workspace/framework/board6_springboot/upload
# file.path.upload-images=/Users/aa/Desktop/workspace/framework/board6_springboot/upload/image
# file.path.upload-files=/Users/aa/Desktop/workspace/framework/board6_springboot/upload/file
#spring.servlet.multipart.location=C:/board/upload/

 

파일 업로드 경로를 properties에 정의하고 컨트롤러에서 @Value 어노테이션으로 받아오려고 한다.

 

 

🔵 컨트롤러

@RestController
@RequestMapping("/admin/attractions")
public class AttractionAdminController {
	
	@Value("${file.path}")
	private String uploadPath;
	
	@Value("${file.path.upload-images}")
	private String uploadImagePath;
	
	@Value("${file.path.upload-files}")
	private String uploadFilePath;
	
	private final AttractionService attractionService;
	private final ResponseService responseService;
	
	public AttractionAdminController(AttractionService attractionService, ResponseService responseService) {
		this.attractionService = attractionService;
		this.responseService = responseService;
	}
	
	@PostMapping("/upload") 
	public ResponseEntity<CommonResponse> uploadAttractionImage(@RequestPart("image") MultipartFile multipartFile) throws Exception {
		if(multipartFile.isEmpty() || multipartFile.getOriginalFilename().isEmpty()) {
			return ResponseEntity.badRequest().build();
		}
		String imageUrl = attractionService.uploadAttractionImage(multipartFile, uploadPath); 
		
		return ResponseEntity.ok().body(responseService.getDataResponse(imageUrl)); 
	}
	 
	
}

 

업로드한 이미지 경로를 반환한다.

FE에서 비동기로 요청을 보내면 이미지를 업로드할 것이다.

 

🟢 Service

@Service
public class AttractionServiceImpl implements AttractionService {
	
	private final AttractionMapper attractionMapper;
	private final FileUtil fileUtil;
	
	
	public AttractionServiceImpl(AttractionMapper attractionMapper, FileUtil fileUtil) {
		super();
		this.attractionMapper = attractionMapper;
		this.fileUtil = fileUtil;
	}


	@Override
	public String uploadAttractionImage(MultipartFile multipartFile, String realPath) throws Exception {
		String fileName = multipartFile.getOriginalFilename();
		
		String today = fileUtil.getFolderName();
		String saveFolder = fileUtil.getFolder(realPath, today);
		fileUtil.makeFolder(saveFolder);
		
		return today + File.separator + fileUtil.upload(fileName, multipartFile, new File(saveFolder));

	}

}

multipartFile.getOriginalFilename()으로 원본 파일명을 받아온다.

폴더명은 오늘 날짜로 한다. 231105 이런식으로 년도도 같이 나온다.

폴더가 없을 수도 있으니까 내가 구현한 makeFolder 메서드로 폴더를 만들어준다.

 

 

🟤 FileUtil

@Component
public class FileUtil {

	public String getNewFileName(String originalFileName) {
        UUID uuid = UUID.randomUUID();
        String saveFileName = uuid.toString() + originalFileName;

        return saveFileName;
	}

	/*
	 * 업로드하려는 위치에 폴더가 없으면 생성한다.
	 * 1 depth만 생성함
	 */
	public void makeFolder(String saveFolder) {
		File folder = new File(saveFolder);

		if(!folder.exists()) {
			try {
				folder.mkdir();		
			} catch (Exception e) {
				e.getStackTrace();
			}
		} 
	}

	public String getFolderName() {
		return new SimpleDateFormat("yyMMdd").format(new Date());
	}

	public String getFolder(String realPath, String today) {
		return realPath + today;
	}

	public String upload(String originalFileName, MultipartFile multipartFile, File folder) throws Exception {
		String saveFileName = UUID.randomUUID().toString()
				+ originalFileName.substring(originalFileName.lastIndexOf('.'));
		
        multipartFile.transferTo(new File(folder, saveFileName));

		return saveFileName;
	}

}

자주 쓰일 것 같아서 Util로 만들었다.

mkdir()은 1 depth만큼 폴더를 생성하는 것에 주의한다.

예를 들어, \instagram\upload 폴더가 없으면 에러는 발생하지 않지만 폴더는 생성되지 않는다.

\instagram 폴더는 있는데 upload 폴더가 없다면 폴더가 생성된다.

저장할 파일명은 UUID를 사용해서 생성했다.

lastIndexOf 메서드는 가장 마지막에 발견한 문자열의 위치를 리턴한다.

originalFileName.substring(originalFileName.lastIndexOf('.'))는 파일의 확장자를 가져오는 부분이다.

transferTo 메서드는 지정한 folder에 파일을 생성해준다.

 

 

 

 

 

 

 

반응형