Post

[코딩 자율학습 스프링 부트 3 자바 백엔드 개발 입문] 8장. 게시글 삭제하기: Delete

[코딩 자율학습 스프링 부트 3 자바 백엔드 개발 입문] 8장. 게시글 삭제하기: Delete

“코딩 자율학습 스프링 부트 3 자바 백엔드 개발 입문” 도서 바로가기

8장. 게시글 삭제하기: Delete

8.1 데이터 삭제 과정

웹 서비스에서 특정 게시글 데이터를 완전히 삭제하는 작업은 다음의 단계별 정형화된 흐름에 따라 수행된다.

  • 클라이언트가 HTTP 메서드를 사용하여 서버로 특정 게시글의 삭제 요청을 전송한다.
  • 삭제 요청을 수신한 컨트롤러는 JPA 리파지터리를 매개로 데이터베이스(DB) 내에 저장되어 있는 레코드를 검색한 후 삭제 연산을 처리한다. 이 영속성 데이터 파기 작업은 데이터베이스 내에 일치하는 기존 데이터가 실존하는 경우에만 선택적으로 실행된다.
  • 데이터베이스 상의 레코드 삭제 처리가 안전하게 완료되면, 서버는 클라이언트 브라우저의 제어권을 최종 결과 페이지로 리다이렉트(재요청) 처리한다.
  • 결과 페이지로 화면 주소가 리다이렉트되는 시점에 클라이언트 측으로 삭제 처리가 완료되었음을 알리는 알림 메시지를 동반하여 전송하기 위해 RedirectAttributes 클래스를 비즈니스 로직에 도입한다. RedirectAttributes 객체가 지원하는 addFlashAttribute() 메서드를 활용하면 리다이렉트가 완료된 목적지 뷰 페이지에서만 단발성으로 접근하여 사용할 수 있는 일회성 휘발성 데이터를 세션에 안전하게 등록하여 전송할 수 있다.

8.2 데이터 삭제하기

개발 서버 애플리케이션을 가동한 뒤 웹 브라우저를 통해 목록 조회 기본 경로인 localhost:8080/articles 주소로 진입하면 이전에 설정한 데이터베이스 초기 더미 데이터 3종이 화면에 출력된다. 이 중 3번 id를 보유한 세 번째 게시글 항목의 타이틀 하이퍼링크를 선택하여 상세조회 페이지 화면으로 진입한 뒤, 해당 화면 내에 데이터를 파기할 수 있는 [Delete] 버튼 컴포넌트를 추가하여 실습을 추진한다.

8.2.1 Delete 버튼 추가하기

  1. 상세조회 뷰 템플릿 소스 수정: 사용자 화면에 삭제 명령 인터페이스를 제공하기 위해 상세 페이지의 레이아웃을 담당하는 src > main > resources > templates > articles > show.mustache 소스 파일을 편집기로 연다. 소스 코드 내부에서 기존에 설계되어 작동 중인 [Edit] 버튼 구현 태그 라인을 찾아 복사한 후 바로 아랫단 줄에 붙여넣고 아래의 세부 규칙에 의거하여 코드를 개정한다.
    • 하이퍼링크 컴포넌트 태그의 화면 노출 텍스트 문구를 Delete로 수정한다.
    • 백엔드 서버 시스템이 해당 요청을 수신했을 때 데이터 수정 처리나 단순 조회 기능과 명확히 구별하여 인지할 수 있도록 요청 전송 타겟 URL 주소 체계를 "/articles/{{article.id}}/delete" 가변 경로 형식으로 수정 지정한다.
    • 사용자 화면상에서 기존 파란색의 수정 버튼과 명확한 시각적 구별을 형성할 수 있도록, 경고 및 삭제를 뜻하는 부트스트랩 전용 테마 클래스 속성값인 빨간색의 "btn btn-danger" 스타일 코드로 교체 적용한다.
    1
    2
    
     <a href="/articles/{{article.id}}/edit" class="btn btn-primary">Edit</a>
     <a href="/articles/{{article.id}}/delete" class="btn btn-danger">Delete</a>
    
  2. UI 컴포넌트 삽입 상태 확인통합개발환경(IDE) 상단의 빌드(망치 모양) 아이콘 버튼을 마우스 클릭하여 변경된 컴파일 소스를 반영시킨 후, 브라우저 화면으로 돌아가 새로고침 명령을 가한다. 정의한 빨간색의 [Delete] 버튼이 레이아웃에 정상 배치되어 활성화되는지 육안 점검한다.

