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ํธ ์ ์๊ฐํ๊ณ ์ ๋ฆฌํ ๋ด์ฉ์ ๋๋ค.