관련포스팅 : Spring - 파일 업로드 연습1 (일반적인 방식)
지난번 포스팅에서 구현한 파일 업로드의 문제점은 새로운 파일을 업로드할 때, 업로드된 파일명과 중복되면 그대로 덮어쓰게 된다는 점이다. 만약 사용자가 파일명만 같고 내용이 다른 파일을 업로드하게 된다면 이전의 파일을 소실하게되는 문제가 발생할 수 있다. 이 때문에 업로드할 때마다 DB와 디렉토리에 중복되지 않는 파일명으로 저장되게 하는 것이 반드시 필수적이다. 그렇다면 파일명을 중복되지 않게 저장하는 법은 무엇이 있을까? 첫번째 방법은 저장 디렉토리에 중복되는 파일이 존재하면 파일명에 뒤에 숫자를 붙이는 방법이 있고, 파일명에 업로드시간 즉 timestamp1를 붙여주는 법이있다. 두번째 방법으로는 랜덤한 문자열을 생성해 파일명에 붙여주는 방법도 있다. 이 방법은 UUID2을 생성하여 파일명을 랜덤하게 생성시켜주는 것인데 지금 구현할 방법이 이것이다.
1. 파일명이 중복되지 않게 파일 업로드 구현 (UUID)
UploadController
기존의 코드
@Controller
public class UploadController {
private static final Logger logger = LoggerFactory.getLogger(UploadController.class);
@Resource(name="uploadPath")
String uploadPath;
@RequestMapping(value="/upload/uploadForm", method=RequestMethod.GET)
public void uplodaForm(){
}
@RequestMapping(value="/upload/uploadForm", method=RequestMethod.POST)
public ModelAndView uplodaForm(MultipartFile file, ModelAndView mav) throws Exception{
logger.info("파일이름 :"+file.getOriginalFilename());
logger.info("파일크기 : "+file.getSize());
logger.info("컨텐트 타입 : "+file.getContentType());
String savedName = file.getOriginalFilename();
File target = new File(uploadPath, savedName);
FileCopyUtils.copy(file.getBytes(), target);
mav.setViewName("upload/uploadResult");
mav.addObject("savedName", savedName);
return mav;
}
}
변경된 코드
변경사항 : 랜덤으로 생성된 문자열과 원본파일명을 합치는 메서드를 작성
@Controller
public class UploadController {
private static final Logger logger = LoggerFactory.getLogger(UploadController.class);
@Resource(name="uploadPath")
String uploadPath;
@RequestMapping(value="/upload/uploadForm", method=RequestMethod.GET)
public void uplodaForm(){
}
@RequestMapping(value="/upload/uploadForm", method=RequestMethod.POST)
public ModelAndView uplodaForm(MultipartFile file, ModelAndView mav) throws Exception{
// 파일의 원본이름 저장
String savedName = file.getOriginalFilename();
logger.info("파일이름 :"+file.getOriginalFilename());
logger.info("파일크기 : "+file.getSize());
logger.info("컨텐트 타입 : "+file.getContentType());
// 랜덤생성+파일이름 저장
// 파일명 랜덤생성 메서드호출
savedName = uploadFile(savedName, file.getBytes());
mav.setViewName("upload/uploadResult");
mav.addObject("savedName", savedName);
return mav; // uploadResult.jsp(결과화면)로 포워딩
}
// 파일명 랜덤생성 메서드
private String uploadFile(String originalName, byte[] fileData) throws Exception{
// uuid 생성(Universal Unique IDentifier, 범용 고유 식별자)
UUID uuid = UUID.randomUUID();
// 랜덤생성+파일이름 저장
String savedName = uuid.toString()+"_"+originalName;
File target = new File(uploadPath, savedName);
// 임시디렉토리에 저장된 업로드된 파일을 지정된 디렉토리로 복사
// FileCopyUtils.copy(바이트배열, 파일객체)
FileCopyUtils.copy(fileData, target);
return savedName;
}
}
2. 구현 확인
동일한 이름을 가진 파일을 업로드해보고, 파일이 그대로 덮어씌어지는지 아니면 고유한 파일명이 생성되는지 확인해보자.
업로드할 파일을 선택
첫번째 파일 업로드
첫번째 파일 업로드 확인
파일명이 uuid+파일명 방식으로 저장
두번째 동일한 이름의 파일 재업로드
두번째 파일 업로드 확인
이번에도 동일하게 uuid+파일명 방식으로 저장
실제 디렉토리에 두 개의 이미지 파일이 저장되었는지 확인
덮어씌어지지 않고 두개의 파일로 저장
타임스탬프(timestamp)는 특정한 시각을 나타내는 문자열이다. 둘 이상의 시각을 비교하거나 기간을 계산할 때 편리하게 사용하기 위해 고안되었으며, 일관성 있는 형식으로 표현된다. 실제 정보를 타임스탬프 형식에 따라 기록하는 행위를 타임스탬핑(en:timestamping)이라 한다. 파일시스템에서 타임스탬프는 저장된 파일이 생성되거나 변경된 시각을 뜻하기도 한다. 타임스탬프의 예: 2005-10-30 T 10:45 UTC, 2007-11-09 T 11:20 UTC, Sat Jul 23 02:16:57 2005 참조 링크: 위키백과↩
범용 고유 식별자(universally unique identifier, UUID)는 소프트웨어 구축에 쓰이는 식별자 표준으로, 개방 소프트웨어 재단(OSF)이 분산 컴퓨팅 환경(DCE)의 일부로 표준화하였다. 네트워크 상에서 서로 모르는 개체들을 식별하고 구별하기 위해서는 각각의 고유한 이름이 필요하다. 이 이름은 고유성(유일성)이 매우 중요하다. 같은 이름을 갖는 개체가 존재한다면 구별이 불가능해 지기 때문이다. 고유성을 완벽하게 보장하려면 중앙관리시스템이 있어서 일련번호를 부여해 주면 간단하지만 동시다발적이고 독립적으로 개발되고 있는 시스템들의 경우 중앙관리시스템은 불가능하다. 개발주체가 스스로 이름을 짓도록 하되 고유성을 충족할 수 있는 방법이 필요하다. 이를 위하여 탄생한 것이 범용고유식별자(UUID)이며 국제기구에서 표준으로 정하고 있다. UUID 표준에 따라 이름을 부여하면 고유성을 완벽하게 보장할 수는 없지만 실제 사용상에서 중복될 가능성이 거의 없다고 인정되기 때문에 많이 사용되고 있다. 참조 링크: 위키백과↩