홈을 생성합니다. 다음과 같이 webapp/WEB-INF/views/home.jsp 를 작성합니다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>스프링 부트 프로젝트</h2>
<ul>
<li><a href="/">루트</a></li>
</ul>
<h2>Validator 인터페이스</h2>
<ul>
<li><a href="./write.do">글쓰기폼</a>
</ul>
</body>
</html>
컨트롤러를 생성합니다. 다음과 같이 com.edu.springboot.MainController.java 를 작성합니다.
package com.edu.springboot;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class MainController {
@RequestMapping("/")
public String home() {
return "home";
}
@RequestMapping("/write.do")
public String insert1() {
return "write";
}
}
뷰를 생성합니다. 다음과 같이 webapp/WEB-INF/views/write.jsp 를 작성합니다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<script>
// 매개변수 f는 <form> 태그의 DOM을 전달받는다.
function sending(f, gubun) {
// gubun에 의해 다른 action 속성을 부여한다.
if(gubun == 1)
f.action="./writeAction1.do"
else
f.action="./writeAction2.do"
// 여기에서 폼값을 전송한다.
f.submit();
}
</script>
<h2>Validator 인터페이스를 통한 유효성 검증</h2>
<form method="post">
일련변호 : <input type="number" name="idx" value="1">
<br/>
아이디 : <input type="text" name="userid" value="${ dto.userId }">
<br/>
제목 : <input type="text" name="title" value="${ dto.title }">
<br/>
내용 : <input type="text" name="content" value="${ dto.content }">
<br/>
<input type="button" value="전송1" onclick="sending(this.form, 1);">
<input type="button" value="전송2" onclick="sending(this.form, 2);">
</form>
</body>
</html>
DTO를 생성합니다. 다음과 같이 com.edu.springboot.BoardDTO.java 를 작성합니다.
package com.edu.springboot;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/* 롬복을 통해 멤버변수에 대한 getter, setter, 기본생성자 등을 일괄적으로 정의할 수 있다.
* 또한 Object 클래스에서 제공되는 toString()과 같은 메서드도 자동으로 오버라이딩 된다. */
@Data
// 인수를 가진 생성자를 추가한다.
@AllArgsConstructor
// 기본 생성자를 추가한다.
@NoArgsConstructor
public class BoardDTO {
private int idx;
private String userid;
private String title;
private String content;
}
검증 클래스를 생성합니다. 다음과 같이 com.edu.springboot.BoardValidator.java 를 작성합니다.
package com.edu.springboot;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
/* 폼값 검증을 위한 클래스 제작을 위해 먼저 Validator 인터페이스를 구현한다.
* 그리고 추상메서드 2개를 필수로 오버라이딩 한다. */
public class BoardValidator implements Validator {
/* 검증을 위한 커맨드 객체의 클래스 타입을 확인하는 용도의 메서드 */
@Override
public boolean supports(Class<?> clazz) {
System.out.println("supports() 호출됨");
// 폼값을 받기 위한 커맨드 객체의 타입만 명시해주면 된다.
return BoardDTO.class.isAssignableFrom(clazz);
}
/* 폼값 검증을 하기 위해 3가지 방법을 사용할 수 있다.
* 1. if문을 이용한 검증
* 2. ValidationUtils 클래스를 이용한 검증
* 3. 사용자 정의 메서드를 이용한 검증 */
@Override
public void validate(Object target, Errors errors) {
System.out.println("validate() 호출됨");
// 폼값 전체를 저장한 DTO 객체는 Object 타입으로 전달되므로 형변환된다.
BoardDTO boardDTO = (BoardDTO) target;
// 폼값을 저장하고 있는 커맨드 객체인지 확인 (필요한 경우에 사용)
if (supports(boardDTO.getClass()) == true) {
System.out.println("폼값 검증에 적합한 인스턴스");
}
else {
System.out.println("폼값 검증에 적합한 인스턴스가 아님");
}
// 1. 아이디 검증
String userid = boardDTO.getUserid();
// 만약 아이디가 null 이거나 빈값이라면 아래 내용을 실행한다.
if (userid == null || userid.trim().isEmpty()) {
// 개발자가 콘솔에 출력하는 검증 내용
System.out.println("아이디를 입력하세요.");
/* 폼값 검증 시 오류가 있는 경우 처리 형식
* Errors인스턴스.rejectValue(폼의name속성, 여러객체명, 디폴트메세지); */
errors.rejectValue("userid", "idError", "아이디 검증 실패");
}
/* 2. 제목 검증
* : ValidationUtils 클래스의 정적메서드를 호출하여 빈 값이거나 null값인 경우를 검증한다. */
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "title", "titleError", "제목 검증 실패");
/* 3. 내용 검증 : 개발자가 정의한 메서드를 통해 검증한다. */
boolean contentValidate = myEmptyOrWhitespace(boardDTO.getContent());
if (contentValidate == false) {
System.out.println("내용을 입력해주세요.");
errors.rejectValue("content", "contentError", "내용 검증 실패");
}
}
public boolean myEmptyOrWhitespace(String value) {
// 내용이 null이거나 길이가 0인 경우 false를 반환한다.
if (value == null || value.trim().length() == 0) {
return false;
}
else {
return true;
}
}
}
컨트롤러를 생성합니다. 다음과 같이 com.edu.springboot.MainController.java 에 추가적인 코드를 작성합니다.
package com.edu.springboot;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class MainController {
@RequestMapping("/")
public String home() {
return "home";
}
@RequestMapping("/write.do")
public String insert1() {
return "write";
}
/* Validator 인터페이스를 통한 폼값의 유효성 검증
* Spring에서 사용하는 커맨드 객체는 전송된 폼값을 한꺼번에 받아 Model 인스턴스에 저장해준다.
* 만약 저장되는 속성명을 변경하고 싶다면 @ModelAttribute 어노테이션을 사용하면 된다.
* 아래의 경우 boardDTO가 아닌 dto라는 이름으로 Model에 저장된다. */
@RequestMapping("/writeAction1.do")
public String writeAction1(@ModelAttribute("dto") BoardDTO boardDTO, BindingResult result) {
// 폼값 검증에 성공한 경우 포워드 할 View의 경로 설정
String page = "result";
System.out.println(boardDTO);
// 폼값 검증을 위한 인스턴스 생성
BoardValidator validator = new BoardValidator();
/* 폼값을 저장한 DTO 및 검증결과 전달을 위한 객체를 인수로 전달한다.
* 여기서 validate()를 호출하여 검증을 진행하게 된다. */
validator.validate(boardDTO, result);
// 폼값 검증에 실패한 경우
if (result.hasErrors()) {
// 실패한 경우 재입력을 받기 위해 쓰기페이지로 포워드
page = "write";
/* result가 폼값 검증에 대한 모든 결과값을 가지고 있다.
* 따라서 아래 부분의 출력문을 주석처리 하더라도 이 부분에서 모든 검증 결과가 출력된다. */
System.out.println("검증 실패 반환값 1 : " + result.toString());
// 제목 검증에 실패한 경우 우리가 생성한 에러코드를 출력한다.
if (result.getFieldError("title") != null) {
System.out.println("제목 검증 1 (에러코드) : " + result.getFieldError("title").getCode());
}
// 내용 검증에 실패한 경우 디폹트 메세지를 출력한다.
if (result.getFieldError("content") != null) {
System.out.println("내용 검증 1 (디폴트 메세지) : " + result.getFieldError("content").getDefaultMessage());
}
}
return page;
}
}
뷰를 생성합니다. 다음과 같이 webapp/WEB-INF/views/result.jsp 를 작성합니다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>글쓰기 결과</h2>
<p>
일련번호 : ${dto.idx} <br />
아이디 : ${dto.userid} <br />
제목 : ${dto.title} <br />
내용 : ${dto.content}
</p>
</body>
</html>
다음과 같이 실행됩니다.

