[Spring] Validation 검증

JJoSuk·2023년 6월 8일
0

본 프로젝트 자료는 김영한님의 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술을 참고 제작됐음을 알립니다.

Validation 검증을 배워볼려고 한다.

요구사항: 검증 로직 추가 타입 검증

  • 가격, 수량에 문자가 들어가면 검증 오류 처리 필드 검증
  • 상품명: 필수, 공백X
  • 가격: 1000원 이상, 1백만원 이하 수량: 최대 9999
  • 특정 필드의 범위를 넘어서는 검증
  • 가격 * 수량의 합은 10,000원 이상

지금까지 만든 웹 애플리케이션은 폼 입력시 숫자를 문자로 작성하거나해서 검증 오류가 발생하면 오류 화면으로 바로 이동했다.

이 부분이 발생하지 않게 직접적으로 화면에 오류를 띄울 수 있게 만들어 볼려고 한다.

예시 화면

컨트롤러의 중요한 역할중 하나는 HTTP 요청이 정상인지 검증하는 것이다.
그리고 정상 로직보다 이런 검증 로직을 잘 개발하는 것이 어쩌면 더 어려울 수 있다.

참고: 클라이언트 검증, 서버 검증

  • 클라이언트 검증은 조작할 수 있으므로 보안에 취약하다.
  • 서버만으로 검증하면, 즉각적인 고객 사용성이 부족해진다.
  • 둘을 적절히 섞어서 사용하되, 최종적으로 서버 검증은 필수
  • API 방식을 사용하면 API 스펙을 잘 정의해서 검증 오류를 API 응답 결과에 잘 남겨주어야 함

자 그럼, 지금부터 이 화면을 만들 수 있게 목표로 하고 작업 해볼까 한다.


검증 직접 처리

위 사진과 같이 고객이 상품 등록 폼에서 상품명을 입력하지 않거나, 가격, 수량 등이 너무 작거나 커서 검증 범위를 넘어서면, 404 화면이나 500 화면 보다는 서버 검증 로직이 실패해야 한다. 이렇게 검증에 실패한 경우 고객에게 다시 상품 등록 폼을 보여주고, 어떤 값을 잘못 입력했는지 친절하게 알려주어야 한다.

현재 요구사항에 맞게 검증 로직을 작성해보고 이해해보고자 한다.

검증 직접 처리 - 개발

예제 코드

@PostMapping("/add")
    public String addItem(@ModelAttribute Item item, RedirectAttributes redirectAttributes, Model model) {
    Item savedItem = itemRepository.save(item);
        redirectAttributes.addAttribute("itemId", savedItem.getId());
        redirectAttributes.addAttribute("status", true);
        return "redirect:/validation/v1/items/{itemId}";
    }

성공 했을 때의 로직 안에 실패 했을 경우의 수를 만들어줘야 위에 요구사항에 맞게 수정할 수 있다. 우선,

검증 오류 보관

검증했을 때 실패 시 어떠한 오류가 생겼는지 정보를 저장해주는 보관소를 만들어야 한다.

검증 로직

  • 검증했을 때 오류가 발생하면 errors 에 담아둔다.
  • 뷰에서 로직 검증을 실패 했을 때 필드명를 Key 로 사용해, 친절한 오류 메시지를 출력할 수 있게 만들어줘야 한다.

추가 로직

특정 필드의 범위를 넘어서는 검증 로직

특정 필드를 넘어서는 오류를 처리해야할 때 필드명을 Key 를 사용할 수 없어 global 을 이용해 대체 Key 로 입력한다.

검증에 실패하면 다시 입력 폼으로

만약 검증에서 오류 메시지가 하나라도 있으면 오류 메시지를 출력하기 위해 model 에 errors 를 담고, 입력 폼이 있는 뷰 템플릿으로 보낸다.

이제 오류 출력할 로직이 준비 끝났으면 HTML로 넘어가 마무리를 해보자.

