์คํ๋ง์์ ์ ๊ณตํ๋ ์ฌ๋ฌ๊ฐ์ง ์์ธ ์ฒ์น ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณด๋ คํฉ๋๋ค.
1. @ControllerAdvice
๋ชจ๋ ์ปจํธ๋กค๋ฌ์ ๋ํด ์ ์ญ์ ์ผ๋ก ์์ธ๋ฅผ ์ฒ๋ฆฌํ๋ ์ค์ ์ง์ค์ ์ ๊ทผ ๋ฐฉ์์ ๋๋ค. ํด๋น ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ฉด Global ์์ธ์ฒ๋ฆฌ, ํน์ package/Controller๋ฅผ ์์ธ ์ฒ๋ฆฌ๋ฅผ ๋ด๋นํฉ๋๋ค.
2. @ExceptionHandler
ํน์ ์์ธ๋ฅผ ์ฒ๋ฆฌํ ๋ฉ์๋๋ฅผ ์ง์ ํ๋๋ฐ ์ฌ์ฉํฉ๋๋ค. ํด๋น ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ฉด ํน์ Controller์ ์์ธ ์ฒ๋ฆฌ๋ฅผ ๋ด๋นํฉ๋๋ค.
์คํ๋ง ๋ถํธ์์ ์์ธ๋ฅผ ์ฒ๋ฆฌํ๋ ์ผ๋ฐ์ ์ธ ๋ฐฉ๋ฒ ์ค ์ผ๋ถ์ด๋ฉฐ ์ ํฉํ ๋ฐฉ๋ฒ์ ์ ํํ์ฌ ์ฌ์ฉํ ์ ์์ต๋๋ค.
1. ์ค์ ์ง์ค์ ์์ธ ์ฒ๋ฆฌ
์คํ๋ง ๋ถํธ๋ ์์ธ ์ฒ๋ฆฌ์ ๋ํ ์ค์ ์ง์ค์ ์ ๊ทผ ๋ฐฉ์์ ์ ๊ณตํฉ๋๋ค. ๊ฐ ์ปจํธ๋กค๋ฌ์์ ์์ธ ์ฒ๋ฆฌ๋ฅผ ๋ฐ๋ณตํ์ง ์๊ณ ๋ก์ง์ ๋ถ๋ฆฌ์์ผ ์ ์ ํ ์ ์์ต๋๋ค. ๋ํ ์ฝ๋ ์ฌ์ฌ์ฉ์ ํ์ง ์๊ณ ์ผ๊ด์ ์ธ ์์ธ ์ฒ๋ฆฌ๋ฅผ ์๋ต, ๋ณด๋ค ์ฌ์ด ์ ์ง ๊ด๋ฆฌ๋ฅผ ํ ์ ์์ต๋๋ค.
2. ์์ธ ์ถ๊ฐ ์ ๋ณด
๋๋ฒ๊น ๋ฐ ๋ฌธ์ ํด๊ฒฐ์ ์ ์ฉํ ์ ์๋ ๋ค์ํ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ๋ณด๋ค ์์ธํ ์ ๋ณด๋ฅผ ์ ๊ณตํ๋ฏ๋ก ๊ฐ๋ฐ์๊ฐ ๋ ์ฝ๊ฒ ์ดํดํ ์ ์์ต๋๋ค.
DTO, Controller
class User {
@NotEmpty
@Size(min = 1, max = 10)
private String name;
@NotNull
@Min(value = 1)
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
@RestController
@RequestMapping("/api")
public class ApiController {
@PostMapping("/user")
public User post(@Valid @RequestBody User user) {
System.out.println(user);
return user;
}
}
GlobalControllerAdvice
@RestControllerAdvice
public class GlobalControllerAdvice {
@ExceptionHandler(value = Exception.class)
public ResponseEntity exception(Exception e) {
System.out.println("msg : " + e.getLocalizedMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body((""));
}
}
์์ธ ๊ด๋ฆฌ์ ๋ํ ๋ก์ง์ ๋ฐ๋ก ๊ตฌํํ๊ธฐ ์ํด GlobalControllerAdvice ํด๋์ค์ @RestControllerAdvice๋ฅผ ์ฌ์ฉํ์ฌ @RestController์ ๋ํ ์์ธ์ฒ๋ฆฌ๋ฅผ ๋ช ์ํด์ค๋๋ค. @RestControllerAdvice์ ๋ฒ์๋ฅผ ์ง์ ํ ์ ์๋๋ฐ ๊ธฐ๋ณธ ๋ฒ์๋ basePackages์ด๋ฉฐ ์ํ๋ ๋งํผ ์ค์ ํ ์๋ ์์ต๋๋ค.
@RestControllerAdvice
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {
/**
* Alias for the {@link #basePackages} attribute.
* <p>Allows for more concise annotation declarations — for example,
* {@code @ControllerAdvice("org.my.pkg")} is equivalent to
* {@code @ControllerAdvice(basePackages = "org.my.pkg")}.
* @since 4.0
* @see #basePackages
*/
@AliasFor("basePackages")
String[] value() default {};
...
}
์์ ๋ฅผ ๋ณด๋ฉด Controller์ @Valid๋ฅผ ์ฌ์ฉํ์ฌ @NotEmpty, @Min, @NotEmpty์ ๊ฐ์ ์ด๋ ธํ ์ด์ ๋ฅผ ๋ชจ๋ธ ํด๋์ค์ ์ฌ์ฉํ๋ค๋ ๊ฒ์ ๋ช ์ํฉ๋๋ค. ์คํ ๊ฒฐ๊ณผ๋ GlobalControllerAdvice์ ์ ์ํ ๋ด์ฉ์ด ๋ํ๋๊ฒ ๋ฉ๋๋ค.
๋ง์ฝ controller์์ ์์ธ๊ฐ ๋ฐ์ํ๊ณ ์ด๋๋ฐ์ด์ค ํด๋์ค์ ํด๋นํ๋ ์์ธ๊ฐ 2๊ฐ์ด์์ธ ๊ฒฝ์ฐ ์ด๋ป๊ฒ ๋ ๊น์?
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public ResponseEntity methodArgumentNotValidException(MethodArgumentNotValidException e) {
System.out.println("-----------global MethodArgumentNotValid----------");
System.out.println("msg : " + e.getLocalizedMessage());
System.out.println("---------------------------");
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
}
ํด๋น ๋ฉ์๋๋ฅผ ์ถ๊ฐํ๋ฉด ์ด์ ์ ๊ตฌํํ Exception.class ๋ณด๋ค ๋ ์์ธํ ์์ธ์ด๊ธฐ ๋๋ฌธ์ ํด๋น ์ฝ๋๊ฐ ์๋๋ฉ๋๋ค.
๊ทธ๋ ๋ค๋ฉด GlobalControllerAdvice์ ์์ฑํ ์์ธ์ Controller์ ์์ฑํ ์์ธ๊ฐ ๊ฐ๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น์?
์์ ์ฝ๋๋ฅผ ์ปจํธ๋กค๋ฌ์ ๊ทธ๋๋ก ์์ฑํ๊ฒ ๋๋ฉด ์ปจํธ๋กค๋ฌ์์ ์์ฑ๋ ์ฝ๋๋ง ์คํ๋ฉ๋๋ค. ์ฆ, ์ฐ์ ์์๋ ์ปจํธ๋กค๋ฌ์ ์์ฑํ ์์ธ๊ฐ ๋จผ์ ๋ผ๋ ๊ฒ์ ์ ์ ์์ต๋๋ค. ๋ํ ์ปจํธ๋กค๋ฌ์์ ์์ธ๋ฅผ ์คํํ๊ธฐ ๋๋ฌธ์ ์ธ๋ถ์ ์๋ ๊ฐ์ ์ฝ๋๋ ์คํ๋์ง ์์ต๋๋ค.