์์ธ ์ฒ๋ฆฌ ๊ณผ์
ํ๋ก๊ทธ๋๋ฐ์์ ์์ธ ์ฒ๋ฆฌ๋ ์์ฃผ ์ค์ํ๋ฉด์๋ ์์ฃผ ์ด๋ ต๋ค.
๊ณผํ๋คํ ๋งํผ ์์ธํ๊ณ ๋ค์ํ๊ฒ ์์ธ๋ฅผ ์ก์ ์ฒ๋ฆฌํด์ค๋ค๋ฉด, ํด๋ผ์ด์ธํธ๋ ๊ทธ๋ ๊ณ ์๋ฒ๋ ๊ทธ๋ ๊ณ ๋ ์์ ์ ์ธ ํ๋ก๊ทธ๋จ์ด ๋ ์ ์๊ฒ ๋์์ค๋ค.
์์ธ ์ฒ๋ฆฌ๋ฅผ ํ๋ ๊ฒฝ์ฐ์ ๋ฐฉ๋ฒ์ ๋ค์ํ๋ค.
- ๋ฉ์๋ ๋ด์์ ์์ธ ์ํฉ์ ์์ธกํด์ ์ฒ๋ฆฌํ๋ try-catch๋ฌธ์ ์ด์ฉํ๋ ๋ฐฉ๋ฒ
- ์๊ตฌ์ฌํญ์ ์ํ ์์ธ ์ฒ๋ฆฌ (ex. validation > ํน์ ๊ฐ์ด 0~255๋ฒ์๊ฐ ์๋๋ฉด ์ ํจํ์ง ์์ ๊ฐ์ผ๋ก ํ๋จํ๊ณ ์์ธ ์ฒ๋ฆฌ)
- ์คํ๋ง ์ํ๋ฆฌํฐ์์ ์ธํฐ์ ํฐ๋ก ์ก์์ UnauthorizedException ๊ฐ์ ์์ธ ์ฒ๋ฆฌ
๊ธฐํ ์ฌ๋ฌ ์์ธ ์ฒ๋ฆฌ๋ค์ ์ ์ฉํ๋ค๋ณด๋ฉด ์ฝ๋๊ฐ ์์ฒญ๋๊ฒ ๋ณต์กํด์ง๋ค.
if๋ฌธ์ผ๋ก ์ก๋ try-catch๋ก ์ก๋ ์์ ๋ฉ์๋๋ก ์์ธ์ฒ๋ฆฌ๋ฅผ ์์ํ๋ ์ฝ๋๋ ๋ณต์กํด์ง๋ค
๊ทธ๋ ๊ฒ ๋๋ฉด ์ ์ง๋ณด์ํ๊ธฐ ์์ฃผ ์ด๋ ค์์ง๋ค.
๋น์ฆ๋์ค ๋ก์ง์ ์ง์คํ๊ธฐ ์ด๋ ต๊ณ , ๋น์ฆ๋์ค ๋ก์ง๊ณผ ๊ด๋ จ๋ ์ฝ๋๋ณด๋ค ์์ธ ์ฒ๋ฆฌ๋ฅผ ์ํ ์ฝ๋๊ฐ ๋ ๋ง์์ง๋ ๊ฒฝ์ฐ๋ ์๊ธด๋ค.
์ด๋ฐ ๋ฌธ์ ๋ฅผ ์กฐ๊ธ์ด๋ผ๋ ๊ฐ์ ํ๊ธฐ ์ํด @ExceptionHandler์ @ControllerAdvice๋ฅผ ์ฌ์ฉํ๋ค๊ณ ๋ณด๋ฉด ์ดํด๊ฐ ์ฌ์์ง๋ค.
@ExceptionHandler
@ExceptionHandler๊ฐ์ ๊ฒฝ์ฐ๋ @Controller, @RestController๊ฐ ์ ์ฉ๋ Bean๋ด์์ ๋ฐ์ํ๋ ์์ธ๋ฅผ ์ก์์ ํ๋์ ๋ฉ์๋์์ ์ฒ๋ฆฌํด์ฃผ๋ ๊ธฐ๋ฅ์ ํ๋ค.
@RestController
public class MyRestController {
...
...
@ExceptionHandler(NullPointerException.class)
public Object nullex(Exception e) {
System.err.println(e.getClass());
return "myService";
}
}
์์ ๊ฐ์ด ์ ์ฉํ๊ธฐ๋ง ํ๋ฉด ๋๋ค. @ExceptionHandler๋ผ๋ ์ด๋ ธํ ์ด์ ์ ์ฐ๊ณ ์ธ์๋ก ์บ์นํ๊ณ ์ถ์ ์์ธํด๋์ค๋ฅผ ๋ฑ๋กํด์ฃผ๋ฉด ๋๋๋ค.
→ @ExceptionHandler({ Exception1.class, Exception2.class}) ์ด๋ฐ์์ผ๋ก ๋ ๊ฐ ์ด์ ๋ฑ๋ก๋ ๊ฐ๋ฅํ๋ค.
์์ ์์ ์์ ์ฒ๋ผํ๋ฉด MyRestController์ ํด๋นํ๋ Bean์์ NullPointerException์ด ๋ฐ์ํ๋ค๋ฉด, @ExceptionHandler(NullPointerException.class)๊ฐ ์ ์ฉ๋ ๋ฉ์๋๊ฐ ํธ์ถ๋ ๊ฒ์ด๋ค.
์ฃผ์์ฌํญ/์์ ๋ ๊ฒ
- Controller, RestController์๋ง ์ ์ฉ๊ฐ๋ฅํ๋ค. (@Service๊ฐ์ ๋น์์๋ ์๋จ.)
- ๋ฆฌํด ํ์ ์ ์์ ๋กญ๊ฒ ํด๋ ๋๋ค. (Controller๋ด๋ถ์ ์๋ ๋ฉ์๋๋ค์ ์ฌ๋ฌ ํ์ ์ response๋ฅผ ํ ๊ฒ์ด๋ค. ํด๋น ํ์ ๊ณผ ์ ํ๋ค๋ฅธ ๋ฆฌํด ํ์ ์ด์ด๋ ์๊ด์๋ค.)
- @ExceptionHandler๋ฅผ ๋ฑ๋กํ Controller์๋ง ์ ์ฉ๋๋ค. ๋ค๋ฅธ Controller์์ NullPointerException์ด ๋ฐ์ํ๋๋ผ๋ ์์ธ๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ค.
- ๋ฉ์๋์ ํ๋ผ๋ฏธํฐ๋ก Exception์ ๋ฐ์์๋๋ฐ ์ด๊ฒ ๋ํ ์์ ๋กญ๊ฒ ๋ฐ์์๋ ๋๋ค.
์์ ๋ฅผ ๋ณด๋ฉด์ ํ ์คํธ๋ฅผ ํด๋ณด๋๋กํ์.
@RestController
public class MyRestController {
@Autowired
private MyService myService;
@GetMapping("/hello")
public String hello() {
return "hello";//๋ฌธ์์ด ๋ฐํ
}
@GetMapping("/myData")
public MyData myData() {
return new MyData("myName");//object ๋ฐํ
}
@GetMapping("/service")
public String serviceCall() {
return myService.serviceMethod();//์ผ๋ฐ์ ์ธ serviceํธ์ถ
}
@GetMapping("/serviceException")
public String serviceException() {
return myService.serviceExceptionMethod(); //service์์ ์์ธ๋ฐ์
}
@GetMapping("/controllerException")
public void controllerException() {
throw new NullPointerException();//controller์์ ์์ธ๋ฐ์
}
@GetMapping("/customException")
public String custom() {
throw new CustomException();//custom์์ธ ๋ฐ์
}
@ExceptionHandler(NullPointerException.class)
public Object nullex(Exception e) {
System.err.println(e.getClass());
return "myService";
}
}
[MyRestController.class]
Stringํ์ ๊ณผ MyData๋ผ๋ ๋๋ง์ ๊ฐ์ฒดํ์ ์ ๋ฆฌํดํ๋ ๋ฉ์๋๋ฑ์ ์กด์ฌํ์ง๋ง ExceptionHandlerํ๋๋ก ๋ค ์ฒ๋ฆฌํ ์ ์๋ค.
myService.serviceExceptionMethod๋ Service์์์ Exception์ด ๋ฐ์ํ๋๋ฐ ์ด ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ์๋น์ค์์ ์์ธ๊ฐ ๋ฐ์ํ์ง๋ง ๊ฒฐ๊ตญ ์ปจํธ๋กค๋ฌ ๋ด์์ ๋ฐ์ํ ๊ฒ๊ณผ ๊ฐ์ผ๋ฏ๋ก ExceptionHandler๊ฐ ์์ธ๋ฅผ ์ก์๋ด์ด "myService"๊ฐ ๋ฆฌํด๋๋ค.
public class CustomException extends RuntimeException{
private static final long serialVersionUID = 1L;
}
RuntimeException์ ํ์ฅํ ํด๋์ค๋ก CustomException์ ๋ง๋ค์๋ค.
์ด ์์ธ๋ NullPointerException์ด ์๋๊ธฐ ๋๋ฌธ์ ๋ฐ์ํ๋๋ผ๋ ExceptionHandler์ ์ํด์ ์ฒ๋ฆฌ๋์ง ์๋๋ค.
๋ง์ฝ ํ๋๋ก ๋ ๋ง์ ์์ธ ์ฒ๋ฆฌ๋ฅผ ํ๊ธธ ์ํ๋ค๋ฉด ๋ชจ๋ ์์ธ์ ๋ถ๋ชจํด๋์ค์ธ Exception.class๋ฅผ ํธ๋ค๋งํ๊ฒํ๋ฉด ๋๋ค.
@ExceptionHandler(Exception.class)
@ControllerAdvice
@ExceptionHandler๊ฐ ํ๋์ ํด๋์ค์ ๋ํ ๊ฒ์ด๋ผ๋ฉด, @ControllerAdvice๋ ๋ชจ๋ @Controller ์ฆ, ์ ์ญ์์ ๋ฐ์ํ ์ ์๋ ์์ธ๋ฅผ ์ก์ ์ฒ๋ฆฌํด์ฃผ๋ annotation์ด๋ค.
@RestControllerAdvice
public class MyAdvice {
@ExceptionHandler(CustomException.class)
public String custom() {
return "hello custom";
}
}
์์ ๊ฐ์ด ์๋ก์ด ํด๋์คํ์ผ์ ๋ง๋ค์ด์ annotation์ ๋ถ์ด๊ธฐ๋ง ํ๋ฉด ๋๋ค. ๊ทธ ๋ค์์ @ExceptionHandler๋ก ์ฒ๋ฆฌํ๊ณ ์ถ์ ์์ธ๋ฅผ ์ก์ ์ฒ๋ฆฌํ๋ฉด ๋๋ค.
๋ณ๋์ ์์ฑ๊ฐ์ด ์์ด ์ฌ์ฉํ๋ฉด ๋ชจ๋ ํจํค์ง ์ ์ญ์ ์๋ ์ปจํธ๋กค๋ฌ๋ฅผ ๋ด๋นํ๊ฒ ๋๋ค.
@RestControllerAdvice๋ @ControllerAdvice๊ฐ ์๋๋ฐ ๋ง ๊ทธ๋๋ก @RestControllerAdvice๋ @RestController์์ ๋ฐ์ํ Exception๋ง ์บ์นํ๊ณ , @ControllerAdvice๋ @Controller์์ ๋ฐ์ํ Exception๋ง ์บ์นํ๋ค.
@RestControllerAdvice์ @ControllerAdvice๊ฐ ์กด์ฌํ๋๋ฐ @RestControllerAdvice ์ด๋ ธํ ์ด์ ์ ๋ค์ฌ๋ค๋ณด๋ฉด ์๋์ ๊ฐ์ด ๋์ด์๋ค.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ControllerAdvice
@ResponseBody
public @interface RestControllerAdvice {
//...
}
์์ ๊ฐ์ด ๋๊ฐ์ ์ปจํธ๋กค๋ฌ๋ฅผ ์์ฑํ์ ๋ @RestControllerAdvice๋ฅผ ์ฌ์ฉํ๋ฉด @Controller๋ก ์ ์ฉํ HelloController์์ ๋ฐ์ํ๋ ์์ธ๋ @RestControllerAdvice์์ ์ก์์ฃผ์ง ๋ชปํ๋ค.
@ControllerAdvice์ ๋์ผํ ์ญํ ์ฆ, ์์ธ๋ฅผ ์ก์ ํธ๋ค๋ง ํ ์ ์๋๋ก ํ๋ ๊ธฐ๋ฅ์ ์ํํ๋ฉด์ @ResponseBody๋ฅผ ํตํด ๊ฐ์ฒด๋ฅผ ๋ฆฌํดํ ์๋ ์๋ค๋ ์๊ธฐ๋ค.
ViewResolver๋ฅผ ํตํด์ ์์ธ ์ฒ๋ฆฌ ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ํธ ์ํค๋ ค๋ฉด @ControllerAdvice๋ง ์จ๋ ๋๊ณ , API์๋ฒ์ฌ์ ์๋ฌ ์๋ต์ผ๋ก ๊ฐ์ฒด๋ฅผ ๋ฆฌํดํด์ผํ๋ค๋ฉด @ResponseBody ์ด๋ ธํ ์ด์ ์ด ์ถ๊ฐ๋ @RestControllerAdvice๋ฅผ ์ ์ฉํ๋ฉด ๋๋ ๊ฒ์ด๋ค.
@RestController์์ ์์ธ๊ฐ ๋ฐ์ํ๋ @Controller์์ ์์ธ๊ฐ ๋ฐ์ํ๋ @ControllerAdvice + @ExceptionHandler ์กฐํฉ์ผ๋ก ๋ค ์บ์นํ ์ ์๊ณ @ResponseBody์ ํ์ ์ฌ๋ถ์ ๋ฐ๋ผ ์ ์ฉํ๋ฉด ๋๋ค๋ ๊ฒ์ด๋ค. (์ ๋ถ์ฐฐ๋ก ์๋ชป๋ ์ ๋ณด๋ฅผ ๊ณต์ ํ๋ ์ ์ ์์ ํ์์ต๋๋ค.)
๋ํ, ๋ง์ฝ์ ์ ์ญ์ ์์ธ๋ฅผ ์ก๊ธดํ๋ ํจํค์ง ๋จ์๋ก ์ ํํ ์๋์๋ค.
@RestControllerAdvice("com.example.demo.login.controller")
login๋ชจ๋์ ์๋ RestController์์ ๋ฐ์ํ๋ ์์ธ๋ฅผ ์ก์ผ๋ ค๋ฉด ์์ ๊ฐ์ด ํ๋ฉด ๋๋ค. (ํจํค์ง ๊ตฌ์ฑ์ ์ํ๋ฉด ์ ์ฉํ๋ค)
์ค๋ฌด์์ ์ด๋ป๊ฒ...?
์ผ๋ฐ์ ์ธ ์ค๋ฌด์์ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง๋ ์ฌ์ค ๋ช ํํ์ง ์๋ค.
ํ์์ ๊ฒฝํ์ ์๋ฌ ์ธํฐํ์ด์ค ์ ์๋ฅผ ์ ๋๋ก ํด์ผํ๋ค.
๋ฌด์จ ์๊ธฐ๋๋ฉด ์๋ฌ๋ฉ์์ง๋ก ๋๊ฐ๋ ํฌ๋งท์ด ์ผ์ ํด์ผํ๋ค๋ ์๊ธฐ๋ค.
๋ง์ฝ ๋ก๊ทธ์ธ ๋ชจ๋์์ ๋ฐ์ํ ์์ธ์ ์๋ตํ๋ ๋ฉ์ธ์ง๋ ์๋ฌ์ฝ๋๋ ์ค๋ช ์ ๋ฆฌํดํด์ค๋ค๊ณ ํ๊ณ , ๋ฐฐ์ก ๋ชจ๋์์ ๋ฐ์ํ ์์ธ๋ ์๋ฌ์ฝ๋๋ ์๋ฌ๊ฐ ๋ ๋ฐฐ์ก ๋ฒํธ๋ฅผ ๋ฆฌํดํด์ค๋ค๊ณ ํ์
๊ทธ๋ฌ๋ฉด @ControllerAdvice๋ฅผ ์ด์ฉํด์ ํตํฉ์ผ๋ก ์ฒ๋ฆฌํ๋ ค๊ณ ํ์ง๋ง ๋ฆฌํด ํ์ ์ด ๋ค๋ฅด๋๊น ํตํฉํด์ ์ฒ๋ฆฌํ ์ ์๋ค.
HTTP ์ํ์ฝ๋, ErrorResponse๊ฐ์ ๊ฒฝ์ฐ๋ ์ข์ ์๋ค.
์๋ฌ ์ธํฐํ์ด์ค, ํฌ๋งท์ด ๋ค ๊ฐ๊ณ ํด๋ผ์ด์ธํธ ์ธก์์๋ ์ดํดํ๊ธฐ ์ข์ ์๋ฌ๊ฐ ๋ ๋ผ์ค๋ ๊ฒ์ด๋ค.
๊ทธ๋์ @ExceptionHandler์ ํจ๊ป @ResponseStatus(value = HttpStatus.UNAUTHORIZED)
์ด๋ฐ ๊ฒ๋ ์ง์ด๋ฃ์ด์ HTTP์ํ์ฝ๋๋ฅผ ๋ฆฌํดํ๊ธฐ๋ ํ๋ค. (์์์ ์ค๋ช ํ์ง ์์์ง๋ง...)
๋ค์ ํ ๋ฒ ์ ๋ฆฌํ์ง๋ง ์๋ฌ ๋ฉ์์ง๊ฐ ์ ์ ์๋์ด์์ด์ผ ํ๋๊ฒ ์ ์ ์กฐ๊ฑด์ด๋ค.
→ ์๋ฌ ๊ด๋ฆฌํ๊ธฐ
public enum LoginErrorCode {
OperationNotAuthorized(6000,"Operation not authorized"),
DuplicateIdFound(6001,"Duplicate Id"),
//...
UnrecognizedRole(6010,"Unrecognized Role");
private int code;
private String description;
private LoginErrorCode(int code, String description) {
this.code = code;
this.description = description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
}
๋ณดํต ์๋ฌ๋ฅผ ์์ ๊ฐ์ด ํ ๊ณณ์ ์ ๋ฆฌ๋ฅผ ํ ๊ฒ์ด๋ค.
์ ๋ ๊ฒ ๋ฏธ๋ฆฌ ์ ์ํด๋๊ณ ์ค์ ์ฌ์ฉํ ๋๋ LoginErrorCode.OperationNotAuthorized.getCode(); ์ด๋ฐ์์ผ๋ก ๋ถ๋ฌ์์ ์๋ฌ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ ๋ฆฌํดํ ๊ฒ์ด๋ค.
๊ทธ๋ฌ๋ฉด 1์ฐจ์ ์ผ๋ก ์๋ฌ๊ฐ์ฒด ๊ด๋ฆฌ๋ ์์ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ๋๋๋ค.
๊ทธ ๋ค์์ ์๊น ๋ฐฐ์ด @ControllerAdvice, @ExeptionHandler๋ฅผ ์ด์ฉํด์ ์๋ฌ๋ฅผ ์ฒ๋ฆฌํด๋ณธ๋ค.
๋ง์ฝ @ControllerAdvice, @ExceptionHandler๋ก ์ฒ๋ฆฌํ ๋, InvalidArgumentProvided ๋ผ๋ ์๋ฌ์ฝ๋๋ฅผ ๋ง๋ค์๋ค๋ฉด, ๋ชจ๋ ์ปจํธ๋กค๋ฌ์์ ๋ค์ด์ค๋ ์ธ์(arguments)์ ๋ํด์ ํ ๊ณณ์์ ์ฒ๋ฆฌํ๊ฒ ๋๋ฏ๋ก, ์ค๋ณต๋ ์ฝ๋๋ฅผ ์ฐ์ง ์๊ฒ ๋๋ค.
๊ทธ๋ก์ธํด ๋น์ฆ๋์ค ๋ก์ง์ ๋ ์ง์คํ ์ ์๊ณ , ์ฝ๋๋ ๊ฐ๋จํ๊ฒ ์กฐ๊ฑด๋ฌธ์ ๋ฐ๋ผ throw new XXXXException(); ํ๊ณ ํธ์ถํด๋ฒ๋ฆฌ๋ฉด ๋๋๊ธฐ ๋๋ฌธ์ ์ ์ง๋ณด์์ ์์ฃผ ํฐ ๋์์ด ๋๋ค.
์ถ์ฒ: https://jeong-pro.tistory.com/195 [๊ธฐ๋ณธ๊ธฐ๋ฅผ ์๋ ์ ์๋ง์ถ์ด ์ฝ๋ฉ๋ธ๋ก๊ทธ]
'Languages | Frameworks > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
BindingResult(rejectValue(), reject())์ฌ์ฉํ๊ธฐ -3 + MessageCodesResolver ์๊ฐ (0) | 2022.03.21 |
---|---|
BindingResult -2 (0) | 2022.03.21 |
BindingResult(error ์ถ๋ ฅ์ ์ ์ฉ) -1 (0) | 2022.03.21 |
Spring AOP(๊ด์ ์งํฅํ๋ก๊ทธ๋๋ฐ) (0) | 2021.09.24 |
SpringBoot JPA (0) | 2021.09.23 |