Part 27. 게시물의 삭제와 첨부파일
- 게시물을 삭제할 때는 게시물이 포함된 첨부파일 역시 같이 삭제할 필요가 있다.
- 단순히 데이터베이스 상에서 삭제만 이루어지는 게 아니라 실제 폴더 내의 파일도 같이 삭제할 필요가 있기 때문에 작업의 순서 역시 신경 써야만 한다.
- 폴더에서의 파일 삭제는 위험한 작업이기 때문에 가능하면 뒤쪽으로 미루고 먼저 데이터베이스의 삭제 작업을 처리한 후 실제 파일을 삭제하도록 한다.
27.1 첨부파일 삭제 처리
- 첨부파일과 관련된 SQL은 BoardAttachMapper 인터페이스와 XML 파일에 작성되어 있으므로 이를 먼저 처리한다.
< BoardAttachMapper 인터페이스 >
package org.zerock.mapper;
import java.util.List;
import org.zerock.domain.BoardAttachVO;
public interface BoardAttachMapper {
public void insert(BoardAttachVO vo);
public void delete(String uuid);
public List<BoardAttachVO> findByBno(Long bno);
public void deleteAll(Long bno);
}
< BoardAttachMapper.xml >
<delete id="deleteAll">
delete tbl_attach where bno = #{bno}
</delete>
27.1.1 BoardServiceImpl의 변경
- BoardServiceImpl은 첨부파일 삭제와 실제 게시물의 삭제가 같이 처리되도록 트랜잭션 하에서 BoardAttachMapper의 deleteAll()을 호출하도록 수정한다.
< BoardServiceImpl 클래스 >
@Transactional
@Override
public boolean remove(Long bno) {
log.info("remove......" + bno);
attachMapper.deleteAll(bno);
return mapper.delete(bno) == 1;
}
27.1.2 BoardController의 파일 삭제
- BoardController는 데이터베이스의 삭제를 먼저 호출하고, 이후 파이를 삭제해야 한다.
- 다만 파일을 삭제하기 위해서는 해당 게시물의 첨부파일 목록이 필요하다.
- 문제는 첨부파일의 목록을 구한다하고 해도 이미지 파일의 경우에는 섬네일 파일이 생성되어 있으므로 이에 대한 처리가 깉이 필요하다는 점이다.
- 따라서 작업의 순서를 정리하면 다음과 같다.
- 해당 게시물의 첨부파일 정보를 미리 준비
- 데이터베이스 상에서 해당 게시물과 첨부파일 데이터 삭제
- 첨부파일 목록을 이용해 해당 폴더에서 섬네일 이미지(이미지 파일인 경우)와 일반 파일을 삭제
Criteria 수정
- 게시물의 삭제 후에 페이지 번호나 검색 조건을 유지하면서 이동하기 위해서는 'redirect'에 필요한 파라미터들을 매번 추가해야 하는 불편함이 있다.
- 이는 Criteria에서 처리할 수 있도록 이미 작성되어 있는지 확인한다.
< Criteria 클래스 >
public String getListLink() {
UriComponentsBuilder builder = UriComponentsBuilder.fromPath("")
.queryParam("pageNum", this.pageNum)
.queryParam("amount", this.getAmount())
.queryParam("type", this.getType())
.queryParam("keyword", this.getKeyword());
return builder.toUriString();
}
- UriComponentesBuilder는 브라우저에서 GET 방식 등의 파라미터 전송에 사용되는 문자열(쿼리스트링(query string))을 손쉽게 처리할 수 있는 클래스다.
파일 삭제 처리
- 파일 삭제는 BoardController에 deleteFiles()라는 메서드를 추가해 처리하도록 한다.
- deleteFiles()는 java.nio.file 패키지의 Path를 이용해 처리한다.
< BoardController >
private void deleteFiles(List<BoardAttachVO> attachList) {
if(attachList == null || attachList.size() == 0) {
return;
}
log.info("delete attach files...................");
log.info(attachList);
attachList.forEach(attach -> {
try {
Path file = Paths.get("D:\\upload\\"+attach.getUploadPath()+"\\" + attach.getUuid()+"_"+ attach.getFileName());
Files.deleteIfExists(file);
if(Files.probeContentType(file).startsWith("image")) {
Path thumbNail = Paths.get("D:\\upload\\"+attach.getUploadPath()+"\\s_" + attach.getUuid()+"_"+ attach.getFileName());
Files.delete(thumbNail);
}
}catch(Exception e) {
log.error("delete file error" + e.getMessage());
}//end catch
});//end foreachd
}
< BoarController >
@PostMapping("/remove")
public String remove(@RequestParam("bno") Long bno, Criteria cri, RedirectAttributes rttr) {
log.info("remove..." + bno);
List<BoardAttachVO> attachList = service.getAttachList(bno);
if (service.remove(bno)) {
// delete Attach Files
deleteFiles(attachList);
rttr.addFlashAttribute("result", "success");
}
return "redirect:/board/list" + cri.getListLink();
}
- BoardController의 remove()는 삭제 젘에 먼저 해당 게시물의 첨부파일 목록을 확보한다.
- 이후에 데이터베이스에서 게시물과 첨부파일 데이터를 삭제한다.
- 만일 삭제에 성공했다면 실제 파일의 삭제를 시도한다.
- 실제 첨부파일을 삭제하는 작업은 원본 파일을 삭제한 후 이미지의 경우 섬네일 파일을 추가적으로 삭제한다.
- 삭제 화면은 별다른 처리 없이 기존 게시물의 수정/삭제 화면에서 동일하게 테스트할 수 있다.
- 첨부파일이 존재하는 게시물을 등록하면 아래 그림과 같이 폴더 내에 파일들이 생성된다.
- 게시물의 수정/삭제 화면에서 게시물을 삭제하면 아래와 같이 모든 내용들이 정리된다.