'글쓰기폼' 링크를 클릭하면 다음과 같이 글을 작성할 수 있습니다.

아무것도 입력하지 않고 '전송1' 버튼을 누르면 콘솔에 다음과 같이 출력됩니다.
BoardDTO(idx=1, userid=, title=, content=)
validate() 호출됨
supports() 호출됨
폼값 검증에 적합한 인스턴스
아이디를 입력하세요.
내용을 입력해주세요.
검증 실패 반환값 1 : org.springframework.validation.BeanPropertyBindingResult: 3 errors
Field error in object 'dto' on field 'userid': rejected value []; codes [idError.dto.userid,idError.userid,idError.java.lang.String,idError]; arguments []; default message [아이디 검증 실패]
Field error in object 'dto' on field 'title': rejected value []; codes [titleError.dto.title,titleError.title,titleError.java.lang.String,titleError]; arguments []; default message [제목 검증 실패]
Field error in object 'dto' on field 'content': rejected value []; codes [contentError.dto.content,contentError.content,contentError.java.lang.String,contentError]; arguments []; default message [내용 검증 실패]
제목 검증 1 (에러코드) : titleError
내용 검증 1 (디폴트 메세지) : 내용 검증 실패
이번에는 내용을 입력한 후에 '전송1' 버튼을 누릅니다.

