Hello

Spring boot 게시판 만들기(게시판 CRUD)

by 볼빵빵오춘기

게시판을 만드는 이유

자바를 배우고 나서 다음 단계를 넘어가려 할 때, 책이나 인터넷에서 자료를 찾아보면 게시판 만들기 예제가 많이 등장하는 것을 알 수 있다.
국비 교육 과정에서도 최종 프로젝트로 게시판을 만들어 포트폴리오로 활용하는 경우가 흔하다.
처음에는 아무 생각 없이 그냥 공부하다 보면 자연스럽게 알게 되겠지 하고 지나쳤던 것 같다.
하지만 다시 생각해보니, 게시판 만들기가 자주 등장하는 데는 이유가 있지 않을까 싶다.

이제 그 이유와 더불어, CRUD의 중요성, 그리고 CRUD를 이용해 게시판을 만드는 이유와 게시판 구현은 어떻게 했는지 정리해본다.

 

CRUD(Create, Read, Update, Delete)가 중요한 이유

더보기

 

  • 데이터 관리의 기본 기능 제공
    대부분의 애플리케이션은 데이터를 다룬다.
    예를 들어, 사용자 정보, 상품 목록, 게시물, 댓글 등 다양한 데이터를 다루는데, 이 데이터를 관리하기 위해서는 생성, 읽기, 수정, 삭제가 필요하다.
    CRUD는 이러한 데이터 관리의 기본적인 요구사항을 충족시킨다.

  • 유연한 데이터 조작 가능
    CRUD 기능을 통해 사용자는 데이터를 쉽게 추가, 조회, 수정, 삭제할 수 있다.
    이는 데이터의 유연한 관리를 가능하게 하며, 사용자가 요구하는 다양한 데이터 조작 작업을 지원한다.

  • 애플리케이션의 기능 확장성
    CRUD는 데이터베이스와의 상호작용을 위한 기본적인 인터페이스를 제공한다.
    이를 기반으로 추가적인 기능을 구현하거나 시스템을 확장할 수 있다.
    예를 들어, 필터링, 정렬, 검색 등의 기능도 CRUD 작업을 기반으로 쉽게 구현할 수 있다.

  • 표준화된 인터페이스 제공
    대부분의 개발자들이 CRUD 개념에 익숙하기 때문에, 이를 사용하면 코드의 가독성과 유지보수성이 향상된다.
    이는 개발팀 간의 협업을 원활하게 하고, 새로운 팀원이 프로젝트에 쉽게 적응할 수 있도록 도와준다.

  • 데이터 무결성 보장
    CRUD를 통해 데이터의 생성부터 삭제까지 일관된 작업을 수행할 수 있다.
    이를 통해 데이터의 무결성을 유지하고, 시스템의 신뢰성을 높일 수 있다.

 

CRUD를 이용해 게시판을 만드는 이유

더보기
  • 실전 같은 학습 경험
    • 기본적인 웹 애플리케이션 구조 이해
      게시판은 대부분의 웹 애플리케이션에서 필요한 기능들을 작은 범위에서 경험할 수 있는 좋은 예시이다.
      사용자는 게시판을 통해 데이터베이스와의 상호작용, 사용자 입력 처리, 화면 렌더링 등 다양한 기술을 종합적으로 학습할 수 있다.
    • 웹 개발 전반에 대한 이해: 게시판 프로젝트는 프론트엔드(HTML, CSS, JavaScript)와 백엔드(서버, 데이터베이스)의 연동을 포함하여, 전반적인 웹 개발의 흐름을 이해할 수 있게 도와준다.

 

  • CRUD 기능의 실습과 이해
    • Create, Read, Update, Delete
      게시판은 자연스럽게 CRUD 기능을 구현할 수 있는 주제이다.
      사용자는 게시판에서 글을 작성(Create), 조회(Read), 수정(Update), 삭제(Delete)하며, 각 기능이 어떻게 작동하는지 직접 경험하게 된다.
      이 과정에서 데이터베이스와의 상호작용, 입력 검증, 트랜잭션 관리 등을 실습할 수 있다.

 

  • 프로젝트 완성도 높이기
    • 포트폴리오에 적합
      게시판은 작은 규모의 프로젝트이지만, 여러 가지 중요한 기능을 포함하고 있어 포트폴리오로 적합하다.
      특히, 이를 통해 얻은 결과물은 취업 준비나 면접에서 유용하게 사용될 수 있다.
    • 확장 가능성
      게시판은 기본적인 CRUD 기능에서 시작하여, 이후에 페이징, 검색, 권한 관리, 댓글 기능 등 다양한 기능을 추가하면서 확장할 수 있다.
      이를 통해 프로젝트를 점진적으로 개선해 나갈 수 있는 경험을 얻게 된다.

 

  • 현실적인 문제 해결 경험
    • 실제 웹 애플리케이션에서 발생할 수 있는 문제를 해결
      게시판 프로젝트를 진행하면서 다양한 문제에 부딪히게 된다.
      예를 들어, 입력 검증, 데이터 무결성 유지, 동시성 이슈 등의 문제를 해결하면서 현실적인 프로그래밍 문제를 경험하게 된다.
    • 보안과 성능 고려
      게시판을 만들 때는 사용자 인증, 권한 관리, 데이터 보호 등 보안 문제도 고려해야 한다.
      이를 통해 보안에 대한 기본적인 이해를 높일 수 있다.

 

  • 커뮤니티와 협업 경험
    • 다른 개발자들과 코드 리뷰 및 협업: 게시판 프로젝트는 다양한 개발자들과 공유하기 쉽고, 코드 리뷰를 통해 피드백을 받을 수 있는 좋은 주제이다.
      이를 통해 협업 능력도 키울 수 있다.

 글쓰기(Create)

