쌓고 쌓다

유효성 검사 직접 처리 및 폼 데이터 유지 방법 본문

프로그래밍/spring

유효성 검사 직접 처리 및 폼 데이터 유지 방법

승민아 2023. 8. 27. 21:33

폼에 데이터를 입력하여 서버에 전달했다.

이때 유효하지 않은 데이터가 있다면 다시 데이터를 작성할 필요가 있다.

이때 작성한 데이터는 유지하고 에러 내용을 같이 넘겨보자.

 

 

폼 데이터 유지

먼저 폼 데이터 유지 방법에 대해 보자.

 

@GetMapping("/add")
public String addForm(Model model) {
    model.addAttribute("item", new Item());
    return "validation/v1/addForm";
}

입력 폼을 요청이 들어왔을때 입력 폼을 통해 바인딩할 빈 객체를 하나 생성해서 넣어준다.

이렇게 빈 객체를 왜 넣어줘야하나싶지만

유효성 검사나 재사용에 매우 좋은 효과를 얻을 수 있다.

 

<form th:action th:object="${item}" method="post">
    <input type="text" id="itemName" th:field="*{itemName}">
</form>

입력 폼에서 th:object와 th:field로 많은 이점을 누릴 수 있다.

 

여기선 유효성 검사와 재사용을 이점을 든다.

 

@PostMapping("/add")
public String addItem(@ModelAttribute Item item, Model model) {

    //검증에 실패하면 다시 입력 폼으로
    if(!errors.isEmpty()) {
        ...
        return "validation/v1/addForm";
    }

}

폼 데이터를 전송하여 서버에서 처리하는 메서드이다.

여기서 에러가 발생했을때 다시 입력 페이지를 보여준다.

이때 @ModelAttribute는 자동으로 model에 "item"을 키값으로 item 값을 넣고 보여준다.

그러면 어떤 일이 일어나나?

 

<form th:action th:object="${item}" method="post">
    <input type="text" id="itemName" th:field="*{itemName}">
</form>

입력 페이지 폼 태그에 th:object에 item이 담겨

th:field로 다시 해당 필드의 값들을 로드하여 폼 데이터를 그대로 유지할 수 있다.

 

유효성 검사

@PostMapping("/add")
    public String addItem(@ModelAttribute Item item, Model model) {

        // 유효성 에러 보관
        Map<String, String> errors = new HashMap<>();

        //필드 검증
        if(!StringUtils.hasText(item.getItemName())) {
            errors.put("itemName", "상품 이름은 필수입니다.");
        }
        
        //복합 검증 - 특정 필드가 아닌 검증
        if(item.getPrice()!=null&&item.getQuantity()!=null) {
            int resultPrice = item.getPrice()*item.getQuantity();
            if(resultPrice<10000) {
                errors.put("globalError", "가격*수량의 합은 10,000원 이상어야야합니다. 현재 값:"+resultPrice);
            }
        }

        //검증에 실패하면 다시 입력 폼으로
        if(!errors.isEmpty()) {
            model.addAttribute("errors", errors);
            return "validation/v1/addForm";
        }
        
        ...
    }

Map을 통해 Key는 에러 필드, Value는 에러 내용을 담는다.

조건문을 통해 원하는 데이터의 형식이 아닐 경우 Map에 에러 내용을 담는다.

 

유효성 검증의 끝부분에 Map이 비어있지 않다면 에러가 발생한 경우이므로

다시 입력 페이지로 넘어가게한다. 이때 Map을 함께 넘긴다.

 

에러 내용 출력

<div th:if="${errors?.containsKey('globalError')}">
    <p class="field-error" th:text="${errors['globalError']}">전체 오류 메시지</p>
</div>

글로벌 에러 같은 경우 해당 키가 있다면 태그를 보이게하여 오류 내용을 출력하면 된다.

errors['key']는 Map에서 해당 키 'key'의 값을 꺼낼때 사용한다.

 

errors?.containsKey의 경우 ?는 타임리프의 문법인데 

null이 아닌경우에 해당 로직을 수행하게할 수 있다.

null인 경우에 erros.containsKey에 접근하는경우 NullException이 발생하기에 주의하자.

 

<div class="field-error" th:if="${errors?.containsKey('itemName')}" th:text="${errors[itemName]}">
    상품명 오류
</div>

필드 에러의 경우 글로벌 에러에서 본 형태와 동일하다

?. 문법으로 null이 아닌경우 키값으로 해당 에러가 있는지 확인하고

있다면 value로 꺼내 출력해주자.

Comments