Validator
객체를 검증하기 위한 인터페이스. 객체 검증기(validator) 구현에 사용
수동 검증
UserValidator.java
package com.fastcampus.app;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
public class UserValidator implements Validator{
@Override
public boolean supports(Class<?> clazz) {
// TODO Auto-generated method stub
return User.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
System.out.println("LocalValidator.validate() is called");
User user = (User)target;
String id = user.getId();
// if (id==null || "".equals(id.trim())) {
// errors.rejectValue("id", "required");
// }
ValidationUtils.rejectIfEmpty(errors, "id", "required");
ValidationUtils.rejectIfEmpty(errors, "pwd", "required");
if (id==null || id.length() < 5 || id.length() > 12) {
errors.rejectValue("id", "invalidLength");
}
}
}
RegisterController.java
package com.fastcampus.app;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.beans.propertyeditors.StringArrayPropertyEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class RegisterController {
@InitBinder
public void toDate(WebDataBinder binder) {
// SimpleDateFormat df = new SimpleDateFormat("yyyy-mm-dd");
// binder.registerCustomEditor(Date.class, new CustomDateEditor(df, false));
binder.registerCustomEditor(String[].class, new StringArrayPropertyEditor("#"));
}
// @RequestMapping("/register/add")
// @RequestMapping(value="/register/save", method= {RequestMethod.GET, RequestMethod.POST})
@GetMapping("/register/add")
public String register() {
return "registerForm";
}
// @RequestMapping(value="/register/save", method=RequestMethod.POST)
@PostMapping("/register/save") // Spring 4.3 부터 추가
public String save(User user, BindingResult result, Model m) throws Exception {
// 수동 검증 - Validator 를 직접 생성하고, validator() 를 호출
UserValidator uservalidator = new UserValidator();
uservalidator.validate(user, result);
// User 객체를 검증한 결과 에러가 있으면, registerForm 을 이용해서 에러를 보여줘야함
if (result.hasErrors()) {
return "registerForm";
}
// 1. 유효성 검사
// if (!isValid(user)) {
//
// String msg = URLEncoder.encode("id를 잘못입력하셨습니다.", "utf-8");
// m.addAttribute("msg", msg);
//
//// return "redirect:/register/add?msg="+msg; // URL 재작성(rewriting)
// return "redirect:/register/add";
// }
// 2. DB에 신규회원 정보를 저장
return "registerInfo";
}
private boolean isValid(User user) {
// TODO Auto-generated method stub
return true;
}
}
자동 검증
@Valid 사용
package com.fastcampus.app;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.beans.propertyeditors.StringArrayPropertyEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class RegisterController {
@InitBinder
public void toDate(WebDataBinder binder) {
// SimpleDateFormat df = new SimpleDateFormat("yyyy-mm-dd");
// binder.registerCustomEditor(Date.class, new CustomDateEditor(df, false));
binder.registerCustomEditor(String[].class, new StringArrayPropertyEditor("#"));
binder.setValidator(new UserValidator()); // UserValidator 를 WebDataBinder 의 로컬 validator로 등록
}
// @RequestMapping("/register/add")
// @RequestMapping(value="/register/save", method= {RequestMethod.GET, RequestMethod.POST})
@GetMapping("/register/add")
public String register() {
return "registerForm";
}
// @RequestMapping(value="/register/save", method=RequestMethod.POST)
@PostMapping("/register/save") // Spring 4.3 부터 추가
public String save(@Valid User user, BindingResult result, Model m) throws Exception {
// 수동 검증 - Validator 를 직접 생성하고, validator() 를 호출
// UserValidator uservalidator = new UserValidator();
// uservalidator.validate(user, result);
// User 객체를 검증한 결과 에러가 있으면, registerForm 을 이용해서 에러를 보여줘야함
if (result.hasErrors()) {
return "registerForm";
}
// 1. 유효성 검사
// if (!isValid(user)) {
//
// String msg = URLEncoder.encode("id를 잘못입력하셨습니다.", "utf-8");
// m.addAttribute("msg", msg);
//
//// return "redirect:/register/add?msg="+msg; // URL 재작성(rewriting)
// return "redirect:/register/add";
// }
// 2. DB에 신규회원 정보를 저장
return "registerInfo";
}
private boolean isValid(User user) {
// TODO Auto-generated method stub
return true;
}
}
MavenRpository 에서 Been validation 검색
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.fastcampus</groupId>
<artifactId>app</artifactId>
<name>firstSpring</name>
<packaging>war</packaging>
<version>1.0.0-BUILD-SNAPSHOT</version>
<properties>
<java-version>11</java-version>
<org.springframework-version>5.0.7.RELEASE</org.springframework-version>
<org.aspectj-version>1.6.10</org.aspectj-version>
<org.slf4j-version>1.6.6</org.slf4j-version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>
<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<additionalProjectnatures>
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
</additionalProjectnatures>
<additionalBuildcommands>
<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
</additionalBuildcommands>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>${java-version}</source>
<target>${java-version}</target>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<mainClass>org.test.int1.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
GlobalValidator
하나의 Validator 로 여러 객체를 검증할 때, 글로벌 Validator 로 등록
글로벌 Validator 로 등록하는 방법
servlet-context.xml
<annotation-driven validator="globalValidator"/>
<beans:bean id="globalVlidator" class="com.fastcampus.app.GlobalValidator"/>
package com.fastcampus.app;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
public class GlobalValidator implements Validator{
@Override
public boolean supports(Class<?> clazz) {
// TODO Auto-generated method stub
return User.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
System.out.println("GlobalValidator.validate() is called");
User user = (User)target;
String id = user.getId();
// if (id==null || "".equals(id.trim())) {
// errors.rejectValue("id", "required");
// }
ValidationUtils.rejectIfEmpty(errors, "id", "required");
ValidationUtils.rejectIfEmpty(errors, "pwd", "required");
if (id==null || id.length() < 5 || id.length() > 12) {
errors.rejectValue("id", "invalidLength");
}
}
}
글로벌 Validator 와 로컬 Validator 를 동시에 적용하는 방법
package com.fastcampus.app;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import javax.validation.Valid;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.beans.propertyeditors.StringArrayPropertyEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class RegisterController {
@InitBinder
public void toDate(WebDataBinder binder) {
// SimpleDateFormat df = new SimpleDateFormat("yyyy-mm-dd");
// binder.registerCustomEditor(Date.class, new CustomDateEditor(df, false));
binder.registerCustomEditor(String[].class, new StringArrayPropertyEditor("#"));
// binder.setValidator(new UserValidator()); // UserValidator 를 WebDataBinder 의 로컬 validator로 등록
binder.addValidators(new UserValidator()); // UserValidator 를 WebDataBinder 의 글로벌 validator로 등록
List<Validator> listValidator = binder.getValidators();
System.out.println("validator="+listValidator);
}
// @RequestMapping("/register/add")
// @RequestMapping(value="/register/save", method= {RequestMethod.GET, RequestMethod.POST})
@GetMapping("/register/add")
public String register() {
return "registerForm";
}
// @RequestMapping(value="/register/save", method=RequestMethod.POST)
@PostMapping("/register/save") // Spring 4.3 부터 추가
public String save(@Valid User user, BindingResult result, Model m) throws Exception {
// 수동 검증 - Validator 를 직접 생성하고, validator() 를 호출
// UserValidator uservalidator = new UserValidator();
// uservalidator.validate(user, result);
// User 객체를 검증한 결과 에러가 있으면, registerForm 을 이용해서 에러를 보여줘야함
if (result.hasErrors()) {
return "registerForm";
}
// 1. 유효성 검사
// if (!isValid(user)) {
//
// String msg = URLEncoder.encode("id를 잘못입력하셨습니다.", "utf-8");
// m.addAttribute("msg", msg);
//
//// return "redirect:/register/add?msg="+msg; // URL 재작성(rewriting)
// return "redirect:/register/add";
// }
// 2. DB에 신규회원 정보를 저장
return "registerInfo";
}
private boolean isValid(User user) {
// TODO Auto-generated method stub
return true;
}
}
validator=[com.fastcampus.app.GlobalValidator@395a2f3b, com.fastcampus.app.UserValidator@52902ad5]
TRACE: org.springframework.web.method.support.InvocableHandlerMethod - Method [com.fastcampus.app.RegisterController.toDate] returned [null]
GlobalValidator.validate() is called
LocalValidator.validate() is called
MessageSource
error_message.properties
required=필수 항목입니다.
required.user.pwd=사용자 비밀번호는 필수 항목입니다.
invalidLength.id=아이디의 길이는 {1}~{2} 사이어야 합니다.
<beans:bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<beans:property name="basenames">
<beans:list>
<beans:value>error_message</beans:value> <!-- /src/main/resources/error_message.properties -->
</beans:list>
</beans:property>
<beans:property name="defaultEncoding" value="UTF-8"/>
</beans:bean>
검증 메시지 출력
registerForm.jsp
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%@ page contentType="text/html;charset=utf-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%@ page import="java.net.URLDecoder" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.8.2/css/all.min.css" />
<style>
* { box-sizing:border-box; }
form {
width:400px;
height:600px;
display : flex;
flex-direction: column;
align-items:center;
position : absolute;
top:50%;
left:50%;
transform: translate(-50%, -50%) ;
border: 1px solid rgb(89,117,196);
border-radius: 10px;
}
.input-field {
width: 300px;
height: 40px;
border : 1px solid rgb(89,117,196);
border-radius:5px;
padding: 0 10px;
margin-bottom: 10px;
}
label {
width:300px;
height:30px;
margin-top :4px;
}
button {
background-color: rgb(89,117,196);
color : white;
width:300px;
height:50px;
font-size: 17px;
border : none;
border-radius: 5px;
margin : 20px 0 30px 0;
}
.title {
font-size : 50px;
margin: 40px 0 30px 0;
}
.msg {
height: 30px;
text-align:center;
font-size:16px;
color:red;
margin-bottom: 20px;
}
.sns-chk {
margin-top : 5px;
}
</style>
<title>Register</title>
</head>
<body>
<%-- <form action="<c:url value="/register/save"/>" method="POST" onsubmit="return formCheck(this)"> --%>
<form:form modelAttribute="user">
<div class="title">Register</div>
<!-- <div id="msg" class="msg">${param.msg}</div> -->
<div id="msg" class="msg"><form:errors path="id"/></div>
<label for="">아이디</label>
<input class="input-field" type="text" name="id" placeholder="8~12자리의 영대소문자와 숫자 조합" autofocus>
<label for="">비밀번호</label>
<input class="input-field" type="text" name="pwd" placeholder="8~12자리의 영대소문자와 숫자 조합">
<label for="">이름</label>
<input class="input-field" type="text" name="name" placeholder="홍길동">
<label for="">이메일</label>
<input class="input-field" type="text" name="email" placeholder="example@fastcampus.co.kr">
<label for="">생일</label>
<input class="input-field" type="text" name="birth" placeholder="2020/12/31">
<label for="">취미</label>
<input class="input-field" type="text" name="hobby">
<div class="sns-chk">
<label><input type="checkbox" name="sns" value="facebook"/>페이스북</label>
<label><input type="checkbox" name="sns" value="kakaotalk"/>카카오톡</label>
<label><input type="checkbox" name="sns" value="instagram"/>인스타그램</label>
</div>
<button>회원 가입</button>
</form:form>
<script>
function formCheck(frm) {
var msg ='';
if(frm.id.value.length<3) {
setMessage('id의 길이는 3이상이어야 합니다.', frm.id);
return false;
}
return true;
}
function setMessage(msg, element){
document.getElementById("msg").innerHTML = `<i class="fa fa-exclamation-circle"> ${'${msg}'}</i>`;
if(element) {
element.select();
}
}
</script>
</body>
</html>
validate 메서드에 String 배열 추가
package com.fastcampus.app;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
public class GlobalValidator implements Validator{
@Override
public boolean supports(Class<?> clazz) {
// TODO Auto-generated method stub
return User.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
System.out.println("GlobalValidator.validate() is called");
User user = (User)target;
String id = user.getId();
// if (id==null || "".equals(id.trim())) {
// errors.rejectValue("id", "required");
// }
ValidationUtils.rejectIfEmpty(errors, "id", "required");
ValidationUtils.rejectIfEmpty(errors, "pwd", "required");
if (id==null || id.length() < 5 || id.length() > 12) {
errors.rejectValue("id", "invalidLength", new String[]{"", "5", "12"}, null);
}
}
}
'Spring > Ch2. Spring MVC' 카테고리의 다른 글
Spring MVC - HTTP 요청과 응답 (0) | 2022.11.16 |
---|---|
Spring MVC - 데이터 변환과 검증 (0) | 2022.09.24 |
Spring MVC - DispatcherServlet (0) | 2022.09.23 |
Spring MVC - 예외 처리2 (0) | 2022.09.22 |
Spring MVC - 예외 처리 (0) | 2022.09.22 |