controller

// 글쓰기 Form
@GetMapping("/communityW")
public String writeForm(){
    return "community/write";
}

 

write.html

  • 기본 글쓰기 부분이라 제목과 내용정도만 입력하도록 하였고 제목과 내용은 required을 하여 필수 입력사항으로 했다.
  • 파일은 파일추가 버튼과 파일삭제버튼을 눌러 갯수를 유동적으로 넣을 수 있도록 했다.(bbsAddFile.js 연결한 이유)
<div class="col-12 mb-15">
    <form method="post" action="/communityW" enctype="multipart/form-data">
        <input type="hidden" name="username" Id="username" placeholder="username" th:value="${#authentication.principal.username}" >

        <div class="form-group">
            <label for="title">제목</label><br>
            <input type="text" name="title" Id="title" placeholder="제목을 입력해주세요." required class="width100p">
        </div>

        <div class="form-group">
            <label for="content">내용</label>
            <div>
               <textarea name="content" id="content" style="width:100%;" rows="3" placeholder="내용을 입력해주세요." required></textarea>
            </div>

        </div>

        <div class="form-group">
            <label>파일 - 이미지 첨부(png, jpeg, jpg만 가능합니다.)</label> <span id="btn-addFile">+</span>
        </div>

        <div id="inputFile">
        </div>


        <button class="btn bg_03A3F1 color-fff" type="submit">글쓰기 완료</button>
    </form>

</div>

 

bbsAddFile.js

html에서 + 버튼을 누르면 파일첨부할 수 있는 input type=’file’를 추가해주도록 만들었고, 추가된 + 버튼 옆에 x 버튼을 만들어 파일첨부를 안할시 삭제하도록 처리하도록 하였다.

let index = {
    init: function() {
        $("#btn-addFile").on("click", () => {
            this.addFile();
        });

        // 이벤트 위임 적용
        $("#inputFile").on("click", ".btn-removeFile", function() {
            index.removeParentFormGroup($(this));
        });

        $("#inputFile").on("click", ".btn-hiddenFile", function() {
            index.hiddenParentFormGroup($(this));
        });
    },
    addFile: function() {
        var addContent = "";
        addContent += '<div class="form-group">'
            + '<input name="files" type="file" accept="image/png, image/jpeg, image/jpg" required>'
            + '<span class="btn-removeFile">x</span>'
            + '</div>';

        $("#inputFile").append(addContent);
    },
    removeParentFormGroup: function(button) {
        button.closest("div.form-group").remove();
    },


    hiddenParentFormGroup: function(button) {
        button.closest("div.form-group").addClass("d-none");
    }
}

index.init();

 

Controller

받아온 file들과 communityDto를 service에 save() 파라미터로 넘겨준다.

// 글 작성
@PostMapping("/communityW")
public String write(CommunityDto communityDto, List<MultipartFile> files,Model model) throws Exception{

    commnunityService.save(communityDto,files);
    model.addAttribute("message", "글 작성이 완료되었습니다.");
    model.addAttribute("searchUrl", "/communityL");

    return "message/message";
}

 

Service

파일을 유동적으로 첨부할 수 있도록 해놓았기 때문에 파일이 있는 경우와 없는 경우를 나누었다. 

