📌 Spring 유효성검사
🌈목차
6. 기타 (이메일, @AssertTrue / @AssertFalse)
8. Book - 유효성 검정 예제1 (수업 파일 Ex03)
9. Product - 유효성 검정 예제2 (수업 파일 Ex05)
10. Football - 유효성 검정 예제3 (수업 파일 Ex07)
❤️pom.xml에 삽입 필수
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
1. Null / 비어있음 검사
| @NotNull | null 금지 | "", " " 허용 |
| @NotEmpty | null + 빈문자열 금지 | " " 허용 |
| @NotBlank | null + 빈문자열 + 공백 금지 | 문자열 전용 |
@NotNull(message="값은 반드시 입력해야 합니다")
private String id;
@NotEmpty(message="비밀번호는 필수입니다")
private String password;
@NotBlank(message="이름은 공백일 수 없습니다")
private String name;
2. 문자열 / 컬렉션 크기 제한
| @Size(min, max) | 문자열, 배열, List, Set의 길이 제한 |
@Size(min=3, max=10, message="아이디는 3~10자리여야 합니다")
private String userId;
3. 숫자 값 제약
| @Min(x) | 최소값 이상 |
| @Max(x) | 최대값 이하 |
| @Positive | 양수만 허용 (0 불가) |
| @PositiveOrZero | 0 이상 |
| @Negative | 음수만 허용 |
| @NegativeOrZero | 0 이하 |
| @Digits(integer, fraction) | 정수/소수 자릿수 제한 |
| @DecimalMin(x), @DecimalMax(x) | 실수 범위 제한 |
@Min(18) @Max(100)
private int age;
@Digits(integer=5, fraction=2) // 최대 99999.99
private BigDecimal price;
4. 정규식 검사
| @Pattern(regexp="정규식") | 문자열이 특정 패턴과 일치하는지 검사 |
@Pattern(regexp="^[a-zA-Z0-9]+$", message="영문자와 숫자만 입력 가능합니다")
private String userId;
5. 날짜 / 시간 제약
| @Past | 과거 날짜만 허용 |
| @PastOrPresent | 과거 또는 오늘까지 허용 |
| @Future | 미래 날짜만 허용 |
| @FutureOrPresent | 오늘 또는 미래 날짜 허용 |
@Past(message="생일은 과거 날짜여야 합니다")
private LocalDate birthDate;
6. 기타
| 이메일 형식 검증 | |
| @AssertTrue | true만 허용 (체크박스 동의 등) |
| @AssertFalse | false만 허용 |
7. 체크박스 유효성검증
- 단일 체크박스 동의 → @AssertTrue
- 복수 체크박스 최소 선택 → @Size(min=1)
1) 단일 체크박스 예시 (동의 여부)
- boolean 필드로 선언
- @AssertTrue 를 붙이면 true(체크 O)일 때만 통과합니다.
public class UserForm {
// 1)NotEmpty
@NotEmpty(message = "동의 누락")
private String agree;
// 2)AssertTrue
@AssertTrue(message = "약관에 동의해야 합니다")
private boolean agree;
// getter/setter
}
📄 HTML
<form th:action="@{/submit}" th:object="${form}" method="post">
<label>
<input type="checkbox" th:field="*{agree}"> 약관에 동의합니다
</label>
<div th:if="${#fields.hasErrors('agree')}" th:errors="*{agree}"></div>
<button type="submit">제출</button>
</form>
2) 복수 체크박스 (최소 1개이상 선택 필수)
Spring Validation에는 기본 제공 어노테이션이 없기 때문에 👉 @Size(min=1) 을 사용
public class UserForm {
@Size(min = 1, message = "취미는 최소 1개 이상 선택해야 합니다")
private List<String> hobbies;
// getter/setter
}
📄 HTML
<form th:action="@{/submit}" th:object="${form}" method="post">
<!-- 취미 선택 -->
취미 선택: <br>
<label><input type="checkbox" th:field="*{hobbies}" value="수영"> 수영</label>
<label><input type="checkbox" th:field="*{hobbies}" value="요리"> 요리</label>
<label><input type="checkbox" th:field="*{hobbies}" value="게임"> 게임</label>
<div th:if="${#fields.hasErrors('hobbies')}" th:errors="*{hobbies}"></div>
<br><br>
<button type="submit">제출</button>
</form>
👉 체크박스를 하나도 안 고르면 검증 실패
✅Controller 예시
@Controller
public class UserController {
@GetMapping("/form")
public String form(Model model) {
model.addAttribute("form", new UserForm());
return "form";
}
@PostMapping("/submit")
public String submit(@Valid @ModelAttribute("form") UserForm form,
BindingResult result) {
if (result.hasErrors()) {
return "form"; // 유효성 실패 → 다시 입력 폼
}
return "success"; // 성공 시 이동할 뷰
}
}
8. Book - 유효성 검정 예제1
🔽BookBean.java
더보기
package com.example.Ex02;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.validator.constraints.Length;
import java.util.List;
@Setter
@Getter
public class BookBean {
@NotBlank(message ="제목 입력 누락")
private String title;
//@Size(min=3, max=5, message = "3~5자리 이하로 입력")
@NotEmpty(message ="저자 입력 누락")
@Length(min=5, message = "5글자 이상 입력")
private String author;
@Pattern(regexp = "^[0-9]+$", message = "price는 숫자로 입력하세요")
@NotEmpty(message = "price 누락")
private String price;
@NotEmpty(message = "출판사 입력 누락")
private String publisher;
@NotEmpty(message = "서점 입력 누락")
private List<String> bookstore;
// ---- getter & setter ----
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getAuthor() { return author; }
public void setAuthor(String author) { this.author = author; }
public String getPrice() { return price; }
public void setPrice(String price) { this.price = price; }
public String getPublisher() { return publisher; }
public void setPublisher(String publisher) { this.publisher = publisher; }
public List<String> getBookstore() { return bookstore; }
public void setBookstore(List<String> bookstore) { this.bookstore = bookstore; }
}
🔽BookController.java
더보기
package com.example.Ex02;
import jakarta.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class BookController {
// 📌 1. 입력 화면 보여주기
@RequestMapping(value = "bookform")
public String book(Model model){
BookBean bb = new BookBean(); // 빈 객체 생성
model.addAttribute("book", bb); // 모델에 "book" 이름으로 담음
return "book/form"; // → templates/book/form.html 이동
}
// 📌 2. 입력값 처리
@RequestMapping(value = "bookProc")
// @ModelAttribute("book") 별칭과 form.html의 th:object="${book}"와 반드시 같아야함
public String book2(@ModelAttribute("book") @Valid BookBean bb, BindingResult br){
System.out.println("br.hasErrors(): " + br.hasErrors());
String page="";
if(br.hasErrors()){
page="book/form"; // 에러 발생 → 다시 입력폼
}else{
page="book/result"; // 정상 입력 → 결과 페이지
}
return page;
}
}
🔑 BookController 핵심 포인트
- bookProc → 입력값 검증 후 에러 있으면 다시 form.html, 없으면 result.html
- @ModelAttribute("book") 이름 = th:object="${book}" 와 반드시 일치해야 함
- @Valid : BookBean 안의 유효성 검사 실행
- BindingResult : 에러 여부 저장
🔽form.html
더보기
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.err{
font-size:9pt;
color:red;
}
</style>
</head>
<body>
book/form.html<br>
<form th:action="@{bookProc}" th:object="${book}" method="post">
책제목 : <input th:field="*{title}"><br>
<div th:if="${#fields.hasErrors('title')}"
th:errors="*{title}" class="err"></div><br>
저자 : <input th:field="*{author}"><br>
<div th:if="${#fields.hasErrors('author')}"
th:errors="*{author}" class="err"></div><br>
가격 : <input th:field="*{price}"><br>
<div th:if="${#fields.hasErrors('price')}"
th:errors="*{price}" class="err"></div><br>
출판사 : <input th:field="*{publisher}"><br>
<div th:if="${#fields.hasErrors('publisher')}"
th:errors="*{publisher}" class="err"></div><br>
구입가능 서점:
<input type="checkbox" th:field="*{bookstore}" value="교보문고">교보문고
<input type="checkbox" th:field="*{bookstore}" value="알라딘">알라딘
<input type="checkbox" th:field="*{bookstore}" value="yes24">yes24
<div th:if="${#fields.hasErrors('bookstore')}"
th:errors="*{bookstore}" class="err"></div>
<input type="submit" value="전송">
</form>
</body>
</html>
🔑 form.html 핵심
- th:object="${book}" → 컨트롤러에서 전달된 BookBean과 연결
- th:field="*{title}" → BookBean의 title 필드와 input 매핑
- #fields.hasErrors('필드명') → 해당 필드에 에러가 있는지 확인
- th:errors="*{필드명}" → BookBean에 정의된 유효성 메시지 출력
🔽result.html
더보기
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
title : <span th:text="${book.title}"></span><br>
author : <span th:text="${book.author}"></span><br>
price : <span th:text="${book.price}"></span><br>
publisher : <span th:text="${book.publisher}"></span><br>
bookstore : <span th:text="${book.bookstore}"></span><br>
<span th:each ="store : ${book.bookstore}" th:text="${store}">
<br>
</span>
</head>
<body>
✅ 정리
- th:object="${book}" : BookBean과 연결 (폼 입력값 ↔ 객체 바인딩)
- th:field="*{필드} : BookBean의 필드와 input 자동 매핑
- @Valid + BindingResult : 검증 실행 + 결과 저장
- th:errors : 해당 필드에 대한 에러 메시지 출력
9. Product-유효성 검정 예제2
🔽ProductBean.java
더보기
package com.example.Ex02;
import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
public class ProductBean {
@NotBlank(message = "아이디 입력 누락")
private String id;
@Size(min=3, max=5 , message = "3~5자리 이하로 입력하세요.")
@NotBlank(message = "비밀번호 입력 누락")
private String passwd;
@Size(min=1, message = "하나 이상 선택하세요")
private List<String> product;
@NotBlank(message = "배송시간 누락")
private String deliveryTime;
@NotBlank(message = "결제방법 선택 누락")
private String radio;
@AssertTrue(message = "동의 누락")
private boolean agree;
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getPasswd() { return passwd; }
public void setPasswd(String passwd) { this.passwd = passwd; }
public List<String> getProduct() { return product; }
public void setProduct(List<String> product) { this.product = product; }
public String getDeliveryTime() { return deliveryTime; }
public void setDeliveryTime(String deliveryTime) { this.deliveryTime = deliveryTime; }
public String getRadio() { return radio; }
public void setRadio(String radio) { this.radio = radio; }
public boolean isAgree() { return agree; } // ✅ boolean getter는 isAgree
public void setAgree(boolean agree) { this.agree = agree; }
}
🔽Controller.java
더보기
package com.example.Ex02;
import jakarta.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
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;
@Controller
public class Con {
@GetMapping(value = "/")
public String home(){
return "home";
}
// 폼 띄우기
@GetMapping(value = "/form")
public String form(Model model){
ProductBean pb = new ProductBean();
model.addAttribute("prod", pb);
return "form";
}
// 입력값 처리
@PostMapping(value = "/submit")
public String proc(@ModelAttribute("prod") @Valid ProductBean pb, BindingResult br){
String page ="";
if(br.hasErrors()){ // 에러가 있다면?
page ="/form";
}else{
page="result";
}
return page;
}
}
🔽form.html
더보기
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>form</title>
</head>
<style>
.err {
color: red;
}
</style>
<body>
<h2>마트 상품 구매 내역</h2>
<form th:action="@{/submit}" th:object="${prod}" method="post">
<label>아이디 </label>
<input type="text" th:field="*{id}"><br>
<div th:if="${#fields.hasErrors('id')}"
th:errors="*{id}" class="err"></div>
<br>
<label>비번 </label>
<input type="text" th:field="*{passwd}"><br>
<div th:if="${#fields.hasErrors('passwd')}"
th:errors="*{passwd}" class="err"></div>
<br>
구매상품:
<input type="checkbox" th:field="*{product}" value="식품">식품
<input type="checkbox" th:field="*{product}" value="의류">의류
<input type="checkbox" th:field="*{product}" value="도서">도서
<input type="checkbox" th:field="*{product}" value="가구">가구
<br>
<div th:if="${#fields.hasErrors('product')}"
th:errors="*{product}" class="err"></div><br>
배송시간:
<select th:field="*{deliveryTime}">
<option value="">선택</option>
<option value="오전">오전 (09:00 ~ 12:00)</option>
<option value="오후">오후 (12:00 ~ 18:00)</option>
<option value="저녁">저녁 (18:00 ~ 21:00)</option>
</select>
<br>
<div th:if="${#fields.hasErrors('deliveryTime')}"
th:errors="*{deliveryTime}" class="err"></div>
<br>
결제방법 :
<input type="radio" th:field="*{radio}" value="카드">카드
<input type="radio" th:field="*{radio}" value="핸드폰">핸드폰
<br>
<div th:if="${#fields.hasErrors('radio')}"
th:errors="*{radio}" class="err"></div><br>
결제동의
<input type="checkbox" th:field="*{agree}" value="동의"><br>
<div th:if="${#fields.hasErrors('agree')}"
th:errors="*{agree}" class="err"></div><br>
<br>
<button type="submit">제출</button>
</form>
</body>
</html>
🔽result.html
더보기
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
result.html<br><br>
아이디 : <span th:text="${prod.id}"></span><br>
비번 : <span th:text="${prod.passwd}"></span><br>
구매상품 : <span th:each="p,stat : ${prod.product}"
th:text="${p + (stat.last? '':',')}"></span><br>
배송시간 : <span th:text="${prod.deliveryTime}"></span><br>
결제 방법 : <span th:text="${prod.radio}"></span><br>
동의 : <span th:text="${prod.agree ? '동의':'미동의'}"></span><br>
</body>
</html>
10. Football - 유효성 검정 예제3 (수업 파일 Ex07)
🔽FootballDto.java
더보기
package com.example.Ex02.dto;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Size;
import java.util.List;
public class FootballDto {
private int num;
@NotBlank(message = "아이디 누락")
private String id;
@NotBlank(message = "비밀번호 누락")
private String pw;
// 라디오 버튼 → 단일 선택
@NotBlank(message = "우승 예상 국가 누락")
private String win;
// 체크박스 → 다중 선택
@Size(min=1, message = "16강 예상 국가 누락")
private List<String> round16;
public int getNum() { return num; }
public void setNum(int num) { this.num = num; }
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 getWin() { return win; }
public void setWin(String win) { this.win = win; }
public List<String> getRound16() { return round16; }
public void setRound16(List<String> round16) { this.round16 = round16; }
}
🔽FootballContriller.java
더보기
package com.example.Ex02;
import com.example.Ex02.dto.FootballDto;
import jakarta.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
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;
@Controller
public class FootballController {
@GetMapping(value = "/write")
public String write(@ModelAttribute("fb") FootballDto FDto){
return "write";
}
@PostMapping(value = "/writeProc")
public String proc(@ModelAttribute("fb") @Valid FootballDto fb, BindingResult rs){
String page="";
if(rs.hasErrors()){
page="write";
}else{
page="result";
}
return page;
}
}
🔽write.html
더보기
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>wrtie</title>
</head>
<style>
.err { color: red; font-size: 12px; }
</style>
<body>
<h3>wrtie.html</h3>
<form th:action="@{/writeProc}" th:object="${fb}" method="post">
<table border="1">
<tr>
<td>아이디</td><td>
<input type="text" th:field="*{id}">
<div th:if="${#fields.hasErrors('id')}"
th:errors="*{id}" class="err"></div>
</td>
</tr>
<tr>
<td>비밀번호</td>
<td><input type="text" th:field="*{pw}">
<div th:if="${#fields.hasErrors('pw')}"
th:errors="*{pw}" class="err"></div>
</td>
</tr>
<tr>
<td>우승 예상 국가</td>
<td>
<input type="radio" th:field="*{win}" value="한국">한국
<input type="radio" th:field="*{win}" value="미국">미국
<input type="radio" th:field="*{win}" value="독일">독일
<input type="radio" th:field="*{win}" value="스페인">스페인
<div th:if="${#fields.hasErrors('win')}"
th:errors="*{win}" class="err"></div>
</td>
</tr>
<tr>
<td>16강 예상 국가</td>
<td>
<input type="checkbox" th:field="*{round16}" value="한국">한국
<input type="checkbox" th:field="*{round16}" value="멕시코">멕시코
<input type="checkbox" th:field="*{round16}" value="독일">독일
<input type="checkbox" th:field="*{round16}" value="브라질">브라질
<input type="checkbox" th:field="*{round16}" value="스위스">스위스
<input type="checkbox" th:field="*{round16}" value="잉글랜드">잉글랜드
<div th:if="${#fields.hasErrors('round16')}"
th:errors="*{round16}" class="err"></div>
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="입력">
<a href="@{list}"> 목록보기</a>
</td>
</tr>
</table>
</form>
</body>
</html>
🔽result.html
더보기
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>result</title>
</head>
<body>
result.html<br>
<table border="1">
<tr>
<td>아이디</td><td th:text="${fb.id}"></td>
</tr>
<tr>
<td>비밀번호</td><td th:text="${fb.pw}"></td>
</tr>
<tr>
<td>우승 예상 국가</td><td th:text="${fb.win}"></td>
</tr>
<tr>
<td>16강 예상 국가</td><td th:text="${fb.round16}"></td>
</tr>
</table>
</body>
</html>
'기초 및 언어 > ▶ Spring' 카테고리의 다른 글
| 07. Spring_마이바티스(MyBatis) + 페이지 설정 (0) | 2025.09.24 |
|---|---|
| 06. Spring_마이바티스(MyBatis) (2) | 2025.09.23 |
| 04. Spring MVC에서 데이터 전달하기 (1) | 2025.09.19 |
| 03. Spring_Lombok 라이브러리 어노테이션(@Setter, @Getter) (0) | 2025.09.19 |
| 02. Spring_import가 안될때 (0) | 2025.09.19 |