POST 컨트롤러 호출시 @RequestBody로 요청받는 Request의 dto는 다음과 같습니다.
public class Request {
private String name;
private ColorType colrType;
private String redApple;
private String greenApple;
private String redOrange;
private String greenOrange;
//getter, setter ...
public enum ColorType {
RED, GREEN
}
colorType의 값이 RED면 redApple과 redOrange의 값은 필수,
GREEN면 greenApple과 greenOrange의 값에 대한 필수값 체크를 하고 싶었습니다.
우선 필드의 그룹지정을 위한 인터페이스를 만듭니다
public interface Red {
}
public interface Blue{
}
만든 그룹을 DTO의 필드에 각각 지정해줍니다.
public class Request {
private String name;
private ColorType colrType;
@NotEmpty(groups = {Red.class})
private String redApple;
@NotEmpty(groups = {Green.class})
private String greenApple;
@NotEmpty(groups = {Red.class})
private String redOrange;
@NotEmpty(groups = {Green.class})
private String greenOrange;
//getter, setter ...
그룹으로 묶으면 해당 그룹을 지정후 그룹에 속한 필드의 유효성을 검사할 수 있습니다.
※ @NotEmpty의 groups의 인자는 비열을 받기 때문에 2개 이상의 Class 타입을 지정할 수 있습니다.
@Documented
@Constraint(validatedBy = { })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(List.class)
public @interface NotEmpty {
Class<?>[] groups() default { };
//...
새로운 제약을 나타내는 어노테이션을 명시합니다.
@Target({TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = ColorTypeConstraintValidator.class)
public @interface ColorTypeConstraint {
String message() default "";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
ColorTypeConstraintValidator의 구현부 입니다.
colorType이 RED일때 Group이 Red로 설정된 필드에 대한 유효성을 검사합니다.
Green일때는 Group이 Green으로 설정된 필드에 대한 유효성을 검사합니다.
public class ColorTypeConstraintValidator implements
ConstraintValidator<ColorTypeConstraint, Request> {
private Validator validator;
public ColorTypeConstraintValidator(Validator validator) {
this.validator = validator;
}
@Override
public boolean isValid(AmSchInsertReq value, ConstraintValidatorContext context) {
if(value.getColorType = ColorType.RED){
final Set<ConstraintViolation<Object>> constraintViolations = validator.validate(value, Red.class);
return isValid(constraintViolations, context);
}else {
final Set<ConstraintViolation<Object>> constraintViolations = validator.validate(value, Green.class);
return isValid(constraintViolations, context);
}
}
private boolean isValid(Set<ConstraintViolation<Object>> constraintViolations, ConstraintValidatorContext context){
if (CollectionUtils.isNotEmpty(constraintViolations)) {
context.disableDefaultConstraintViolation();
constraintViolations
.forEach(constraintViolation -> {
context.buildConstraintViolationWithTemplate(constraintViolation.getMessageTemplate())
.addPropertyNode(constraintViolation.getPropertyPath().toString())
.addConstraintViolation();
});
return false;
}
return true;
}
}
※ 참고로 CollectionUtils.isNotEmpty를 사용하기 위해선 아래 라이브러리를 추가해야 합니다.
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
해당 DTO의 클래스에 새롭게 정의한 어노테이션을 붙힙니다.
@ColorTypeConstraint
public class Request {
private String name;
private ColorType colrType;
@NotEmpty(groups = {Red.class}) //중복 지정 가능
private String redApple;
@NotEmpty(groups = {Green.class}) //중복 지정 가능
private String greenApple;
@NotEmpty(groups = {Red.class}) //중복 지정 가능
private String redOrange;
@NotEmpty(groups = {Green.class}) //중복 지정 가능
private String greenOrange;
//getter, setter ...
컨트롤러 메소드의 인자에 명시한 Request 옆에 @Validated와 @Valid 어노테이션을 붙힙니다.
@PostMapping("mapping")
public Response fruit(
@RequestBody @Validated @Valid Request reqDTO
https://meetup.toast.com/posts/223
'Tech > Spring' 카테고리의 다른 글
2개 이상의 DB를 사용하는 Spring Boot 환경에서 Spring Data Jpa 사용시 트랜잭션 관련 에러 (0) | 2023.01.29 |
---|---|
요청으로 들어온 language 값에 따른 GlobalExceptioner에서 다국어 처리 (i18n, yml) + spring validaiton 다국어처리 (0) | 2022.05.23 |
Mybatis와 Jpa 사용시 트랜잭션 묶어서 사용하는 방법(※ 멀티 datasource 설정 / QueryDsl) (0) | 2021.07.24 |
Spring Filter에서 request Body 가공하기 (0) | 2021.07.19 |
단위 테스트를위한 ReflectionTestUtils (1) | 2021.03.23 |