티스토리 뷰
Chapter13. 유효성 검사 : 도서 등록 페이지의 오류 메시지 출력하기
13.1 유효성 검사의 개요
유효성 검사는 폼 페이지에서 입력 항목의 데이터 값이 서버로 전송되기 전에 정해진 규정으로 정확히 입력되었는지 계산 결과 등이 타당한지 검사하는 것이다.
예를 들어 숫자 검사, 아이디 중복 검사, 로그인 인증 시 아이디나 패스워드 검사, IP 패킷 검사 등이 있다.
13.1.1 유효성 검사의 유형
- JSR-380(Java Bean Validation 2.0) 방식 : 웹 애플리케이션을 구성하는 특정 도메인 클래스의 멤버 변수, 즉 필드에 대한 유효성 검사 제약 사항(constraints) 애너테이션을 선언하여 해당 값이 올바른지 검증하는 방식
- Validator 인터페이스의 구현체 방식 : 웹 애플리케이션을 구성하는 특정 도메인 클래스의 멤버 변수에는 제약 사항 애너테이션을 선언하지 않는다. 그 대신 스프링에서 제공하는 Validator 인터페이스로 구현하고 이를 Validator 인스턴스로 사용하여 해당 속성 값의 유효성 검사를 수행한다. 스프링 Validator 인터페이스는 애플리케이션의 모든 계층에서 유효성 검증을 위해 사용할 수 있다.
* 두가지 방법은 결과가 비슷한데 방식이 조금 다르다.
유효성 검사를 해야하는 폼 데이터 항목
- 입력 데이터가 null인지에 대한 유효성 검사
- 날짜나 이메일을 입력할 떄 형식에 맞느지에 대한 유효성 검사
- 나이를 입력할 떄 숫자인지에 대한 유효성 검사
- 입력 데이터의 제한 길이를 초과했는지에 대한 유효성 검사
- 로그인 인증을 할 때 아이디와 패스워드에 대한 유효성 검사
- 회원 가입을 할 때 아이디 중복 여부에 대한 유효성 검사
입력 데이터의 유효성 검사 기능을 이용한다면 다양한 사용자가 작성하는 페이지임에도 폼 페이지는 동일한 양식과 형태를 유지할 수 있다.
13.1.2 @Valid를 이용한 유효성
스프링 MVC에서는 사용자가 폼 페이지에서 입력한 데이터의 유효성을 검사하기 위해 코드를 작성할 필요 없이 @Valid 애너테이션을 제공한다.
@Valid 사용하기 위한 환경설정
@Valid 는 스프링 MVC에서 사용자가 폼 페이지에서 입력한 데이터의 유효성 검사를 위해 코드를작성할 필요 없이 간단한 방법으로 @Valid 애너테이션을 제공한다.
step1. pom.xml 파일에 의존 라이브러리 등록하기
@Valid 를 이용해 폼 데이터 값에 대한 유효성 검사를 하고자하면 pom.xml 파일에 validation-api.jar과 hibernate-validator.jar 의존 라이브러리를 등록해야 한다.
<!-- Validation-->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.2.Final</version>
</dependency>
stpe2. 요청 처리 메서드의 매개변수에 @Valid 선언하기
@Vlid를 이용하면 컨트롤러 내 요청 처리메서드의 매개변수에 전달되는 폼데이터 값에 대한 유효성 검사를 실행할 수 있다.
@PostMapping("/...")
public String 메서드 이름(@Valid 매개변수, ..., BindinfReuslt result){
if(result.hasErrors()){
//오류 메시지 저장
}
return "뷰 이름";
}
* @Valid 매개변수와 input 매개변수, form:errors path의 변수 이름은 모두 같아야 한다.
step3. 뷰 페이지에 오류 메시지 출력하기
유효성 검사를 해 발생한 오류 메시지를 jsp 뷰 페이지에 출력하려면 폼 태그 라이브러리인 <form:errors> 태그를 사용해야 한다.
<%@ taglib prefix="form" uri="http://www.springframework.org.tags" %>
...
<form:errors path="커맨드 객체의 멤버 변수 이름">
13.2 JSR-380으로 유효성 검사
JSR-380 애너테이션을 이용한 유효성 검사는 웹 애플리케이션을 구성하는 특정 도메인 클래스(DTO)의 프로퍼티(멤버 변수), 필드에 대해 유효성 검사의 제약 사항 애너테이션을 선언해 해당 멤버 변수 값이 오른지 검사하는 것이다.
이것은 Bena Validation 2.0이라고 부른다.
13.2.1 JSR-380 애너테이션 선언
유효성 검사가 필요한 도메인 클래스의 프로퍼티에 제약 사항을 설정하기 위해 JSR-380 애너테이션을 사용한다.
이때 애너테이션의 작성 위치는 DTO 변수의 위에 작성된다.
public class 클래스 이름{
@제약 사항 애너테이션(속성[, message="오류 메시지 또는 [오류 코드]"])
private String 멤버 변수;
...
//Setter()와 Getter() 메서드 구현 생략
}
JSR-380 애너테이션 유형
유형 | 설명 | 속성 |
@AssertFalse | 프로퍼티 값이 거짓인지 검사합니다. | |
@AssertTrue | 프로퍼티 값이 참인지 검사합니다. | |
@DecimalMax | 프로퍼티 값이 가질 수 있는 최대 실수 값을 검사한다. | - value : 값 - inclusive : true/false |
@DecimalMin | 프로퍼티 값이 가질 수 있는 최소 실수 값을 검사한다. | - value : 값 - inclusive : true/false |
@Digits | 프로퍼티가 가질 수 있는 지정된 범위(정수 부분의 자릿수와 소수 부분의 자릿수)를 검사한다. | - integer : 정수의 자릿수 - fraction : 소수의 자릿수 |
@Future | 프로퍼티 값이 미래 날짜(현재일 이후)인지 검사한다. | |
@Max | 프로퍼티 값이 가질 수 있는 최대 길이를 검사한다. | value : 값 |
@Min | 프로퍼티 값이 가질 수 있는 최소 길이를 검사한다. | value : 값 |
@NotNull | 프로퍼티 값이 Null이 아닌지 검사한다. | |
@Null | 프로퍼티 값이 Null인지 검사한다 | |
@Past | 프로퍼티 값이 과거 날짜(현재일 이전)인지 검사한다 | |
@Pattern | 프로퍼티 값이 정의된 정규 표현식에 일치하는 지 검사한다. | regexp : 정규표현식 |
@Size | 프로퍼티 값이 가질 수 있는 최대, 최소 길이를 검사한다. | - min : 최소 길이 - max : 최대 길이 |
@Valid | 객체에 대해 유효성 검사를 한다. |
JSR-380 의 기본 메시지 사용하기
유효성 검사 시 JSR-380이 선언된 클래스의 멤버 변수가 제약사항을 위반해 오류가 발생하면 hibernate-validator-xx.jar 라이브러리에서 제공하는 기본 메시지가 출력된다.
만약 기본 메시지가 아닌 사용자 정의 오류 메시지를 출력하려면 message 속성 값에 출력할 오류 메시지를 직접설정해야 한다.
JSR-380의 기본 메시지
애너테이션 | 기본 메시지 |
@AssertFalse | 반드시 거짓(false)이어야 합니다. |
@AssertTrue | 반드시 참(true)이어야 합니다. |
@DecimalMax | 반드시 {value}보다 같거나 작아야 합니다. |
@DecimalMin | 반드시 {value}보다 같거나 커야 합니다. |
@Digits | 숫자 값이 허용 범위를 벗어납니다(허용 범위:<{integer} 자리>.<{fraction} 자리>). |
@Future | 반드시 미래 날짜이어야 합니다. |
@Max | 반드시 {value}보다 같거나 작아야 합니다. |
@Min | 반드시 {value}보다 같거나 커야 합니다. |
@NotNull | 반드시 값이 있어야 합니다. |
@Null | 반드시 값이 없어야 합니다. |
@Past | 반드시 과거 날짜이어야 합니다. |
@Patern | 정규 표현식 "{regexp}" 패턴과 일치해야 합니다. |
@Size | 반드시 최솟값 {min}과(와) 최댓값 {max} 사이의 크기이어야 합니다. |
사용자 정의 오류 메시지 설정하기
기본 메시지가 아닌 사용자 정의 메시지를 출력하려면 message 속성을 사용해야 한다.
message 속성 값에 출력할 오류 메시지를 직접 정의하거나 메시지 리소스 파일(*.proeprties)을 만들어 '오류 코드=출력할 오류 메시지' 형식으로 정의해 message 속성 값에 오류 코드를 설정한다.
애너테이션.커맨드 객체 이름.필드 이름 = 출력할 오류 메시지
or
애너테이션 = 출력할 오류 메시지
@NotNull 애너테이션과 @Min 애너테이션에 오류 메시지 설정한 예시 (속성.클래스.key)
Notnull.Product.name = 값을 입력해주세요
Min.Product.price = 0 이상의 값을 입력해 주세요
13.2.2 @Valid 를 이용한 유효성 검사
@PostMapping("/add")
public String submitAddNewBook(@Valid @ModelAttribute("NewBook") Book book, BindingResult result, HttpServletRequest request) {
if(result.hasErrors()) {
return "addBook";
}
MultipartFile bookImage = book.getBookImage();
폼 페이지에서 입력된 값이 커맨드 객체 book으로 매핑될 때 유효성 검사를 진행한다. 이때 오류가 발생하면 오류 결과 값은 reulst 객체에 담기고 뷰 페이지인 addBooj으로 이동한다.
13.2.3 <form:errors> 태그로 오류 메시지 출력
유효성 검사를 할 때 발생한 오류 메시지를 jsp 뷰 페이지에 출력하려면 <form:errors> 태그를 사용해야한다.
<div class="col-sm-6">
<form:errors path="unitPrice" cssClass="text-danger" />
</div>
unitPrice에 오류가 발생하면 message 속성에 설정된 사용자가 정의한 오류 메시지를 출력하고 설정되어 있지 않으면 기본 메시지를 출력한다.
13.2.4 JSR-380을 이용해 유효성 검사하기
pom.xml
<!-- Validation-->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.2.Final</version>
</dependency>
messages.properties
Pattern =\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uB3C4\uC11CID\uC785\uB2C8\uB2E4(\uC22B\uC790\uB85C \uC870\uD569\uD558\uACE0 ISBN\uC73C\uB85C \uC2DC\uC791\uD558\uC138\uC694).
Size =\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uB3C4\uC11C\uBA85\uC785\uB2C8\uB2E4(\uCD5C\uC18C 4\uC790\uC5D0\uC11C \uCD5C\uB300 50\uC790\uAE4C\uC9C0 \uC785\uB825\uD558\uC138\uC694).
Min =\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uAC00\uACA9\uC785\uB2C8\uB2E4(0\uC774\uC0C1\uC758 \uC218\uB97C \uC785\uB825\uD558\uC138\uC694)
Digits =\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uAC00\uACA9\uC785\uB2C8\uB2E4(\uC18C\uC218\uC810 2\uC790\uB9AC\uAE4C\uC9C0, 8\uC790\uB9AC\uAE4C\uC9C0 \uC785\uB825\uD558\uC138\uC694)
NotNull = \uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uAC00\uACA9\uC785\uB2C8\uB2E4(\uAC00\uACA9\uC744 \uC785\uB825\uD558\uC138\uC694).
Book.java
public class Book
{
@Pattern(regexp="ISBN[1-9]+")
private String bookId;
@Size(min=4, max=50)
private String name;
@Min(value=0)
@Digits(integer=8, fraction=2)
@NotNull
private int unitPrice;
.......
}
BookController.java
@PostMapping("/add")
public String submitAddNewBook(@Valid @ModelAttribute("NewBook") Book book, BindingResult result, HttpServletRequest request) {
if(result.hasErrors()) {
return "addBook";
}
MultipartFile bookImage = book.getBookImage();
addBook.jsp
에러가 생기면 출력하기 위해 <form:errors>를 추가적으로 입력해준다.
<div class="col-sm-6">
<form:errors path="bookId" cssClass="text-danger" />
</div>
<div class="col-sm-6">
<form:errors path="name" cssClass="text-danger" />
</div>
<div class="col-sm-6">
<form:errors path="unitPrice" cssClass="text-danger" />
</div>
<body>
<nav class="navbar navbar-expand navbar-dark bg-dark">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="./home">Home</a>
</div>
</div>
</nav>
<div class="jumbotron">
<div class="container">
<!-- <h1 class="display-3">도서 등록</h1> -->
<h1 class="display-3">
<spring:message code="addBook.form.title.label" />
</h1>
</div>
</div>
<div class="container">
<div class="float-right">
<form:form action="${pageContext.request.contextPath }/logout" method="post">
<input type="submit" class="btn btn-sm btn-success" value="Logout" />
</form:form>
</div>
<div class="float-right" style="padding-right:30px">
<a href="?language=ko">Korean</a>|<a href="?language=en">English</a>
</div>
<br><br>
<form:form modelAttribute="NewBook" action="./add?${_csrf.parameterName }=${_csrf.token }" class="form-horizontal" enctype="multipart/form-data">
<fieldset>
<%-- <legend>${addTitle}</legend> --%>
<legend><spring:message code="addBook.form.subtitle.label" /></legend>
<div class="form-group row">
<label class="col-sm-2 control-label">
<!-- <label class="col-sm-2 control-label">도서ID</label> -->
<spring:message code="addBook.form.bookId.label" />
</label>
<div class="col-sm-3">
<form:input path="bookId" class="form-control" />
</div>
<div class="col-sm-6">
<form:errors path="bookId" cssClass="text-danger" />
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 control-label">
<!-- <label class="col-sm-2 control-label">도서명</label> -->
<spring:message code="addBook.form.name.label" />
</label>
<div class="col-sm-3">
<form:input path="name" class="form-control" />
</div>
<div class="col-sm-6">
<form:errors path="name" cssClass="text-danger" />
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 control-label">
<!-- <label class="col-sm-2 control-label">가격</label> -->
<spring:message code="addBook.form.unitPrice.label" />
</label>
<div class="col-sm-3">
<form:input path="unitPrice" class="form-control" />
</div>
<div class="col-sm-6">
<form:errors path="unitPrice" cssClass="text-danger" />
</div>
</div>
'코딩 > spring' 카테고리의 다른 글
[17주 1일차] 유효성 검사 (2) (0) | 2024.01.29 |
---|---|
spring & jsp 객체 & 애너테이션 정리 (0) | 2024.01.29 |
[16주 4일차] 다국어 처리 : 도서 등록 페이지에서 다국어 페이지 만들기 (0) | 2024.01.25 |
[16주 4일차] 로그 순서 (1) | 2024.01.25 |
[16주 4일차] 로그 (2) (0) | 2024.01.25 |
- Total
- Today
- Yesterday