2026. 4. 24. 19:30ㆍ대우개발원 수업 내용/spring boot, framework
게시판 시스템의 핵심인 데이터베이스 삭제와 물리적 파일 삭제의 동기화를 처리하며,
이로써 첨부파일이 포함된 전체 CRUD 사이클이 마무
게시글 삭제 시 물리적 파일 시스템과 DB의 데이터 무결성 동기화 구현
1. 삭제 버튼 이벤트 리스너 및 데이터 수집 통합 (modify.html)
삭제 프로세스 제어: 사용자가 Remove 버튼을 클릭했을 때, 즉시 삭제하는 대신 폼 데이터를 구성하는 appendFileData와 appendNotShownData를 호출하여 현재 상태를 서버로 보낼 준비를 함
데이터 유실 방지: 화면에 보이는 파일(유지할 파일)뿐만 아니라, 수정 과정에서 'X' 버튼을 눌러 removeFileList에 담겼던 파일 정보까지 모두 수집하여 서버로 전달함
비동기 연동: formObj.action을 /board/remove로 변경하고 POST 방식을 강제하여, 단순 게시글 번호뿐만 아니라 삭제해야 할 파일 목록이 담긴 BoardDTO가 서버에 도착하도록 설계함
2. 화면에서 제외된 파일 데이터의 hidden 필드 전환 (modify.html)
appendNotShownData 함수: 사용자가 삭제를 선택하여 화면상에서는 사라졌던 파일들의 정보(removeFileList)를 루프를 통해 추출하고, 이를 서버가 인식할 수 있는 uuid_파일명 형식의 hidden 입력 태그로 생성함
폼 데이터 주입: 생성된 hidden 필드들을 .uploadHidden 영역에 삽입함으로써, 서버 측 컨트롤러가 BoardDTO 내의 fileNames 리스트로 해당 정보를 정확히 수신할 수 있도록 보장함
3. 컨트롤러의 게시글 삭제 및 파일 정리 로직 (BoardController.java)
서비스 호출 연계: boardService.remove(bno)를 통해 DB에서 게시글과 연관된 이미지 정보를 먼저 삭제한 후, 전달받은 fileNames 리스트를 바탕으로 실제 저장소의 파일 삭제를 진행함
물리 파일 접근: @Value를 통해 설정된 uploadPath와 FileSystemResource를 사용하여 서버 내에 저장된 실제 파일 객체에 접근하고 삭제 연산을 수행함
상태 관리: 삭제 완료 후 addFlashAttribute를 통해 리스트 페이지로 이동 시 사용자에게 삭제 성공 메시지(removed)를 전달하여 작업의 결과를 명확히 알림
4. 이미지 파일 및 섬네일의 연쇄 삭제 처리 (BoardController.java)
removeFiles 메서드: 리스트로 전달된 파일명을 순회하며 실제 파일을 삭제하고, Files.probeContentType을 사용하여 해당 파일의 MIME 타입을 확인함
섬네일 처리 로직: 만약 삭제 대상이 이미지 파일일 경우, 원본 파일뿐만 아니라 앞에 s_가 붙은 섬네일 파일까지 경로를 계산하여 물리적으로 완벽하게 제거함
예외 처리: 파일 삭제 과정에서 발생할 수 있는 오류를 try-catch로 묶어 로그를 남기도록 설계하여, 특정 파일 삭제가 실패하더라도 전체 프로세스가 중단되지 않도록 안정성을 확보함
5. 파일 업로드 시스템의 최종 정합성 검증
저장소 최적화: 게시글이 삭제될 때 DB 데이터만 지워지는 것이 아니라 서버 저장소의 용량까지 확보하게 되어, 장기적으로 시스템 자원을 효율적으로 관리할 수 있는 구조를 완성함
CRUD 사이클 마감: 등록 시의 업로드, 수정 시의 교체, 삭제 시의 일괄 정리가 조화롭게 작동하며, 사용자 인터페이스(UI)와 백엔드 로직 간의 유기적인 데이터 흐름을 검증함
[요약]
게시글 삭제 시 물리적 파일 시스템과 DB의 데이터 무결성 동기화 구현
1. 삭제 버튼 클릭 시 화면 노출/비노출 파일 전체 정보를 수집하는 이벤트 리스너 구현
2. removeFileList 내의 삭제 대상을 hidden 필드로 변환하는 appendNotShownData 로직 완성
3. 컨트롤러에서 DB 데이터 삭제와 파일 저장소 삭제를 연동하는 remove 메서드 고도화
4. FileSystemResource를 활용한 원본 이미지 및 s_ 섬네일 파일의 물리적 삭제 처리
5. @Value와 Resource 객체를 통한 서버 경로 제어 및 안정적인 예외 처리 구조 확립
Remove버튼을 클릭했을때 발생하는 이벤트 리스너를 추가
modify.html
코드에 추가
게시글 삭제 시점에 화면에 남아 있는 파일과 이미 삭제 처리된 파일 정보를 모두 수집하여
서버의 실제 파일까지 완벽하게 제거하기 위한 최종 데이터 정리 로직.
- 삭제 프로세스 통합 제어: 게시글 본문만 지우는 것이 아니라, 연관된 모든 파일 정보를 폼에 담아 /board/remove 경로로 POST 요청을 보냄으로써 데이터베이스와 물리 저장소의 정합성을 맞춤.
- 이중 데이터 수집: 현재 화면에 유지되고 있는 파일(appendFileData)과 사용자가 삭제를 선택하여 리스트에 담긴 파일(appendNotShownData) 정보를 모두 폼 데이터로 변환하여 서버에 전달함.
- 가상 리스트 활용: 사용자가 수정 화면에서 'X' 버튼을 눌러 화면에서만 사라졌던 파일들의 정보(removeFileList)를 루프를 통해 추출하고, 서버가 인식할 수 있는 uuid_파일명 형식의 hidden 필드로 재구성함.
- 동적 폼 데이터 주입: .uploadHidden 영역에 생성된 hidden 입력 태그들을 삽입함으로써, 폼 제출 시 게시글 번호(bno)와 함께 삭제 대상 파일 목록이 배열 형태로 서버에 전송되도록 설계함.
- 서버 측 연쇄 삭제 유도: 이 로직을 통해 서버는 어떤 파일을 실제 경로에서 지워야 할지 명확한 목록을 받게 되며, 이를 바탕으로 DB 데이터 삭제와 실제 파일 시스템의 파일 삭제를 동시에 수행할 수 있게 됨.
document.querySelector(".removeBtn").addEventListener("click", function(e){
e.preventDefault()
e.stopPropagation()
//화면에 보이는 파일들을 form 태그에 추가
appendFileData()
// 화면에서 안 보이도록 처리된 파일들을 form 태그에 추가
appendNotShownData()
formObj.action = `/board/remove`
formObj.method ='post'
// formObj.submit() // 테스트 이후에 주석 해제
}, false)
// 삭제할 파일들의 정보를 숨겨진 입력 필드로 추가하는 함수
function appendNotShownData() {
// 삭제할 파일이 없다면 함수 종료
if (removeFileList.length > 0) {
return;
}
// 숨겨진 데이터 입력 영역 가져오기
const target = document.querySelector(".uploadHidden");
let str = '';
// 삭제할 파일 리스트를 순회하면서 숨겨진 입력 필드를 추가
for (let i = 0; i< removeFileList.length; i++) {
const { uuid, fileName } = removeFileList[i];
// 파일 정보 (UUID + 피일명)을 숨겨진 입력 요소로 추가
str += `<input type ='hidden' name='fileNames' value="${uuid}_${fileName}">`;
}
// 생성된 숨겨진 입력 필드를 target 영역에 추가
target.innerHTML += str;
}
// formObj.submit() // 테스트 이후에 주석 해제
을 주석 처리 하고
실행하면




