<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>${javax.validation-version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${org.hibernate.validator-version}</version>
</dependency>
@AssertTrue : true
@AssertFalse : false
@Max(value) : value 값이 최대! (value 값보다 크면 오류)
@Min : value 값이 최소! (value 값보다 작으면 오류)
@DecimalMax(value=, inclusive=true/false) : value 값이 최대! true value<=, false value <
ex) DecimalMax(value=100, inclusive=false) < 100
ex) DecimalMax(value=100, inclusive=true) <= 100
@DecimalMin(value=, inclusive=true/false)
@Null : Null 이어야 한다. (값이 없어야 정상)
@NotNull : Null이 아니어야 한다. (값이 있어야 정상)
@Digits(integer=3, fraction=5) : 숫자 자릿수!
ex) integer 세자리수(정수형 3자리수) fraction(소수점자릿수 5자리)
@Size(min=5, max=10) : 글자 자릿수 (5~10자리면 정상)
@Pattern(regexp=정규식) : 정규식이 맞아야 정상!
ex) @Pattern(regexp="^01([0|1|6|7|8|9])-?([0-9]{3,4})-?([0-9]{4})$/;");
@NotEmpty : 값이 뭐라도 있어야 정상! (띄어쓰기 입력하며 인정)
@NotBlank : 값이 뭐라도 있어야 정상! (띄어쓰기 제외하고 뭐라도 입력)
@Positive : 양수가 들어와야 정상
@PositiveOrZero : 양수 + 0까지 인정
@Negative : 음수가 들어와야 정상
@NegativeOrZero : 음수 + 0까지 인정
@Email : 이메일 형식이 맞아야한다. (입력값 사이에 @가 있느냐)
ex) ab@cd : 이메일로 인정
ex. input에 들어온 값의 유효성 검사 후, 형식에 맞지 않을 경우 오류 메세지를 화면에 띄워주는 경우
package com.app.dto;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
public class InputFormDto {
// 길이 8~14
@Size(min = 8, max = 14)
String input1;
// 값이 최대 1000
@Max(1000)
String input2;
// 띄어쓰기 제외한 값이 뭐라도 입력 되어야함
@NotBlank
String input3;
public String getInput1() {
return input1;
}
public void setInput1(String input1) {
this.input1 = input1;
}
public String getInput2() {
return input2;
}
public void setInput2(String input2) {
this.input2 = input2;
}
public String getInput3() {
return input3;
}
public void setInput3(String input3) {
this.input3 = input3;
}
}
@PostMapping("/valid_form")
public String valid_input(@Valid InputFormDto inputFormDto ,
BindingResult bindingResult,
Model model) {
//@Valid 요청으로 부터 들어온 값을 inputFormDto 객체에 매핑 시키고
//내부에 Valid 검증 유효성 기준으로 검증을 수행해달라
System.out.println(inputFormDto.getInput1()); // 1234
System.out.println(inputFormDto.getInput2()); // 5000
System.out.println(bindingResult); // org.springframework.validation.BeanPropertyBindingResult: 4 errors (..이하 생략)
if(bindingResult.hasErrors()) { // 에러가 있을 경우 true
System.out.println("잘못된게 있다.");
for(ObjectError objErr : bindingResult.getAllErrors()) {
// ObjectError타입의 List 리턴받음
System.out.println("---------------------------");
System.out.println(objErr.getDefaultMessage());
System.out.println(objErr.getObjectName());
System.out.println(objErr.getCode());
String[] codes = objErr.getCodes();
System.out.println("---------codes------------");
for(String str : codes) {
System.out.println(str);
}
if(codes[0].equals("Size.inputFormDto.input1")) {
System.out.println("얘는 input1 사이즈가 잘못됐다.");
}
if(codes[0].equals("Max.inputFormDto.input2")) {
System.out.println("얘는 input2 맥스값 잘못됐다.");
}
if(codes[0].equals("NotBlank.inputFormDto.input3")) {
System.out.println("얘는 input3 공백이면 안되는데...");
}
}
model.addAttribute("isError", "true");
return "valid_form";
}
return "valid_end";
}
org.springframework.validation.BeanPropertyBindingResult: 4 errors
Field error in object 'inputFormDto' on field 'input3': rejected value []; codes [NotBlank.inputFormDto.input3,NotBlank.input3,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [inputFormDto.input3,input3]; arguments []; default message [input3]]; default message [공백일 수 없습니다]
Field error in object 'inputFormDto' on field 'input1': rejected value [1234]; codes [Size.inputFormDto.input1,Size.input1,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [inputFormDto.input1,input1]; arguments []; default message [input1],14,8]; default message [크기가 8에서 14 사이여야 합니다]
Field error in object 'inputFormDto' on field 'input2': rejected value [5000]; codes [Max.inputFormDto.input2,Max.input2,Max.java.lang.String,Max]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [inputFormDto.input2,input2]; arguments []; default message [input2],1000]; default message [1000 이하여야 합니다]
bindingResult.hasErrors() : boolean값 리턴 (오류가 있는지 없는지)!
bindingResult.hasAllErrors() : ObjectError 타입의 List 리턴
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
.errMsg {
color:red;
font-style: italic;
}
</style>
</head>
<body>
<h1>valid_view</h1>
<form action="" method="post">
<label>input1<input type="text" name="input1" value="${inputFormDto.input1}"></label><br/>
<span class="errMsg">
<!-- name : 오류 검사를 해야하는 객체 이름 -->
<spring:hasBindErrors name="inputFormDto">
<!-- input1에 대한 에러를 가지고 있으면 (boolean) -->
<!-- hasBindErrors 태그 안에 있어야 bindingResult 안에 있는 errors 값에 접근 가능 -->
<c:if test="${errors.hasFieldErrors('input1') }">
<!-- input3에 대한 에러를 가져와서 defaultMessage 출력 -->
${errors.getFieldError('input1').defaultMessage}
<br />
<spring:message code="${errors.getFieldError('input1').codes[0]}" /> (spring message로 처리한 custom error message)
<!-- Size.inputFormDto.input1 -->
</c:if>
</spring:hasBindErrors>
</span>
<hr/>
<label>input2<input type="text" name="input2" value="${inputFormDto.input2}"></label><br/>
<span class="errMsg">
<!-- name : 오류 검사를 해야하는 객체 이름 -->
<spring:hasBindErrors name="inputFormDto">
<!-- input2에 대한 에러를 가지고 있으면 (boolean) -->
<!-- hasBindErrors 태그 안에 있어야 bindingResult 안에 있는 errors 값에 접근 가능 -->
<c:if test="${errors.hasFieldErrors('input2') }">
<!-- input2에 대한 에러를 가져와서 defaultMessage 출력 -->
${errors.getFieldError('input2').defaultMessage}
<br />
<spring:message code="${errors.getFieldError('input2').codes[0]}" />(spring message로 처리한 custom error message)
<!-- Max.inputFormDto.input2 -->
</c:if>
</spring:hasBindErrors>
</span>
<hr/>
<label>input3<input type="text" name="input3" value="${inputFormDto.input3}"></label><br/>
<span class="errMsg">
<!-- name : 오류 검사를 해야하는 객체 이름 -->
<spring:hasBindErrors name="inputFormDto">
<!-- input3에 대한 에러를 가지고 있으면 (boolean) -->
<!-- hasBindErrors 태그 안에 있어야 bindingResult 안에 있는 errors 값에 접근 가능 -->
<c:if test="${errors.hasFieldErrors('input3') }">
<!-- input3에 대한 에러를 가져와서 defaultMessage 출력 -->
${errors.getFieldError('input3').defaultMessage}
<br />
<spring:message code="${errors.getFieldError('input3').codes[0]}" />(spring message로 처리한 custom error message)
<!-- NotBlank.inputFormDto.input3 -->
</c:if>
</spring:hasBindErrors>
</span>
<hr/>
<c:if test="${isError == true }">
입력 내용을 확인해주세요.
</c:if>
<button type="submit">보내기</button>
</form>
</body>
</html>
errors.properties 파일 내용 : 에러 코드와 키값을 맞춰줌
화면 오류메세지 출력 결과
+ spring 자체에서 제공하는 태그들 ( 출처 : [Spring] 29. 스프링 JSP 태그 라이브러리와 <spring:message> 태그|작성자 Do KY )
요소명 | 설명 |
---|---|
<spring:message> | 클라이언트의 Locale에 따라 다른 메시지를 출력한다. (국제화) |
<spring:theme> | 사용자가 지정한 테마에 따라 다른 stylesheet를 적용한다. |
<spring:argument> | 메시지의 플레이스홀더(인덱스 값)의 값을 지정한다. <spring:message> 또는 <spring:theme>의 arguments 속성 대신 사용할 수 있다. |
<spring:hasBindErrors> | 입력값 검사 오류, 바인딩 오류의 발생 여부와 오류 정보를 출력한다. |
<spring:bind> | 지정한 객체와 프로퍼티에 연결된 바인딩 정보(BindStatus)를 구한다. |
<spring:nestedPath> | 바인딩 정보(BindingStatus)에 접근할 때 지정하는 경로에 루트 경로를 지정한다. |
<spring:url> | URL을 생성한다. |
<spring:param> | 요청 파라미터와 URL템플릿의 경로 변수값을 지정한다.<spring:url>에서 사용한다. |
<spring:htmlEscape> | HTML Escape 여부에 대한 기본값을 설정한다. |
: spring 자체에서 제공하는 인터페이스
public class MemberDtoValidator implements Validator {
@Override
// 주어진 객체(clazz)에 대해 Validator가 지원 가능한가?
public boolean supports(Class<?> clazz) {
// TODO Auto-generated method stub
return false;
}
@Override
// 주어진 객체(target)에 대해서 유효성 체크를 수행하고, 유효성 에러 발생시 주어진 Errors객체에 관련 정보를 저장할 수 있음
public void validate(Object target, Errors errors) {
// TODO Auto-generated method stub
}
}
(출처 : [java] 전자정부프레임워크 validation 사용법 )
메소드 형식 | 설명 |
---|---|
reject(String errorCode) | 전 객체에 대한 글로벌 에러 코드를 추가 |
reject(String errorCode, String defaultMessage) | 전 객체에 대한 글로벌 에러 코드를 추가하고, 에러코드에 대한 메세지가 존재하지 않을 경우 defaultMessage 사용 |
reject(String errorCode, Object[] errorArgs, String defaultMessage) | 전 객체에 대한 글로벌 에러 코드를 추가하, 메세지 인자로 errorArgs를 전달, 에러코드에 대한 메세지가 존재하지 않을 경우 defaultMessage 사용 |
메소드 형식 | 설명 |
---|---|
rejectValue(String field, String errorCode) | 필드에 대한 에러 코드를 추가 |
rejectValue(String field, String errorCode, String defaultMessage) | 필드에 대한 에러 코드를 추가하고, 에러코드에 대한 메세지가 존재하지 않을 경우 defaultMessage 사용 |
rejectValue(String field, String errorCode, Object[] errorArgs, String defaultMessage) | 필드에 대한 에러 코드를 추가, 메세지 인자로 errorArgs를 전달, 에러코드에 대한 메세지가 존재하지 않을 경우 defaultMessage 사용 |
ex. 로그인 시 아이디와 비밀번호의 길이의 유효성 검사를 해야하는 경우
1. memberDto
package com.app.dto;
public class MemberDto {
private String id;
private String pw;
private String name;
public MemberDto() {
}
public MemberDto(String id, String pw, String name) {
this.id = id;
this.pw = pw;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPw() {
return pw;
}
public void setPw(String pw) {
this.pw = pw;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "MemberDto [id=" + id + ", pw=" + pw + ", name=" + name + "]";
}
}
package com.app.validator;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import com.app.dto.MemberDto;
public class MemberDtoValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
// TODO Auto-generated method stub
return MemberDto.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
// TODO Auto-generated method stub
MemberDto memberDto = (MemberDto)target;
// 아이디에 대한 유효성 검사
if (memberDto.getId().length() < 2 || memberDto.getId().length() > 13) {
// errors 객체에 에러 코드 추가
errors.rejectValue("id", "id.sizeError", "아이디 길이를 확인해주세요");
}
// 비밀번호에 대한 유효성 검사
if (memberDto.getPw().length() < 4 || memberDto.getPw().length() > 12) {
// errors 객체에 에러 코드 추가
errors.rejectValue("pw", "pw.sizeError", "비밀번호 길이를 확인해주세요");
/*
bindingResult에서 getCodes 반복문 돌리면 아마 이런식으로 나올 것..
-----------codes-----------
pw.sizeError.memberDto.pw << properties 파일에 프로퍼티 키로 추가해서 spring:message로 처리
pw.sizeError.pw
pw.sizeError.java.lang.String
pw.sizeError
*/
}
}
}
package com.app.controller;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import com.app.dto.MemberDto;
import com.app.validator.MemberDtoValidator;
@Controller
public class QuizLoginController {
@GetMapping("/quiz_login")
public String quizView() {
return "login_form";
}
@PostMapping("/quiz_login")
public String postQuizView(@ModelAttribute MemberDto memberDto, BindingResult bindingResult) {
MemberDtoValidator mValidator = new MemberDtoValidator();
// 수동으로 유효성 검증 수행!
mValidator.validate(memberDto, bindingResult);
// validator에서 에러가 발생하면 bindingResult에 담길 것
if (bindingResult.hasErrors()) {
return "login_form";
}
return "login_success";
}
}
(출처 및 참고 : Spring form 유효성 검사 (Spring Validator) )