@Autowired
private CommunityReplyRepository communityReplyRepository;

public void save(CommunityDto communityDto, List<MultipartFile> files) throws Exception{

    CommunityEntity communityEntity = CommunityEntity.toSaveCommnunityEntity(communityDto);

    // 여러 개의 파일을 가져올 경우
    if(files!=null){ // 파일이 있을 경우
        communityEntity.setFileAttached(1);
        CommunityEntity saveEntitiy = commnunityRepository.save(communityEntity);

        // 파일 이름가져오기
        for(MultipartFile file : files){

            // 원본 이름
            String originalFileName = file.getOriginalFilename();

            // 확장자 가져오기
            String[] extension = originalFileName.split("[.]");
            int lastIdx = extension.length-1;

            // 저장용 파일 이름 만들기
            UUID uuid = UUID.randomUUID();
            String storedFileName = System.currentTimeMillis()+"-"+uuid+"."+extension[lastIdx];

            // boardFile DB에 넣을 BoardFileEntity 세팅
            BoardFileEntity boardFileEntity = new BoardFileEntity();
            boardFileEntity.setBoardId(saveEntitiy.getId());
            boardFileEntity.setOriginalFileName(originalFileName);
            boardFileEntity.setStoredFileName(storedFileName);
            boardFileEntity.setBoard("community");

            // 파일 저장용 폴더
            String savePath = System.getProperty("user.dir")+"/src/main/resources/static/img/community";

            // 파일 저장
            File saveFile = new File(savePath,storedFileName);
            file.transferTo(saveFile);

            // boardFile DB에 넣음
            boardFileRepository.save(boardFileEntity);
        }

    }else{ // 파일이 없을 경우
        communityEntity.setFileAttached(0);
        commnunityRepository.save(communityEntity);
    }

}

 

 

글 상세페이지(Read)

Controller

글 상세페이지는 게시글과 그 게시물과 연관되어있는 댓글들을 보여준다.

(※ 댓글은 댓글 crud 참고)

// 글 상세
@GetMapping("/communityV/{id}")
public String view(Model model,@PathVariable int id){

    // community에서 글 정보 가져오기
    CommunityEntity communityEntity =  commnunityService.view(id);
    model.addAttribute("board", communityEntity);

    // 저장 파일 가져오기
    List<BoardFileEntity> boardFiles = commnunityService.getFileList(id); // Entity로 변경하기
    model.addAttribute("boardFileList",boardFiles);

    // 댓글 가져오기 
    // 댓글은 가져올 필요x
    // communityEntity를 보면
    // private List<CommunityReplyEntity> reply;
    // 이 부분을 통해 reply는 board 검색 시 그냥 가지고 오게 된다.
    // 그렇기 때문에 따로 가져오는 로직을 만들 필요가 없다.
    // 여기서 내가 말한 로직이란 service -> repository로 가는 로직을 말한다.
    List<CommunityReplyEntity> replies = communityEntity.getReply();
    // 각 댓글 내용 출력 model에 담기
    model.addAttribute("replies",replies);
    return "community/view";
}

 

Service

게시글의 내용과 제목, 파일 등 정보를 가져오면서 해당 글을 작성한 이가 아니면 조회수를 올라가도록 처리했다.

@Transactional
public CommunityEntity view(int id){

    CommunityEntity communityEntity = commnunityRepository.findById(id).get();

    // 조회수 올리기
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

    if (authentication != null && authentication.isAuthenticated() && authentication.getPrincipal() instanceof UserDetails) {
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        String username = userDetails.getUsername();

        // 로그인한 사용자의 정보를 이용하여 처리
        if(username!=communityEntity.getUsername()){
            commnunityRepository.updateConunt(id);
            // 위의 코드에 @transation을 이용하여 바로 DB는 변경이 되나 view페이지에는 +1 된 숫자로 세팅이 되지않으므로 위에 가져온 communityEntity의 count를 +1해서 다시 세팅해준다.
            // 사용자가 view페이지에 들어오는 순간 작성자가 아니라면 바로 +1해서 보여준다.
            communityEntity.setCount(communityEntity.getCount()+1);
        }
    }else {
        // 기획안에 첨은에는 로그인한 회원만을 하였기 떄문에 비로그인사용자는 따로 추가 처리하지는 않았다.
        commnunityRepository.updateConunt(id);
        communityEntity.setCount(communityEntity.getCount()+1);
    }

    return commnunityRepository.findById(id).get();
}

 

Repository

