๐Ÿ“‚ ์Šคํ”„๋ง/๊ธฐ๋ณธ ๊ฐœ๋…

[Spring] ๊ฒ€์ฆ(Validation) - Validator

Amenable 2023. 5. 2. 23:39

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ํƒ„ - ๋ฐฑ์—”๋“œ ์›น ๊ฐœ๋ฐœ ํ™œ์šฉ ๊ธฐ์ˆ '์„ ์ฐธ๊ณ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.