스프링/4. 스프링 MVC-2 87

37. 빈 검증

이거 쓸려면 새로 종속성에 implementation 'org.springframework.boot:spring-boot-starter-validation' 추가시켜 줘야 한다. 아마 스프링 부트에서 처음부터 추가해서 쓰는 게 좋을 듯 하다. public class Item { private Long id; @NotBlank(message="공백X") private String itemName; @NotNull @Range(min=1000,max=100000) private Integer price; @NotNull @Max(9999) private Integer quantity; public Item() { } public Item(String itemName, Integer price, Integer..

36. 검증로직 분리 2

컨트롤러의 로직에서 따로 관리할 수 있다. @Slf4j @Controller @RequestMapping("/validation/v2/items") @RequiredArgsConstructor public class ValidationItemControllerV2 { private final ItemRepository itemRepository; private final ItemValidator itemValidator; @InitBinder public void init(WebDataBinder dataBinder){ dataBinder.addValidators(itemValidator); } @PostMapping("/add") public String addItemV6(@Validated @Mode..

35. 검증로직 분리

사실 역할이 있는 컨트롤러에 떡하니 검증 로직이 있는것도 마음에 안들었다. 예를 들면 addUser면 addUser역할만 해야 하는데 검증로직이 상당한 양을 차지한다. 이번에는 그냥 따로 함수로 빼는 정도일 것 같지만, 나중에는 아예 Bean으로 분리할 것 같다. @Component public class ItemValidator implements Validator { @Override public boolean supports(Class clazz) { return Item.class.isAssignableFrom(clazz); } @Override public void validate(Object target, Errors errors) { Item item = (Item) target; //검증 ..

34. 오류메시지 4

우리가 타입미스매치의 오류 같은 경우는 컨트롤러에서 인자로 들어오는 단계에서 발생한다. @PostMapping("/add") public String addItemV4(@ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes, Model model) { //검증 오류 보관 //검증 로직 if(!StringUtils.hasText(item.getItemName())){ bindingResult.rejectValue("itemName", "required"); } if(item.getPrice() == null || item.getPrice() 10..

33. 오류메시지 3

사실 그동안 resolve에 대해 익히 학습하였기 때문에 이 개념까지 자세히 파야 할 이유가 있나 싶긴 하다. 우리가 과거 bindingResult.rejectValue("itemName", "required"); 이렇게 하면 required라는 이름으로 템플릿이 렌더링 될 때 th:errors를 수행할 때 errors.properties에서 저 required 코드를 찾아 넣는다. 이 때, 우선순위가 있다. 더 자세한 순이다. 저 rejectValue를 해 놓으면, new FieldError("item", "itemName", item.getItemName(), false, new String[]{"required.item.itemName"}, null, null) 자동으로 이걸 생성해 주는거다. 근데..

32. 오류 메시지 2

bindingResult.rejectValue("itemName", "required"); rejectValue를 쓰면 훨씬 간단해진다. 필드, 오류메시지코드 사실 이미 bindingResult는 내가 어떤 객체를 참조하는지 알고 있다. 왜냐하면 컨트롤러의 인자로 bindingResult를 받을 때 우리가 에러관리를 하고자 하는 객체의 바로 다음 순서에 인자로 넣었기 때문. 그래서 bindingResult.getObjectName() bindingResult.getTarget() 이렇게 해 보면 item이라는 이름과, item의 toString이 나온다. 그러므로 우리가 기존 쓰던 대상 오브젝트이름, 등을 생략할 수 있다. errors에서 오류 메시지를 찾는것도 꽤나 단순해졌는데, required.ite..

31. 오류 메시지 처리

우리가 오류 메시지를 messages.properties 했던 것 처럼 처리도 가능. (그럼 마찬가지로 국제화 처리도 가능 하려나?) errors.properties 라고 만들고, 오류 메시지를 담아놓으면 됨. required.item.itemName=상품 이름은 필수입니다. range.item.price=가격은 {0} ~ {1} 까지 허용합니다. max.item.quantity=수량은 최대 {0} 까지 허용합니다. totalPriceMin=가격 * 수량의 합은 {0}원 이상이어야 합니다. 현재 값 = {1} 그리고 이제 default로 messages.properties만 들어가는데, 명시적으로 이것도 들어가서 접근할 수 있게 해 줘야 함. spring.messages.basename=messages,..

30. FieldError, ObjectError

@PostMapping("/add") public String addItemV2(@ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes, Model model) { //검증 오류 보관 //검증 로직 if(!StringUtils.hasText(item.getItemName())){ bindingResult.addError(new FieldError("item", "itemName", item.getItemName(), false, null, null, "상품 이름은 필수입니다.")); } if(item.getPrice() == null || item.getPrice() < 1000 || item..

29. BindingResult2

BindingResult가 있으면 에러가 나도 오류 정보를 여기에 담아서 컨트롤러를 호출한다. 원래 에러나면 그냥 클라이언트한테 오류코드 뿌려주고 끝이다. BindingResult는 말 그대로 바인딩에 관련한 건데, 만약 Integer인데 문자를 담으면 바인딩에 문제가 있는거니, 그거에 관한 걸 BindingResult에 담고 컨트롤러 로직을 이어간다. 위 같은 경우는 어떤 필드에 담을 데이터의 형식이 안 맞는거니 필드오류이기 때문에, BindingResult가 자동으로 FieldError를 생성해서 담는다. BingResult 검증오류 3가지 타입오류 시 스프링이 자동을 FIeldError 생성해서 BindingResult에 넣음 개발자가 직접 Validator (이건 나중에) 그냥 바인딩과 관련한 타..

28. BindingResult

BindingResult는 스프링에서 제공해주는 에러관련 기능이다. @PostMapping("/add") public String addItemV1(@ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes, Model model) { //검증 오류 보관 //검증 로직 if(!StringUtils.hasText(item.getItemName())){ bindingResult.addError(new FieldError("item", "itemName", "상품 이름은 필수입니다.")); } if(item.getPrice() == null || item.getPrice() < 1000 || item...