본문 바로가기
프로젝트/게시판 프로젝트

[기능구현#1] 패스워드 검증 추가하기

by 거북이의 기술블로그 2024. 10. 23.
1. 직접 검증
2. BindingResult
3. 애노테이션 사용

 

직접검증

  • HashMap을 이용하여, error를 담고 ModelAttribute로 반환
  • thymeleaf의 조건문과 삼항문을 이용하여, error 인 경우와 정상인경우 렌더링
//[Controller]


       Map<String,String> errors = new HashMap<>();
       
       if ( member.getPasswd() != null && member.getPasswd().length() >= 8 ){
            if (member.getPasswd().matches("[a-zA-Z]+")){
                errors.put("passwd", "비밀번호는 숫자와 특수문자를 포함해야합니다.");
            }else if (member.getPasswd().matches("[0-9]+")) {
                errors.put("passwd", "비밀번호는 문자와 특수문자를 포함해야합니다.");
            }else if (member.getPasswd().matches("[a-zA-Z0-9]+")){
                errors.put("passwd", "비밀번호는 특수문자를 포함해야합니다.");
            }
        }else{
            errors.put("passwd", "비밀번호는 문자,숫자,특수문자를 포함하여 8자이상이어야합니다.");
        }
        
        
        if(!errors.isEmpty()){
            model.addAttribute("errors",errors);
            return "member/member-form";
        }
[Thymeleaf]

<input 태그>
th:class="${errors?.containsKey('[모델attribute값]')} ? '[오류형태]' : '[정상형태]'"

<div 태그>
th:if = "${errors?.containsKey('[모델 attribute값]')}" th:text="${errors'[모델 attribute값]'}"
(* th:if 는 model.addAttribute로 값이 넘어왔는지 확인)
(* th:text는 값이 넘어왔을경우, 해당 MAP에 기록되어있는 오류메시지)

<!-- [html] -->

<div class="form-group mb-3">
    <label for="passwd">Password:</label>
    <input type="password" id="passwd" th:field="*{passwd}" th:class="${errors?.containsKey('passwd')}? 'form-control field-error':'form-control'", class="form-control">
    <div class="field-error" th:if="${errors?.containsKey('passwd')}" th:text="${errors['passwd']}"> 비밀번호 입력 오류 </div>
</div>

 

BindingResult

  • BindingResult는 @ModelAttribute 뒤에 바로 인자값으로 들어와야함 (spring 인지 가능)
    • BindingResult의 경우, Model에 자동으로 포함됨
  • FieldError를 통해서, 에러값 넣기 (HashMap역할)
    • FieldError(String ObjectName, String Field, String DefaultMessage) {}
      • objectName : @ModelAttribute 이름
      • field : 오류가 발생한 필드 이름
      • defaultMessage : 오류 기본 메시지
    • FieldError(String ObjectName, String field, Object rejectedValue, boolean bindingFailure, @Nullable String[] codes, @Nullable Object[] argument, @Nullable String defaultMessage(
      • ObjectName : 오류가 발생한 객체 이름
      • field : 오류 필드
      • rejectedValue : 사용자가 입력한 값
      • bindingFailure : 타입 오류 같은 바인딩 실패인지 검증실패인지 구분값
      • codes : 메시지 코드
      • argument : 메시지에서 사용하는 인자
      • defaultMessage : 기본 오류 메시지
    • 추가) ObjectError(String objectName, String DefaultMessage){}
      • objectName : @ModelAttribute 이름
      • defaultMessage : 오류기본메시지
      • 특정필드 이외의 오류가 필요한경우 사용
  • thymeleaf의 th:errorclass 및 th:errors를 이용하여 표현
public String registryMember(@ModelAttribute Member member, BindingResult bindingResult){       

//...
       if ( member.getPasswd() != null && member.getPasswd().length() >= 8 ){
            if (member.getPasswd().matches("[a-zA-Z]+")){
                bindingResult.addError(new FieldError("member","passwd", "비밀번호는 숫자와 특수문자를 포함해야합니다."));
            }else if (member.getPasswd().matches("[0-9]+")) {
                bindingResult.addError(new FieldError("member", "passwd", "비밀번호는 문자와 특수문자를 포함해야합니다"));
            }else if (member.getPasswd().matches("[a-zA-Z0-9]+")){
                bindingResult.addError(new FieldError("member","passwd", "비밀번호는 특수문자를 포함해야합니다 "));
            }
        }else{
            bindingResult.addError(new FieldError("member","passwd", "비밀번호는 문자,숫자,특수문자를 포함하여 8자이상이어야합니다."));
        }

        if (bindingResult.hasErrors()){
            return "member/member-form";
        }
        
//... 성공시나리오
}
th:errors : 해당 필드에 오류가 있는경우 태그 출력 (th:if의 편의 버전)
th:errorclass : th:field에서 지정한 필드에 오류가 있으면 class 정보를 추가함
<div class="form-group mb-3">
     <label for="passwd">Password:</label>
     <input type="password" id="passwd" th:field="*{passwd}" th:errorclass="field-error" class="form-control">
     <div class="field-error" th:errors="*{passwd}"> 비밀번호 입력 오류 </div>
</div>

 

애노테이션 사용

  • 검증기 직접 생성방법
public class BindigResultValidate implements Validator {
    @Override
    public boolean supports(Class<?> clazz) {
        return Member.class.isAssignableFrom(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {

        Member member = (Member) target;
        BindingResult bindingResult = (BindingResult) errors;

        //로그인ID
        if ( !StringUtils.hasText(member.getLoginId())){
            bindingResult.addError(new FieldError("member", "loginId","로그인 아이디는 필수입력입니다."));
        }

        //이름
        if (!StringUtils.hasText(member.getName())){
            bindingResult.addError(new FieldError("member", "name", "이름은 필수 입력값입니다."));
        }

        //비밀번호
        if ( member.getPasswd() != null && member.getPasswd().length() >= 8 ){
            if (member.getPasswd().matches("[a-zA-Z]+")){
                bindingResult.addError(new FieldError("member","passwd", "비밀번호는 숫자와 특수문자를 포함해야합니다."));
            }else if (member.getPasswd().matches("[0-9]+")) {
                bindingResult.addError(new FieldError("member", "passwd", "비밀번호는 문자와 특수문자를 포함해야합니다"));
            }else if (member.getPasswd().matches("[a-zA-Z0-9]+")){
                bindingResult.addError(new FieldError("member","passwd", "비밀번호는 특수문자를 포함해야합니다 "));
            }
        }else{
            bindingResult.addError(new FieldError("member","passwd", "비밀번호는 문자,숫자,특수문자를 포함하여 8자이상이어야합니다."));
        }

    }
}
@PostMapping("/form")
    public String registryMember(@ModelAttribute Member member, BindingResult bindingResult, Model model){
        
        //생성자 주입으로 넣기
        bindingResultValidate.validate(member,bindingResult);

        if (bindingResult.hasErrors()){
            return "member/member-form";
        }

        memberRepository.save(member);
        return "redirect:/members/login";
    }
  • @Validated로 적용
    • bindingResultValidate 미리 등록
      • @InitBinder -> WebDataBinder로 validate 등록
    • @Validated 를 @ModelAttribute앞에 추가
@InitBinder
private void init(WebDataBinder webDataBinder){    
    webDataBinder.addValidators(bindingResultValidate);
}

@PostMapping("/form")
    public String registryMember(@Validated @ModelAttribute Member member, BindingResult bindingResult, Model model){

        if (bindingResult.hasErrors()){
            return "member/member-form";
        }

        memberRepository.save(member);
        return "redirect:/members/login";
    }