spring mvc 오류코드

Jb·2025년 4월 8일

Spring

목록 보기
1/5

📚 스프링 MVC Validation 공부 기록

스프링을 공부하면서, 검증(Validation)에 대한 내용을 깊이 있게 다루게 되었습니다. 검증이란, 사용자가 입력한 값이 서버에서 요구하는 형식이나 조건을 잘 충족하고 있는지 확인하는 과정을 의미합니다. 이번에 제가 학습한 내용을 좀 더 기억하기 쉽게 정리해 봤습니다.

🧐 왜 Validation이 중요할까?

스프링 웹 애플리케이션에서는 사용자가 입력한 값이 항상 정상적인 값이라는 보장이 없습니다. 예를 들어, 상품의 가격이나 수량을 입력할 때 사용자가 실수로 문자를 입력하거나, 가격이 너무 크거나 작을 수 있습니다. 이런 입력 오류를 서버에서 제대로 처리하지 못하면, 예상치 못한 에러가 발생하거나, 사용자 경험이 크게 떨어질 수 있습니다.

그래서 Validation이 중요합니다. 특히, 서버 측에서의 검증은 보안상 매우 중요하며, 클라이언트 측 검증은 사용자 경험 향상을 위해 중요합니다.

🚩 학습한 주요 요구사항

스프링 MVC의 검증 기능을 실습하기 위해 다음 요구사항을 설정했습니다.
• 상품명: 필수 입력, 공백 입력 불가능
• 가격: 1,000원 ~ 1,000,000원 사이의 값만 허용
• 수량: 최대 9,999개까지만 허용
• 가격 × 수량의 합계는 최소 10,000원 이상이어야 함

✅ Validation을 처리하는 방법 (직접 구현 → 스프링 기능 활용)

① 컨트롤러에서 직접 구현하기 (가장 기초적 방법)

초기에는 컨트롤러 안에 직접 로직을 넣어 검증했습니다.

Map<String, String> errors = new HashMap<>();

if (!StringUtils.hasText(item.getItemName())) {
    errors.put("itemName", "상품 이름은 필수입니다.");
}

if (item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() > 1000000) {
    errors.put("price", "가격은 1,000 ~ 1,000,000원까지만 허용됩니다.");
}

if (!errors.isEmpty()) {
    model.addAttribute("errors", errors);
    return "validation/addForm";
}

설명:
단순한 검증 로직은 빠르게 구현할 수 있지만, 점점 폼이 많아지고 조건이 복잡해질수록 유지보수가 어려워집니다.

② BindingResult를 활용한 방법 (실무에서 자주 사용)

스프링이 제공하는 BindingResult를 활용해 더 체계적으로 검증할 수 있습니다.

@PostMapping("/add")
public String addItem(@ModelAttribute Item item, BindingResult bindingResult) {

    if (!StringUtils.hasText(item.getItemName())) {
        bindingResult.addError(new FieldError("item", "itemName", "상품 이름은 필수입니다."));
    }

    if (item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() > 1000000) {
        bindingResult.addError(new FieldError("item", "price", "가격 범위를 벗어났습니다."));
    }

    if (bindingResult.hasErrors()) {
        return "validation/addForm";
    }

    return "redirect:/items";
}

설명:
BindingResult를 쓰면 오류가 발생해도 사용자가 입력한 값을 유지할 수 있습니다. 또한, FieldError를 통해 어떤 필드에 문제가 있는지 명확하게 보여줄 수 있습니다.

③ rejectValue(), reject()를 사용한 더 효율적인 방법

스프링은 메시지 관리 기능을 제공합니다. 이를 통해 코드가 깔끔해지고 유지보수가 더 쉬워집니다.

if (!StringUtils.hasText(item.getItemName())) {
    bindingResult.rejectValue("itemName", "required.item.itemName");
}

if (item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() > 1000000) {
    bindingResult.rejectValue("price", "range.item.price", new Object[]{1000, 1000000}, null);
}

if (bindingResult.hasErrors()) {
    return "validation/addForm";
}

그리고 메시지는 별도 파일(errors.properties)에서 관리합니다.

required.item.itemName=상품 이름은 꼭 입력해 주세요.
range.item.price=가격은 {0}원에서 {1}원 사이여야 합니다.

설명:
이 방식은 실제 현업에서도 가장 선호되는 방식입니다. 오류 메시지를 코드 밖에서 관리함으로써, 메시지 수정이나 국제화도 쉽게 할 수 있습니다.

④ Validator 클래스 분리로 관리 효율성 극대화

검증 로직이 복잡해질수록 관리의 어려움이 커집니다. 그래서 Validator 클래스를 별도로 만들어 관리합니다.

@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;

        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "itemName", "required.item.itemName");

        if (item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() > 1000000) {
            errors.rejectValue("price", "range.item.price", new Object[]{1000, 1000000}, null);
        }

        if (item.getQuantity() != null && item.getPrice() != null) {
            int resultPrice = item.getPrice() * item.getQuantity();
            if (resultPrice < 10000) {
                errors.reject("totalPriceMin", new Object[]{10000, resultPrice}, null);
            }
        }
    }
}

컨트롤러에서 Validator를 자동 적용하는 방법도 있습니다.

@InitBinder
public void init(WebDataBinder binder) {
    binder.addValidators(new ItemValidator());
}

@PostMapping("/add")
public String addItem(@Validated @ModelAttribute Item item, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        return "validation/addForm";
    }
    return "redirect:/items";
}

설명:
Validator 클래스 분리 방식은 로직이 깔끔해지고 재사용성이 높아지므로, 현업에서 적극 추천되는 방식입니다.

🎈 마치며

스프링 MVC의 검증을 공부하면서 느낀 점은 사용자 경험과 보안 모두를 충족시키는 것이 생각보다 어렵지만 매우 중요하다는 것입니다. 특히 Validation을 어떻게 처리하느냐에 따라 서비스 품질이 크게 달라질 수 있기 때문입니다.

0개의 댓글