Blog-v3(리팩토링), 제네릭, 아작스 이용하여 댓글 삭제

리팩토링, 제네릭, 아작스
홍윤's avatar
Sep 06, 2024
Blog-v3(리팩토링), 제네릭, 아작스 이용하여 댓글 삭제
 

1. error Package

1. GlobalApiExceptionHandler

@RestControllerAdvice public class GlobalApiExceptionHandler { // 유효성 검사 실패 (잘못된 클라이언트의 요청) @ExceptionHandler(ExceptionApi400.class) public ResponseEntity<?> ex400(Exception e) { //프론트앤드 개발자가 알기 쉽게 해주기 위해(배려) return new ResponseEntity<>(Resp.fail(400, e.getMessage()), HttpStatus.BAD_REQUEST); } // 인증 실패 (클라이언트가 인증없이 요청했거나, 인증을 하거나 실패했거나) @ExceptionHandler(ExceptionApi401.class) public ResponseEntity<?> ex401(Exception e) { return new ResponseEntity<>(Resp.fail(401, e.getMessage()), HttpStatus.UNAUTHORIZED); } // 권한 실패 (인증은 되어 있는데, 삭제하려는 게시글이 내가 적은게 아니다) @ExceptionHandler(ExceptionApi403.class) public ResponseEntity<?> ex403(Exception e) { return new ResponseEntity<>(Resp.fail(403, e.getMessage()), HttpStatus.FORBIDDEN); } // 서버에서 리소스(자원) 찾을 수 없을때 @ExceptionHandler(ExceptionApi404.class) public ResponseEntity<?> ex404(Exception e) { return new ResponseEntity<>(Resp.fail(404, e.getMessage()), HttpStatus.NOT_FOUND); } // 서버에서 심각한 오류가 발생했을때 (알고 있을 때) @ExceptionHandler(ExceptionApi500.class) public ResponseEntity<?> ex500(Exception e) { return new ResponseEntity<>(Resp.fail(404, e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR); }
💡
이 코드는 Spring BootResponseEntity 객체를 사용하여, 예외 발생 시 프론트엔드로 적절한 HTTP 상태 코드와 예외 메시지를 반환하는 역할을 합니다. 각 라인은 서로 다른 HTTP 상태 코드와 함께 예외 메시지를 전달하며, 예외 상황에 따라 클라이언트가 그에 맞는 응답을 받을 수 있도록 처리합니다.

각 라인의 코드 설명

1. return new ResponseEntity<>(Resp.fail(400, e.getMessage()), HttpStatus.BAD_REQUEST);

  • HTTP 400 (Bad Request): 클라이언트가 서버로 잘못된 요청을 보낸 경우 반환됩니다.
    • Resp.fail(400, e.getMessage()): 예외 메시지와 함께 400 상태 코드가 포함된 응답 본문을 생성합니다.
    • HttpStatus.BAD_REQUEST: 400 Bad Request 상태 코드를 응답으로 설정합니다.
    • 사용 예시: 유효성 검사 실패나 필수 필드 누락 등 클라이언트 요청이 잘못되었을 때.

2. return new ResponseEntity<>(Resp.fail(401, e.getMessage()), HttpStatus.UNAUTHORIZED);

  • HTTP 401 (Unauthorized): 클라이언트가 인증되지 않은 상태에서 서버에 요청을 보낼 때 반환됩니다.
    • Resp.fail(401, e.getMessage()): 예외 메시지와 함께 401 상태 코드가 포함된 응답 본문을 생성합니다.
    • HttpStatus.UNAUTHORIZED: 401 Unauthorized 상태 코드를 응답으로 설정합니다.
    • 사용 예시: 로그인하지 않은 사용자가 인증이 필요한 API에 접근하려 할 때.

3. return new ResponseEntity<>(Resp.fail(403, e.getMessage()), HttpStatus.FORBIDDEN);

