ํฐ์คํ ๋ฆฌ ๋ทฐ
๊ฐ์
Spring-validation์ ๋ํด์ ํ์ตํ๊ณ ์ ๋ฆฌํ ๊ธ์ ๋๋ค.
ํด๋น ๊ธ์ spring-boot 2.5.2 ์์ ์งํ๋์์ต๋๋ค.
Spring Validation์ ์ด๋ ธํ ์ด์ ์ผ๋ก ๊ฐํธํ๊ฒ ํน์ ๊ฐ์ validationํ ์ ์๋๋ก ๋์์ค๋๋ค.
Gradle
spring validation ์ฌ์ฉ์ ์ํด์ ๊ทธ๋์ด๋ค ์์กด์ฑ์ ์ถ๊ฐํฉ๋๋ค.
dependencies {
...
implementation 'org.springframework.boot:spring-boot-starter-validation'
...
}
์์
spring-validation์ ๋ค์๊ณผ ๊ฐ์ด ๊ฐ๊ฐ์ ๋ง๋ Annotation์ ๋ถ์ฌ์ค์ผ๋ก์จ ๊ฐ์ ๊ฒ์ฆํ ์ ์์ต๋๋ค.
๋จผ์ ์๋ ์์ ์ฝ๋๋ฅผ ๋ณด๊ณ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง ๊ฐ์ ์ก์๋ณด์ธ์.
์๋ช
์ด ์ ๋์ด์์ด์ ์ด๋์ ๋ ์ ์ถํ ์ ์์ ๊ฒ๋๋ค!
์ดํ ๋ด์ฉ์์ ๊ด๋ จ Annotation์ ๋ํด ๋ค๋ฃน๋๋ค.
// Api.java
@GetMapping
public User get(@RequestParam @NotBlank String name,
@RequestParam @Min(value = 1, message = "age๋ 1์ด์์ด์ด์ผ ํฉ๋๋ค.") Integer age) {
User user = new User();
user.setName(name);
user.setAge(age);
return user;
}
@PostMapping
public User post(@RequestBody @Valid UserDto user) {
System.out.println(user);
return user;
}
// UserDto.java
public class UserDto {
@Size(min = 1, max = 10) // ๊ธธ์ด
private String name;
@NotNull // null ๋ถ๊ฐ๋ฅ
@Min(1) // 1 ์ด์
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
๊ด๋ จ Annotation
@Valid
: ํด๋น object์ validation์ ํ๊ฒ ๋ค๋ ํ์@NotNull
: null ๋ถ๊ฐ๋ฅ@NotEmpty
: null, ""(๊ณต๋ฐฑ) ๋ถ๊ฐ๋ฅ@NotBlank
: null, "", " " ๋ถ๊ฐ๋ฅ@Pattern
: ์ ๊ท์์ ์ด์ฉํด์ ๊ฒ์ฆ ๊ฐ๋ฅ@Size
: ๋ฌธ์ ๊ธธ์ด ๊ฒ์ฆ, ์ซ์ type์ ๋ถ๊ฐ๋ฅ ex) @Size(min = 0, max = 11)@Max
: ์ต๋๊ฐ ๊ฒ์ฆ@Min
: ์ต์๊ฐ ๊ฒ์ฆ@AssertTrue
/@AssertFalse
: ๋ณ๋์ ๋ก์ง์ผ๋ก ๊ฒ์ฆ ๊ฐ๋ฅ → ์กฐ๊ธ ์๋์์ ์ดํด๋ด ๋๋ค.@Past
: ๊ณผ๊ฑฐ ๋ ์ง (์ค๋ ์ด์ )@PastOrPresent
: ์ค๋์ด๊ฑฐ๋ ๊ณผ๊ฑฐ@Future
: ๋ฏธ๋ ๋ ์ง (์ค๋ ์ดํ)@FutureOfPresent
: ์ค๋์ด๊ฑฐ๋ ๋ฏธ๋
๊ฒ์ฆ ์คํจ ์ Message
Validation์ ์คํจํ๋ฉด message๋ฅผ ํตํด์ ๊ฒ์ฆ ์คํจ ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํ ์ ์์ต๋๋ค.
๊ฒ์ฆ ์คํจ ์ ์๋์ ๊ฐ์ด server error๊ฐ ๋ฐ์ํ๊ณ message๊ฐ ์ถ๋ ฅ๋๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
Message ๋ณ๊ฒฝํ๊ธฐ
Validation ๊ด๋ จ Annotation์ ์ดํด๋ณด๋ฉด
์๋์ ๊ฐ์ด message๋ผ๋ ๋ฉค๋ฒ๋ฅผ ๊ฐ์ง ๊ฑธ ์ ์ ์์ต๋๋ค.
์ด๋ฅผ ํ ๋ฒ ์ปค์คํ ํด๋ณผ๊ฒ์
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(List.class)
@Documented
@Constraint(validatedBy = { })
public @interface Min {
String message() default "{javax.validation.constraints.Min.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
/**
* @return value the element must be higher or equal to
*/
long value();
์๋์ ๊ฐ์ด ๊ฐ๋จํ api๋ฅผ ๋ง๋ค๊ณ @Min
์ ์ด์ฉํด์ age๊ฐ 19 ๋ฏธ๋ง์ผ ๋๋ฅผ ๊ฒ์ฆํ๊ณ error ๋ฐ์ ์ message
๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์ค์ ํด ๋ณด๊ฒ ์ต๋๋ค.
@GetMapping
public User get(@RequestParam @NotBlank String name,
@RequestParam @Min(value = 19, message = "ํด๋น ์ปจํด์ธ ๋ 19์ธ ์ด์ ์ ๊ทผ ๊ฐ๋ฅํฉ๋๋ค.")
Integer age) {
User user = new User();
user.setName(name);
user.setAge(age);
return user;
}
์ด์ ํด๋น uri๋ก ์ ๊ทผํ๋ฉด?
๋ค์๊ณผ ๊ฐ์ด message๊ฐ ๋ณ๊ฒฝ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค
๊ฒ์ฆ ๋ก์ง ์ปค์คํ ํ๊ธฐ
์ํ๋ ๊ฒ์ฆ ๋ก์ง์ ์ค์ ํ ์๋ ์์ต๋๋ค.
๊ทธ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
@AssertTrue
์@AssertFalse
์ด์ฉํ๊ธฐ@AsserFalse
๋ ์ฌ๊ธฐ์ ๋ค๋ฃจ์ง ์์ต๋๋ค.
๊ฐ๋จํ๊ฒ @AssertTrue์ ๋ฐ๋๋ก return๊ฐ์ ์ฃผ๋ฉด ๋ฉ๋๋ค.
return๊ฐ์ ๋ํ ์์ธํ ๋ด์ฉ์ ์๋ @AssertTrue๋ฅผ ํ์ธํด์ฃผ์ธ์Annotation
+Validator
์ ์ํ๊ธฐ
@AssertTrue
@AssertTrue
๋ฅผ ์ฌ์ฉํ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋ฉ์๋๋ฅผ ์๋ก ์ ์ํด์ ๊ฒ์ฆ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ฃผ์์ : ์์ boolean๊ฐ์ return ํด์ผํ๋ฉฐ, ๋ฉ์๋ ๋ช
์ ์ ๋์ฌ๋ก is๋ฅผ ๋ถ์ฌ์ผํฉ๋๋ค.
์ ๋ถ์ด๋ฉด ์ธ์์ ๋ชป ํ๋๋ผ๊ตฌ์..
Day๋ผ๋ dto๋ฅผ ์์ฑํ๊ณ ์ด๋ฅผ ํ ์คํธํด๋ณด๊ฒ ์ต๋๋ค.
public class Day {
String localDate;
@AssertTrue(message = "yyyy-MM-dd ํ์์ ๋ง์ง ์์ต๋๋ค.")
public boolean isValidLocalDate() {
try {
LocalDate.parse(getLocalDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
} catch (Exception e) {
return false;
}
return true;
}
public String getLocalDate() {
return localDate;
}
public void setLocalDate(String localDate) {
this.localDate = localDate;
}
}
BindingResult๋ฅผ Controller ๋งค๊ฐ๋ณ์์ ์ถ๊ฐํ๋ฉด validation ์คํจ ์์ error ์ ๋ณด๋ฅผ ๋ฐ์์ฌ ์ ์์ต๋๋ค.
์๋ ์ฝ๋๋ ์ด๋ฅผ ์ด์ฉํด์ error ๋ฉ์์ง๋ฅผ response๋ก ์ ๋ฌํ ์ ์๊ฒ ๊ตฌ์ฑํ์ต๋๋ค.
@RestController
@RequestMapping("/v1")
public class Api {
@PostMapping("/day")
public ResponseEntity day(@RequestBody @Valid Day dto, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
StringBuilder sb = new StringBuilder();
List<ObjectError> errors = bindingResult.getAllErrors();
errors.forEach(objectError -> {
FieldError fieldError = (FieldError) objectError;
String field = fieldError.getField();
String message = fieldError.getDefaultMessage();
sb.append("field : " + field + "\n");
sb.append("message : " + message + "\n");
});
return ResponseEntity.badRequest()
.body(sb.toString());
}
return ResponseEntity.ok(dto);
}
}
postman์ ์ด์ฉํด์ ํ ์คํธ๋ฅผ ํด๋ณด๋ฉด validation์ด ์ ์ ์ฉ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค์!
Annotation + Validator ์ ์ํ๊ธฐ
์ฌ์ค ์ @AssertTrue ๋ฐฉ์์ ๋งค๋ฒ DTO๋ง๋ค ๋ฉ์๋๋ฅผ ์ ์ํด์ค์ผ ํ๊ธฐ์ ์ฝ๋๊ฐ ์ค๋ณต๋ ๊ฐ๋ฅ์ฑ์ด ์์ต๋๋ค.
์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด์ Annotation
๊ณผ Validator
๋ฅผ ์ ์ํด์ ํ๋ก์ ํธ ์ ์ญ์์ Annotation๋ง์ผ๋ก Validation์ ์ํํ ์ ์์ต๋๋ค!
๋จผ์ DateTime ์ด๋ผ๋ Annotation์ ์ ์ํด๋ณด๊ฒ ์ต๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก yyyy-MM-dd ํ์์ผ๋ก ๊ฒ์ฆ์ ์งํํ๊ณ , pattern์ ์ปค์คํ ํ ์๋ ์๊ฒ ๊ตฌ์ฑํ์ต๋๋ค.
์ฐธ๊ณ ๋ก validation message์๋ EL(ํํ์ธ์ด)๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
message์ ${validatedValue}๋ Request๋ก ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ ๊ฐ์ด๊ณ , {pattern}์ DateTime ํ๋์ธ pattern๊ฐ ์ ๋๋ค.
// DateTime.java
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {DateTimeValidator.class}) // (1)
public @interface DateTime {
// (2)
String message() default "${validatedValue}๋ {pattern}ํ์๊ณผ ์ผ์นํ์ง ์์ต๋๋ค.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
// (3)
String pattern() default "yyyy-MM-dd";
}
์ด์ Validator
๋ฅผ ์ ์ํด๋ด
์๋ค. ConstraintValidator
interface๋ฅผ ์์๋ฐ์ ๊ตฌํํฉ๋๋ค.
์๋ ๋ณด์ด๋ DateTimeValidator๋ @DateTime์ด ์๋ ํ๋ ํน์ ๋งค๊ฐ๋ณ์๋ฅผ ๊ฒ์ฆํฉ๋๋ค.
public class DateTimeValidator implements ConstraintValidator<DateTime, String> {
private String pattern;
@Override
public void initialize(DateTime constraintAnnotation) {
this.pattern = constraintAnnotation.pattern(); // (1)
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// (2)
try {
LocalDate.parse(value, DateTimeFormatter.ofPattern(this.pattern));
} catch (Exception e) {
return false;
}
return true;
}
}
- (1) @DateTime์ parttern์ ๊ฐ์ ธ์ต๋๋ค.
- (2) LocalDate๋ก parsing์ด ๊ฐ๋ฅํ์ง ๊ฒ์ฆํฉ๋๋ค. parsing ๋ถ๊ฐ๋ฅ ์ error๊ฐ ๋ฐ์ํ์ฌ try catch ๋ฌธ์ ์ฌ์ฉํฉ๋๋ค.
์ด์ Validation์ ์ํ ์ค๋น๋ฅผ ๋ง์ณค์ต๋๋ค
์ด๋ฒ์๋ QueryString์ Validation ํด๋ณด๋ ค๊ณ ํฉ๋๋ค. ๊ทธ๋ฌ๊ธฐ ์ํด์ ๋ช๊ฐ์ง ์์ ์ด ๋ ํ์ํฉ๋๋ค.
QueryString์ Validationํ๊ธฐ ์ํด์๋ ํด๋น ์ปจํธ๋กค๋ฌ ํด๋์ค์ @Valdated
๋ฅผ ์ถ๊ฐํ๊ณ , ํ
์คํธ์ ์ฌ์ฉํ api๋ฅผ ์ ์ํฉ๋๋ค.
@Validated
๋ฅผ ์ฌ์ฉํ๋ฉด service๊ฐ์ด controller๊ฐ ์๋ ๋ค๋ฅธ class์์๋ validation์ ์ํํ ์ ์์ต๋๋ค.
@Validated // (1)
@RestController
@RequestMapping("/v1")
public class Api {
@GetMapping("/items") // (2)
public ResponseEntity items(@RequestParam("createdDate") @DateTime String createdDate) {
return ResponseEntity.ok(createdDate);
}
}
- (1) @Validated๋ฅผ ์ถ๊ฐํด์ค๋๋ค.
- (2) QueryString์ผ๋ก createdDate ๊ฐ์ ๋ฐ์์ ๊ฒ์ฆํ api์ ๋๋ค. @DateTime๋ฅผ ํ์ธํด์ฃผ์ธ์
์ดํ์ postman์ผ๋ก ํ ์คํธ ํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๊ฒ์ฆ ๋ก์ง์ด ์ ์ ์ฉ๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค!
์ฃผ์! ๋์น์ฑ์ ๋ถ๋ ์๊ฒ ์ง๋ง ์ด๋ฒ items() GET API์์ BindingResult๋ฅผ ๋งค๊ฐ๋ณ์๋ก ์ฌ์ฉํ์ง ๋ชป ํ์ต๋๋ค. BindingResult
๋ @RequestBody
ํน์ @RequestPart
์ฌ์ฉ ์์๋ง ๋งค๊ฐ๋ณ์๋ก ์ฌ์ฉํ ์ ์์ผ๋ ์ด ์ ์ฃผ์ํด์ฃผ์ธ์!
๋ง๋ฌด๋ฆฌ
์ฌ๊ธฐ๊น์ง Spring Validation์ ๋ํด์ ์์๋ดค์ต๋๋ค.
๋ค์์๋ Spring Validation๊ณผ exceptionHandler๋ฅผ ์กฐํฉํด์ API ์ฌ์ฉ์๊ฐ ์ด๋ค ๊ฐ์ ๋ณด๋๋์ง์ ๋ํด์ ์๋ง๋ Response๋ฅผ ๋ณด๋ด์ค ์ ์๊ฒ ํ๋ ๊ณผ์ ์ ๋ํด์ ๊ธ์ ์์ฑํด๋ณด๊ฒ ์ต๋๋ค!
์ฐธ๊ณ
Validation์ ๋ํด์ ๋ ๋ง์ ์ ๋ณด๋ฅผ ์๊ณ ์ถ๋ค๋ฉด ์๋ ๊ธ๋ค์ ์ฐธ๊ณ ํ๋ ๊ฑธ ์ถ์ฒํฉ๋๋ค!
https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/
'Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
JPA UUID varchar๋ก ์ ์ฅํ๊ธฐ (0) | 2021.11.29 |
---|
- Total
- Today
- Yesterday
- ๊น์ด/๋๋น ์ฐ์ ํ์(DFS/BFS)
- Golang
- ์ฝ๋ฉํ ์คํธ
- 2๋ ์ฐจ ์๋ฒ ๊ฐ๋ฐ์
- 2023 ํ๊ณ
- ์ฅ์ ํ๊ณ
- rate limit
- Aws Reinvent 2023
- ๋ฑ ํฌ์๋ฌ๋ ๊ฐ๋ฐ์
- Go
- ํ๋ก๊ทธ๋๋จธ์ค
- ์ข์ ๊ฐ๋ฐ์ ๋๊ธฐ
- AWS re:Invent 2023
- mysql
- kotlin s3 upload
- ์๊ณ ๋ฆฌ์ฆ
- 2023 ๊ฐ๋ฐ์ ํ๊ณ
- ํด์
- ํธ๋์ญ์ ๊ฒฉ๋ฆฌ ์์ค
- golang oomkilled
- ์ข์ ์์ง๋์ด
- mysql ์คํ ๊ณํ
- ์คํ/ํ
- grpc client
- ์ข์ ๊ฐ๋ฐ์
- ์ถ์ ์ง๋
- ์ข์ ์ฝ๋๋ ๋ฌด์์ธ๊ฐ?
- HTTP
- ํ(Heap)
- ๋ฐฑ์ค
์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |