Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

예외처리 컨벤션 통일 #13

Closed
thals0 opened this issue Mar 22, 2023 · 0 comments
Closed

예외처리 컨벤션 통일 #13

thals0 opened this issue Mar 22, 2023 · 0 comments

Comments

@thals0
Copy link
Owner

thals0 commented Mar 22, 2023

🌀 문제점

  • 유효성 검사를 위해 @Valid, @Size, @Pettern등의 어노테이션을 사용했더니 dto단에서 예외처리를 하게 되었다.
  • 유효성 검사를 제외한 모든 예외처리는 서비스단에서 이뤄지는데 유효성 검사만 dto에서 예외처리가 이루어짐
  • 예외처리 컨벤션을 지키지 못하는 상황 발생
  • 뿐만아니라, 유효성검사에서 발생한 에러는 핸들링하기도 어려운 상황이 되었음

🥊 시도해본 것들

  • @Valid, @Size, @Pettern등의 어노테이션을 살리면서 예외처리만 서비스단에서 해주면 되지 않을까 ?

  • 하지만 이 방법 역시 서비스 단까지 에러가 넘어오지 않았음 (클라이언트에서 들어오자마자 에러 발생하기 때문)

    UserController

    // 회원 가입( @Valid 사용)
       @PostMapping("/signup")
       public ResponseEntity<String> signup(@Valid @RequestBody final SignupRequestDto signupRequestDto, Errors errors){
           if(errors.hasErrors()){
               // 유효성 통과 못한 필드와 메시지를 핸들링
               Map<String, String> validatorResult = userService.validateHandling(errors);
               return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(validatorResult.toString());
           }
           userService.signup(signupRequestDto);
           return ResponseEntity.status(HttpStatus.CREATED).body("회원가입 성공");
       }

    UserService

        // DONE: @Valid 에러 처리
        // 회원가입 시, 유효성 체크
        public Map<String, String> validateHandling(Errors errors) {
            Map<String, String> validatorResult = new HashMap<>();
    
            for (FieldError error : errors.getFieldErrors()) {
                String validKeyName = String.format("valid_%s", error.getField());
                validatorResult.put(validKeyName, error.getDefaultMessage());
            }
    
            return validatorResult;
        }

    SignupRequestDto

    @Getter
    @Setter
    public class SignupRequestDto {
        private boolean admin= false;
        private String adminToken = "";
    
        @Size(min = 6, max = 50, message = "이메일 주소는 6~50자 이내로 입력해주세요.")
        @Pattern(regexp = "^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$", message = "올바른 이메일 주소를 입력해주세요.")
        private String email;
    
        @Size(min = 4, max = 10, message = "username은 최소 4자 이상, 10자 이하이어야 합니다.")
        @Pattern(regexp = "^[a-z0-9]+$", message = "username은 알파벳 소문자(a~z), 숫자(0~9)로 구성되어야 합니다.")
        private String username;
    
        @Size(min = 8, max = 15, message = "password는 최소 8자 이상, 15자 이하이어야 합니다.")
        @Pattern(regexp = "^[a-zA-Z0-9!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?]+$", message = "password는 알파벳 대소문자(a~z, A~Z), 숫자(0~9), 특수문자로만 구성되어야 합니다.")
        private String password;
    }

