// MemberController
@GetMapping("/members/{memberId}")
public ResponseEntity<GetMemberResponse> getMember(
@PathVariable Long memberId
) {
return ResponseEntity.status(HttpStatus.OK).body(memberService.findOne(memberId));
}
// MemberService
@Transactional(readOnly = true)
public GetMemberResponse findOne(Long memberId) {
Member member = memberRepository.findById(memberId).orElseThrow(
() -> new IllegalStateException("์๋ ๋ฉค๋ฒ์
๋๋ค.")
);
return new GetMemberResponse(
member.getId(),
member.getNickname()
);
}
IllegalStateException("์๋ ๋ฉค๋ฒ์
๋๋ค.") ๋ฅผ ๋ ๋ ค์ค๋ค. ์ฌ๊ธฐ์ ์ผ๋ถ๋ฌ ์๋ฌ๋ฅผ ๋ฐ์์ํค๋ฉด

500์๋ฌ๊ฐ ๋ฐ์ํ๋ค. ๋ฉค๋ฒ๋ฅผ ์๋ชป ํธ์ถํ ๊ฒ์ ์๋ฒ์ ์๋ชป์ด ์๋ ํด๋ผ์ด์ธํธ์ ์๋ชป์ด๊ธฐ ๋๋ฌธ์ 500์ด ์๋ 400์๋ฌ ์ฝ๋๊ฐ ๋ ์ผ ํ๋ค.
์๋ฐ์ try-catch๋ฌธ์ผ๋ก ์์ธ์ฒ๋ฆฌ๋ฅผ ํ ์ ์์ง๋ง ์คํ๋ง์์๋ ์๋ฌ๋ฅผ 3๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก ํธ๋ค๋งํ ์ ์๋ค.
์คํ๋ง ์์ธ ์ฒ๋ฆฌ ์ ๋ต 3๊ฐ์ง
1. @ExceptionHandler
2. @RestControllerAdvice
3. Spring ๊ธฐ๋ณธ ์์ธ ์ฒ๋ฆฌ
์ด๋ ๊ฒ 3๊ฐ์ง๊ฐ ์๊ณ ๋์์ ์กด์ฌํ ๊ฒฝ์ฐ 1 > 2 > 3 ์์๋๋ก ์ฐ์ ์์๋ฅผ ๊ฐ์ง๋ค.
@Service
@RequiredArgsConstructor
public class MemberService {
@Transactional
public GetAllMemberResponseDto findOne(Long id) {
Member member = memberRepository.findById(id).orElseThrow(
() -> new IllegalStateException("์๋ ๋ฉค๋ฒ์
๋๋ค.")
);
return GetAllMemberResponseDto.from(member);
}
@RestController
@RequiredArgsConstructor
public class MemberController {
private final MemberService memberService;
@GetMapping("/members/{memberId}")
public ResponseEntity<GetMemberResponse> getMember(
@PathVariable Long memberId
) {
return ResponseEntity.status(HttpStatus.OK).body(memberService.findOne(memberId));
}
// ๐จ ์์ธ ์ฒ๋ฆฌ ๋ฉ์๋
@ExceptionHandler(IllegalStateException.class)
public ResponseEntity<String> handlerIllegalStateException(IllegalStateException e) {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body("์์ฒญ ์ค๋ฅ: " + e.getMessage());
}
}

์์ฒญ ์ค๋ฅ: : ์๋น์ค์์ ๋์ง IllegalStateException ์๋ฌ ๋ฉ์์ง์ธ "์๋ ๋ฉค๋ฒ์
๋๋ค."๊ฐ ๋ฐํ๋๋ค.
์์ธ ์ฒ๋ฆฌ ๋ฉ์๋์ ResponseEntity์ ์ค์ ํ ๋๋ก (.status(HttpStatus.BAD_REQUEST) 400 Bad Request๋ก ์๋ฌ ์ฝ๋๊ฐ ์๋ต๋๋ค.
ํ์ง๋ง ์ด๋ ๊ฒ ๊ฐ๋ณ์ ์ผ๋ก ์ปจํธ๋กค๋ฌ๋ง๋ค @ExceptionHandler๋ฅผ ์ค์ ํ๋ ๋ฐฉ๋ฒ์ ์ ์ฌ์ฉํ์ง ์๋๋ค. ์ด์ ๋ ์ปจํธ๋กค๋ฌ๋ง๋ค ์์ธ์ฒ๋ฆฌ๋ฅผ ์์ฑํ๋ฉด ์ค๋ณต์ด ์ฌํด์ง๋ค.
์ค๋ณต์ด ์ฌํด์ง๋ค๋ ๋ง์ ๋ฉค๋ฒ ์ปจํธ๋กค๋ฌ์์ @ExceptionHandler๊ฐ ์๊ณ ์ผ์ ์ปจํธ๋กค๋ฌ์๋ @ExceptionHandler์ด ์์ผ๋ฉด ๋์ค์ ์ปจํธ๋กค๋ฌ๊ฐ ์๊ธฐ๋ฉด ์๊ธธ์๋ก ์ค๋ณต์ด ์ฌํด์ง๋ค๋ ์๋ฏธ์ด๋ค.
๋ฐ๋ผ์ ํ๋ก์ ํธ์ ์ ์ฒด์ ์ผ๋ก ์ ์ฉํ ์ ์๋ ์ ์ญ ์์ธ ์ฒ๋ฆฌ๊ธฐ๋ฅผ ๋ง๋ค์ด ์ฒ๋ฆฌํ๋ฉด ๋๋ค.
๊ทธ๊ฒ์ด @RestControllerAdvice ๋ฐฉ์์ด๋ค. (์ด ๋ฐฉ์์ด ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋๋ค.)
@RestControllerAdvice
public class GlobalExceptionHandler {
// ๐ฏ ์ปค์คํ
๋น์ฆ๋์ค ์์ธ ์ฒ๋ฆฌ
@ExceptionHandler(IllegalStateException.class)
public ResponseEntity<String> handleIllegalStateException(IllegalStateException e) {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body("์์ฒญ ์ค๋ฅ: " + e.getMessage());
}
}
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ํฉ์ ๋ฑ ๋ง๋ ์์ธ๋ฅผ ์ง์ ๋ง๋ค์ด์ ์ฌ์ฉํ๋ค.
RuntimeException์ ์์๋ฐ์์ ์ฐ๋ฆฌ๋ง์ ์์ธ ํด๋์ค๋ฅผ ๋ง๋ ๋ค.package com.example.scheduledevelop.exception;
import org.springframework.http.HttpStatus;
public class ScheduleNotFoundException extends RuntimeException {
public ScheduleNotFoundException(String message) {
super(message);
}
}
RuntimeException์ ์์ํด์ผ ํ๋ค.
@Transactional(readOnly = true)
public FindByOneResponseDto findOne(Long id) {
Schedule schedule = scheduleRepository.findById(id).orElseThrow(
() -> new ScheduleNotFoundException("์๋ ์ผ์ ์
๋๋ค.")
);
return FindByOneResponseDto.from(schedule);
}
GlobalExceptionHandler๋ก ์ปค์คํ
์๋ฌ๋ฅผ ํธ๋๋ง ํ ์ ์๋ค.์ด๋ฆ์ด Global์ธ๋ฐ Globalํ์ง ์๋ค๋ ๊ฒ์ด๋ค.
์์ผ๋ก ScheduleNotFoundException๋ฟ๋ง ์๋๋ผ ์์ผ๋ก ์๋ฐฑ ์์ฒ๊ฐ์ง ์ด์์ ์ปค์คํ ์๋ฌ๊ฐ ์๊ธธ ํ ๋ฐ, ๊ทธ ๋๋ง๋ค GlobalExceptionHandler์ ํ๋ํ๋ ๋ฐ๋ก๋ฐ๋ก ๋ง๋ค์ด ์ค์ผ ํ๋ค.
์์ ์ฝ๋๋ณด๋ฉด HttpsStatus.Not_Found๋ก ๊ณ ์ ๋์ด์๊ธฐ๋ํ๋ค.
์ด๋ฅผ ์ํด ๊ณตํต๋ ๋ถ๋ชจ ์๋ฌ ํ์ ์ ํ๋ ๋์ถ๊ฐํ๋ฉด ๋๋ค.
package com.example.scheduledevelop.exception;
import lombok.Getter;
import org.springframework.http.HttpStatus;
@Getter
public class ServiceException extends RuntimeException {
// ์์ธ ๋ฐ์ ์ ๋ฐํํ HTTP ์๋ต ์ํ ์ฝ๋
private final HttpStatus status;
public ServiceException(HttpStatus status, String message) {
super(message);
this.status = status;
}
}
package com.example.scheduledevelop.exception;
import org.springframework.http.HttpStatus;
public class ScheduleNotFoundException extends ServiceException {
public ScheduleNotFoundException(String message) {
super(HttpStatus.NOT_FOUND, message);
}
}
@Transactional(readOnly = true)
public FindByOneResponseDto findOne(Long id) {
Schedule schedule = scheduleRepository.findById(id).orElseThrow(
() -> new ScheduleNotFoundException("์๋ ์ผ์ ์
๋๋ค.")
);
return FindByOneResponseDto.from(schedule);
}
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ServiceException.class)
public ResponseEntity<String> handleServiceException(ServiceException e) {
return ResponseEntity
.status(e.getStatus())
.body(e.getMessage());
}
// extends ServerException ์ค์!
public class DuplicateEmailException extends ServiceException {
public DuplicateEmailException(String message) {
super(HttpStatus.BAD_REQUEST, message);
}
}