사진1

  1. 컨트롤러 미매핑 예외 확인화면에 생성된 [Delete] 버튼을 마우스로 선택하면 브라우저 상에 404 Not Found 에러 코드를 포함하는 화이트라벨 에러 페이지가 강제로 표출된다. 이는 클라이언트 브라우저가 전송한 /articles/3/delete 라우팅 경로 요청을 백엔드 서버 컨텍스트 상에서 수신하여 가공 제어할 매핑 컨트롤러 비즈니스 메서드를 아직 구현하지 않았기 때문에 발생하는 정상적인 시스템 에러 반응이다.

8.2.2 Delete 요청을 받아 데이터 삭제하기

HTTP 표준 규격 기반의 삭제 매핑 원리

클라이언트 시스템과 웹 서버 프로그램이 자원을 상호 교환할 때는 데이터 생성(POST), 데이터 조회(GET), 데이터 수정(PATCH/PUT), 데이터 삭제(DELETE)에 각각 직관적으로 상응하는 4가지 계층의 HTTP 프로토콜 표준 메서드를 선언하여 통신을 전개하는 것이 아키텍처 규칙에 부합한다. 따라서 본 데이터 삭제 실습 프로세스 역시 기술적으로는 DELETE 메서드를 선언하여 요청하는 것이 이상적이다. 그러나 웹 브라우저 화면을 구성하는 기본 마크업 요소인 HTML의 <form> 및 <a> 태그 규격 사양은 과거 설계 표준의 한계로 인해 내이티브 환경에서 오직 GET과 POST 단 두 가지 종류의 통신 프로토콜 메서드 작동만을 제한적으로 허가한다. 따라서 자바스크립트를 연동하는 고도화된 스크립트 제어 단계를 제외한 표준 HTML 링크 기반 인터페이스 환경 하에서는, 자원 인출 및 화면 이동의 규격을 담당하는 GET 방식의 매핑 프로토콜을 우회 매개하여 삭제 비즈니스 요청을 안전하게 접수하도록 시스템을 구축한다.

delete() 메서드 기본 틀 만들기

  1. 백엔드 제어 컨트롤러 파일인 ArticleController.java 소스를 엽니다. 기존 데이터 수정을 총괄하던 update() 메서드의 바로 아래 공간을 찾아 자원 삭제 처리를 담당할 delete() 메서드의 아키텍처 틀을 추가 선언하고 초기 반환 구조는 null 상태로 지정한다. HTML 양식 제약 사양에 상응하도록 자원 바인딩 어노테이션은 @GetMapping("/articles/{id}/delete") 속성으로 기입하여, 클라이언트가 상세조회 화면의 삭제 단추를 눌렀을 때 가변 경로로 유입되는 일련의 변수 주소 패킷을 컨트롤러 레이어가 차단 없이 원활하게 가로채어 접수하도록 맵을 형성한다.

    1
    2
    3
    4
    
     @GetMapping("/articles/{id}/delete")
     public String delete(){
         return null;
     }
    
  2. 제어 흐름이 라우팅 경로에 상응하여 성공적으로 진입하는지 검증하기 위해 메서드 실행 블록 초입 위치에 디버깅용 메시지 출력 코드인 log.info("삭제 요청이 들어왔습니다!!"); 구문을 기술한다.
  3. 로컬 서버 애플리케이션 프로세스를 재가동한 뒤 웹 페이지 화면 목록에서 상세 페이지로 넘어가 [Delete] 버튼을 마우스 클릭한다. 브라우저는 여전히 미완성 에러 화면을 나타내지만, 개발 환경의 하단 실행 콘솔 로그 화면 레이어 상에 설정한 "삭제 요청이 들어왔습니다!!" 문구가 누수 없이 정상 출력됨을 확인한다.
  4. 데이터 삭제를 완수하기 위한 세부 백엔드 비즈니스 연산 로직은 처리 순서에 입각하여 다음의 3가지 처리 이정표 단락으로 역할을 분할 정의하고 주석 코드를 소스 내에 배치하여 코딩을 전개합니다. (1) 삭제할 대상 가져오기 (2) 대상 엔티티 삭제하기 (3) 결과 페이지로 리다이렉트하기

