💡 같은 역할인데 왜 둘 다 쓰지?
- 결론은
둘 다 써야 한다
- 각자의 역할이 다르기 때문
Spring Validation
public class HumanName {
@NotBlank
private String name;
public HumanName(String name) {
this.name = name;
}
protected HumanName() {}
public String getName() {
return name;
}
}
@PostMapping
public ResponseEntity<HumanName> createHumanName(
@Valid @RequestBody HumanName name
) {
...
}
- Spring Boot 에서 지원하는
유효성 검사 도구
- 실질적으로
hibernate validator
(Bean Validation 프레임워크 구현체) 를 사용함.
- SpringBoot 가
@Valid
매개변수 찾으면 하이버네이트 Validator를 자동으로 부트스트랩해서 매개변수 검증
@Valid
를 사용하지 않은 곳에서는 validation 유효성 검사하지 않음
💡 @Valid vs @Validated 차이
@Valid
@Validated
- Spring 에서 지원해주는 어노테이션
@Valid
기능 포함
- 유효성 검토할 그룹 지정 기능 포함
💡 의존성
- SpringBoot 2.3 이후부터 Web 의존성 내부에 있던 validation이 사라짐
- 따로 추가해줘야 한다
생성자 가드
public User(String name) {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("이름 이렇게 지으면 아니됨");
}
Assert.isTrue(StringUtils.isNotBlank(name), "이렇게 지으면 안 된다고");
this.name = name;
}
- 이렇게 생성자 메소드 안에
if 조건문
혹은 Assert
클래스를 이용해 유효하지 않은 생성자 파라미터를 차단하는 것을 말한다.
- 생성자 가드를 통해 유효하지 않은 값을 가진 객체 생성을 원천적으로 방지할 수 있으므로 프로그램 전반적인 안정성을 높일 수 있다.
조건문 방식
- 코드가 조금 지저분할 수 있다.
- 원하는 조건을 만들어 쉽게 만들어낼 수 있다.
- 원하는 예외를 쉽게 던질 수 있다.
Assert 방식
- 코드가 간단해질 수 있다.
IllegalArgumentException
으로 제한된다.
그래서 왜 둘 다 써야해?
Validation 미사용 + 생성자 가드 사용
@PostMapping(consumes = APPLICATION_JSON_VALUE)
public String postUser(@RequestBody AddUserRequest request) {
LoggerFactory.getLogger(getClass()).info("결과 - {}", request.getName());
return request.getName();
}
public class AddUserRequest {
private String name;
public AddUserRequest(String name) {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("생성자 가드에 걸림!");
}
this.name = name;
}
protected AddUserRequest() {
}
public String getName() {
return name;
}
}
Validation 사용 + 생성자 가드 미사용
- 컨트롤러에서는 문제 없지만, 프로그램 내부에서 직접 생성자로 객체를 생성하는 경우에는 유효성 판단이 불가하다.
@PostMapping(consumes = APPLICATION_JSON_VALUE)
public String postUser(@Valid @RequestBody AddUserRequest request) {
LoggerFactory.getLogger(getClass()).info("결과 - {}", request.getName());
return request.getName();
}
public class AddUserRequest {
@NotBlank
private String name;
public AddUserRequest(String name) {
this.name = name;
}
protected AddUserRequest() {
}
public String getName() {
return name;
}
}
결론
- 둘 다 사용하는 것이 프로그램 전반적으로 유리한 일이다.
- 그게 아니라면, 모든 validation 사용처에
@Valid
어노테이션을 달아줘야 함