Spring Validation
Spring Validationμ μ¬μ©μ μ
λ ₯ λ°μ΄ν°μ μ ν¨μ±μ κ²μ¦νλ κΈ°λ₯μ μ 곡ν©λλ€. μ ν리μΌμ΄μ
μμ μλͺ»λ λ°μ΄ν°κ° μ²λ¦¬λλ κ²μ λ°©μ§νκ³ , λ°μ΄ν°μ 무결μ±μ 보μ₯νλλ° λμμ μ€λλ€.
μ£Όμ νΉμ§
β’
Bean Validation APIλ₯Ό μ¬μ©ν μ¬μ΄ μ ν¨μ± κ²μ¦
β’
λ€μν λ΄μ₯ κ²μ¦ μ΄λ
Έν
μ΄μ
μ 곡
β’
컀μ€ν
κ²μ¦ λ‘μ§ κ΅¬ν κ°λ₯
β’
컨νΈλ‘€λ¬μμ μλ κ²μ¦ μ²λ¦¬
β’
μ€λ₯ λ©μμ§ μ»€μ€ν°λ§μ΄μ§ μ§μ
μ΄ κ°μμμλ Springκ³Ό MyBatisλ₯Ό μ΄μ©νμ¬ user ν
μ΄λΈ κΈ°λ° νμκ°μ
κΈ°λ₯μ ꡬννκ³ , Validationμ μ μ©νλ λ°©λ²μ νμ΅ν©λλ€.
Validation μ£Όμ μ΄λ
Έν
μ΄μ
μ΄λ
Έν
μ΄μ
| μ€λͺ
|
@NotNull | null κ° λΆν |
@NotBlank | null, λΉ λ¬Έμμ΄, 곡백λ§μΌλ‘ μ΄λ£¨μ΄μ§ λ¬Έμμ΄ λΆν |
@Size | λ¬Έμμ΄, λ°°μ΄μ κΈΈμ΄ κ²μ¦ (min, max μμ±) |
@Email | μ΄λ©μΌ νμ κ²μ¦ |
@Past | κ³Όκ±° λ μ§λ§ νμ© |
@Future | λ―Έλ λ μ§λ§ νμ© |
@Valid | μ€μ²©λ κ°μ²΄μ μ ν¨μ± κ²μ¬ μ€ν |
BidingResult μ£Όμ λ©μλ
λ©μλ | μ€λͺ
|
hasErrors() | μ΄λ€ μ’
λ₯λ μ€λ₯κ° μλμ§ νμΈ |
hasGlobalErrors() | κ°μ²΄ λ 벨μ μ€λ₯κ° μλμ§ νμΈ |
hasFieldErrors() | νλ λ 벨μ μ€λ₯κ° μλμ§ νμΈ |
getFieldError() | νΉμ νλμ 첫 λ²μ§Έ μ€λ₯ λ©μμ§ λ°ν |
getAllErrors() | λͺ¨λ μ€λ₯ λͺ©λ‘ λ°ν |
DB ν
μ΄λΈ μ μ
CREATE TABLE `user` (
`no` INT AUTO_INCREMENT PRIMARY KEY,
`id` VARCHAR(64) UNIQUE,
`username` VARCHAR(100) UNIQUE,
`password` VARCHAR(100) NOT NULL,
`name` VARCHAR(100) NOT NULL,
`email` VARCHAR(100) NOT NULL,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
SQL
볡μ¬
DTO + Validation μ΄λ
Έν
μ΄μ
μ΄λ
Έν
μ΄μ
| μ€λͺ
|
@NotBlank | null λ° κ³΅λ°± λΆν |
@Size | κΈΈμ΄ μ μ½ μ€μ |
@Email | μ΄λ©μΌ νμ κ²μ¦ |
User.java
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import java.util.Date;
public class User {
private Integer no;
@Size(min = 4, max = 64, message = "μμ΄λλ 4μ μ΄μ 64μ μ΄νλ‘ μ
λ ₯νμΈμ.")
private String id;
@NotBlank(message = "μμ΄λλ νμμ
λλ€.")
private String username;
@NotBlank(message = "λΉλ°λ²νΈλ νμμ
λλ€.")
private String password;
@NotBlank(message = "μ΄λ¦μ νμμ
λλ€.")
private String name;
@Email(message = "μ΄λ©μΌ νμμ΄ μλλλ€.")
@NotBlank(message = "μ΄λ©μΌμ νμμ
λλ€.")
private String email;
private Date createdAt;
private Date updatedAt;
}
Java
볡μ¬
Controller + Validation
UserController.java
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/join")
public String joinForm(Model model) {
model.addAttribute("User", new User());
return "join";
}
@PostMapping("/join")
public String join(@Validated @ModelAttribute("User") User User,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "join";
}
userService.registerUser(User);
return "redirect:/login";
}
}
Java
볡μ¬
BindingResult λμ ꡬ쑰
Springμ Validation μ²λ¦¬ κ³Όμ μμ BindingResultλ λ€μκ³Ό κ°μ μμλ‘ λμν©λλ€:
1.
μ ν¨μ± κ²μ¬ μ€ν: @Validated μ΄λ
Έν
μ΄μ
μ΄ λΆμ κ°μ²΄μ λν΄ κ²μ¦ μ€ν
2.
μ€λ₯ μμ§: BindingResult κ°μ²΄κ° κ²μ¦ κ³Όμ μμ λ°μν λͺ¨λ μ€λ₯ μ 보λ₯Ό μμ§
β’
νλ μ€λ₯ (Field Errors)
β’
κΈλ‘λ² μ€λ₯ (Global Errors)
3.
μ€λ₯ μ²λ¦¬: bindingResult.hasErrors()λ‘ μ€λ₯ μ‘΄μ¬ μ¬λΆ νμΈ
β’
true λ°ν μ νΌ νμ΄μ§λ‘ λ€μ μ΄λ
β’
μ€λ₯ λ©μμ§λ μλμΌλ‘ Modelμ ν¬ν¨λμ΄ λ·°λ‘ μ λ¬
μμ μ½λ λμ:
// 1. νΌμμ λ°μ΄ν° μ μΆ
// 2. @Validatedλ‘ κ²μ¦ μ€ν
// 3. BindingResultμ μ€λ₯ μ 보 μ μ₯
if (bindingResult.hasErrors()) {
// 4. μ€λ₯ λ°μ μ νΌ νμ΄μ§λ‘ 리ν΄
// - μ€λ₯ λ©μμ§κ° μλμΌλ‘ λ·°λ‘ μ λ¬λ¨
// - form:errors νκ·Έλ₯Ό ν΅ν΄ μ€λ₯ νμ
return "join";
}
// 5. κ²μ¦ ν΅κ³Ό μ μ μ μ²λ¦¬
Java
볡μ¬
JSPμμμ μ€λ₯ νμ:
<form:errors path="username" cssClass="error" />
<!-- username νλμ μ€λ₯κ° μμ κ²½μ° λ©μμ§ νμ -->
HTML
볡μ¬
BindingResultμ μλ¬ λ©μμ§ μ²λ¦¬ κ³Όμ
BindingResultκ° νΌμ μλ¬ λ©μμ§λ₯Ό μ λ¬νλ κ³Όμ μ λ€μκ³Ό κ°μ΅λλ€:
1.
μλ¬ κ°μ§: Validation μ΄λ
Έν
μ΄μ
κ²μ¦ μ€ν¨ μ μλ¬ μ λ³΄κ° μμ±λ¨
2.
μλ¬ μ μ₯: BindingResult κ°μ²΄μ μλ¬ μ 보 μλ μ μ₯
β’
νλ μλ¬: FieldError κ°μ²΄λ‘ μ μ₯
β’
κΈλ‘λ² μλ¬: ObjectError κ°μ²΄λ‘ μ μ₯
3.
Model μ λ¬: Spring MVCκ° μλμΌλ‘ BindingResultλ₯Ό Modelμ μΆκ°
β’
λ³λμ model.addAttribute() λΆνμ
β’
λ·°μμ μλμΌλ‘ μ κ·Ό κ°λ₯
4.
JSP μΆλ ₯: form:errors νκ·Έκ° ν΄λΉ μλ¬ λ©μμ§ νμ
β’
νλλ³ μλ¬: <form:errors path="νλλͺ
" />
β’
κΈλ‘λ² μλ¬: <form:errors path="*" />
// μμ: 컨νΈλ‘€λ¬μμμ μ²λ¦¬
@PostMapping("/join")
public String join(@Validated User user, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
// μλμΌλ‘ μλ¬ μ λ³΄κ° λ·°λ‘ μ λ¬λ¨
return "join";
}
// κ²μ¦ ν΅κ³Όμ μ²λ¦¬
}
Java
볡μ¬
JSPμμλ λ€μκ³Ό κ°μ΄ μλ¬ λ©μμ§λ₯Ό νμν μ μμ΅λλ€:
<form:form modelAttribute="user">
<form:input path="username" />
<form:errors path="username" cssClass="error" />
<!-- λͺ¨λ κΈλ‘λ² μλ¬ νμ -->
<form:errors path="*" cssClass="error" />
</form:form>
HTML
볡μ¬
form:errorsμ FieldErrorμ κ΄κ³
form:errors νκ·Έλ BindingResultμ μ μ₯λ FieldError κ°μ²΄λ‘λΆν° μ€λ₯ λ©μμ§λ₯Ό κ°μ Έμ νμν©λλ€. μ΄ κ³Όμ μ λ€μκ³Ό κ°μ΅λλ€:
1.
FieldError μμ±: κ²μ¦ μ€ν¨ μ Springμ΄ μλμΌλ‘ FieldError κ°μ²΄ μμ±
β’
νλλͺ
β’
κ±°μ λ κ°
β’
μλ¬ λ©μμ§
2.
λ©μμ§ κ²μ: form:errors νκ·Έκ° BindingResultμμ ν΄λΉ νλμ FieldErrorλ₯Ό μ°Ύμ
3.
λ©μμ§ μΆλ ₯: FieldErrorμμ μ€μ λ λ©μμ§λ₯Ό νλ©΄μ νμ
μμ μ½λ:
// 컨νΈλ‘€λ¬μμ FieldError νμΈ
if (bindingResult.hasFieldErrors("username")) {
FieldError error = bindingResult.getFieldError("username");
String message = error.getDefaultMessage(); // @NotBlank λ±μμ μ€μ ν λ©μμ§
}
Java
볡μ¬
JSPμμλ κ°λ¨ν λ€μκ³Ό κ°μ΄ μ¬μ©:
<form:errors path="username" /> <!-- username νλμ λͺ¨λ μλ¬ λ©μμ§ νμ -->
HTML
볡μ¬
MyBatis Mapper μ€μ
UserMapper.xml
<insert id="insertUser" parameterType="com.aloha.spring.dto.User">
INSERT INTO user (id, username, password, name, email)
VALUES (#{id}, #{username}, #{password}, #{name}, #{email})
</insert>
XML
볡μ¬
UserMapper.java
@Mapper
public interface UserMapper {
void insertUser(User User);
}
Java
볡μ¬
Service
β’
UserService.java
β’
UserServiceImpl.java
UserService.java
@Service
public interface UserService {
}
Java
볡μ¬
UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {
}
Java
볡μ¬
JSP νΌ κ΅¬μ± (spring form νκ·Έ)
join.jsp
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<h2>νμκ°μ
</h2>
<form:form modelAttribute="User" method="post" action="/join">
μμ΄λ: <form:input path="id" />
<form:errors path="id" cssClass="error" /><br/>
μ¬μ©μλͺ
: <form:input path="username" />
<form:errors path="username" cssClass="error" /><br/>
λΉλ°λ²νΈ: <form:password path="password" />
<form:errors path="password" cssClass="error" /><br/>
μ΄λ¦: <form:input path="name" />
<form:errors path="name" cssClass="error" /><br/>
μ΄λ©μΌ: <form:input path="email" />
<form:errors path="email" cssClass="error" /><br/>
<button type="submit">νμκ°μ
</button>
</form:form>
HTML
볡μ¬
μμ λλ ν°λΈ νκ·Έλ₯Ό λͺ
μν΄μΌ Spring Form νκ·Έλ₯Ό μ¬μ©ν μ μμ΅λλ€.
μ΄ λλ ν°λΈκ° μμΌλ©΄ λ€μκ³Ό κ°μ λ¬Έμ κ° λ°μν©λλ€:
β’
form:form, form:input λ±μ νκ·Έλ₯Ό μΈμνμ§ λͺ»ν¨
β’
μ»΄νμΌ μλ¬ λ°μ
β’
νμ΄μ§ λ λλ§ μ€ν¨
Spring Form νκ·Έ λΌμ΄λΈλ¬λ¦¬λ λ€μκ³Ό κ°μ μ΄μ μ μ 곡ν©λλ€:
β’
λͺ¨λΈ κ°μ²΄μ μλ λ°μΈλ©
β’
μ ν¨μ± κ²μ¬ μ€λ₯ λ©μμ§ νμ κΈ°λ₯
β’
HTML νΌ μμλ€μ λ μ½κ² μ²λ¦¬
β’
Springμ λ°μ΄ν° λ°μΈλ© κΈ°λ₯κ³Ό μλ²½ν ν΅ν©
ν΅μ¬ μ 리
μμ | μ€λͺ
|
DTO | μ
λ ₯ λ°μ΄ν° ꡬ쑰 μ μ λ° μ ν¨μ± κ²μ¬ μ€μ |
Controller | @Validated, BindingResultλ‘ μ
λ ₯ κ²μ¦ μ²λ¦¬ |
Service | λΉμ¦λμ€ λ‘μ§ μ²λ¦¬ |
MyBatis | DB μ μ₯ μ²λ¦¬ |
JSP | spring form νκ·Έλ‘ μ
λ ₯ λ° μ€λ₯ νμ |