<input type="hidden" name="fileNames" value="e98a7553-d2a2-4045-960d-509328dfa916_aaa.png">
aaa.png 파일 삭제 후 사라지는게 아닌 hidden안에 파일이 남아 있음(마지막 사진 로그 확인)
BoardController
코드 수정
@Value("${file.upload.path}") // import 시에 springframework으로 시작하는 것으로 할 것
private String uploadPath;
// 게시물 삭제 처리 메소드
@PostMapping("/remove")
public String remove(BoardDTO boardDTO, RedirectAttributes redirectAttributes) {
// 삭제할 번호를 가져오기
Long bno = boardDTO.getBno();
log.info("remove post..." + bno);
// 서비스 호출하여 게시물 삭제
boardService.remove(bno);
// 게시물이 데이터베이스에서 삭제되었으면, 첨부파일도 삭제
log.info(boardDTO.getFileNames());
// 삭제할 파일 리스트 가져오기
List<String> fileNames = boardDTO.getFileNames();
// 파일명이 존재하면 파일 삭제 처리
if (fileNames != null && fileNames.size() > 0) {
removeFiles(fileNames);
}
// 삭제 결과를 플래시 속성에 추가(리다이렉트 시 메세지를 전달)
redirectAttributes.addFlashAttribute("result", "removed");
// 게시판 목록 페이지로 리다이렉트
return "redirect:/board/list";
}
// 첨부 파일 삭제 처리 메소드
public void removeFiles(List<String> files) {
// 삭제할 파일들 순회
for (String fileName : files){
// 파일 경로를 이용해 리소스 객체 생성
Resource resource = new FileSystemResource(uploadPath + File.separator + fileName);
String resourceName = resource.getFilename();
try {
// 파일의 mime 타입을 확인 (이미지 파일인지 여부)
String contentType = Files.probeContentType(resource.getFile().toPath());
// 파일 삭제
resource.getFile().delete();
// 만약 이미지 파일이라면 섬네일도 삭제
if (contentType.startsWith("image")) {
File thumbnailFile = new File(uploadPath + File.separator + "s_" + fileName);
thumbnailFile.delete();
}
} catch (Exception e) {
// 예외 발생 시 에러 메세지 로그 출력
log.error(e.getMessage());
}
}// end for
}
실행하면
remove가 된다
파일 업로드는 이걸로 마무리
'대우개발원 수업 내용 > spring boot, framework' 카테고리의 다른 글
| 자바 스프링 부트 15일차 / b01Security Spring Security 기반 자동 로그인 구현 및 사용자별 보안 로직 강화 (0) | 2026.04.28 |
|---|---|
| 자바 스프링 부트 14일차 /b01Security 회원가입(Security) 핵심 설정 및 커스텀 인증 시스템 구축 (0) | 2026.04.27 |
| 자바 스프링 부트 13일차 b01Upload (1) | 2026.04.23 |
| 자바 스프링 부트 12일차 b01Upload /첨부파일 비동기 업로드 구현 및 파일 정보를 포함한 게시글 등록 처리 (0) | 2026.04.22 |
| 자바 스프링 부트 11일차 b01Upload /첨부파일 이미지와 댓글 조회 및 처리 (0) | 2026.04.21 |