// 조회수 올리기
@Modifying
@Query(value=" update CommunityEntity c set c.count = c.count + 1 where c.id = :id ")
void updateConunt(@Param("id") int id);

 

글 수정(Update)

controller

// 글 수정 Form 
@GetMapping("/communityU/{id}")
public String updateForm(@PathVariable int id,Model model){

    CommunityEntity communityEntity = commnunityService.updateForm(id);

    // 등록되어있던 글 정보 가져오기
    model.addAttribute("board",communityEntity);

    // 등록되어있던 글에 파일 정보 가져오기
    if(communityEntity.getFileAttached()==1){
        List<BoardFileEntity> boardFiles = commnunityService.getFileList(id); // Entity로 변경해서 받아오기
        model.addAttribute("boardFileList",boardFiles);
    }

    return "community/update";
}

 

update.html

  • write.html 과 동일하나 input value에 값을 가져오고 파일에도 첨부된 파일은 보여주도록 처리했다.
  • 수정 시에도 파일은 유동적이로 첨부할 수 있기에 bbsAddFile.js 연결했다.
<form method="post" action="/communityU" enctype="multipart/form-data">
    <input type="hidden" name="id" Id="id" placeholder="id" th:value="${board.id}" >
    <input type="hidden" name="count" Id="count" placeholder="count" th:value="${board.count}" >
    <input type="hidden" name="username" Id="username" placeholder="username" th:value="${#authentication.principal.username}" >

    <div class="form-group">
        <label for="title">제목</label><br>
        <input type="text" name="title" Id="title" th:value="${board.title}" placeholder="제목을 입력해주세요." class="width100p" required>
    </div>

    <div class="form-group">
        <label for="content">내용</label>
        <div>
           <textarea name="content" id="content" style="width:100%;" th:utext="${board.content}" rows="3" placeholder="내용을 입력해주세요." required></textarea>
        </div>

    </div>


    <div class="form-group">
        <label>파일 - 이미지 첨부(png, jpeg, jpg만 가능합니다.)</label> <span id="btn-addFile">+</span>
    </div>

    <div id="inputFile">
        <div class="form-group" th:if="${board.fileAttached}==1" th:each="boardFile : ${boardFileList}">
            <input name="files" type="file" accept="image/png, image/jpeg, image/jpg" ><br>
            첨부 되어있는 파일 : <span th:text="${boardFile.originalFileName}"></span><br>
            <input name="del" type="checkbox" th:value="${boardFile.id}">첨부 파일 삭제
        </div>
    </div>

    <button class="btn bg_03A3F1 color-fff" type="submit">수정 완료</button>
</form>

 

controller

// 글 수정
@PostMapping("/communityU")
public String update(CommunityDto communityDto, List<MultipartFile> files, @RequestParam (required = false) List<Integer> del,Model model,@AuthenticationPrincipal PrincipalDetails principalDetails) throws Exception{
    commnunityService.update(communityDto,files,del);
    return "redirect:/communityL";
}

 

Service

  • 파일 첨부와 첨부된 파일삭제조건에 따라 실행되도록 했다.
  • 조건은 다음과 같다.
    • 새로 들어온 파일이 없고 삭제도 없을 때 => 파일 변경 없음.
    • 새로 들어온 파일이 없고 삭제만 있을 때
    • 새로 들어온 파일만 있고 삭제는 없을 때
    • 새로 들어온 파일이 있고 삭제도 있을 때
@Transactional
public void update(CommunityDto communityDto,List<MultipartFile> files,List<Integer> del)throws Exception{
    CommunityEntity communityEntity = CommunityEntity.toUpdateCommnunityEntity(communityDto);

    // 조건
    // 새로 들어온 파일이 없고 삭제도 없을 때 => 파일 변경 없음.
    // 새로 들어온 파일이 없고 삭제만 있을 때
    // 새로 들어온 파일만 있고 삭제는 없을 때
    // 새로 들어온 파일이 있고 삭제도 있을 때
    // 조건을 정리하자면
    // 1. del 삭제해야할 파일이 있는가? => 있다면 orginalName, storedName 을 공백으로 변경
    if(del !=null){
        for(Integer id : del){
            boardFileRepository.gapUpdate(id);
        }
    }

    // 2. 새로 들어온 파일이 있는가?
    // 기존 파일 List
    List<BoardFileEntity> boardFileEntities = boardFileRepository.findByBoardIdAndBoard(communityDto.getId(), "community");

    // 2-1. 조건1. 기존파일 리스트 길이보다 작거나 같은경우 새로운 파일로 update
    if(files != null){ // 새 파일이 있을 때
        if(files.size()<=boardFileEntities.size()){
            for(int i=0;i<boardFileEntities.size();i++){

                // 기존 해당 인덱스 부분에 새로운 파일을 set해주기
                MultipartFile file = files.get(i);
                if (!file.getOriginalFilename().isEmpty()) {
                    // 원본 이름
                    String originalFileName = file.getOriginalFilename();

                    // 확장자 가져오기
                    String[] extension = originalFileName.split("[.]");
                    int lastIdx = extension.length-1;

                    // 저장용 파일 이름 만들기
                    UUID uuid = UUID.randomUUID();
                    String storedFileName = System.currentTimeMillis()+"-"+uuid+"."+extension[lastIdx];

                    BoardFileEntity newFile = new BoardFileEntity();
                    newFile.setId(boardFileEntities.get(i).getId());
                    newFile.setBoard(boardFileEntities.get(i).getBoard());
                    newFile.setBoardId(boardFileEntities.get(i).getBoardId());
                    newFile.setOriginalFileName(originalFileName);
                    newFile.setStoredFileName(storedFileName);

                    boardFileEntities.set(i,newFile);

                    // 파일 저장용 폴더
                    String savePath = System.getProperty("user.dir")+"/src/main/resources/static/img/community";

                    // 파일 저장
                    File saveFile = new File(savePath,storedFileName);
                    file.transferTo(saveFile);

                }
            }

            for(BoardFileEntity file : boardFileEntities){
                boardFileRepository.update(file.getId(),file.getOriginalFileName(),file.getStoredFileName());
            }

        }else{ // 2-2. 조건2. 기존파일 리스트 길이보다 크다. 큰 부분만 insert
            for(int i=0;i<boardFileEntities.size();i++){
                // 기존 해당 인덱스 부분에 새로운 파일을 set해주기

                MultipartFile file = files.get(i);
                if (!file.getOriginalFilename().isEmpty()) {
                    // 원본 이름
                    String originalFileName = file.getOriginalFilename();

                    // 확장자 가져오기
                    String[] extension = originalFileName.split("[.]");
                    int lastIdx = extension.length-1;

                    // 저장용 파일 이름 만들기
                    UUID uuid = UUID.randomUUID();
                    String storedFileName = System.currentTimeMillis()+"-"+uuid+"."+extension[lastIdx];

                    BoardFileEntity newFile = new BoardFileEntity();
                    newFile.setId(boardFileEntities.get(i).getId());
                    newFile.setBoard(boardFileEntities.get(i).getBoard());
                    newFile.setBoardId(boardFileEntities.get(i).getBoardId());
                    newFile.setOriginalFileName(originalFileName);
                    newFile.setStoredFileName(storedFileName);

                    boardFileEntities.set(i,newFile);

                    // 파일 저장용 폴더
                    String savePath = System.getProperty("user.dir")+"/src/main/resources/static/img/community";

                    // 파일 저장
                    File saveFile = new File(savePath,storedFileName);
                    file.transferTo(saveFile);
                }
            }

            for(BoardFileEntity file : boardFileEntities){
                boardFileRepository.update(file.getId(),file.getOriginalFileName(),file.getStoredFileName());
            }

            for(int i = boardFileEntities.size();i <files.size();i++){
                MultipartFile file = files.get(i);
                // 원본 이름
                String originalFileName = file.getOriginalFilename();

                // 확장자 가져오기
                String[] extension = originalFileName.split("[.]");
                int lastIdx = extension.length-1;

                // 저장용 파일 이름 만들기
                UUID uuid = UUID.randomUUID();
                String storedFileName = System.currentTimeMillis()+"-"+uuid+"."+extension[lastIdx];

                // boardFile DB에 넣을 BoardFileEntity 세팅
                BoardFileEntity boardFileEntity = new BoardFileEntity();
                boardFileEntity.setBoardId(communityDto.getId());
                boardFileEntity.setOriginalFileName(originalFileName);
                boardFileEntity.setStoredFileName(storedFileName);
                boardFileEntity.setBoard("community");

                // 파일 저장용 폴더
                String savePath = System.getProperty("user.dir")+"/src/main/resources/static/img/community";

                // 파일 저장
                File saveFile = new File(savePath,storedFileName);
                file.transferTo(saveFile);

                // boardFile DB에 넣음
                boardFileRepository.save(boardFileEntity);

            }
        }
    }

    // 3. DB에서 orginalName, storedName 을 공백인 컬럼은 삭제한다.
    boardFileRepository.deleteFile(communityDto.getId(),"community");

    // 4. 해당 게시물에 첨부파일이 있다면 community BBS table에 fileattached 를 1로 바꿔준다.
    boardFileEntities = boardFileRepository.findByBoardIdAndBoard(communityDto.getId(), "community");

    if(boardFileEntities == null || boardFileEntities.isEmpty()){
        communityEntity.setFileAttached(0);
    }else{
        communityEntity.setFileAttached(1);
    }

    commnunityRepository.save(communityEntity);
}

 

