티스토리 뷰
개요
- Spring MVC는 클라이언트의 입력 데이터를 도메인 객체로 자동 바인딩하고, 유효성 검증을 통해 데이터 무결성을 보장할 수 있는 기능을 제공
- @Valid 어노테이션과 BindingResult를 활용하면, 입력 데이터에 대한 제약 조건(@NotEmpty, @Email, @Size 등)을 손쉽게 검사할 수 있음
- 검증 실패 시, BindingResult에 오류 정보를 담아 사용자에게 상세한 피드백을 제공하거나, REST API의 경우 JSON 형태로 에러 정보를 반환할 수 있음
주요 어노테이션과 활용
@Valid
기능
- 컨트롤러 메서드의 파라미터에 선언된 도메인 객체에 대해 필드별 검증 어노테이션을 실행하여 유효성 검사를 수행
특징
- 데이터 바인딩 이후에 자동으로 검증 로직이 실행
- 검증 실패 시 BindingResult에 상세한 오류 정보가 저장되어 후속 처리가 가능
BindingResult
기능
- @Valid에 의해 수행된 검증 결과를 저장하는 객체로, 오류 여부를 확인하고 오류 메시지 목록을 제공할 수 있음
특징
- @Valid 파라미터 바로 뒤에 위치해야 하며, 이를 통해 검증 오류가 있는지 여부를 컨트롤러에서 확인할 수 있음
- 검증 오류가 발생한 경우, 사용자에게 재입력 폼으로 안내하거나 Ajax 응답으로 오류 정보를 전달할 수 있음
예시 코드
1. 폼 데이터를 바인딩하고 검증하는 컨트롤러
import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserController {
// 사용자 등록 폼 전송 처리
@PostMapping("/register")
public String registerUser(@Valid User user, BindingResult bindingResult, Model model) {
// 검증 오류가 있으면 폼으로 다시 이동
if (bindingResult.hasErrors()) {
model.addAttribute("errors", bindingResult.getAllErrors());
return "registerForm";
}
// 성공 로직 처리 (예: DB 저장)
model.addAttribute("message", "사용자 등록 성공!");
return "registerSuccess";
}
}
2. 도메인 객체(User)와 검증 어노테이션 사용 예시
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;
public class User {
@NotEmpty(message = "이름은 필수 항목입니다.")
private String name;
@Email(message = "유효한 이메일 주소를 입력하세요.")
@NotEmpty(message = "이메일은 필수 항목입니다.")
private String email;
@Size(min = 6, message = "비밀번호는 최소 6자 이상이어야 합니다.")
private String password;
// 비밀번호 확인 필드 (다중 필드 검증을 위한 예시)
@NotEmpty(message = "비밀번호 확인은 필수 항목입니다.")
private String confirmPassword;
// getter, setter 생략
}
3. 다중 필드 검증을 위한 커스텀 검증 어노테이션
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Documented
@Constraint(validatedBy = PasswordMatchesValidator.class)
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface PasswordMatches {
String message() default "비밀번호와 비밀번호 확인이 일치하지 않습니다.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class PasswordMatchesValidator implements ConstraintValidator<PasswordMatches, User> {
@Override
public void initialize(PasswordMatches constraintAnnotation) {}
@Override
public boolean isValid(User user, ConstraintValidatorContext context) {
if (user.getPassword() == null || user.getConfirmPassword() == null) {
return false;
}
return user.getPassword().equals(user.getConfirmPassword());
}
}
적용 방법
User 클래스 선언 시 @PasswordMatches 어노테이션을 추가하여 다중 필드 검증을 수행할 수 있음
데이터 바인딩 및 검증의 상세 활용
검증 프로세스
데이터 바인딩
- 클라이언트로부터 전달받은 폼 데이터를 도메인 객체(User)에 매핑
유효성 검증
- @Valid 어노테이션을 통해 객체의 필드에 선언된 제약 조건을 체크하며, 다중 필드 검증의 경우 클래스 레벨 커스텀 어노테이션을 사용
오류 처리
- BindingResult를 활용하여 발생한 오류를 확인한 후, 사용자에게 적절한 피드백을 제공하거나 JSON 응답으로 반환
확장 및 추가 고려사항
커스텀 검증 어노테이션
- 복잡한 비즈니스 로직에 따른 검증을 위해 직접 어노테이션과 Validator를 구현하여 유연하게 사용할 수 있음
전역 Validator 등록
- WebMvcConfigurer를 통해 전역적으로 Validator를 등록하여 모든 컨트롤러에 일관된 검증 로직을 적용할 수 있음
에러 메시지 국제화
- MessageSource를 활용해 다국어 지원을 위한 에러 메시지를 관리할 수 있음
Ajax 요청 처리
- RESTful 환경에서는 ResponseEntity나 ExceptionHandler를 사용해 검증 오류 정보를 JSON 형식으로 반환할 수 있음
보안 측면
- 데이터 바인딩 과정에서 불필요한 필드가 바인딩되지 않도록 @InitBinder를 통해 허용 필드를 제한하는 방법도 고려해야 함
면접 대비 질문
기본 질문
Q1. @Valid와 BindingResult의 역할은 무엇이며, 이 둘의 위치가 중요한 이유는 무엇인가요?
모범 답안
@Valid는 컨트롤러 메서드의 파라미터로 전달된 도메인 객체에 대해 선언된 제약 조건을 기반으로 유효성 검증을 수행합니다. BindingResult는 이 검증 결과를 저장하는 객체로, @Valid 바로 뒤에 위치해야 검증 결과를 올바르게 받아 처리할 수 있습니다.
Q2. 검증 오류가 발생했을 때, 컨트롤러에서는 어떻게 처리하나요?
모범 답안
검증 오류가 발생하면 BindingResult에 오류 정보가 저장됩니다. 컨트롤러 메서드에서는 BindingResult의 hasErrors() 메서드를 통해 오류 여부를 확인한 후, 오류가 있는 경우 폼 페이지로 다시 이동하거나, 에러 메시지를 모델에 담아 사용자에게 피드백을 제공합니다.
심화 질문
Q1. 커스텀 검증 어노테이션과 Validator를 구현하는 방법에 대해 설명해주세요.
모범 답안
커스텀 검증 어노테이션을 만들기 위해서는 먼저 어노테이션 인터페이스를 정의하고, @Constraint 어노테이션을 사용하여 Validator 클래스를 지정합니다. Validator 클래스는 ConstraintValidator 인터페이스를 구현하여 isValid() 메서드에서 커스텀 검증 로직을 작성합니다. 이 방식은 단순한 필드 검증을 넘어 여러 필드를 비교하거나 복잡한 로직을 검증할 때 유용합니다.
Q2. 다중 필드 검증(cross-field validation)은 무엇이며, 어떻게 구현할 수 있나요?
모범 답안
다중 필드 검증은 단일 필드의 제약 조건으로는 처리할 수 없는 경우에, 클래스 레벨에서 여러 필드의 값을 비교하여 유효성을 판단하는 방식입니다. 이를 위해 커스텀 검증 어노테이션과 해당 어노테이션을 처리하는 Validator를 구현하고, 도메인 객체에 적용하여 예를 들어 비밀번호와 비밀번호 확인 필드의 일치 여부를 검증할 수 있습니다.
압박 질문
Q1. Ajax 요청 시 검증 오류 정보를 효과적으로 전달하는 방법은 무엇이며, 이를 어떻게 구현할 수 있나요?
모범 답안
Ajax 요청에서는 폼 제출 후 전체 페이지 리로딩 없이 클라이언트 측에서 검증 결과를 처리할 수 있어야 합니다. 이를 위해 컨트롤러는 BindingResult에서 오류 정보를 추출한 후, 에러 메시지와 필드별 오류를 포함하는 DTO를 구성하고 JSON 형식으로 ResponseEntity를 반환하는 방식으로 구현할 수 있습니다.
Q2. 데이터 바인딩 과정에서 발생할 수 있는 보안 취약점과 그 예방 방법에 대해 설명해주세요.
모범 답안
데이터 바인딩 시 클라이언트가 의도치 않은 필드 값을 전송하면 도메인 객체의 민감한 속성이 오염될 수 있는 위험이 있습니다. 이를 예방하기 위해 @InitBinder를 사용하여 바인딩 허용 필드를 명시적으로 설정하거나, DTO를 사용해 필요한 데이터만 바인딩하도록 설계하는 방법을 사용할 수 있습니다.
Q3. 전역 Validator를 등록하는 방법과 그 장점에 대해 설명해주세요.
모범 답안
전역 Validator는 WebMvcConfigurer의 addValidators() 메서드를 오버라이드하여 커스텀 Validator를 등록하는 방식으로 적용할 수 있습니다. 이를 통해 애플리케이션 전반에 걸쳐 일관된 검증 로직을 사용할 수 있으며, 개별 컨트롤러에서 중복된 검증 코드를 제거하여 유지보수를 용이하게 합니다.
'Spring' 카테고리의 다른 글
[Spring] MyBatis (0) | 2025.02.24 |
---|---|
[Spring] JDBC Template (0) | 2025.02.20 |
[Spring] 예외 처리 (@ExceptionHandler, @ControllerAdvice 등) (0) | 2025.02.18 |
[Spring] 요청 매핑 (@RequestMapping, @GetMapping 등) (0) | 2025.02.17 |
[Spring] @Controller vs @RestController (0) | 2025.02.17 |
- Total
- Today
- Yesterday
- HTTP
- 우선순위 큐
- 스프링
- 동적 프로그래밍
- CPU 스케줄링
- Spring
- devops
- 탐색 알고리즘
- 그리디 알고리즘
- MSA
- 운영체제
- 우아한 테크코스
- CS
- Java
- 해시 테이블
- 자바
- 분할 정복
- 백트래킹
- 자료구조
- k8
- 알고리즘
- 우테코
- restful api
- db
- B+Tree
- Spring Boot
- i/o모델
- TRIE
- 프리코스
- 데이터베이스
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |