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 Boot의
ResponseEntity
객체를 사용하여, 예외 발생 시 프론트엔드로 적절한 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 연결 실패, 서버 로직 오류 등).
ResponseEntity
와 Resp.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 상태 코드와 함께 성공 응답을 받게 됩니다.
요약:
- 세션 체크: 로그인된 사용자의 세션 정보를 확인하여 인증 상태를 확인합니다.
- 서비스 호출:
replyService.댓글삭제(id, sessionUser)
를 통해 댓글 삭제 로직을 실행합니다. 여기서id
는 댓글의 ID,sessionUser
는 현재 로그인된 사용자입니다.
- 응답 반환: 삭제가 성공하면 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);
}
}
이 코드는 댓글 삭제 로직을 처리하는 서비스 메소드입니다.
- 트랜잭션 처리:
@Transactional
: 이 메소드 내의 작업들이 트랜잭션으로 처리됩니다. 즉, 모든 작업이 성공해야만 커밋되고, 실패하면 롤백됩니다.
- 댓글 조회:
replyRepository.findById(id)
: 해당id
로 댓글을 조회합니다.- 만약 댓글이 존재하지 않으면
Exception404
예외를 던집니다. ("해당 댓글을 찾을 수 없습니다.")
- 권한 체크:
- 댓글 작성자와 현재 로그인한 사용자의 ID를 비교하여, 삭제 권한이 있는지 확인합니다.
- 권한이 없으면
ExceptionApi403
예외를 던집니다. ("댓글 삭제 권한이 없습니다.")
- 댓글 삭제:
- 권한이 확인되면 **
replyRepository.deleteById(id)
*를 호출하여 해당 댓글을 삭제합니다.
요약:
이 메소드는 댓글을 삭제하기 전에 댓글 존재 여부를 확인하고, 삭제 권한을 체크한 후, 권한이 있으면 댓글을 삭제합니다.
Share article