👏🏻 해결 방법

  • UserValidator라는 클래스를 만들어서 유저의 유효성 검사 기능을 하는 매서드들을 생성해 준 뒤

  • 다른 예외처리와 마찬가지로 Service단에서 예외처리를 해주었다.

    UserController

    @PostMapping("/signup")
        public ResponseEntity<String> signup(@RequestBody final SignupRequestDto signupRequestDto){
            userService.signup(signupRequestDto);
            return ResponseEntity.status(HttpStatus.CREATED).body("회원가입 성공");
        }

    UserService

    @Transactional
        public void signup(final SignupRequestDto signupRequestDto) {
            String email = signupRequestDto.getEmail();
            String username = signupRequestDto.getUsername();
            String password = passwordEncoder.encode(signupRequestDto.getPassword());
    
            // DONE: @Valid를 사용하지 않고 유효성 검사하기
            if(!UserValidator.emailValidate(email)){
                throw new CustomException(INVALID_EMAIL);
            }
    
            if(!UserValidator.usernameValidate(username)){
                throw new CustomException(INVALID_USERNAME);
            }
    
            if(!UserValidator.passwordValidate(signupRequestDto.getPassword())){
                throw new CustomException(INVALID_PASSWORD);
            }
    
            // 중복 아이디 불가
            Optional<User> found = userRepository.findByEmail(email);
            if(found.isPresent()){
                // DONE: CustomException 쓰기
                throw new CustomException(DUPLICATE_USER);
            }
    
            // 사용자 ROLE 확인
            UserRoleEnum role = UserRoleEnum.USER;
            if (signupRequestDto.isAdmin()) {
                if (!signupRequestDto.getAdminToken().equals(ADMIN_TOKEN)) {
                    throw new CustomException(WRONG_ADMIN_TOKEN);
                }
                role = UserRoleEnum.ADMIN;
            }
    
            User user = new User(email, username, password, role);
            userRepository.save(user);
        }

    UserValidator

    // 회원가입시 유효성 검사를 위한 클래스 생성
    @Slf4j
    public class UserValidator {
        // email 유효성 검사
        public static boolean emailValidate(String email) {
            // email 필드가 null이거나 빈 문자열인 경우 false를 반환
            if (email == null || email.isEmpty()) {
                return false;
            }
            // email 필드가 6~50자 이내가 아닌 경우 false를 반환
            if (email.length() < 6 || email.length() > 50) {
                return false;
            }
            // email 필드가 올바른 이메일 형식이 아닌 경우 false를 반환
            if (!email.matches("^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$")) {
                return false;
            }
            return true;
        }
    
        // username 유효성 검사
        public static boolean usernameValidate(String username) {
            // username 필드가 null이거나 빈 문자열인 경우 false를 반환
            if (username == null || username.isEmpty()) {
                return false;
            }
            // username 필드가 최소 4자 이상, 10자 이하가 아닌 경우 false를 반환
            if (username.length() < 4 || username.length() > 10) {
                return false;
            }
            // username 필드가 알파벳 소문자(a~z), 숫자(0~9)로 구성되어 있지 않은 경우 false를 반환
            if (!username.matches("[a-z0-9]+")) {
                return false;
            }
            return true;
        }
    
        // password 유효성 검사
        public static boolean passwordValidate(String password) {
            // password 필드가 null이거나 빈 문자열인 경우 false를 반환
            if (password == null || password.isEmpty()) {
                return false;
            }
            // password 필드가 최소 8자 이상, 15자 이하가 아닌 경우 false를 반환
            if (password.length() < 8 || password.length() > 15) {
                return false;
            }
            // password 필드가 알파벳 대소문자(a~z, A~Z), 숫자(0~9), 특수문자로만 구성되어 있지 않은 경우 false를 반환
            if (!password.matches("^[a-zA-Z0-9!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?]+$")) {
                return false;
            }
            return true;
        }
    }
    
    
    

    SignupRequestDto

    @Getter
    @Setter
    public class SignupRequestDto {
        private boolean admin= false;
        private String adminToken = "";
    
        // DONE: 예외처리 및 유효성 검사 서비스 단으로 통일
        private String email;
        private String username;
        private String password;
    }

👩🏻‍💻 알게 된 것

  • 예외처리 뿐만아니라 코드를 작성할 때 컨벤션을 지키는게 정말 중요하다는 사실을 알았다.
  • 앞으로 개발을 할 때, 일단 인텔리제이켜서 코드를 와랄라 적는게 아니라 설계하는 시간을 충분히 가진 뒤 천천히 코드를 작성하는 연습이 필요할 것 같다.
@thals0 thals0 closed this as completed May 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant