
API์ ๋ํ ์์ธ๋ HTMLํ์ด์ง์ ๋ํ ์์ธ ์ฒ๋ฆฌ์๋ ์๋นํ ๋ค๋ฅด๊ฒ ์ฒ๋ฆฌํด์ฃผ์ด์ผ ํฉ๋๋ค.
์ฐ๋ฆฌ๋ ์ด์ ํฌ์คํธ์์ MVC์์ ์๋ฌ ํ์ด์ง๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์์ต๋๋ค. ์์ธ ์ํฉ(์๋ฌ์ฝ๋)์ ๋ง๋ ์์ธ ํ์ด์ง๋ฅผ ์ ์ฑ ์ ๋ง๋ ๊ฒฝ๋ก, ์ด๋ฆ์ผ๋ก ์ง์ ํด์ฃผ๋ ๊ฒ๋ง์ผ๋ก ์ฌ์ฉ์์๊ฒ ์ ํฉํ ์๋ฌ ํ์ด์ง๋ฅผ ๋ณด์ฌ์ค ์ ์์์ฃ .
API์ ๊ฒฝ์ฐ ์๋ฌ์ ๋ํ ์๋ต์ผ๋ก HTMLํ์ด์ง๋ฅผ ๋ณด์ฌ์ค์ ์ ๋ฉ๋๋ค.
์ผ๋จ API์์ฒญ์ View๋ฅผ ๋๋๋ง ๋ฐ๊ธฐ ์ํ ๋ชฉ์ ์ด ์๋๋๋ค. ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๊ฑฐ๋ ๊ฐ๊ณต์ฒ๋ฆฌ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๊ธฐ ์ํจ์ด์ฃ .
๋ํ API์ ๊ฒฝ์ฐ ์๋ํฌ์ธํธ ์ฌ์ฉ์๊ฐ ์กฐ๊ธ ๋ค๋ฅธ ์ฑ๊ฒฉ์ ๊ฐ๋๋ค๊ณ ์๊ฐํฉ๋๋ค. ๋๋ถ๋ถ ํด๋น API๋ฅผ ์ฌ์ฉํ๋ ํด๋ผ์ด์ธํธ๋ ์ ํํ ๋ชฉ์ ์ ์ง๋๊ณ ์์ต๋๋ค. ๋ณดํต ์น ํ์ด์ง๋ฅผ ์ฌ์ฉํ๋ ํด๋ผ์ด์ธํธ๋ ๋ชฉ์ ์ ์ง๋๊ณ ์์ง๋ง ๋ณด๋ค ๋ฒ์ฉ์ ์ด๋ฏ๋ก ์กฐ๊ธ ์ถ์์ ์ผ์ง๋ผ๋ ์ดํด ๊ฐ๋ฅํ ๋ฒ์์ ์๋ฌ ํ์ด์ง๋ฅผ ๋ณด์ฌ์ฃผ๋ฉด ๋๋ ๊ฒ ์
๋๋ค.
ํ์ง๋ง API๋ ํด๋น API์ ์คํ์ ๋ง๋ ๋ณด๋ค ์ ๋ฐํ ์์ธ ์ฒ๋ฆฌ๋ฅผ ํ์๋ก ํฉ๋๋ค. ์๋ต ๋ฐฉ์๋ ๋น์ฐํ HTMLํ์ด์ง๊ฐ ์๋ JSONํ์์ด ๋์ด์ผ ํฉ๋๋ค.
์ด์ ๊ฐ๋จํ ์์ธ ์ํฉ์ ๊ฐ์ ํ๊ณ JSONํํ๋ก API์คํ์ ๋ง๋ ์์ธ๋ฅผ ๋ฐ์์ํค๋ ์์ ๋ฅผ ํด๋ณด๊ฒ ์ต๋๋ค.
ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ์
๋ ฅ๋ฐ์ memberId๋ฅผ ์ด์ฉํด ์ฌ๋ฌ ์๋ฌ๋ฅผ ๋ฐ์์ํค๋ ๋ฉ์๋์
๋๋ค.
@Slf4j
@RestController
public class ApiExceptionController {
@GetMapping("/api/members/{memberId}")
public String getMember(@PathVariable String memberId) {
if (memberId.equals("bad"))
throw new IllegalArgumentException("์๋ชป๋ ์
๋ ฅ์
๋๋ค.");
if (memberId.equals("user-ex"))
throw new UserException("์ฌ์ฉ์ ์ค๋ฅ์
๋๋ค.");
if (memberId.equals("runtime"))
throw new RuntimeException("์๋ชป๋ ์ฌ์ฉ์์
๋๋ค.");
return "ok";
}
}
๊ฐ์ฅ ๋จผ์ memberId๊ฐ "bad"๋ก ์์ฒญ๋์์ ๋ ๋ฐ์ํ๋ IllegalArgumentException์ ๋ํ ์์ธ์ฒ๋ฆฌ๋ฅผ ํด์ฃผ๊ฒ ์ต๋๋ค.
@ExceptionHandler๋ก IllegalArgumentException์ ๋ํ ์์ธ๋ฅผ ํธ๋ค๋ง ๋ฉ์๋๋ผ๋ ๊ฒ์ ์๋ ค์ค๋๋ค.์ด๋ ๊ฒ @ExceptionHandler๋ก ์ค์ ํด์ฃผ๋ฉด ์ปจํธ๋กค๋ฌ ๋ด์์ ํด๋น ์์ธ ๋ฐ์์ ์๋ ๋ฉ์๋๊ฐ ์คํ๋๊ฒ ๋ฉ๋๋ค.
์์ธ ๋ฐ์์ ํด๋น ํด๋์ค ๋ด๋ถ์์๋ง ๋ชจ๋ ๋์์ด ์ผ์ด๋๋ ๊ฒ์ ์๋๋๋ค.
์ผ๋จ ์์ธ๊ฐ ๋ฐ์ํ๋ฉด ์ผ๋จ DispatcherServlet๊น์ง๋ ์์ธ๋ฅผ ๋์ง๋๋ค.
์ด๋ @ExceptionHandler๊ฐ ๋ถ์ด์๋ค๋ฉด ExceptionHandlerExceptionResolver์ ์ํด ์๋ ๋ฉ์๋๋ฅผ ํธ์ถํ ์ ์๊ฒ ๋๋ ๊ฒ ์
๋๋ค.
๋ง์น ์ปจํธ๋กค๋ฌ์ฒ๋ผ ๋์ํ๊ธฐ ๋๋ฌธ์ ๋ฆฌํด๋๋ ํ์ ์ ์ผ๋ง๋ ์ง ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
์ถ๊ฐ๋ก ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌ๋๋ ์์ธ๊ฐ์ฒด๊ฐ์ @ExceptionHandler์ ํ๋ผ๋ฏธํฐ์ ๊ฐ๋ค๋ฉด @ExceptionHandler์ ํ๋ผ๋ฏธํฐ๋ ์๋ต ๊ฐ๋ฅํฉ๋๋ค.
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(IllegalArgumentException.class)
public ErrorResult illegalArgumentExceptionHandler(IllegalArgumentException e) {
log.info("[ExceptionHandler: IllegalArgumentException", e);
return new ErrorResult("BAD", e.getMessage());
}
[ ErrorResult ]
@Data
@AllArgsConstructor
public class ErrorResult {
private String code;
private String message;
}
๋ ๋ฒ์งธ ์์ธ์ฒ๋ฆฌ ๋ฐฉ๋ฒ ์
๋๋ค. UserException์ด ๋ฐ์ํ์ ๋์
๋๋ค.
์ด๋ฒ์๋ @ExceptionHandler์ ํ๋ผ๋ฏธํฐ๋ฅผ ์๋ตํ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
๋ํ ์ด๋ฒ์๋ ResponseEntity๋ฅผ ์๋ต๊ฐ์ผ๋ก ์ฌ์ฉํ์์ต๋๋ค.
@ExceptionHandler
public ResponseEntity<ErrorResult> userExceptionHandler(UserException e) {
log.info("[ExceptionHandler: UserExceptionHandler", e);
ErrorResult errorResult = new ErrorResult("USER-EXCEPTION", e.getMessage());
return new ResponseEntity<ErrorResult>(errorResult, HttpStatus.BAD_REQUEST);
}
๋ง์ง๋ง์ผ๋ก ๊ทธ์ธ Exception์ ๋ํ ์๋ฌ ํธ๋ค๋ง ๋ฉ์๋์
๋๋ค.
์ ๋ ๊ฐ ์์ธ๋ฅผ ๋น๋กฏํด ๋ชจ๋ ์์ธ๋ Exception์ ์์์
๋๋ค.
์ด์ ๋ ๋ญ๊ฐ ์คํ๋ง์ ๋์์น์ด ๋๋ ๊ฒ ๊ฐ์ต๋๋ค ..
๊ตฌ์ฒด์ ์ธ ๊ฒ๋ถํฐ ๋ ๊ตฌ์ฒด์ ์ธ ๊ฒ ์์ผ๋ก.
(๊ตฌ์ฒด์ ์ธ ๊ฒ->์์ํด๋์ค, ๋ ๊ตฌ์ฒด์ ์ธ ๊ฒ -> ๋ถ๋ชจ ํด๋์ค)
์์ํด๋์ค๋ก ์ ์๋ ์์ธ๋ ํด๋น ๋ฉ์๋์์ ์ฒ๋ฆฌ๋๊ณ ๊ทธ์ธ ๋ชจ๋ ์์ธ๋ Exception์ ์ฒ๋ฆฌํ๋ ์๋ ๋ฉ์๋๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค.
์์ธ์ฝ๋๋ 500 ์๋ฒ ๋ด๋ถ ์๋ฌ๋ก ์ค์ ํ์์ต๋๋ค.
(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler
public ErrorResult exceptionHandler(Exception e) {
log.info("[ExceptionHandler: Exception", e);
ErrorResult errorResult = new ErrorResult("EX", e.getMessage());
return errorResult;
}
์ปจํธ๋กค๋ฌ ์ ์ฒด ์ฝ๋์ ๋๋ค.
@Slf4j
@RestController
public class ApiExceptionController {
/**
* ์ด ์ปจํธ๋กค๋ฌ์์ IllegalArgumentException ๋ฐ์์ ๋ฐ๋ก ์ด ๋ฉ์๋๊ฐ ์คํ๋๋ ๊ฒ์ ์๋
* ์ผ๋จ ์์ธ๋ DispatcherServlet๊น์ง ์ ํ๋๊ณ DispatcherServlet์์ ์ ํฉํ ExceptionResolver๋ฅผ ์ฐพ์
* @ExceptionHandler๊ฐ ๋ถ์ด์๋ ๊ฒฝ์ฐ ExceptionHandlerExceptionResolver๋ฅผ ์ฌ์ฉ
* ExceptionHandlerExceptionResolver๋ฅผ๊ฐ ์ด๋
ธํ
์ด์
์ ๋ถ์ํ์ฌ ์๋ง๋ ๋ฉ์๋๋ฅผ ์คํ์์ผ ์ฃผ๋ ๊ฒ.
*/
@ResponseStatus(HttpStatus.BAD_REQUEST) // ๋ฐ๋ก ์ค์ ํด์ฃผ์ง ์์ผ๋ฉด ์๋ ๋ฉ์๋๋ก ์์ธ๋ฅผ ์ก์ ์ฒ๋ฆฌํ์ฌ๋ 200 OK๋ก ๋จ (์ ์ํ๋ฆ์ด๊ธฐ ๋๋ฌธ)
@ExceptionHandler(IllegalArgumentException.class)
public ErrorResult illegalArgumentExceptionHandler(IllegalArgumentException e) {
log.info("[ExceptionHandler: IllegalArgumentException", e);
return new ErrorResult("BAD", e.getMessage());
}
/**
* ๋ฆฌํด๊ฐ์ผ๋ก ResponseEntity๋ฅผ ์ฌ์ฉ
*/
@ExceptionHandler
public ResponseEntity<ErrorResult> userExceptionHandler(UserException e) {
log.info("[ExceptionHandler: UserExceptionHandler", e);
ErrorResult errorResult = new ErrorResult("USER-EXCEPTION", e.getMessage());
return new ResponseEntity<ErrorResult>(errorResult, HttpStatus.BAD_REQUEST);
}
/**
* Exception์ ์์ํ๋ ์์ ์์ธ ํด๋์ค (๋ํ
์ผํ ์์ธ ํด๋์ค)๊ฐ ์๋ค๋ฉด Exceptionํด๋์ค๋ฅผ ํธ๋ค๋งํ๋ ์๋ ๋ฉ์๋๊ฐ ํธ์ถ
* @ExceptionHandler๋ก ์ฒ๋ฆฌํ์ง ์์ RunTImeException์ ๋ฐ์์ํค๋ฉด ์๋ ๋ฉ์๋๊ฐ ์คํ๋ ๊ฒ์.
*/
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler
public ErrorResult exceptionHandler(Exception e) {
log.info("[ExceptionHandler: Exception", e);
ErrorResult errorResult = new ErrorResult("EX", e.getMessage());
return errorResult;
}
@GetMapping("/api/members/{memberId}")
public String getMember(@PathVariable String memberId) {
if (memberId.equals("bad"))
throw new IllegalArgumentException("์๋ชป๋ ์
๋ ฅ์
๋๋ค.");
if (memberId.equals("user-ex"))
throw new UserException("์ฌ์ฉ์ ์ค๋ฅ์
๋๋ค.");
if (memberId.equals("runtime"))
throw new RuntimeException("์๋ชป๋ ์ฌ์ฉ์์
๋๋ค.");
return "ok";
}
}
๊ฐ ์์ธ ๋ฐ์ ์์ฒญ์ ๋ํ Postman ํ
์คํธ ๊ฒฐ๊ณผ์
๋๋ค.

์์ธ์ฒ๋ฆฌ๋ฅผ ์ํ ์ฝ๋๊ฐ ์๊ฐ๋ณด๋ค ๊ธธ๊ณ ์ ์์ ์ธ ์ฝ๋์ ํจ๊ป ์๋ ๊ฒ์ด ๋ณ๋ก ๋ณด๊ธฐ ์ข์ง ์์ต๋๋ค.. ๋ถ๋ฆฌํด๋ณด๊ฒ ์ต๋๋ค.
์ด์ ์ปจํธ๋กค๋ฌ์์ ์์ธ์ฒ๋ฆฌ ์ฝ๋๋ง ๋ฑ ๋ณต์ฌํด์ ์๋ก์ด ํด๋์ค๋ฅผ ํ๋ ์์ฑํฉ๋๋ค.
@RestControllerAdvice๋ @ControllerAdvice์ @ResponseBody๊ฐ ๋ถ์ ์ด๋
ธํ
์ด์
์
๋๋ค.
@RestController์ Controller์ ๋์ผํ ๊ด๊ณ๋ค์.
์ด๋ ๊ฒ @ControllerAdvice๋ง์ ์ฌ์ฉํ๋ฉด ์ ์ํ ์์ธ ํธ๋ค๋ง ๋ฉ์๋๊ฐ ๊ธ๋ก๋ฒํ๊ฒ ์ ์ฉ๋ฉ๋๋ค. ๋ชจ๋ ์ปจํธ๋กค๋ฌ์ ์ ์ฉ๋๋ ๊ฒ ์
๋๋ค.
์ ์ฉ๋ฒ์๋ ์ด๋ ธํ ์ด์ ๋จ์, ํจํค์ง ๋จ์, ์์๊ด๊ณ ๋จ์ ๋ฑ ์ฌ๋ฌ๊ฐ์ง๋ก ์ค์ ๊ฐ๋ฅํฉ๋๋ค.
[ ์ด๋
ธํ
์ด์
๋จ์ ]
@ControllerAdvice(annotations = RestController.class)
public class ExceptionControllerAdvice1 {}
[ ํจํค์ง ๋จ์ ]
@ControllerAdvice("com.package.dhk22")
public class ExceptionControllerAdvice2 {}
[ ์์๊ด๊ณ ๋จ์ ]
@ControllerAdvice(
assignableTypes = {ClassInterface.class,
AbstractController.class})
public class ExceptionControllerAdvice3 {}
ControllerAdvice ์ ์ฒด ์ฝ๋
@Slf4j
@RestControllerAdvice
public class ExceptionControllerAdvice {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(IllegalArgumentException.class)
public ErrorResult illegalArgumentExceptionHandler(IllegalArgumentException e) {
log.info("[ExceptionHandler: IllegalArgumentException", e);
return new ErrorResult("BAD", e.getMessage());
}
@ExceptionHandler
public ResponseEntity<ErrorResult> userExceptionHandler(UserException e) {
log.info("[ExceptionHandler: UserExceptionHandler", e);
ErrorResult errorResult = new ErrorResult("USER-EXCEPTION", e.getMessage());
return new ResponseEntity<ErrorResult>(errorResult, HttpStatus.BAD_REQUEST);
}
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler
public ErrorResult exceptionHandler(Exception e) {
log.info("[ExceptionHandler: Exception", e);
ErrorResult errorResult = new ErrorResult("EX", e.getMessage());
return errorResult;
}
}
์ธํ๋ฐ ๊น์ํ๋์ ์คํ๋ง MVC 2ํธ ์ ์๊ฐํ๊ณ ์ ๋ฆฌํ ๋ด์ฉ์ ๋๋ค.