HTML

상품 등록 form 안에 div(전체 오류 메시지) 를 집어넣어 복합 오류가 발생했을 때 감지 및 오류 처리를 하게 해준다.

그 이후 단일 로직들은 각 input 에 검증 로직을 넣어 입력 오류가 발생 시 오류 처리해줄 수 있게 처리해준다.

글로벌 오류 메시지

입력했을 경우 오류 발생 시 아래와 같이 화면에 출력된다.

복합오류 같은 경우 타임리프의 th:if 를 사용해 조건을 만족했을 경우 해당 오류 메시지를 출력해준다.

나머지들도 똑같이 적용해주면 끝난다.

가격 입력 창

입력했을 경우 오류 발생 시 아래와 같이 화면에 출력된다.

수량 입력 창

입력했을 경우 오류 발생 시 아래와 같이 화면에 출력된다.

출력 결과

하지만 경고로 보기엔 글씨가 검정색이라 검정으로 보이지 않고 경고라고 인식하기엔 색상이 경각심을 심어주지 않는다.

빨간색으로 변환시켜보자.

HTML Style

넣어주면 빨간색으로 출력할 수 있다.

적용할 장소도 추가 입력해줘야 한다.

ㅁ 경고 메시지 색상 변경

ㅁ 테두리도 같이 색상 변경 시켜줬다.

결과 화면


BindingResult

바인딩리절트 는 위에 배운 방식을 좀 더 효율적으로 코드를 고치기 위해 사용해볼려고 한다.

  • 수정하기 전에 코드 하나를 추가해줘야 한다.
  • BindingResult bindingResult

검증 로직

수정 전

수정 후

글로벌 오류 메시지

수정 전

수정 후

검증에 실패하면 다시 입력 폼으로

수정 전

수정 후

특정 필드의 범위를 넘어서는 검증 로직

수정 전

수정 후

  • 주의: @ModelAttribute Item item 뒤로 BindingResult bindingResult 넣어야 한다. 순서가 바뀌면 x

필드 오류 - FieldError

  • 특정 필드를 넘어서는 오류가 있으면 ObjectError 객체를 생성해서 bindingResult 에 담아두면 된다.
  • objectName : @ModelAttribute 의 이름
  • defaultMessage : 오류 기본 메시지

뒤로 HTMl 도 수정해줘야 작동하는지 확인할 수 있다.

HTML

수정 전

수정 후

코드가 간결해진걸 확인할 수 있다.

타임리프 스프링 검증 오류 통합 기능

  • 타임리프는 스프링의 BindingResult 를 활용해서 편리하게 검증 오류를 표현하는 기능을 제공한다.
  • #fields : #fields 로 BindingResult 가 제공하는 검증 오류에 접근할 수 있다.
  • th:errors : 해당 필드에 오류가 있는 경우에 태그를 출력한다. th:if 의 편의 버전이다.
  • th:errorclass : th:field 에서 지정한 필드에 오류가 있으면 class 정보를 추가한다.

FieldError, ObjectError

위 코드 작동 방식

  • 잘못된 값을 입력했을 때 화면에서 잘못된 값이 날아가지 않고 보존.

이렇게 코드를 변경하면 잘못된 값을 입력하더라도 코드가 유지하는 모습을 확인할 수 있다.

위 사진과 같이 가격은 Integer 로 설정되어 있어 문자를 입력 할 경우 보관할 방법이 없어 저장되지 않는다. 하지만 FieldError 는 오류 발생시 사용자 입력 값을 저장하는 기능을 제공해 유지하는 모습을 보여준다.

여기서 rejectedValue 가 바로 오류 발생시 사용자 입력 값을 저장하는 필드다.
bindingFailure 는 타입 오류 같은 바인딩이 실패했는지 여부를 적어주면 된다. 여기서는 바인딩이 실패한 것은 아니기 때문에 false 를 사용한다.

profile
안녕하세요

0개의 댓글