본문 바로가기
웹개발/스프링부트

Springboot Exception Handling(스프링부트 exception 핸들링)

by 어컴띵 2021. 3. 10.

스프링부트에서 exception을 처리하는 방법을 알아보자

 

순서는 다음과 같다

1. 에러코드 정리 enum 클래스로 작성

2. Exception 발생시 응답하는 에러 정보 클래스 작성

3. 사용자 정의 Exception 클래스 작성

4. Exception 발생시 전역으로 처리할 exception handler 작성

5. 사용자등록관련 클래스작성 서비스에서 중복 exception 발생

6. api 실행 및 exception 결과 확인

 

1. 에러코드 정리 enum 클래스로 작성

@AllArgsConstructor
public enum ErrorCode {
    NOT_FOUND(404,"COMMON-ERR-404","PAGE NOT FOUND"),
    INTER_SERVER_ERROR(500,"COMMON-ERR-500","INTER SERVER ERROR"),
    EMAIL_DUPLICATION(400,"MEMBER-ERR-400","EMAIL DUPLICATED"),
    ;

    private int status;
    private String errorCode;
    private String message;
}

2. exception 발생시 응답하는 에러 정보 클래스 작성

@Getter
@Setter
public class ErrorResponse {
    private int status;
    private String message;
    private String code;

    public ErrorResponse(ErrorCode errorCode){
        this.status = errorCode.getStatus();
        this.message = errorCode.getMessage();
        this.code = errorCode.getErrorCode();
    }
}

3. 사용자 정의 exception 클래스 작성

RuntimeException 상속받는 사용자 exception을 작성한다.

 

@Getter
public class EmailDuplicateException extends RuntimeException{

    private ErrorCode errorCode;

    public EmailDuplicateException(String message, ErrorCode errorCode){
        super(message);
        this.errorCode = errorCode;
    }
}

4. exception 발생시 전역으로 처리할 exception handler 작성

@RestControllerAdvice, @ExceptionHandler 어노테이션을 이용하여 exception 발생시 적절한 에러 응답을 생성해서 리턴한다.

@RestControllerAdvice : 모든 rest 컨트롤러에서 발생하는 exception을 처리한다.

@ExceptionHandler(xxException.class) : 발생한 xxException에 대해서 처리하는 메소드를 작성한다.  

 

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(EmailDuplicateException.class)
    public ResponseEntity<ErrorResponse> handleEmailDuplicateException(EmailDuplicateException ex){
        log.error("handleEmailDuplicateException",ex);
        ErrorResponse response = new ErrorResponse(ex.getErrorCode());
        return new ResponseEntity<>(response, HttpStatus.valueOf(ex.getErrorCode().getStatus()));
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleException(Exception ex){
        log.error("handleException",ex);
        ErrorResponse response = new ErrorResponse(ErrorCode.INTER_SERVER_ERROR);
        return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

 

5. 사용자등록관련 클래스작성 서비스에서 중복등록시 exception 발생처리

UserService에서 사용자를 등록시에 한번 등록된 사용자를 다시 등록할경우 EmailDuplicationException을 발생시키며 GlobalExceptionHandler에서 해당 exception을 캐치해서 적절한 에러응답을 생성해서 json결과를 내려준다.

 

SignVo

@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class SignVo {
    String email;
    String password;
    String name;
}

User

@Setter
@Getter
@Entity(name = "user")
@NoArgsConstructor
public class User {
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true)
    private String email;
    private String password;
    private String name;

    @Builder
    public User(Long id, String email, String password,String name){
        this.id = id;
        this.email = email;
        this.password = password;
        this.name = name;
    }
}

 

UserRepository

@Repository
public interface UserRepository extends JpaRepository<User,Long> {
    public Optional<User> findByEmail(String email);
}

 

UserService

@Service
public class UserService {

    UserRepository repository;
    PasswordEncoder passwordEncoder;

    @Autowired
    public UserService(UserRepository repository, PasswordEncoder passwordEncoder){
        this.repository = repository;
        this.passwordEncoder = passwordEncoder;
    }

    public void save(User user){
        Optional<User> aleadyUser = repository.findByEmail(user.getEmail());
        if( aleadyUser.isPresent()){
            throw new EmailDuplicateException("email duplicated",ErrorCode.EMAIL_DUPLICATION);
        }
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        repository.save(user);
    }

    public Optional<User> findUserByEmail(String email){
        Optional<User> aleadyUser = repository.findByEmail(email);
        return aleadyUser;
    }
}

Controller

@RestController
public class UserController {

    @Autowired
    UserService userService;

    @PostMapping("/api/v1/user")
    public void saveUser(@RequestBody SignVo signVo){
        User user = User.builder()
                .email(signVo.getEmail())
                .password(signVo.getPassword())
                .name(signVo.getName())
                .build();
        userService.save(user);
    }
 }

service

@Service
public class UserService {

    UserRepository repository;
    PasswordEncoder passwordEncoder;

    @Autowired
    public UserService(UserRepository repository, PasswordEncoder passwordEncoder){
        this.repository = repository;
        this.passwordEncoder = passwordEncoder;
    }

    public void save(User user){
        Optional<User> aleadyUser = repository.findByEmail(user.getEmail());
        if( aleadyUser.isPresent()){
            throw new EmailDuplicateException("email duplicated",ErrorCode.EMAIL_DUPLICATION);
        }
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        repository.save(user);
    }

    public Optional<User> findUserByEmail(String email){
        Optional<User> aleadyUser = repository.findByEmail(email);
        return aleadyUser;
    }
}

6. api 실행 및 exception 결과 확인

사용자를 중복등록하여 에러응답이 제대로 생성되는지 확인한다.

 

 

참조 : cheese10yun.github.io/spring-guide-exception/

 

Spring Guide - Exception 전략 - Yun Blog | 기술 블로그

Spring Guide - Exception 전략 - Yun Blog | 기술 블로그

cheese10yun.github.io