폼에 입력한 값이 전송된 페이지가 나타납니다.

콘솔에는 다음과 같이 출력됩니다.
BoardDTO(idx=1, userid=harim, title=제목, content=제목입니다)
validate() 호출됨
supports() 호출됨
폼값 검증에 적합한 인스턴스
다음과 같이 build.gradle 파일에 Validation 어노테이션을 위한 위존을 설정합니다.
// validation 어노테이션을 위한 의존설정
implementation 'org.springframework.boot:spring-boot-starter-validation'
VO를 생성합니다. 다음과 같이 com.edu.springboot.BoardVO.java 를 작성합니다.
package com.edu.springboot;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
/* 어노테이션을 통한 폼값 검증을 위해 디펜던시를 추가해야 한다.
* build.gradle에 starter-validation 항목을 추가한 후 refresh 한다. */
@Data
public class BoardVO {
private int idx;
/* @NotNull : 폼값이 null일 때 메세지를 출력한다.
* @NotEmpty : 빈값일 때 메세지를 출력한다.
* @Size : 입력값의 길이를 지정한다. 해당 범위를 벗어났을 때 메세지를 출력한다. */
@NotNull(message = "아이디가 null입니다.")
@NotEmpty(message = "아이디를 입력해주세요.")
@Size(min = 5, max = 12, message = "아이디는 5~12자로 입력해주세요.")
private String userid;
@NotNull(message = "제목이 null입니다.")
@NotEmpty(message = "제목을 입력해주세요.")
private String title;
@NotNull(message = "내용이 null입니다.")
@NotEmpty(message = "내용을 입력해주세요.")
private String content;
}
컨트롤러를 생성합니다. 다음과 같이 com.edu.springboot.MainController.java 를 작성합니다.
/* 어노테이션을 통한 검증이므로 폼값 저장을 위한 VO객체에 @Validated를 추가한다. */
@RequestMapping("/writeAction2.do")
public String writeAction2(@ModelAttribute("dto") @Validated BoardVO boardVO, BindingResult result) {
String page = "result";
System.out.println(boardVO);
/* 검증을 위한 클래스는 별도로 정의할 필요가 없으므로 주석 처리한다. */
// BoardValidator validator = new BoardValidator();
// validator.validate(boardVO, result);
if (result.hasErrors()) {
page = "write";
System.out.println("검증 실패 반환값 1 : " + result.toString());
if (result.getFieldError("title") != null) {
System.out.println("제목 검증 1 (에러코드) : " + result.getFieldError("title").getCode());
}
if (result.getFieldError("content") != null) {
System.out.println("내용 검증 1 (디폴트 메세지) : " + result.getFieldError("content").getDefaultMessage());
}
}
return page;
}
다음과 같이 실행됩니다.

폼에 아무것도 입력하지 않고 '전송2' 버튼을 누르면 콘솔에 다음과 같이 출력됩니다.
BoardVO(idx=1, userid=, title=, content=)
검증 실패 반환값 1 : org.springframework.validation.BeanPropertyBindingResult: 4 errors
Field error in object 'dto' on field 'userid': rejected value []; codes [NotEmpty.dto.userid,NotEmpty.userid,NotEmpty.java.lang.String,NotEmpty]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [dto.userid,userid]; arguments []; default message [userid]]; default message [아이디를 입력해주세요.]
Field error in object 'dto' on field 'userid': rejected value []; codes [Size.dto.userid,Size.userid,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [dto.userid,userid]; arguments []; default message [userid],12,5]; default message [아이디는 5~12자로 입력해주세요.]
Field error in object 'dto' on field 'content': rejected value []; codes [NotEmpty.dto.content,NotEmpty.content,NotEmpty.java.lang.String,NotEmpty]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [dto.content,content]; arguments []; default message [content]]; default message [내용을 입력해주세요.]
Field error in object 'dto' on field 'title': rejected value []; codes [NotEmpty.dto.title,NotEmpty.title,NotEmpty.java.lang.String,NotEmpty]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [dto.title,title]; arguments []; default message [title]]; default message [제목을 입력해주세요.]
제목 검증 1 (에러코드) : NotEmpty
내용 검증 1 (디폴트 메세지) : 내용을 입력해주세요.
모든 내용을 입력한 후에 '전송2'를 누르면 콘솔에 다음과 같이 출력됩니다.
BoardVO(idx=1, userid=harim, title=제목, content=내용입니다)