1. Validator ๐ฉ
์ด์ ๊น์ง ๊ฒ์ฆ ๊ธฐ๋ฅ๋ค์ ์ปจํธ๋กค๋ฌ ์์ ์์๋ค. ๋น์ฐํ ์ด๋ฐ ๊ฒฝ์ฐ์๋ ๋ณ๋์ ํด๋์ค๋ฅผ ๋ง๋ค์ด์ ์ญํ ์ ๋ถ๋ฆฌํ๋ ๊ฒ์ด ์ข๋ค.
๊ธฐ์กด ์ฝ๋๋ฅผ ๋จผ์ ์ดํด๋ณด๊ณ , ItemValidator๋ผ๋ ํด๋์ค๋ฅผ ๋ง๋ค์ด์ ์ด๋ป๊ฒ ๋ณ๋์ ํด๋์ค๋ก ๊ฒ์ฆ ๊ธฐ๋ฅ์ ๋ถ๋ฆฌํ์๋์ง ์์๋ณด์.
// ๊ธฐ์กด ์ฝ๋
@Slf4j
@Controller
@RequiredArgsConstructor
public class ValidationController3 {
private final ItemRepository itemRepository;
@PostMapping("/add")
public String addItem(@ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes) {
// 1. ์์ดํ
์ด๋ฆ(itemName)์ด ์๋ ๊ฒฝ์ฐ
ValidationUtils.rejectIfEmptyOrWhitespace(bindingResult, "itemName", "required");
// 2. ๊ฐ๊ฒฉ(itemPrice)์ ๋ฒ์๊ฐ 1,000 ~ 1,000,000์ด ์๋ ๊ฒฝ์ฐ
if(item.getPrice() == null || item.getPrice() < 1000 | item.getPrice() > 1_000_000){
bindingResult.rejectValue("price", "range", new Object[]{1_000, 1_000_000}, null);
}
// 3. ๊ฐ์(quantity)๊ฐ ์ต๋ 9,999๊ฐ๊ฐ ์๋ ๊ฒฝ์ฐ
if(item.getQuantity() == null || item.getQuantity() > 10_000) {
bindingResult.rejectValue("quantity", "max", new Object[]{9_999}, null);
}
// ํน์ ํ๋ ์์ธ๊ฐ ์๋ ์ ์ฒด ์์ธ
// 4. ์ต์ข
๊ฐ(๊ฐ๊ฒฉ(itemPrice) * ๊ฐ์(quantity))์ด 10,000์ ๋ฏธ๋ง์ธ ๊ฒฝ์ฐ
if(item.getPrice() != null && item.getQuantity() != null){
int resultPrice = item.getPrice() * item.getQuantity();
if(resultPrice < 10_000) {
bindingResult.reject("totalPriceMin", new Object[]{10_000, resultPrice}, null);
}
}
if(bindingResult.hasErrors()){
return "item/addForm"; // ๋ค์ ์ํ ๋ฑ๋กํ์ด์ง๋ก ์ด๋
}
Item savedItem = itemRepository.save(item);
redirectAttributes.addAttribute("itemId", savedItem.getId());
redirectAttributes.addAttribute("status", true);
return "redirect:/items/{itemId}";
}
}
// ๊ฒ์ฆ๊ธฐ๋ฅ ๋ถ๋ฆฌ
@Component
public class ItemValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return Item.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
Item item = (Item) target;
// 1. ์์ดํ
์ด๋ฆ(itemName)์ด ์๋ ๊ฒฝ์ฐ
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "itemName", "required");
// 2. ๊ฐ๊ฒฉ(itemPrice)์ ๋ฒ์๊ฐ 1,000 ~ 1,000,000์ด ์๋ ๊ฒฝ์ฐ
if(item.getPrice() == null || item.getPrice() < 1000 | item.getPrice() > 1_000_000){
errors.rejectValue("price", "range", new Object[]{1_000, 1_000_000}, null);
}
// 3. ๊ฐ์(quantity)๊ฐ ์ต๋ 9,999๊ฐ๊ฐ ์๋ ๊ฒฝ์ฐ
if(item.getQuantity() == null || item.getQuantity() > 10_000) {
errors.rejectValue("quantity", "max", new Object[]{9_999}, null);
}
// ํน์ ํ๋ ์์ธ๊ฐ ์๋ ์ ์ฒด ์์ธ
// 4. ์ต์ข
๊ฐ(๊ฐ๊ฒฉ(itemPrice) * ๊ฐ์(quantity))์ด 10,000์ ๋ฏธ๋ง์ธ ๊ฒฝ์ฐ
if(item.getPrice() != null && item.getQuantity() != null) {
int resultPrice = item.getPrice() * item.getQuantity();
if(resultPrice < 10_000) {
errors.reject("totalPriceMin", new Object[]{10_000, resultPrice}, null);
}
}
}
}
์คํ๋ง์ Validator๋ผ๋ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๋ค. ํ๋ผ๋ฏธํฐ์ ๋ฉ์๋์ ์ค๋ช ์ ์ฃผ์์ ํตํด์ ํ์ธํ์.
public interface Validator {
// ๊ฐ์ฒด ํ์
์ด ์ด๋ค ๊ฒ์ฆ๊ธฐ๋ฅผ ์ฌ์ฉํด์ผํ๋์ง ์๋ ค์ค๋ค.
boolean supports(Class<?> clazz);
// target = ๊ฒ์ฆ ๋์ ๊ฐ์ฒด, errors = BindingResult
void validate(Object target, Errors errors);
}
Validator๋ ํ๋์ ํด๋์ค์ ์ ์ฉํ ์๋ ์๊ณ ๊ธ๋ก๋ฒ ์ค์ ์ผ๋ก ์ ์ฉํ ์๋ ์๋ค. ๋ ๊ฐ์ง ์ค์ ๋ฐฉ๋ฒ๋ค์ ๊ฐ๊ฐ ์์๋ณด์.
2. Validator ์ ์ฉ ๋ฐฉ๋ฒ - ํ๋์ ์ปจํธ๋กค๋ฌ์ ์ ์ฉ ๐ช
WebDataBinder๋ฅผ ์ฌ์ฉํ๋ฉด ์คํ๋ง์ ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ์ ์ญํ ์ ํด์ฃผ๊ณ ๊ฒ์ฆ ๊ธฐ๋ฅ๋ ๋ด๋ถ์ ํฌํจํ๋ค.
์ฌ์ฉ๋ฐฉ๋ฒ์ @InitBinder๋ฅผ ์ด์ฉํ ์ฝ๋๋ฅผ ํด๋น ์ปจํธ๋กค๋ฌ์ ์ถ๊ฐํ๊ณ , ๊ฒ์ฆ์ ํ ๊ฐ์ฒด ์์ @Validated๋ฅผ ์ ์ด์ฃผ๋ฉด ๋๋ค.
@Slf4j
@Controller
@RequiredArgsConstructor
public class ValidationController4 {
private final ItemRepository itemRepository;
private final ItemValidator itemValidator;
@InitBinder
public void init(WebDataBinder dataBinder) {
dataBinder.addValidators(itemValidator);
}
@PostMapping("/add")
public String addItem(@Validated @ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes) {
// ๊ธฐ์กด์ ๊ฒ์ฆ ๊ธฐ๋ฅ์ด ์๋ ์ฝ๋๋ค์ด ์์ด์ก๋ค. (ItemValidator๋ก ์ด๋)
if(bindingResult.hasErrors()){
return "item/addForm"; // ๋ค์ ์ํ ๋ฑ๋กํ์ด์ง๋ก ์ด๋
}
Item savedItem = itemRepository.save(item);
redirectAttributes.addAttribute("itemId", savedItem.getId());
redirectAttributes.addAttribute("status", true);
return "redirect:/items/{itemId}";
}
}
3. Validator ์ ์ฉ ๋ฐฉ๋ฒ - ๊ธ๋ก๋ฒ ์ค์ ๐ฐ
์๋์ ๊ฐ์ด ์ค์ ํ๋ฉด ๊ธ๋ก๋ฒ ์ค์ ์ด ๋๋ค. ์ปจํธ๋กค๋ฌ์ ์๋ @InitBinder์ ๋ถ๋ถ์ ์ญ์ ํด๋ ๊ธ๋ก๋ฒ ์ค์ ์ผ๋ก ์ธํด์ ์ฝ๋๊ฐ ๋์ํ๋ค.
@SpringBootApplication
public class DemoApplication implements WebMvcConfigurer {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public Validator getValidator() {
return new ItemValidator();
}
}
ํ์ง๋ง, ์ด๋ ๊ฒ ํ๋ฉด BeanValidator๊ฐ ์๋ ๋ฑ๋ก๋์ง ์๋๋ค๋ ๊ฒ์ ์ผ๋์ ๋์.
ํด๋น ๊ธ์ ๊น์ํ ๋์ '์คํ๋ง MVC 2ํ - ๋ฐฑ์๋ ์น ๊ฐ๋ฐ ํ์ฉ ๊ธฐ์ '์ ์ฐธ๊ณ ํ์์ต๋๋ค.
'๐ ์คํ๋ง > ๊ธฐ๋ณธ ๊ฐ๋ ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring] ๊ฒ์ฆ(Validation) - bindingResult.rejectValue(), binding.reject() (0) | 2023.05.02 |
---|---|
[Spring] ๊ฒ์ฆ(Validation) - BindingResult, FieldError, ObjectError (0) | 2023.05.01 |
์คํ๋ง ์ธํฐ์ ํฐ(Spring Interceptor) (0) | 2023.04.30 |
์๋ธ๋ฆฟ ํํฐ(Servlet Filter) (0) | 2023.04.29 |
๋ฉ์์ง & ๊ตญ์ ํ (Message & Internationalization) (0) | 2023.04.25 |