Search

Spring Validation

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
์ด๋ฉ”์ผ ํ˜•์‹ ๊ฒ€์ฆ

build.gradle

plugins { id 'java' id 'war' id 'org.springframework.boot' version '3.5.9' id 'io.spring.dependency-management' version '1.1.7' } group = 'com.aloha' version = '0.0.1-SNAPSHOT' description = 'Demo project for Spring Boot' java { toolchain { languageVersion = JavaLanguageVersion.of(23) } } configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.5' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.5' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } tasks.named('test') { useJUnitPlatform() }
Java
๋ณต์‚ฌ
User.java
@Data public class Users { private Integer no; @Size(min = 4, max = 64, message = "์•„์ด๋””๋Š” 4์ž ์ด์ƒ 64์ž ์ดํ•˜๋กœ ์ž…๋ ฅํ•˜์„ธ์š”.") private String id; @NotBlank(message = "์•„์ด๋””๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") @Pattern( regexp = "^[A-Za-z0-9]{6,20}$", message = "์•„์ด๋””๋Š” ์˜๋ฌธ๊ณผ ์ˆซ์ž๋งŒ ๊ฐ€๋Šฅํ•˜๋ฉฐ 6~20์ž ์ด๋‚ด๋กœ ์ž‘์„ฑํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค." ) private String username; @NotBlank(message = "๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") @Pattern( regexp = "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$", message = "๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” 8์ž ์ด์ƒ์ด๋ฉฐ, ์˜๋ฌธ, ์ˆซ์ž, ํŠน์ˆ˜๋ฌธ์ž๋ฅผ ํฌํ•จํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค." ) private String password; @NotBlank(message = "์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") @Size(min = 2, max = 10, message = "์ด๋ฆ„์€ 2~10๊ธ€์ž ์ด๋‚ด๋กœ ์ž‘์„ฑํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.") private String name; @Email(message = "์ด๋ฉ”์ผ ํ˜•์‹์ด ์•„๋‹™๋‹ˆ๋‹ค.") @NotBlank(message = "์ด๋ฉ”์ผ์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.") private String email; private Date createdAt; private Date updatedAt; }
Java
๋ณต์‚ฌ

Controller + Validation