  • HTTP 403 (Forbidden): 클라이언트가 인증은 되었지만, 권한이 없는 작업을 수행하려 할 때 반환됩니다.
    • Resp.fail(403, e.getMessage()): 예외 메시지와 함께 403 상태 코드가 포함된 응답 본문을 생성합니다.
    • HttpStatus.FORBIDDEN: 403 Forbidden 상태 코드를 응답으로 설정합니다.
    • 사용 예시: 사용자가 자신이 소유하지 않은 리소스를 삭제하거나 수정하려 할 때.

4. return new ResponseEntity<>(Resp.fail(404, e.getMessage()), HttpStatus.NOT_FOUND);

  • HTTP 404 (Not Found): 클라이언트가 요청한 리소스를 찾을 수 없을 때 반환됩니다.
    • Resp.fail(404, e.getMessage()): 예외 메시지와 함께 404 상태 코드가 포함된 응답 본문을 생성합니다.
    • HttpStatus.NOT_FOUND: 404 Not Found 상태 코드를 응답으로 설정합니다.
    • 사용 예시: 사용자가 존재하지 않는 페이지나 API 경로에 접근할 때.

5. return new ResponseEntity<>(Resp.fail(500, e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);

  • HTTP 500 (Internal Server Error): 서버에서 심각한 내부 오류가 발생했을 때 반환됩니다.
    • Resp.fail(500, e.getMessage()): 예외 메시지와 함께 500 상태 코드가 포함된 응답 본문을 생성합니다.
    • HttpStatus.INTERNAL_SERVER_ERROR: 500 Internal Server Error 상태 코드를 응답으로 설정합니다.
    • 사용 예시: 서버 내부에서 예상하지 못한 예외가 발생한 경우 (DB 연결 실패, 서버 로직 오류 등).

ResponseEntityResp.fail() 설명

  • ResponseEntity: Spring Boot에서 HTTP 응답을 구성하는 객체입니다. 이 객체는 응답의 본문(body), 상태 코드(status), 헤더(headers)를 포함할 수 있습니다. 즉, 클라이언트로 보낼 HTTP 응답을 설정할 수 있습니다.
  • Resp.fail(): 이 메소드는 실패 응답을 만드는 역할을 합니다. 주어진 HTTP 상태 코드(예: 400, 401 등)와 예외 메시지를 조합하여 응답 본문을 구성하는 함수입니다. 이 함수는 실패 응답의 형식을 맞춰서 반환하는 역할을 합니다.

전체적인 흐름

각 예외 상황에서 ResponseEntity 객체를 통해 HTTP 상태 코드예외 메시지를 프론트엔드로 반환합니다. 이를 통해 프론트엔드는 서버에서 어떤 문제가 발생했는지 알 수 있으며, 이를 바탕으로 적절한 처리를 할 수 있습니다.

요약

  • 400 Bad Request: 클라이언트의 잘못된 요청.
  • 401 Unauthorized: 인증되지 않은 요청.
  • 403 Forbidden: 권한이 없는 요청.
  • 404 Not Found: 요청한 리소스를 찾을 수 없음.
  • 500 Internal Server Error: 서버 내부 오류.
이러한 각각의 상태 코드와 함께 예외 메시지를 클라이언트에게 명확하게 전달하는 것이 이 코드의 주요 역할입니다.

 

2. reply package

 

1. ReplyController

@DeleteMapping("/api/reply/{id}") public ResponseEntity<?> delete(@PathVariable Integer id){ // 1. 세션 체크(인증 체크) -> 주소로 처리 가능 (클리어) //2. Service 로직을 호출 - 댓글삭제 User sessionUser = (User) session.getAttribute("sessionUser"); replyService.댓글삭제(id, sessionUser); //3.응답 //상태 코드 넣을려고 ResponseEntity.ok 내부적으로 new 한다. return ResponseEntity.ok(Resp.ok(null)); }
💡
이 코드는 Spring Boot에서 댓글을 삭제하는 HTTP DELETE 요청을 처리하는 컨트롤러 메소드입니다. 주어진 댓글 ID에 해당하는 댓글을 삭제하는 API입니다.

1.@DeleteMapping("/api/reply/{id}"):

  • 이 어노테이션은 HTTP DELETE 요청을 처리하는 엔드포인트를 정의합니다. 클라이언트가 /api/reply/{id} 경로로 DELETE 요청을 보내면 이 메소드가 실행됩니다.
  • {id}: URL 경로에서 댓글 ID를 변수로 받습니다. id는 삭제하려는 댓글의 고유 식별자입니다.

2. 메소드 선언:

public ResponseEntity<?> delete(@PathVariable Integer id)
  • @PathVariable Integer id: URL 경로에 있는 {id} 값을 받아서 메소드의 id 매개변수로 할당합니다. 이 값은 삭제할 댓글의 ID입니다.
  • ResponseEntity<?>: HTTP 응답을 나타내는 객체입니다. 제네릭 타입 <?>은 반환할 데이터의 타입을 제한하지 않는다는 의미입니다.
  • 메소드 내부에서는 댓글 삭제 후 적절한 응답을 반환합니다

3.서비스 호출 (댓글 삭제):

replyService.댓글삭제(id, sessionUser);
  • 서비스 로직 호출: 댓글 삭제 비즈니스 로직을 담당하는 replyService.댓글삭제 메소드를 호출합니다.
  • id: 삭제할 댓글의 ID.
  • sessionUser: 현재 로그인된 사용자 정보를 넘깁니다. 이를 통해 댓글을 작성한 사용자와 현재 요청한 사용자가 일치하는지, 즉 권한이 있는지 확인할 수 있습니다.
  • 이 부분은 실제 댓글을 삭제하는 로직이며, 주로 서비스 계층에서 데이터베이스와 상호작용하여 댓글을 삭제합니다.

4. 응답 반환:

return ResponseEntity.ok(Resp.ok(null)
  • ResponseEntity.ok(): HTTP 응답으로 200 OK 상태 코드를 반환합니다. ResponseEntity.ok()는 내부적으로 HTTP 200 OK 응답을 생성합니다.
  • Resp.ok(null): 응답 본문으로 성공 메시지를 반환합니다. 여기서 null은 추가적인 데이터가 필요 없음을 의미합니다.
  • 최종적으로 클라이언트는 HTTP 200 OK 상태 코드와 함께 성공 응답을 받게 됩니다.

요약:

  1. 세션 체크: 로그인된 사용자의 세션 정보를 확인하여 인증 상태를 확인합니다.
  1. 서비스 호출: replyService.댓글삭제(id, sessionUser)를 통해 댓글 삭제 로직을 실행합니다. 여기서 id는 댓글의 ID, sessionUser는 현재 로그인된 사용자입니다.
  1. 응답 반환: 삭제가 성공하면 HTTP 200 OK 응답을 반환하고, 응답 본문에는 Resp.ok(null)로 처리된 성공 메시지가 포함됩니다.
이 코드는 클라이언트로부터 DELETE 요청을 받아서 해당 댓글을 삭제하고, 성공적으로 삭제되면 HTTP 200 OK 응답을 반환하는 역할을 합니다.
 

2. ReplyRepository(interface)

package org.example.springv3.reply; import org.springframework.data.jpa.repository.JpaRepository; public interface ReplyRepository extends JpaRepository<Reply, Integer> { }
💡
이 코드는 Spring Data JPA를 사용하여 **댓글 데이터(Reply)**를 데이터베이스에 저장, 조회, 수정, 삭제 등의 작업을 할 수 있는 레포지토리(Repository) 인터페이스를 정의하는 것입니다. 아래에서 상세히 설명해드리겠습니다.

1. public interface ReplyRepository:

  • *ReplyRepository*는 인터페이스로 정의되어 있습니다.
  • 이 인터페이스는 Spring Data JPA에서 기본적으로 제공하는 **JpaRepository*를 상속받고 있습니다.
  • 이 인터페이스는 Spring Data JPA가 자동으로 **CRUD(Create, Read, Update, Delete)**와 같은 데이터베이스 작업을 구현해줍니다.

2. extends JpaRepository<Reply, Integer>:

  • *JpaRepository<T, ID>*는 Spring Data JPA에서 제공하는 기본적인 데이터베이스 조작 메소드들을 포함하는 인터페이스입니다.
    • T: 이 자리에 해당 엔티티 클래스가 들어갑니다. 여기서는 Reply 엔티티를 의미합니다.
    • ID: 이 자리에 해당 엔티티의 기본 키(Primary Key)의 타입이 들어갑니다. 여기서는 **Integer*가 사용되고 있습니다. 이는 Reply 엔티티의 기본 키가 Integer 타입임을 나타냅니다.

예시: JpaRepository가 제공하는 기본적인 메소드들

  • save(Reply entity): 주어진 Reply 객체를 데이터베이스에 저장합니다. 객체가 이미 존재하면 업데이트, 없으면 새로운 객체를 생성합니다.
  • findById(Integer id): 기본 키(ID)로 해당 댓글을 조회합니다.
  • findAll(): 모든 댓글 데이터를 조회합니다.
  • deleteById(Integer id): 기본 키로 댓글을 삭제합니다.
  • existsById(Integer id): 특정 ID로 댓글이 존재하는지 여부를 확인합니다.

JpaRepository<Reply, Integer>의 구성 요소:

  • Reply: 이 인터페이스는 Reply 엔티티와 연결됩니다. 즉, Reply 객체와 관련된 데이터베이스 작업을 수행할 수 있습니다.
  • Integer: Reply 엔티티의 기본 키 타입Integer임을 나타냅니다.

3. 코드의 동작 방식:

  • *ReplyRepository*는 데이터베이스에 댓글과 관련된 기본적인 CRUD 작업을 할 수 있는 인터페이스입니다.
  • JpaRepository를 상속받았기 때문에, 별도로 구현을 하지 않아도 Spring Data JPA가 내부적으로 필요한 메소드를 자동으로 생성해줍니다.
  • 개발자는 ReplyRepository인터페이스로만 정의해도 Spring Data JPA가 기본적인 데이터 조작 메소드를 자동으로 제공하기 때문에, 별도의 SQL을 작성할 필요가 없습니다.

3. ReplyService

@Transactional(readOnly = true) @RequiredArgsConstructor @Service //IoC 등록 public class ReplyService { private final ReplyRepository replyRepository; //1. 조회를 먼저 해본다 DB에서 터지는거 보다 서버에서 터지는게 더 낫다. // 지금 만든 것은 트랙잭션과 비즈니스 로직을 만든 거다! @Transactional public void 댓글삭제(int id, User sessionUser){ //2.권한 체크 //팀프로젝트에 닉네임을 찾을 거면 mfintbYid를 하나 더 만들어서 해보자! Reply replyPs = replyRepository.findById(id) .orElseThrow(()-> new Exception404("해당 댓글을 찾을 수 없습니다.")); //DB에 Reply를 조회했을때 if (replyPs.getUser().getId() != sessionUser.getId()){ throw new ExceptionApi403("댓글 삭제 권한이 없습니다."); } replyRepository.deleteById(id); } }
💡
이 코드는 댓글 삭제 로직을 처리하는 서비스 메소드입니다.
  1. 트랜잭션 처리:
      • @Transactional: 이 메소드 내의 작업들이 트랜잭션으로 처리됩니다. 즉, 모든 작업이 성공해야만 커밋되고, 실패하면 롤백됩니다.
  1. 댓글 조회:
      • replyRepository.findById(id): 해당 id로 댓글을 조회합니다.
      • 만약 댓글이 존재하지 않으면 Exception404 예외를 던집니다. ("해당 댓글을 찾을 수 없습니다.")
  1. 권한 체크:
      • 댓글 작성자와 현재 로그인한 사용자의 ID를 비교하여, 삭제 권한이 있는지 확인합니다.
      • 권한이 없으면 ExceptionApi403 예외를 던집니다. ("댓글 삭제 권한이 없습니다.")
  1. 댓글 삭제:
      • 권한이 확인되면 **replyRepository.deleteById(id)*를 호출하여 해당 댓글을 삭제합니다.

요약:

이 메소드는 댓글을 삭제하기 전에 댓글 존재 여부를 확인하고, 삭제 권한을 체크한 후, 권한이 있으면 댓글을 삭제합니다.
 
Share article

Uni