Spring ControllerAdvice
포스트
취소

Spring ControllerAdvice

웹을 개발하다보면 클라이언트에서 에러메세지를 작성해서 보여줄 수 있지만 서버에서 작성한 에러메세지를 클라이언트로 보내야 하는 경우가 있다 spring mvc 에서는 예외처리를 이렇게 하게 된다

클라이언트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/*회원가입 로직*/

const url = "http://localhost:8080/signUp/"
const method = "post"
const data = {
    "email" : email ,
    "password" : password ,
    "confirm_password" : confirm_password
}

try{

    fetch(url , {
        "method" : method ,
        "headers" : {
            "Content-Type" : "application/json"
        } ,
        "body" : JSON.stringify(data)

    }).then( res => {

        console.log(res);

        return res.json();

    }).then( result => {

        console.log(result);
    })

}catch(error){


}


이 코드는 서버와 통신을 하기 위한 자바 스크립트 promise 객체로 signUp 곳으로 요청을 주게 되면

백엔드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@PostMapping(value =  "/" )
public ResponseEntity<?> signUp (@RequestBody SignUpDto signUpDto)
{

    try{

        signUpService.signUp(signUpDto);

        return null;
    }catch(Exception e){
        throw new RuntimeException(e.getMessage());
    }


}

이런식으로 작성이 되어 있고 signUp 코드가 진행함에 따라서 에러가 발생을 하면 throw new RuntimeException(e.getMessage()); 으로 전달이 되고 끝이 난다 그럼 signUp 소스를 코드를 한번보게 되면

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void signUp(SignUpDto signUpDto) {

    String email = signUpDto.getEmail();
    String password = signUpDto.getPassword();
    String confirm_password = signUpDto.getConfirmPassword();

    Matcher matcher = pattern.matcher(email);

    if(!StringUtils.hasText(email)) throw new RuntimeException("이메일이 존재하지 않습니다");
    if(!StringUtils.hasText(password) || !StringUtils.hasText(confirm_password)) throw new RuntimeException("비밀번호가 존재하지 않습니다");
    if(!password.equals(confirm_password)) throw new RuntimeException("비밀번호가 일치하지 않습니다");
    if(!matcher.matches()) throw new RuntimeException("이메일 형식이 아닙니다");
}

이렇게 각 상황에 맞추어서 throw new RuntimeException 에러를 발생시키는데 이때 구체적으로 어떤 에러가 발생되는지 적고 있다 만약 이렇게 해서 내가 에러를 한번 발생을 시키게 되면

서버 에러

1
2
java.lang.RuntimeException: 이메일이 존재하지 않습니다

우리가 보는 서버 에러에서는 이렇게 나오고

클라이언트 에러

1
2
3
4
5
error: "Internal Server Error"
path: "/signUp/"
status: 500
timestamp : "2023-11-28T12:45:53.256+00:00"

이렇게 에러가 발생한것은 알겠는데 구체적으로 어떤 에러가 발생했는지 알 수가 없다 이때 사용할 수 있는게 바로 ControllerAdvice 가 존재하는데

ControllerAdvice 정의

@ControllerAdvice 어노테이션은 전역 예외 처리를 담당하는 클래스로서 어떤 핸들러에서 에러가 발생시 최종적으로는 @ControllerAdvice 로 전달되어서 커스텀하기 나름에 따라서 클라이언트에 적절한 메세지를 전달해줄 수 있습니다

ControllerAdvice 작성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@ControllerAdvice
public class ExceptionControllerAdvice {

    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseEntity<?> handleException(Exception e) {

        Map<String , Object> resultMsg = new HashMap<>();
        resultMsg.put("errorMsg" , e.getMessage());

        return new ResponseEntity<>(resultMsg ,  HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

@ControllerAdvice 에노테이션은 그래서 @ExceptionHandler(Exception.class) 발생한 핸들러는 최종적으로 이 핸들러로 들어오게 되고 return 으로 우리가 만든 특정 에러 메세지를 전달할 수 있습니다 그러면 이제 이를 기동해서 에러를 일으키게 되면 back-end 로그는 아까와 마찬가지로 같은 모양의 에러가 발생하게 되는데

1
2
{errorMsg: '이메일이 존재하지 않습니다'}
errorMsg: "이메일이 존재하지 않습니다"

이렇게 서버에서 작성한 에러메세지가 전달되게 됩니다 이