UserController.java
@Slf4j @Controller @RequiredArgsConstructor public class UserController { private final UserService userService; /** * ํšŒ์›๊ฐ€์ž… ํ™”๋ฉด * @param model * @param user * @return */ @GetMapping("/signup") public String signup(Model model, Users user) { return "signup"; } /** * ํšŒ์›๊ฐ€์ž… ์ฒ˜๋ฆฌ * @param user * @param bindingResult * @return * @throws Exception * โญ @Validated : ์ง€์ •ํ•œ ๊ฐ์ฒด์— ๋Œ€ํ•ด์„œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์‹คํ–‰ * โญ BindingResult : ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์—์„œ ๋ฐœ์ƒํ•œ ์—๋Ÿฌ ๊ฒฐ๊ณผ๋ฅผ ๋‹ด์€ ๊ฐ์ฒด */ @PostMapping("/signup") public String signup( @Validated @ModelAttribute("user") Users user, BindingResult bindingResult ) throws Exception { // ์œ ํšจ์„ฑ ๊ฒ€์ฆ ์—๋Ÿฌ ๋ฐœ์ƒํ•˜๋ฉด โžก ๋‹ค์‹œ ํšŒ์›๊ฐ€์ž… ํ™”๋ฉด์œผ๋กœ if( bindingResult.hasErrors() ) { return "signup"; } // ์œ ํšจ์„ฑ ๊ฒ€์ฆ ์„ฑ๊ณตํ•˜๋ฉด, ํšŒ์›๊ฐ€์ž… ์ฒ˜๋ฆฌ ํ›„ ๋ฉ”์ธํ™”๋ฉด์œผ๋กœ boolean result = userService.insert(user); log.info("ํšŒ์›๊ฐ€์ž… ์„ฑ๊ณต ์—ฌ๋ถ€ : " + result); return "redirect:/"; } }
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
๋ณต์‚ฌ
View์—์„œ์˜ ์˜ค๋ฅ˜ ํ‘œ์‹œ:
<form:errors path="username" cssClass="error" /> <!-- username ํ•„๋“œ์— ์˜ค๋ฅ˜๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ -->
HTML
๋ณต์‚ฌ
BindingResult๋Š” ๋ฐ˜๋“œ์‹œ @Validated ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”๋กœ ๋‹ค์Œ์— ์œ„์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ˆœ์„œ๊ฐ€ ๋‹ค๋ฅผ ๊ฒฝ์šฐ ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

BindingResult์˜ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ ๊ณผ์ •

BindingResult๊ฐ€ ํผ์— ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
1.
์—๋Ÿฌ ๊ฐ์ง€: Validation ์–ด๋…ธํ…Œ์ด์…˜ ๊ฒ€์ฆ ์‹คํŒจ ์‹œ ์—๋Ÿฌ ์ •๋ณด๊ฐ€ ์ƒ์„ฑ๋จ
2.
์—๋Ÿฌ ์ €์žฅ: BindingResult ๊ฐ์ฒด์— ์—๋Ÿฌ ์ •๋ณด ์ž๋™ ์ €์žฅ
โ€ข
ํ•„๋“œ ์—๋Ÿฌ: FieldError ๊ฐ์ฒด๋กœ ์ €์žฅ
โ€ข
๊ธ€๋กœ๋ฒŒ ์—๋Ÿฌ: ObjectError ๊ฐ์ฒด๋กœ ์ €์žฅ
3.
Model ์ „๋‹ฌ: Spring MVC๊ฐ€ ์ž๋™์œผ๋กœ BindingResult๋ฅผ Model์— ์ถ”๊ฐ€
โ€ข
๋ณ„๋„์˜ model.addAttribute() ๋ถˆํ•„์š”
โ€ข
๋ทฐ์—์„œ ์ž๋™์œผ๋กœ ์ ‘๊ทผ ๊ฐ€๋Šฅ
4.
View ์ถœ๋ ฅ: form:errors ํƒœ๊ทธ๊ฐ€ ํ•ด๋‹น ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ
โ€ข
ํ•„๋“œ๋ณ„ ์—๋Ÿฌ: <form:errors path="ํ•„๋“œ๋ช…" />
โ€ข
๊ธ€๋กœ๋ฒŒ ์—๋Ÿฌ: <form:errors path="*" />
// ์˜ˆ์‹œ: ์ปจํŠธ๋กค๋Ÿฌ์—์„œ์˜ ์ฒ˜๋ฆฌ @PostMapping("/join") public String join(@Validated User user, BindingResult bindingResult) { if (bindingResult.hasErrors()) { // ์ž๋™์œผ๋กœ ์—๋Ÿฌ ์ •๋ณด๊ฐ€ ๋ทฐ๋กœ ์ „๋‹ฌ๋จ return "join"; } // ๊ฒ€์ฆ ํ†ต๊ณผ์‹œ ์ฒ˜๋ฆฌ }
Java
๋ณต์‚ฌ
View ์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:
<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
๋ณต์‚ฌ
View์—์„œ๋Š” ๊ฐ„๋‹จํžˆ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉ:
<form:errors path="username" /> <!-- username ํ•„๋“œ์˜ ๋ชจ๋“  ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ -->
HTML
๋ณต์‚ฌ

MyBatis Mapper ์„ค์ •

UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- namespace="๋งคํผ ์ธํ„ฐํŽ˜์ด์Šค ๊ฒฝ๋กœ" --> <mapper namespace="com.aloha.validation.mapper.UserMapper"> <insert id="insert"> INSERT INTO user( id, username, password, name, email ) VALUES ( #{id}, #{username}, #{password}, #{name}, #{email} ) </insert> </mapper>
XML
๋ณต์‚ฌ
UserMapper.java
@Mapper public interface UserMapper { // ํšŒ์› ๋“ฑ๋ก int insert(Users user) throws Exception; }
Java
๋ณต์‚ฌ

Service

โ€ข
UserService.java
โ€ข
UserServiceImpl.java

UserService.java

public interface UserService { boolean insert(Users user) throws Exception; }
Java
๋ณต์‚ฌ

UserServiceImpl.java

@Service @RequiredArgsConstructor public class UserServiceImpl implements UserService { private final UserMapper userMapper; @Override public boolean insert(Users user) throws Exception { int result = userMapper.insert(user); return result > 0; } }
Java
๋ณต์‚ฌ

ํผ ๊ตฌ์„ฑ (spring form ํƒœ๊ทธ)

signup.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ํšŒ์›๊ฐ€์ž…</title> </head> <body> <h2>ํšŒ์›๊ฐ€์ž…</h2> <form th:action="@{/signup}" th:object="${user}" method="post"> <div> ์•„์ด๋”” : <input type="text" th:field="*{username}"> <span th:errors="*{username}" class="error"></span> </div> <div> ๋น„๋ฐ€๋ฒˆํ˜ธ : <input type="password" th:field="*{password}"> <span th:errors="*{password}" class="error"></span> </div> <div> ์ด๋ฆ„ : <input type="text" th:field="*{name}"> <span th:errors="*{name}" class="error"></span> </div> <div> ์ด๋ฉ”์ผ : <input type="email" th:field="*{email}"> <span th:errors="*{email}" class="error"></span> </div> <button type="submit">ํšŒ์›๊ฐ€์ž…</button> </form> </body> </html>
HTML
๋ณต์‚ฌ

Thymeleaf Form ํƒœ๊ทธ ์„ค๋ช…

ํƒœ๊ทธ/์†์„ฑ
์„ค๋ช…
์˜ˆ์‹œ
th:object
ํผ๊ณผ ๋ฐ”์ธ๋”ฉํ•  ๋ชจ๋ธ ๊ฐ์ฒด๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ „๋‹ฌ๋œ ๊ฐ์ฒด์™€ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค.
<form th:object="${user}">
th:field
๋ชจ๋ธ ๊ฐ์ฒด์˜ ํŠน์ • ํ•„๋“œ์™€ input ์š”์†Œ๋ฅผ ๋ฐ”์ธ๋”ฉํ•ฉ๋‹ˆ๋‹ค. id, name, value ์†์„ฑ์„ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
<input th:field="*{username}" />
#fields.hasErrors()
ํŠน์ • ํ•„๋“œ์— ์œ ํšจ์„ฑ ๊ฒ€์ฆ ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
th:if="${#fields.hasErrors('username')}"
th:errors
ํŠน์ • ํ•„๋“œ์˜ ์œ ํšจ์„ฑ ๊ฒ€์ฆ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. BindingResult์˜ ์˜ค๋ฅ˜ ์ •๋ณด๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.
<span th:errors="*{username}"></span>
*{field}
th:object๋กœ ์ง€์ •๋œ ๊ฐ์ฒด์˜ ํ•„๋“œ๋ฅผ ์ฐธ์กฐํ•˜๋Š” ์„ ํƒ ๋ณ€์ˆ˜ ํ‘œํ˜„์‹์ž…๋‹ˆ๋‹ค.
*{username}์€${user.username}๊ณผ ๋™์ผ
th:action
ํผ ์ œ์ถœ ์‹œ ์š”์ฒญํ•  URL์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. @{} ํ‘œํ˜„์‹์œผ๋กœ ์ปจํ…์ŠคํŠธ ๊ฒฝ๋กœ๊ฐ€ ์ž๋™์œผ๋กœ ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.
th:action="@{/join}"
th:field์˜ ์ž๋™ ์ƒ์„ฑ ์†์„ฑ
th:field="*{username}"์„ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์Œ ์†์„ฑ๋“ค์ด ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค:
โ€ข
id="username"
โ€ข
name="username"
โ€ข
value="${user.username}" (๊ธฐ์กด ๊ฐ’์ด ์žˆ๋Š” ๊ฒฝ์šฐ)
Spring Form ํƒœ๊ทธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์ ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค:
โ€ข
๋ชจ๋ธ ๊ฐ์ฒด์™€ ์ž๋™ ๋ฐ”์ธ๋”ฉ
โ€ข
์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ ๊ธฐ๋Šฅ
โ€ข
HTML ํผ ์š”์†Œ๋“ค์„ ๋” ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌ
โ€ข
Spring์˜ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ ๊ธฐ๋Šฅ๊ณผ ์™„๋ฒฝํ•œ ํ†ตํ•ฉ

ํ•ต์‹ฌ ์ •๋ฆฌ

์š”์†Œ
์„ค๋ช…
DTO
์ž…๋ ฅ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์ •์˜ ๋ฐ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์„ค์ •
Controller
@Validated, BindingResult๋กœ ์ž…๋ ฅ ๊ฒ€์ฆ ์ฒ˜๋ฆฌ
Service
๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ฒ˜๋ฆฌ
MyBatis
DB ์ €์žฅ ์ฒ˜๋ฆฌ
View (html)
spring form ํƒœ๊ทธ๋กœ ์ž…๋ ฅ ๋ฐ ์˜ค๋ฅ˜ ํ‘œ์‹œ