Spring JSR-303 Validation example
Message Resource 를 이용하지 않는 JSR-303 데이터 검증 방법은 여기를 참조하세요
테스트 환경
Windows 7, JDK1.7, Tomcat 8, Eclipse luna, Spring 3.2, STS, Maven
필요한 라이브러리(https://mvnrepository.com/ )
- Java Bean Validation API
- Hibernate Validation
Message Resource 파일의 생성
messages_ko.properties, messages_en.properties, messages.properties
위의 이름으로 메시지 리소스파일을 생성한다
Message Resource 파일이 위치
메시지 리소스파일은 클래스패스에 두면 되므로...
WEB-INF/ 아래에 classes 라는 폴더를 만들고 그 안에 위의 3가지 파일을 저장해둔다
classes/ 안에 messages 라는 폴더를 생성하고 그 안에 둘 수도 있는데, 클래스패스 안에만 두면 된다.
여기서는 메시지 리소스 파일의 경로를 WEB-INF/classes/messages/messages_ko.properties 으로 설정했다.
각 언어 환경에 따라서 자동으로 위의 3가지 파일 중에서 한가지가 사용된다.
Message Resource 파일의 경로 등록
servlet-context.xml 파일에 다음과 같이 등록한다
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Process annotations on registered beans like @Autowired... -->
<context:annotation-config/>
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven/>
<context:component-scan base-package="org.kdea.java" />
<context:component-scan base-package="org.kdea.service" />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
<beans:property name="contentType" value="text/html; charset=UTF-8"/>
</beans:bean>
<beans:bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<beans:property name="basename" value="messages/messages"/>
</beans:bean>
<beans:bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
</beans:beans>
데이터 검증대상 빈의 속성에 Annotation 적용
아래에서 사용된 디폴트 메시지의 내용은 메시지 리소스를 사용하지 않을 때에 자동으로 사용된다
package org.kdea.java;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotEmpty;
public class LoginBean {
// 아래에 사용된 디폴트 메시지는 메시지 리소스를 사용하지 않을 때 자동으로 사용된다
@Size(min=1,max=10, message="1~10 자 사이")
private String id;
@NotEmpty(message="필수입력")
private String pwd;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
위의 Annotation 외에도 다음과 같은 것들이 사용된다
@Range(min = 1, max = 10)
int age;
@Min(1)
@Max(10)
int age;
@NotNull
@Size(min=4, max=10, message="아이디는 4자 ~ 10자 사이로 입력하세요!")
private String id;
@NotNull
@Size(min=6, max=12, message="비밀번호는 6자에서12자 사이로 입력하세요!")
private String pwd
@NotEmpty(message="필수입력")
private String pwd;
@NotNull(message="이름을 입력하세요!")
@Size(max=10, message="한글이름은 공백포함 5자, 영문은 공백포함 10자 사이로 입력하세요!")
private String name;
@Length(min=6,max=20)
private String name;
@Pattern(regexp=".+@.+\\.[a-z]+")
private String email;
@NotEmpty @Pattern(".+@.+\\.[a-z]+")
private String from;
@Past(message="생일은 과거날짜만 입력하세요")
private Date dateOfBirth;
private String email;
@DateTimeFormat(pattern="MM/dd/yyyy")
@NotNull @Past
private Date birthday;
@DecimalMax(value="180") @DecimalMin(value="20")
@Digits(integer=3, fraction=0)
private int weight;
@DateTimeFormat(iso = ISO.DATE)
@Future
private Date releaseDate;
@NumberFormat(pattern = "#,###")
@Digits(integer=5, fraction=0)
private int ticketPrice;
@AssertFalse
@AssertTrue
Message Resource 파일에 메시지 입력
위의 빈 속성에 적용한 Annotation의 이름과 빈객체의 참조변수 이름, 속성이름과 메시지 내용을 입력한다.
한글을 입력하면 자동으로 유니코드 16진수 숫자로 변경되어 저장된다.
WEB-INF/classes/messages/messages_ko.properties 의 내용
NotEmpty.loginBean.pwd=\uC554\uD638\uB294 \uD544\uC218\uD56D\uBAA9\uC785\uB2C8\uB2E4
Size.loginBean.id=\uC544\uC774\uB514\uB294 1~10\uC790 \uC0AC\uC774\uB85C \uC785\uB825\uD574\uC8FC\uC138\uC694
Controller 클래스의 검증대상 파라미터에 @Valid 를 붙인다
package org.kdea.java;
import javax.annotation.Resource;
import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class LoginController {
@RequestMapping(value="/login.htm", method=RequestMethod.GET)
public String login(Model model){
model.addAttribute("loginBean", new LoginBean());
return "loginForm";
}
// 데이터 검증시 오류가 있으면 request 영역에 저장되므로
// forward 목적 jsp에서는 오류 메시지에 접근할 수 있다
// 그러므로 redirect:/login.htm을 사용하면 오류 메시지가 폼에 전달되지 않음
@RequestMapping(value="/login.htm", method=RequestMethod.POST)
public String login(@Valid LoginBean loginBean, BindingResult result){
if(result.hasErrors()){
System.out.println(result);
return "loginForm";
}
return "hello";
}
}
위의 내용은 LoginBean 에서 데이터 검증오류가 발생하면 loginForm.jsp 가 다시 브라우저에 전송되고 브라우저의 폼에는 오류 메시지가 출력된다.
폼에서 오류 메시지가 출력되도록 하려면 아래와 같이 스프링에서 제공하는 태그를 이용하는 것이 간편하다
폼에서 데이터 검증오류 출력하기
loginForm.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>로그인 폼</title>
<style type="text/css">
.errorMsg { color: red; }
</style>
</head>
<body>
<h2>로그인 폼</h2>
<%--
<div class="errorMsg">
<spring:bind path="loginBean.id">
${status.errorMessage }
</spring:bind>
<spring:bind path="loginBean.pwd">
${status.errorMessage }
</spring:bind>
</div>
<form action="login.htm" method="post">
I D <input type="text" name="id"><br>
PWD <input type="password" name="pwd"><br>
<input type="submit" value="Login">
</form>
--%>
<form:form method="POST" commandName="loginBean" action="login.htm">
<!--loginBean의 모든 속성에 대한 오류를 아래에 출력한다-->
<form:errors path="*" cssClass="errorMsg" element="div" />
<table>
<tr>
<td>I D :</td>
<td><form:input path="id" /></td>
<td><form:errors path="id" cssClass="errorMsg" /></td>
</tr>
<tr>
<td>PWD :</td>
<td><form:input path="pwd" /></td>
<td><form:errors path="pwd" cssClass="errorMsg" /></td>
</tr>
<tr>
<td colspan="3"><input type="submit" /></td>
</tr>
</table>
</form:form>
</body>
</html>
위의 코드에서 loginBean 은 서버측에서 폼 데이터를 저장하는 커맨드 오브젝트의 키이다
테스트
http://localhost:8080/SpringMVC/login.htm 으로 접속하여 폼이 출력되면 폼을 비워둔채로 전송버튼을 눌러서 결과를 확인한다