본문 바로가기
✨ Back-end/etc

[Spring] 검증(Validation) -2 BindingResult

by 환풍 2023. 9. 27.
728x90
반응형

MemberController

BindingResult

데이터 바인딩 과정에서 발생하는 검증 오류를 보유하고 있는 객체이다.  주로 폼 데이터를 도메인 객체에 바인딩할 때 사용된다. 예를 들어, 사용자가 웹 폼을 통해 입력한 데이터를 서버로 전송하고 해당 데이터를 처리하기 위해 폼 데이터를 도메인 객체에 바인딩하려 할 때 사용된다.

BindingResult 객체는 바인딩 시 발생할 수 있는 검증 오류를 저장하고 관리한다. 이를 통해 개발자는 검증 오류를 쉽게 확인하고 처리할 수 있다. 데이터 바인딩 중 오류가 발생하면, 해당 오류 정보를 BindingResult 객체를 통해 확인할 수 있다.

예를 들어, 아래와 같이 컨트롤러 메서드에서 @Valid 어노테이션을 사용하여 데이터 바인딩 및 검증을 수행하고, 그 결과를 BindingResult 객체로 받아오는 것이 일반적이다

 

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
@PostMapping("/joinCommit")
    public String joinCommit(MemberVO memberVO,BindingResult bindingResult, Model model ) {
        
        //Map<String, String> errors = new HashMap<>();
        if(!StringUtils.hasText(memberVO.getMemId())){
            //errors.put("memId", "* 아이디는 필수항목입니다.");
            bindingResult.addError(new FieldError("memberVO""memId""* 아이디는 필수 항목."));
        }
        if(!StringUtils.hasText(memberVO.getMemName())){
            //errors.put("memName", "* 이름은 필수항목입니다.");
            bindingResult.addError(new FieldError("memberVO""memName""* 이름은 필수항목입니다."));
        }
        if(!StringUtils.hasText(memberVO.getMemPwd())){
           // errors.put("memPwd", "* 비밀번호는 필수항목입니다.");
            bindingResult.addError(new FieldError("memberVO""memPwd""* 비밀번호는 필수항목입니다."));
        }
        if(memberVO.getMemAge() > 100 && memberVO.getMemAge() != 0){
            //errors.put("memAge", "* 나이는 1 ~ 99 까지입니다.");
            bindingResult.addError(new FieldError("memberVO""memAge""* 나이는 1 ~ 99 까지입니다."));
        }
        
        if(bindingResult.hasErrors()) {
            log.info("errors = {}", bindingResult);
            return "/join";
        }
        /*
        if(!errors.isEmpty()){
            log.info("errors ={}", errors);
            model.addAttribute("errors", errors );
            return "/join";
        }
        */
        memberService.insertMember(memberVO);
        
        return "redirect:/";
    }
cs

 

Map에 담았던 errors를 bindingResult로 바꿔 넣었다.

FieldError는 두 가지의 생성자를 제공하는데 아래 문법이 바로 첫번째 생성자이다. 두번째 생성자는 검증-3 에서 다뤄보자.

bindingResult.addError(new FieldError (객체 이름, 필드 이름, 오류메시지)); 

그리고 bindingResult는 자동으로 View에 넘어간다. 따라서 modelAttribute가 필요없다.

 

중요할 사항으로,

* BindingResult bindingResult 파라미터의 위치는 @ModelAttribute MemberVO memberVO 다음에 위치해야한다.

 

 

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
    xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="/css/join.css">
 <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
<form action="/joinCommit" method="post" th:object="${memberVO}" >
  <div class="container">
    <h2 class="text-center">로그인</h2>
    <div class="form-group">
      <label for="memId">아이디:</label>
      <input type="text" th:field="*{memId}">
      <!-- <div class="errorText" th:if="${errors?.containsKey('memId')}" th:text="${errors['memId']}"></div> -->
      <!-- <div class="errorText"  th:if="${#fields.hasErrors('memId')}" th:text="${#fields.errors('memId')}"></div> -->
      <div class="errorText"  th:errors="*{memId}"></div>
    </div>
    <div class="form-group">
      <label for="memPwd">비밀번호:</label>
      <input type="password" th:field="*{memPwd}" placeholder="다시 입력하세요.">
      <!-- <div class="errorText" th:if="${errors?.containsKey('memPwd')}" th:text="${errors['memPwd']}"></div> -->
      <div class="errorText"  th:errors="*{memPwd}"></div>
    </div>
    <div class="row">
      <div class="col-9">
        <div class="form-group">
          <label for="memName">이름:</label>
          <input type="text" th:field="*{memName}" >
         <!--  <div class="errorText" th:if="${errors?.containsKey('memName')}" th:text="${errors['memName']}"></div> -->
          <div th:errorclass="errorText"  th:errors="*{memName}"></div>
        </div>
      </div>
      <div class="col-3">
        <div class="form-group">
          <label for="memAge">나이:</label>
          <input type="text" th:field="*{memAge}">
          <!-- <div class="errorText" th:if="${errors?.containsKey('memAge')}" th:text="${errors['memAge']}"></div> -->
          <div class="errorText"  th:errors="*{memAge}"></div>
        </div>
      </div>
    </div>
    <div class="form-group buttons">
        <input type="submit" value="완료">
    </div>
  </div>
</form>
</body>
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
</html>
cs

<div class="errorText" th:if="${errors?.containsKey('memId')}" th:text="${errors['memId']}"></div> 을 대신해서
<div class="errorText"  th:if="${#fields.hasErrors('memId')}" th:text="${#fields.errors('memId')}"></div> 을 써준다.
#fields는 BindingResult가 제공하는 검증 오류에 접근할 수 있다.
하지만, 더 간단하게 표현하기 위해 
<div> class="errorText" th:errors="*{memId}"></div> 와 같이바꿔주었다.
th:errors : 해당 필드에 오류가 있는 경우 태그를 출력한다. th:if의 편의 버전.
사용하진 않았지만, th:errorclass : th:field 에서 지정한 필드에 오류가 있으면  class 정보를 추가할 수 있다.

BindingResult는 에러가 뜨면, 페이지 오류대신 나이와 같이 오류 메시지가 직접 표기되는 장점이 있다.

 

하지만, 아이디는 필수항목, 비밀번호는 필수항목, 이름은 필수항목과 같이 다른 곳에서도 중복으로 사용해야할 경우가 있을 것이다. 그럴 때마다 컨트롤러에 new FieldError를 만들어버리면 굉장히 중복된 코드가 많아질 것이다. 

따라서 다음엔 properties에 오류메시지를 등록해 일괄적으로 관리를 해보려고한다.

 

 

[Spring] 검증(Validation) -3 , FieldError와 properties값 가져오기

[Spring] 검증(Validation) -2 BindingResult MemberController BindingResult 데이터 바인딩 과정에서 발생하는 검증 오류를 보유하고 있는 객체이다. 주로 폼 데이터를 도메인 객체에 바인딩할 때 사용된다. 예를

bright-landscape.tistory.com

 

728x90
반응형

댓글