inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

스프링 MVC 2편 - 백엔드 웹 개발 활용 기술

Validator 분리2

@InitBinder와 @Validated 사용 시 문제 IllegalStateException: Invalid target for Validator

해결된 질문

1191

irostub

작성한 질문수 5

8

검증 시 @InitBinder 를 사용해서 Validator 를 추가했을 때, 강의 예제와 같은 상황에선 문제가 없습니다. 하지만, 너무 햇갈리는 상황이 일어나서 질문드립니다.

컨트롤러의 매핑 메서드의 인자에 @Validated 애노테이션을 추가하지 않더라도  매핑 메서드에서 model.addAttribute(); 에 Item 이 아닌 객체를 넣을 시 다음과 같은 오류가 발생합니다..

java.lang.IllegalStateException: Invalid target for Validator

======

추가.

우선 디버깅을 하다보니 @Validated 를 붙이지 않아도 무엇이든지 값을 매핑해야할 일이 있다면 @InitBinder 를 통해 등록한 Validator 의 support() 가 호출 된다는 것을 알 수 있었습니다.

근데, 이걸 보고나니 더욱 의문이 남는게 Validator의  support() 를 실행했을 때 false 가 나와서 해당 검증기를 지원하지 않는다고 하면 그냥 검증을 안하고 넘어가는게 아닌가봅니다..잘 이해가 가지 않습니다.

결국 Model 객체에다가 Item이 아닌 다른 객체를 넣을 때, 결과적으로 DataBinder.java 안의  assertValidators(Validator ... validators); 메서드에서 

if (validator != null && (target != null && !validator.supports(target.getClass()))) {
	throw new IllegalStateException("Invalid target for Validator [" + validator + "]: " + target);
}

조건이 참이되버려서 지원하지 않는다면 그냥 예외가 터져버리고 맙니다.

이런식으로 된다면 @InitBinder 로 검증기를 등록해서 사용하다간,  되려 예측하지 못한 검증찾기 실패 오류만 늘어나는것이 아닌지 생각됩니다...

한 컨트롤러내에서 Model 객체에 Item 객체 말고도 실제론 다양한 객체를 넣을텐데 이런 경우엔 @InitBinder 를 사용하지 않고 전부 수동으로 메서드에서 검증을 해야하는건가요?

해결 방법이 궁금합니다..

마지막으로 해당 상황을 재현할 수 있는 샘플코드를 작성해보았습니다..

뭔가 질문이 난잡한거 같아서 죄송합니다..ㅠ 항상 감사드립니다.

MyController.java

@Controller
@RequiredArgsConstructor
public class MyController {
private final MyValidator myValidator;

@InitBinder
public void init(WebDataBinder webDataBinder) {
webDataBinder.addValidators(myValidator);
}

@GetMapping("/index/{text}")
public String myView(@PathVariable String text, Model model) {
SomeObject someObject = new SomeObject();
someObject.setText(text);
model.addAttribute("someObject", someObject);
return "myView";
}

@GetMapping("/index")
public String index(@ModelAttribute TargetObject targetObject, Model model) {
model.addAttribute("targetObject", targetObject);
return "myView";
}
}

MyValidator.java

@Component
public class MyValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return clazz.isAssignableFrom(TargetObject.class);
}

@Override
public void validate(Object target, Errors errors) {
TargetObject myTarget = (TargetObject) target;
if (myTarget.getText().equals("error")) {
errors.reject("error");
}
}
}

SomeObject.java

@Data
public class SomeObject {
private String text;
}

TargetObject.java

@Data
public class TargetObject {
private String text;
}

검증 MVC spring

답변 1

11

김영한

안녕하세요. irostub님

일반적으로 컨트롤러를 만들 때 하나의 컨트롤러는 하나의 모델 객체(Command 객체)를 사용하기 때문에 이렇게 사용해도 큰 이슈가 없습니다.

하지만 여러 모델 객체를 사용하고 싶으시면 다음과 같이 적용하시면 됩니다.

@InitBinder("targetObject")
public void initTargetObject(WebDataBinder webDataBinder) {
log.info("webDataBinder={}, target={}", webDataBinder, webDataBinder.getTarget());
webDataBinder.addValidators(/*TargetObject 관련 검증기*/);
}

@InitBinder("sameObject")
public void initSameObject(WebDataBinder webDataBinder) {
log.info("webDataBinder={}, target={}", webDataBinder, webDataBinder.getTarget());
webDataBinder.addValidators(/*SameObject 관련 검증기*/);
}

@InitBinder에 지금처럼 이름을 넣어주면 해당 모델 객체에만 영향을 줍니다. 반면에 이름을 넣지 않으면 모든 모델 객체에 영향을 줍니다.

만약 targetObject는 검증기를 사용하고, sameObject는 검증기를 사용하고 싶지 않다면 다음과 같이 하나만 명식적으로 적용하면 됩니다.

@InitBinder("targetObject")
public void initTargetObject(WebDataBinder webDataBinder) {
log.info("webDataBinder={}, target={}", webDataBinder, webDataBinder.getTarget());
webDataBinder.addValidators(/*TargetObject 관련 검증기*/);
}

감사합니다.

이미지 업로드와 db 트랜잭션 묶는법

0

42

1

Could not resolve org.springframework.boot:spring-boot-starter-validation:2.4.4

0

52

2

MessageSourceTest 코드

0

47

1

인터셉터 에러 설정

0

48

1

resolveArgument()메서드 질문

0

57

1

43강 검증1 에서 실패 로직 관련 질문있습니다.

0

55

2

타임리프 3.X 버전 rendering, serializer 에러 해결 방법

2

133

3

스프링 빈에 등록이 안되는거 같은데 어떻게 하면 좋을까요?ㅠㅠ

0

90

3

pdf 오타 문의

0

57

1

ItemUpdateForm 검증 관련 질문입니다.

0

48

1

22page 링크 주소 변경

0

59

2

특정 데이터와 파일을 함께 저장 시, 테이블 구조 질문

0

53

1

섹션3번 수업에 대한 질문입니다.

0

80

2

@Autowired 보다 더 좋은 방법이 어떤 걸까요?

0

85

2

타입컨버터 가 람다랑 비슷해 보이는데 저의 생각이 맞는지?.

0

65

1

자바스크립트 인라인에서 객체 직렬화 시 오류가 납니다

0

142

3

스프링부트 - 오류페이지2 에서 500.html 에서 쓰인 객체 질문

0

63

1

톰캣 에러 페이지가 안보입니다.

0

102

2

apiEceptionController에서 센드 에러 호출하면 안되는지?

0

81

1

세션 타임아웃시 쿠키 삭제 방법이 없나요?

0

118

2

ApiExceptionController 질문드립니다.

0

64

1

셀렉박스 챕터에서 option value에 ==배송 방식 선택== 이것을 넣은 이유가 궁금함, 이렇게 구상해도 되는지?

0

66

1

MemberRepository 필드의 fianl 선언 유무

0

85

2

혹시 index.html 에서는 fragment 사용이 안되는건가요

0

58

1