삭제할 대상 가져오기

  1. 자바 런타임 환경에서 물리 데이터베이스 레이어에 직접 접근하여 엔티티 자원을 제어하기 위해 JPA 명세에 따라 주입된 리파지터리 객체 변수인 articleRepository를 선언한다. 레코드 구별의 고유 척도 키인 일련번호 정수 인자를 기반으로 엔티티를 수색하기 위해 내장 명령어인 findById(id) 메서드를 연속 호출한다. 데이터베이스 내에 조회 대상이 정상 포착되면 도메인 엔티티 모델 규격인 Article target 변수 공간에 해당 객체를 바인딩 대입하며, 만약 예외적으로 조회가 실패하여 빈 자원으로 판명될 경우에는 null 값이 수증되도록 예외 옵션 핸들러 구문을 체이닝 처리한다. 이때 라우팅 매핑 경로 주소 줄에 동적 중괄호 구조로 선언되어 유입된 경로 변수 {id} 값을 자바 메서드의 매개 파라미터 변수로 캡처하여 일치시키기 위해, 매개변수 변수명 선언부 바로 앞에 @PathVariable Long id 데이터 매핑 어노테이션을 정밀하게 기입해 주어야 한다.

    1
    2
    3
    4
    5
    6
    7
    8
    
     @GetMapping("/articles/{id}/delete")
     public String delete(@PathVariable Long id){ // 경로 변수 id를 매개변수로 안전하게 바인딩
         log.info("삭제 요청이 들어왔습니다!!");
        
         // 1. 삭제할 대상 가져오기
         Article target = articleRepository.findById(id).orElse(null);
         return null;
     }
    
  2. 영속 레이어에서 복구해 낸 인스턴스 데이터의 무결성을 검사하기 위해 변수 할당 라인 하단에 객체 내부 정보를 강제 문자열로 디코딩하여 콘솔에 뿌려주는 디버그 코드 log.info(target.toString()); 구문을 배치한다.

