Part 24. 첨부파일의 다운로드 혹은 원본 보여주기
24.3 첨부파일 삭제
- 첨부파일 삭제는 생각보다 많은 고민이 필요한 작업이다.
- 단순히 파일 하나만을 삭제한다고 생각할 수 있지만 실제로는 다음과 같은 문제점들을 고민해야 한다.
- 이미지 파일의 경우에는 섬네일까지 같이 삭제되어야 하는 점
- 파일을 삭제한 후에는 브라우저에서도 섬네일이나 파일 아이콘이 삭제되도록 처리하는 점
- 비정상적으로 브라우저의 종료 시 업로드된 파일의 처리
24.3.1 일반 파일과 이미지 파일의 삭제
- 업로드된 첨부파일의 삭제는 Ajax를 이용하거나 < form > 태그를 이용하는 방식 모두를 적용할 수 있다.
- 이미 업로드된 첨부파일의 삭제는 일반 파일의 경우에는 업로드된 파일만을 삭제하면 되지만, 이미지의 경우에는 생성된 섬네일 파일과 원본 파일을 같이 삭제해야 한다.
- 서버 측에서는 삭제하려는 파일의 확장자를 검사해서 일반 파일인지 이미지 파일인지를 파악하거나 파라미터로 파일의 종류를 파악하고, 이를 이용해 처리를 다르게 한다.
화면에서 삭제 기능
- 첨부파일이 업로드된 후에 생기는 이미지 파일 옆에 'x' 표시를 추가하도록 아래와 같이 수정한다.
< uploadAjax.jsp >
function showUploadedFile(uploadResultArr){
var str = "";
$(uploadResultArr).each(function(i, obj){
if(!obj.image){
var fileCallPath = encodeURIComponent( obj.uploadPath+"/"+ obj.uuid +"_"+obj.fileName);
var fileLink = fileCallPath.replace(new RegExp(/\\/g),"/");
str += "<li><a href='/download?fileName="+fileCallPath+"'><img src='/resources/img/attach.png'>"+obj.fileName+"</a>"+
"<span data-file=\'"+fileCallPath+"\' data-type='file'> x </span>"+
"<div></li>"
}else{
var fileCallPath = encodeURIComponent( obj.uploadPath+ "/s_"+obj.uuid +"_"+obj.fileName);
var originPath = obj.uploadPath+ "\\"+obj.uuid +"_"+obj.fileName;
originPath = originPath.replace(new RegExp(/\\/g),"/");
str += "<li><a href=\"javascript:showImage(\'"+originPath+"\')\"><img src='/display?fileName="+fileCallPath+"'></a>"+
"<span data-file=\'"+fileCallPath+"\' data-type='image'> x </span>"+
"<li>";
}
});
uploadResult.append(str);
}
- 변경된 부분은 < span > 태그를 이용해 섬네일이나 파일 아이콘 옆에 'x' 표시를 추가한 점과 < span > 태그에 'data-file'과 'data-type' 속성을 추가한 부분이다.
- 화면을 보면 테스트할 수 있도록 만든 'x'표시가 보인다.
- 'x'표시에 대한 이벤트 처리는 아래와 같이 작성한다.
< uploadAjax.jsp >
$(".uploadResult").on("click","span", function(e){
var targetFile = $(this).data("file");
var type = $(this).data("type");
console.log(targetFile);
$.ajax({
url: '/deleteFile',
data: {fileName: targetFile, type:type},
dataType:'text',
type: 'POST',
success: function(result){
alert(result);
}
}); //$.ajax
});
- 첨부파일의 삭제는 < span > 태그를 이용해 처리하지만, 첨부파일의 업로드 후에 생성되기 때문에 '이벤트 위임' 방식으로 처리해야 한다.
- 이벤트 처리에서는 Ajax를 이용해서 첨부파일의 경로와 이름, 파일의 종류(이미지 혹은 일반)를 전송한다.
서버에서 첨부파일의 삭제
- 서버 측에서 첨부파일은 전달되는 파라미터의 이름과 종류를 파악해 처리한다.
< UploadController >
@PostMapping("/deleteFile")
@ResponseBody
public ResponseEntity<String> deleteFile(String fileName, String type) {
log.info("deleteFile: " + fileName);
File file;
try {
file = new File("d:\\upload\\" + URLDecoder.decode(fileName,"UTF-8"));
file.delete();
if (type.equals("image")) {
String largeFileName = file.getAbsolutePath().replace("s_", "");
log.info("largeFileName: " + largeFileName);
file = new File(largeFileName);
file.delete();
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<String>("deleted", HttpStatus.OK);
}
- deleteFIle()은 브라우저에서 전송하는 파일 이름과 종류를 파라미터로 받아서 파일의 종류에 따라 다르게 동작한다.
- 브라우저에서 전송되는 파일 이름은 '경로+UUID+_+파일이름'으로 구성되어 있으므로, 일반 파일의 경우에는 파일만을 삭제한다.
- 이미지의 경우 섬네일이 존재하므로, 파일 이름의 중간에 's_'가 들어가 있다.
- 일반 이미지 파일의 경우 's_'가 없도록 되어 있으므로, 이 부분을 변경해 원본 이미지 파일도 같이 삭제하도록 처리한다.
24.3.2 첨부파일의 삭제 고민
- 첨부파일을 삭제하는 작업의 최대 고민은 사용자가 비정상적으로 브라우저를 종료하고 나가는 행위다.
- 서버에는 Ajax를 이용해 업로드했기 때문에 이미 저장이 된 상태지만, 사용자가 '작업 관리자'나 전원 버튼을 누르는 등의 조치를 해서 브라우저 자체를 종료해 버린다면 이를 감지할 수 있는 적당한 방법이 없다(브라우저의 창이 닫히는 이벤트는 가능하지만 비정상적인 종료는 문제가 된다.).
- 이에 대한 가장 좋은 해결책은 실제 최종적인 결과와 서버에 업로드된 파일의 목록을 비교해서 처리하는 것이다.
- 보통 이런 작업은 spring-batch나 Quartz 라이브러리를 이용해 처리한다.