본문 바로가기
Spring Framework/SPRING MVC

Bean Validation

by 거북이의 기술블로그 2024. 9. 25.
Bean Validation

 

Bean Validation 사전 준비

  • Bean Validation 사용 전 gradle 추가
 implementation 'org.springframework.boot:spring-boot-starter-validation'

 

 

검증 Annotation

  • @NotBlank
    • 빈값 + 공백만 있는 경우를 허용하지 않는다
  • @NotNull
    • null을 허용하지 않는다
  • @Range(min=숫자1, max= 숫자2)
    • 숫자1 ~ 숫자2 범위까지 가능
  • @Max(숫자)
    • 지정 숫자까지 최대 지정 가능

 

Bean Validation 검증 순서

  1. @ModelAttribute로 객체로 변환 ( -> 실패시, typeMistMatch로 FieldError 추가 == Bean Validation 적용 x)
  2. 객체로 변환될시, Validator 적용

 

Bean Validation 에러코드

  • Validation과 동일하게 bean validation도 BindingResult의 규율에 따르게 됨
  • 메시지를 이용하여 에러 메시지 작성 가능 -> errors.properties
  • 예시)
    • @NotBlank
      • NotBlank.item.itemName
      • NotBlank.itemName
      • NotBlank.java.lang.String
      • NotBlank

 

Bean Validation 기본

@Getter
@Setter
public class Item{
    
    
    private Long id;
    
    @NotBlank
    private String itemName;
    
    @NotNull
    @Range(min=1000, max=100000)
    private Integer price;
    
    @NotNull
    private Integer quantity;
}



@Controller
public class Controller{
    
    @Autowired private final ItemRepository itemRepository;
    
    @PostMapping("/add")
    public String addFunc(@Validated @ModelAttribute("item") Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes){
        
        if (bindingResult.hasErrors()){
            return "rollback View";
        }
        
        Item savedItem = itemRepository.save(item);
        redirectAttributes.addAttribute("itemId", savedItem.getId());
        redirectAttributes.addAttribute("status", true);
        return "redirect:/[URL]";
  }
  ...
  
}

 

Bean Validation 한계

  • 같은 객체에서, 각기 다른 폼에 대입되어 검증을 진행할 수 없음 (같은 객체 , 검증기준은 여러개)
    • 해결책)
      • groups
      • Form 객체
  • groups
    • 인터페이스 생성
    • 적용하고 싶은 group에 Bean Validation 적용
public interface SaveCheck{}
public interface UpdateCheck{}


@Data
 public class Item {
    
    @NotNull(groups = UpdateCheck.class) //수정시에만 적용 
    private Long id;
    
    @NotBlank(groups = {SaveCheck.class, UpdateCheck.class})
    private String itemName;
    
    @NotNull(groups = {SaveCheck.class, UpdateCheck.class})
    @Range(min = 1000, max = 1000000, groups = {SaveCheck.class,UpdateCheck.class})
    private Integer price;


....
}


@PostMapping("/add")
public String addfunc(@Validated(SaveCheck.class) @ModelAttribute Item item,BindingResult bindingResult, RedirectAttributes redirectAttributes) {
//...
}


@PostMapping("/edit")
public String editfunc(@Validated(UpdateCheck.class) @ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes){
//...
}

 

 

  • Form 객체
    • 과정 : HTML -> Controller ( 객체변환 -> ItemSaveForm OR ItemUpdateForm ) -> 검증 -> Item 객체로 변환 -> View 렌더링
@Data
 public class Item {
     private Long id;
     private String itemName;
     private Integer price;
     private Integer quantity;
}

 @Data
 public class ItemSaveForm {
     @NotBlank
     private String itemName;
     
     @NotNull
     @Range(min = 1000, max = 1000000)
     private Integer price;
     
     @NotNull
     @Max(value = 9999)
     private Integer quantity;
}


@Data
 public class ItemUpdateForm {
     @NotNull
     private Long id;
     
     @NotBlank
     private String itemName;
     
     @NotNull
     @Range(min = 1000, max = 1000000)
     private Integer price; 
    
     //수정에서는 수량은 자유롭게 변경할 수 있다.  
     private Integer quantity;
}


@Controller
public class Controller{

@PostMapping("/add")
public String addfunc(@Validated @ModelAttribute("itemSaveForm") ItemSaveForm itemSaveForm,
BindingResult bindingResult, RedirectAttributes redirectAttributes)
{
    //검증에 걸림
    if (bindingResult.hasErrors()){
        return "[view]";
    }
    
    //검증 통과
    Item item = new Item(itemSaveForm.getItemName(), itemSaveForm.getPrice(), itemSaveForm.getQuantity());
    Item savedItem = itemRepository.save(item);
    redirectAttributes.addAttribute("itemId", savedItem.getId());
    redirectAttributes.addAttribute("status", true);
    return "redirect:/[URL]";
}
}

 

  • 정리
    • Group은 인터페이스를 활용하여, 옵션을 이용한 처리
    • Form 객체는 각기다른 Form HTML 별로 객체를 준비해서 검증이 끝난후, 진짜 객체에 저장함

 

Bean Validation의 메시지 컨버터

@Slf4j
@RestController
@RequestMapping("/validation/api/items")
public class ValidationItemApiController {
     
     @PostMapping("/add")
     public Object addItem(@RequestBody @Validated ItemSaveForm form,BindingResult bindingResult) {
         
         log.info("API 컨트롤러 호출");

         if (bindingResult.hasErrors()) {
             log.info("검증 오류 발생 errors={}", bindingResult); 
             return bindingResult.getAllErrors();
         }
         
         log.info("성공 로직 실행");
         return form;
     }
}
  • @RequestBody를 이용하여 Json형태로도 검증이 가능
  • bindingResult.getAllErrors()의 경우 모든 오류 메시지 관련 내용을 가지고 있음
    • 해당 부분에서 필요한 부분만 필터해서, RequestBody로 전달 가능
  • Return 값으로 객체 전달 (form)

 

 

'Spring Framework > SPRING MVC' 카테고리의 다른 글

Session 사용법  (0) 2024.10.06
Cookie 사용법  (0) 2024.10.06
Validation (BindingResult, Validator) + @Validated  (1) 2024.09.25
메시지, 국제화  (0) 2024.09.24