대상 엔티티 삭제하기

  1. 수집된 target 데이터 인스턴스가 물리적으로 실존하는 유효한 상태인지를 정밀 검사한 뒤 최종 파기 연산을 실행한다. 데이터 정합성 방어를 목적으로 if (target != null) 조건 검증 분기문을 수립하고, 조건이 참(True)으로 확인되어 내부 실행 블록으로 진입이 확정되면 JPA 리파지터리 인터페이스가 규격 제공하는 레코드 파기 전문 메서드인 articleRepository.delete(target); 코드를 발동시켜 데이터베이스 내부의 해당 영속 엔티티 레코드를 최종 파기한다.

    1
    2
    3
    4
    
     // 2. 대상 엔티티 삭제하기
     if (target != null) {
         articleRepository.delete(target); // 리파지터리를 통해 데이터베이스 레코드 파기 연산 집행
     }
    
  2. 영속성 소거 로직의 정합성을 1차 검증하기 위해 서버를 재시작하고 localhost:8080/articles/1 상세 페이지 화면으로 진입하여 [Delete] 단추를 선택한다. 화면단 제어권 반환이 이뤄지지 않아 브라우저 상에는 임시로 에러 메시지가 표출되지만, 개발 툴 로그 실행창을 조회하여 삭제 요청 감지 문구와 함께 1번 데이터 객체 정보가 target 변수에 정상 포착되어 데이터베이스 파기 프로세스가 이상 없이 가동되었음을 콘솔 출력으로 확인한다.
  3. 자바 코드가 트리거한 소거 명령에 상응하여 실제 영속 저장소 내부의 로우 레코드가 삭제 정리가 완수되었는지 실증하기 위해 새로운 브라우저 주소창 탭을 개설하여 H2 데이터베이스 웹 관리 UI 화면(localhost:8080/h2-console)으로 재진입한다. 런타임 로그 레이어 상에서 검색하여 확인한 고유의 최신 가상 JDBC URL 텍스트 주소값을 주소 입력 상자 안에 정밀하게 붙여넣고 세션 연결(Connect)을 수행한다.
  4. 관리 테이블 트리 메뉴 리스트에서 ARTICLE 도메인을 선택 지정하고 상단의 질의 가동 단추인 [Run]을 마우스 클릭하여 테이블 저장 상태를 전체 출력한다. 영속성 소거 연산이 확실히 실행되어 기존에 적재되어 있던 식별자 일련번호 1번 데이터 행 레코드가 테이블 레이아웃 상에서 흔적 없이 완전 파기 소멸하였으며, 차순위 인덱스 레코드인 2번과 3번 데이터 로우 행들만 영속성 오염 없이 안전하게 잔존 관리되고 있음을 최종 증명한다.
  5. 연속적인 흐름 제어를 검증하기 위해 브라우저 주소를 입력하여 3번 게시글 상세 뷰 화면(localhost:8080/articles/3)으로 다이렉트 접근한 후 [Delete] 버튼을 트리거한다. 데이터베이스 관리 콘솔창으로 회귀하여 기 기입된 조회 쿼리 기반의 [Run] 명령을 재실행한 뒤, 3번 데이터 로우까지 깔끔하게 밀려 지워지고 최종적으로 데이터베이스 내부에 오직 2번 레코드 자원 한 건만이 보존되어 남아있음을 연쇄 검증한다.

결과 페이지로 리다이렉트하기

  1. 백엔드 영역의 영속성 소거 가공 연산 처리가 완결된 직후 클라이언트 브라우저 화면의 끊김 현상을 해결하고 제어권을 넘겨주기 위해 메서드의 최종 반환 return 구문을 전면 수정한다. 특정 글의 영구 소거 처리를 끝마친 사용자가 다시 최신의 전체 글 데이터 정돈 현황을 대시보드로 관측할 수 있도록, 기존의 임시 null 반환 코드를 영구 삭제하고 메인 글 목록 조회 URL 주소 규격 체계인 "redirect:/articles" 문자열 구문을 반환값으로 명시한다.

    1
    2
    
     // 3. 결과 페이지로 리다이렉트하기
     return "redirect:/articles";
    
  2. 전체 소스 코드를 동기화하여 서버 인스턴스를 재가동하고 메인 목록 화면 페이지 주소(localhost:8080/articles)로 재진입한 후, 유일하게 잔존 중이던 2번 게시글 데이터의 상세 정보 화면으로 들어가 파란색 버튼 옆에 새로 추가한 [Delete] 단추를 최종 누른다. 이제 더 이상 브라우저 화면 상에 시스템 에러 가동 중단 페이지가 노출되지 않으며, 즉시 글 목록 대시보드 메인 화면으로 브라우저 경로 주소가 강제 리다이렉트 자동 전환되면서 테이블 리스트 상에서 2번 데이터 로우 행이 완전 소거되었음을 화면 상으로 확인한다.
  3. 목록에 남아있는 다른 가상 적재 데이터인 1번과 3번 레코드 정보에 대해서도 세부 상세 화면 진입 및 삭제 명령 연산을 순차적으로 적용하여, 최종적으로 데이터 테이블 구조체 내부에 단 하나의 레코드 요소도 잔존하지 않는 청결하고 완전하게 비어있는 목록 화면 상태가 도출됨을 확인한다.

