WEEK 6-5: Spring Validation

ensalada.de.pollo·2025년 5월 17일

be

목록 보기
27/44

Validation

특정 데이터(주로 요청 데이터)의 값이 유효한지 확인하는 단계를 의미합니다.
Controller의 주요 역할에 해당하며, HTTP 요청이 정상인지 검증합니다.

왜 사용하는가?

잘못된 입력 값으로 인해 서버에 오류가 발생할 수도 있고...
서버의 문제로 인해서 작성 페이지에서 error 페이지로 넘어갈 수도 있고...
이렇게 페이지로 넘어가면서 작성 중이었던 폼이 모두 리셋될 수도 있고...
이러한 모든 경우가 사용자의 입장에서는 굉장히 불편할 것입니다.

역할

  • 검증을 통해 적절한 메세지를 유저에게 보여주어야 합니다.
  • 검증 오류로 인해 정상적인 동작을 하지 못하는 경우는 없어야 합니다.
  • 사용자가 입력한 데이터는 유지된 상태여야 합니다.

종류

프론트 검증

해당 검증은 사용자가 조작할 수 있기 때문에 보안에 취약합니다. 하지만, 이러한 이유에도 꼭 필요합니다. 예를 들어서, 비밀번호가 6글자 이상이어야 하는 경우에 즉각적인 알림을 준다면 유저 사용성이 증가할 것입니다.

서버 검증

프론트 검증 없이 서버에서만 검증하게 되면 유저 사용성이 떨어지게 됩니다.
API Spec을 정의해 Validation 오류를 Response 예시에 남겨주어야 합니다. 즉, API 명세서를 잘 만들어야 그에 맞는 대응을 할 수 있습니다.

유저 사용성이 떨어지게 되더라도 어떤 Validation 오류가 존재하는지 알려주어야 하기 때문에 선택이 아닌 필수입니다.

데이터베이스 검증

Not null, Default와 같은 제약 조건을 설정합니다. 이 경우 최종 방어선의 역할을 수행합니다.

기본적으로는, 모든 부분에서 검증을 꼼꼼하는 것이 가장 좋습니다.

BindingResult

Validation 오류를 보관하는 객체입니다. 주로 사용자 입력 폼을 검증할 때 많이 사용되고, Field Error와 ObjectError를 보관합니다.

public interface BindingResult extends Errors {

BindingResult 인터페이스는 Error 인터페이스를 상속받습니다. Error 인터페이스는 에러의 저장과 조회 기능을 제공하고, BindingResult는 이에 더해 addError()와 같은 추가 기능을 제공합니다.

Spring에서는 기본적으로 BeanPropertyBindingResult라는 구현체를 사용합니다.

파라미터에 BindingResult가 없는 경우

@Data
public class MemberCreateRequestDto {
    private Long point;
    private String name;
    private Integer age;
}
// View 반환
@Controller
public class BingdingResultController {
	
    @PostMapping("/v1/member")
    public String createMemberV1(@ModelAttribute MemberCreateRequestDto request, Model model) {
        // Model에 저장
        System.out.println("/V1/member API가 호출되었습니다.");
        model.addAttribute("point", request.getPoint());
        model.addAttribute("name", request.getName());
        model.addAttribute("age", request.getAge());

        // Thymeleaf Template Engine View Name
        return "complete";
    }

}

여기서 정상적인 요청이라면 정상적인 응답이 오고, viewName인 complete 페이지로 이동하게 됩니다.

파라미터에 BindingResult가 있는 경우

여기서 BindingResult 파라미터는 검증대상 파라미터 뒤에 위치해야 합니다.

@Controller
public class BindingResultController {

    @PostMapping("/v2/member")
    public String createMemberV2(
            // 1. @ModelAttribute 뒤에 2. BindingResult가 위치한다.
            @ModelAttribute MemberCreateRequestDto request,
            BindingResult bindingResult,
            Model model
    ) {

        System.out.println("/V2/member API가 호출되었습니다.");

        // BindingResult의 에러 출력
        List<ObjectError> allErrors = bindingResult.getAllErrors();
        System.out.println("allErrors = " + allErrors);

        // Model에 저장
        model.addAttribute("point", request.getPoint());
        model.addAttribute("name", request.getName());
        model.addAttribute("age", request.getAge());

        return "complete";
    }
    
}

정상 요청이라면 정상 응답이 올 것입니다.
만약 잘못된 요청이 온다면, @ModelAttribute 필드 또는 객체에 파라미터 바인딩 오류가 발생하게 됩니다. 오류가 난 필드를 제외한 필드만 바인딩 되고 Controller는 정상적으로 호출이 됩니다. 그리고 발생한 오류는 BindingResult에 보관이 됩니다.

자료 및 코드 출처: 스파르타 코딩클럽

0개의 댓글