안녕하세요! 이번 포스팅에서는 Spring Boot에서 Custom Valid Annotation를 적용하는 방법에 대해 알아보겠습니다.
전체 코드는 Github에서 확인이 가능합니다. ✍️
스프링에서 제공되는 Valid 관련 어노테이션을은 많지만, 가끔 제공해주지 않는 어노테이션을 Valid 처리하고 싶을 때가 있습니다. 예를 들어, Request 받을 때 전화번호 포맷을 확인하고 싶은데, 이와 관련된 Valid 어노테이션은 없습니다. 그렇다면 아래와 같이 구현해야하는 상황이 생기게 됩니다.
public class Obj {
@NotBlank
private String tel;
}
@RestController
public class ValidController {
@PostMapping("/valid")
public Obj valid(@RequestBody @Valid Obj object){
// 전화번호 포맷을 확인하는 로직
return object;
}
}
하지만 Custom Valid Annotation을 만들면 @Valid
실행 과정에서 함께 유효성 검사가 가능합니다.
public class Obj {
@Tel
private String tel;
}
📚 사전준비
1. 사전 준비
위 예제는 예전에 포스팅했던 Validation 예제에 코드를 추가해서 진행합니다.
💻 구현
1. 커스텀 어노테이션 만들기
annotation/Tel.java
@Target(ElementType.FIELD) // 1
@Retention(RetentionPolicy.RUNTIME) // 2
@Constraint(validatedBy = TelValidator.class) // 3
public @interface Tel {
String message() default "휴대폰 번호"; // 4
Class[] groups() default {};
Class[] payload() default {};
}
가장 먼저, 커스텀 어노테이션을 만들어줍니다.
- 변수 위에 사용하는 어노테이션이기 때문에 Target은
FIELD
로 설정해줍니다. - 어노테이션의 유지범위는 실행하는 동안으로 설정해주기 위해 Retention을
RUNTIME
으로 설정해줍니다. - 검증 클래스를 지정해주기 위해
validateBy
로 클래스를 지정해줍니다. - 기본적인 메세지를 설정할 수 있습니다.
이외에 groups, payload 설정이 있지만, 따로 설정하지 않겠습니다.
2. 검증 클래스 만들기
annotation/validator/TelValidator.java
public class TelValidator implements ConstraintValidator<Tel, String> { // 1
@Override
public boolean isValid(String value, ConstraintValidatorContext context) { // 2
if (value == null) {
return false;
}
return value.matches("(01[016789])(\\d{3,4})(\\d{4})");
}
}
검증 클래스는 검증 로직이 들어가는 클래스입니다.
- 검증 클래스를 만들기 위해서는
ConstraintValidator
를 구현해주어야합니다. 첫 번째 제네릭 값으로는 검증 어노테이션을, 두 번째 값으로는 필드의 데이터 유형을 넣어줍니다. - isValid를 구현해서 값을 검증할 로직을 넣어줍니다.
3. 필드에 어노테이션 추가
dto/Obj.java
@Getter
public class Obj {
// ...
@Tel
private String tel;
}
이제 어노테이션을 추가해보겠습니다!
변수를 추가해주고, 휴대폰 번호의 유효성을 검증하는 역할을 하는 @Tel
을 추가합니다. 만약 message가 default로 나오는 값이 아닌 다른 값을 넣고 싶다면, message
속성을 통해 바꿀 수 있습니다.
4. 컨트롤러에 @Valid 추가하기
controller/ValidController.java
@RestController
public class ValidController {
@PostMapping("/valid")
public Obj valid(@RequestBody @Valid Obj object){
return object;
}
}
객체 앞에 @Valid
를 추가해줍니다.
5. 테스트
이제 구현이 끝났으니 테스트 코드를 작성해보겠습니다!
test/controller/ValidControllerTest.java
@RunWith(SpringRunner.class)
@WebMvcTest(ValidController.class)
public class ValidControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@Test
public void 핸드폰번호_validation_성공() throws Exception { // 이름, 나이, 핸드폰번호
String content = objectMapper.writeValueAsString(new Obj("냠냠이", 10, "01012345678"));
mockMvc.perform(post("/valid")
.content(content)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(print());
}
@Test
public void 핸드폰번호_validation_실패() throws Exception { // 이름, 나이, 핸드폰번호
String content = objectMapper.writeValueAsString(new Obj("냠냠이", 10, "123456789123"));
mockMvc.perform(post("/valid")
.content(content)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().is4xxClientError())
.andExpect(jsonPath("$.message").value("유효성 검사 실패 : 휴대폰 번호"))
.andDo(print());
}
}
✨ 정리
이런식으로 커스텀 어노테이션으로 Controller 또는 Service단에 비즈니스로직을 넣지 않아도 Validation 처리를 할 수 있습니다!
혹시 글을 읽으면서 잘못된 내용이 있으면 댓글로 알려주시면 감사하겠습니다. 읽어주셔서 감사합니다! 😊
👏 참고
'Backend > SpringBoot' 카테고리의 다른 글
JUnit4에서 JUnitParams 이용해서 파라미터 테스트하기 (0) | 2021.02.02 |
---|---|
단위 테스트에 Spring Securiy 인증 관련 어노테이션들 사용하기 (3) | 2020.12.08 |
Spring Boot에서 이벤트 사용하기 (6) | 2020.08.27 |
Spring Boot에서 CORS 적용해보기 (7) | 2020.08.05 |
Spring Boot에서 Spring Rest Docs 사용해보기 (4) | 2020.07.24 |