사진2

8.2.3 삭제 완료 메시지 남기기

  1. RedirectAttributes 아규먼트 주입 선언: 화면 주소가 리다이렉트 처리되어 완전히 끊어지는 찰나의 네트워크 통신 과정 속에서도, 소거 연산이 안전하게 종료되었다는 핵심 인자 데이터를 목적지 뷰 화면 레이어로 안정적으로 실어 보내기 위해 delete() 메서드의 아큐먼트 매개변수 선언 구조 내에 RedirectAttributes rttr 전달 객체 변수를 추가 명시하여 인스턴스를 주입받는다.
1
public String delete(@PathVariable Long id, RedirectAttributes rttr){
  1. 단발성 알림 메시지 데이터 등록HTML: RedirectAttributes 객체가 지원하는 휘발성 자원 바인딩 도구 메서드인 addFlashAttribute()를 사용하여 비즈니스 로직을 보완한다. 해당 메서드는 목적지 경로 화면으로 리다이렉트되는 특정 시점에만 시스템 세션 메모리에 일시 상주하다가, 단 한 번의 화면 출력을 만족하는 즉시 메모리 상에서 흔적 없이 자동 소멸하는 휘발성 일회성 데이터를 캐싱 적재하는 역할을 전담한다. 메서드 내 if 제어문 내부의 리파지터리 물리 소거 명령 줄 바로 하단 영역을 타겟 지정하여, 데이터 통신용 식별 키값 문구 명칭을 "msg"로 선언하고 브라우저 팝업 내에 가시적으로 띄워 표현할 알림 문자열 내용 객체로 "삭제됐습니다!"를 기입하여 폼 데이터를 채운다.

    1
    2
    3
    4
    5
    
     if (target != null) {
         articleRepository.delete(target);
         // 리다이렉트 완료 직후 단 한 번만 일회성으로 사용할 휘발성 알림 데이터 바인딩
         rttr.addFlashAttribute("msg", "삭제됐습니다!");
     }
    
  2. 메시지 수신 표출 타겟 뷰 식별: 모델 객체 내에 일시 은폐 저장되어 인출 통과된 단발성 알림 문구가 화면상에 가시적으로 렌더링되어 풀려야 하는 최종 타겟 뷰 영역은, 메서드의 최종 마감 return 제어 명세 상에 명확히 명시해 둔 목적지 경로 주소인 /articles, 즉 전체 글 목록 레이아웃 파일인 index.mustache 뷰 파일 영역이다.

사진3

  1. 공통 상단 헤더 레이아웃 파일 개정: 알림 팝업 창이 특정 화면에 국한되지 않고 전체 시스템 내에서 상단 내비게이션 바 아래 공간에 일관되게 표출되는 완성도 높은 인프라를 구축하기 위해, src > main > resources > templates > layouts > header.mustache 공통 소스 파일을 편집기에 로드한다. 상단 메뉴 구성을 닫는 </nav> 태그 바로 아랫단 하부 공간을 찾아, 백엔드로부터 특정 속성 키가 수신되었는지 여부를 감지하여 조건부 렌더링을 집행하는 머스테치 범위 지시 제어 문법 기호인 {{#msg}}와 {{/msg}} 구문을 정의하여 변수 사용 영역의 경계를 확립합니다.

사진4

  1. 실제 화면 렌더링 및 닫기 기능 실증 검증: 백엔드 및 뷰 레이어의 모든 코딩 수정을 완료한 후 서버 인스턴스를 완전 재가동하고, 브라우저 주소창 입력을 통해 목록 페이지 메인 화면(localhost:8080/articles)으로 진입한다. 1번 일련번호 데이터 상세 페이지 화면으로 넘어가 새로 연동한 [Delete] 버튼을 마우스 클릭 처리한다. 글 목록 메인 대시보드로 제어 주소 리다이렉트가 깨끗하게 집행됨과 동시에, 화면 레이아웃 최상단 영역에 파란색 테마 배경으로 감싸진 "삭제됐습니다!" 알림창 팝업 컴포넌트가 선명하게 렌더링되어 표출되는지 검사하고, 팝업창 우측 끝단에 일치 배치된 [X] 닫기 단추 기호를 선택했을 때 화면 프레임에 어떠한 구조적 밀림 현상도 없이 해당 알림창 컴포넌트만 깔끔하게 소거되어 사라지는지 안정성을 검증한다.

사진5

  1. 다중 처리 제어 연속성 검증: 테이블 목록 상에 여전히 적재되어 대기 중인 차순위 2번 레코드 항목의 세부 내용으로 다시 진입하여 [Delete] 명령 처리를 연속으로 가한다. 비즈니스 로직 연산이 순차적으로 올바르게 맞물려 구동되면서, 화면 상단 인터페이스 내에 실시간 삭제 완료 알림 팝업창이 연이어 오차 없이 완벽하게 재구동되어 수신되는지 최종 확인한다.

8.2.4 SQL 문으로 직접 DB 삭제하기

데이터베이스에서 데이터를 삭제할 때는 SQL의 DELETE 문을 사용하며, 특정 데이터만 선택하여 삭제할 때는 WHERE 조건절을 지정한다.

  • 기본 형식: DELETE FROM 테이블명 WHERE 조건; (FROM은 생략 가능)
  • 사용 예시 (id가 3인 데이터 삭제): DELETE article WHERE id = 3;
    DELETE 문 실행 완료 후에는 데이터 조회 명령어인 SELECT * FROM article; 문을 통해 해당 레코드가 정상적으로 삭제되었는지 최종 확인할 수 있다.

8.2.5 최종정리

8장에서는 게시글을 삭제하는 기능을 구현했다. 전체적인 처리 흐름과 핵심 기술 요약은 다음과 같다.

  1. 삭제 요청 수신 및 경로 변수 확보
    • 클라이언트가 특정 게시글의 삭제를 요청하면 컨트롤러의 delete() 메서드가 @GetMapping 어노테이션을 통해 요청을 수신한다.
    • 삭제 대상을 식별하기 위해 고유한 식별자(id) 값이 필요하며, 이를 메서드의 매개변수로 가져오기 위해 @PathVariable 어노테이션을 사용한다. @PathVariable은 @GetMapping에 정의된 URL 경로 중 중괄호({ })로 둘러싸인 값을 매개변수로 바인딩하는 역할을 한다.
  2. 데이터베이스 조회 및 리파지터리를 통한 삭제
    • 확보한 id를 매개로 하여 데이터베이스(DB)에서 삭제할 대상을 조회한다.
    • 조회된 대상 엔티티는 JPA 리파지터리가 제공하는 delete() 메서드를 통해 삭제 처리가 집행된다. 이 과정에서 데이터베이스 내부적으로는 DELETE 형식의 SQL 문이 자동으로 생성되어 수행된다.
  3. 결과 페이지 리다이렉트 및 알림 메시지 전달
    • 데이터베이스상의 레코드 삭제 작업이 끝나면 화면 제어권을 게시글 목록 페이지("redirect:/articles")로 리다이렉트한다.
    • 이때 삭제가 완료되었음을 알리는 메시지를 화면에 함께 출력하기 위해 RedirectAttributes 객체의 addFlashAttribute() 메서드를 이용한다. addFlashAttribute() 메서드는 리다이렉트가 완료되어 화면이 전환되는 시점에 단 한 번만 일회성으로 사용할 수 있는 휘발성 데이터를 등록하여 안전하게 전달하는 역할을 한다.
This post is licensed under CC BY 4.0 by the author.