Repository

// 파일 변경
// 첨부되어있는 파일 삭제에 체크박스에 체크 했을 경우
@Modifying
@Query(value=" update BoardFileEntity c set c.originalFileName = '', c.storedFileName = ''  where c.id = :id  ")
void gapUpdate(@Param("id") int id);

// 파일 변경
// 첨부되어있는 파일 삭제에 체크 했고 새 파일을 넣을 경우 or 해당 새 파일 넣는 경우 => 새 파일을 넣는 경우
@Modifying
@Query(value=" update BoardFileEntity c set c.originalFileName = :originalFileName, c.storedFileName = :storedFileName  where c.id = :id ")
void update(@Param("id") int id,@Param("originalFileName") String originalFileName,@Param("storedFileName") String storedFileName);

// 첨부되어있는 파일 삭제에 체크박스에 체크 했고 새 파일이 들어오지않은경우 - c.originalFileName = '' and c.storedFileName = '' 빈칸으로 변경했고 불필요한 데이터이므로 삭제
// 두 번 나눠서 삭제이유는 기존 파일은 냅둬야하기때문에 구분하고자 '' 으로 변경 후 삭제함.
@Modifying
@Query(value=" delete BoardFileEntity c where c.boardId = :boardId and c.originalFileName = '' and c.storedFileName = '' and c.board = :board ")
void deleteFile(@Param("boardId") int boardId,@Param("board") String board);

// boardId 와 board를 통해 파일 정보 삭제
// boardId만 있을 경우 다른 테이블에 pk인 boardId도 삭제 될 수 있기 때문에 board(protect,shelter,community)인지 확인
@Modifying
@Query(value=" delete BoardFileEntity c where c.boardId = :boardId and c.board = :board")
void deleteBbsFile(@Param("boardId") int boardId,@Param("board") String board);

 

글 삭제(Delete)

Controller

//글 삭제
@GetMapping("/communityD/{id}")
public String delete(@PathVariable int id,Model model){
    // community table에서 해당 글 삭제하기
    // reply tabled에서 해당 글과 관련된 댓글 삭제하기
    // entity만들 때 연관관계에 의해 reply table에서 댓글은 같이 삭제된다.
    // file table에서 해당 게시글에 연관된 파일 삭제하기 file table에서 boardID 가 매개변수로 받은 id와 같으면 삭제하기
    commnunityService.delete(id);

    model.addAttribute("message", "글이 삭제가 되었습니다.");
    model.addAttribute("searchUrl", "/communityL");

    return "message/message";
}

 

Service

// 글 삭제
@Transactional
public void delete(int id){
    commnunityRepository.deleteById(id);
    boardFileRepository.deleteBbsFile(id,"community");

    // 실질적 저장 파일 삭제하기
    List<BoardFileEntity> boardFiles = getFileList(id);
    if(boardFiles!=null){
        for (BoardFileEntity s : boardFiles) {
            String srcFileName = null;
            String fileName = s.getStoredFileName();
            String uploadPath = System.getProperty("user.dir")+"/src/main/resources/static/img/community";
            try {
                srcFileName = URLDecoder.decode(fileName,"UTF-8");
                File file = new File(uploadPath + File.separator + srcFileName); // 매개변수 => 파일경로 이다.
                boolean result = file.delete(); // true이면 지우기 성공, false면 지우기 실패
            }catch (UnsupportedEncodingException e){
                e.printStackTrace();
            }
        }
    }
}

 

Repository

// boardId 와 board를 통해 파일 정보 삭제
// boardId만 있을 경우 다른 테이블에 pk인 boardId도 삭제 될 수 있기 때문에 board(protect,shelter,community)인지 확인
@Modifying
@Query(value=" delete BoardFileEntity c where c.boardId = :boardId and c.board = :board")
void deleteBbsFile(@Param("boardId") int boardId,@Param("board") String board);

 

블로그의 정보

Hello 춘기's world

볼빵빵오춘기

활동하기