데이터의 유효성을 검증하기 위한 @Valid애노테이션을 사용할 수 있다.
관련된 내용은 여기.
https://gomnezip.tistory.com/421?category=943736
근데 다음과 같은 경우에는 내가 MyDTO에 정의한 Validation이 안되더라..
@Getter
@Setter
public class MyDTO{
@NotEmpty
private String myName;
}
@Controller
public class MyController{
@RequestMapping(value = {"/myTest"})
public @ResponseBody Object myTest(@RequestBody @Valid List<MyDTO> dtoList){
}
}
이유는.. 저 List 자체가 유효한지 안한지 Validation을 수행하는 것..
그러면, 저 MyDTO List중에 누가 이상한 녀석인지 검증할 방법이 없는건가???
아니.. 있더라. (그럼 그렇지... 그렇게 허술할리가..)
애노테이션이 좀 바뀌어야한다. MyDTO는 그대로 유지하면 되고, 컨트롤러에서만 변경하자.
@Validated
@Controller
public class MyController{
@RequestMapping(value={"/myTest"})
public @ResponseBody Object myTest(@RequestBody
@NotEmpty(message = "list is empty!")
List<@Valid MyDTO> list){
...
}
}
컨트롤러에게 @Validated 애노테이션을 붙여주고, @Valid List<MyDTO>를 List<@Valid MyDTO>로 변경해준다.
@NotEmpty는 List가 비어있는 경우 Validation Fail을 발생시키고자 저렇게 붙여보았다. (List자체에 대한 Validation은 저기에 붙이면 된다.)
이러면 Validation에 실패하면 Exception을 던져준다.
이전에 포스팅을 참고하면, @Valid 애노테이션이 붙은 Item은 org.springframework.validation.BindException이 발생했지만, List안에 속한 Item의 Validation실패는 javax.validation.ValidationException이 발생한다.
Exception을 받아와서 처리할 때에는.. 저 exception에 대한 핸들러를 추가할것.
근데, BindException과 ValidationException은 데이터 형식이 다르다. 나는 Target과 메시지를 뽑아내기위해 다음과 같이 처리했음.
public @ResponseBody Object handleValdiationException(javax.validation.ValidationException e){
if( e.getClass().equals(ConstraintViolationException.class)){
Set<ConstraintViolation<?>> exceptions =
((ConstraintViolationException)e).getConstraintViolations();
for(ConstraintViolation<?> ex : exceptions){
String targetName = "";
for(Path.Node node : ex.getPropertyPath){
if( node.getKind().equals(ElementKind.PROPERTY)){
targetName = node.getName();
}
}
String message = ex.getMessage();
}
}
}
ex.getLeafBean이 현재 문제를 일으킨 녀석을 반환하는듯.. 근데 이 녀석은 List에서 오류난 항목이 두개이면 두개를 모두 반환한다.
참고로.. @Valid와 @Validated를 같이 붙였을 때, 실행 시 Bean에서 오류를 뿜어낼 때가 있다. mvcValidator와 다른 validator (나의 경우 localValidator)가 둘 다 있다고.. 이때에는 한쪽을 비활성화 하거나, 아니면 @Primary를 붙여서 누구를 우선할지 지정해주면 됨.
댓글