春の勉強検証2 Bean Validation



Bean Validation


:論理の汎用化、標準化を検証します.このようにすると、プレゼンテーションで検証ロジックを簡単に適用できます.
検証スキームは、例えば、@NotBlank@NotNull@Range(min=1000, max=100000)である.

: javax.検証から、実装にかかわらず、標準インタフェースです.

: org.hibernate.validatorで始まる場合は、Hypernight validator実装を使用する場合にのみ検証が提供されます.
:ただし、実際の操作では、仮想ベリファイアが使用される場合が多く、自由に使用できます.
Ben Validatorは標準化されたインタフェースで、一般的な空の値、範囲などの検証ロジックをすべてのプロジェクトに共通させることができます.すなわち,bean Validationは特定の実装ではない.1つの技術基準として,複数の態様と複数のインタフェースの集合である.bean Validationの実装としてHibernate Validatorを使用します.
ブログ参照

bean Validationスプリングの適用


検証順序

  • @ModelAttribute各フィールドでタイプを変換しようとします.成功した場合は、次のステップに進みます.失敗した場合は、typeMismatchFieldErrorに追加します.
  • その後Validatorを適用する.
  • このように、タイプの変換に成功し、バインドに成功しました.フィールドこそbean Validationです.

    BenValidationエラーコード


    :bean Validationを適用し、bindingResultにエラーコードを別名で登録します.
    :NotBlankは、エラーコードMessageCodeResolverに基づく例であり、フィールドError用の様々なメッセージコードが順次生成される.
    : NotBlank.item.itmeName
    : NotBlank.itemName
    : NotBlank.java.lang.String
    : NotBlank
    MessageCodesResolverは、認証エラーコードを使用してメッセージコードを生成します.このインタフェースにより、開発者は汎用メールと詳細メールを簡単に追加できます.BindingResultにFieldErrorまたはObjectErrorを追加すると、メッセージコードResolverはメッセージコードを生成します.
    :FieldErrorのメッセージコードとして、解析器は次の順序で4つのメッセージコードを生成します.
    1. code + "."+ object name + "."+ field
    2. code + "."+ field
    3. code + "."+ field type
    4. code
    :スプリングがデフォルト値よりも特定の値を検出すると、特定の設定値が使用されます.
    :ObjectErrorのメッセージコードは次のとおりです.(オブジェクトエラー)
    1. code + "."+ object name
    2. code
    :フィールドエラーには便利ですが、オブジェクトに関連するエラーはフィールドに説明を追加できないため、@ScriptAssert()を使用できます.
    @Data
    @ScriptAssert(lang="javascript", script="_this.price*_this.quantity>=10000")
    public class Item{
    
    }
    :ただし、Object Errorを使用すると、制約と複雑さが増加します.したがって、オブジェクトエラー(グローバルエラー)では、個別のjavaコードで記述すると便利です.

    BenValidationメッセージの検索順序

  • 生成されたメッセージコードの順にメッセージを検索する(前述のメッセージコード)
  • プレゼンテーションのメッセージ属性を使用
  • @NotBlank(messgae="공백을 입력할 수 없습니다.")
  • ライブラリが提供するデフォルト値を使用
  • Ben Validationの制限


    :データ登録と変更の要件が異なる場合があります.
    たとえば、メンバー登録については、承諾条件などの初期情報が表示される場合があります.

    :ただし、会員情報を変更する場合は、登録と全く同じ情報が必要になる場合がありますが、そうではないことを確認できます.

    :スプリングには2つの方法があります.
    1.BenValidationのGroups機能を使用する
    2.フォーム転送用にItemSaveFormやItemUpdateFormなどの個別モデルオブジェクトを作成する

    グループ機能の使用


    ストレージグループと
    package hello.itemservice.domain.item;
    public interface SaveCheck {
    }
    変更するグループ
    package hello.itemservice.domain.item;
    public interface UpdateCheck {
    }
    Itemクラスに作成して適用するには、次の手順に従います.
    @Data
    public class Item {
    	@NotNull(groups = UpdateCheck.class) //수정시에만 적용
    	private Long id;
    	@NotBlank(groups = {SaveCheck.class, UpdateCheck.class})
    	private String itemName;
    ...
    }
    }
    ストレージロジックには、次のものが含まれます.
    public String addItemV2(@Validated(SaveCheck.class) ...)
    修正ロジックは次のとおりです.
    public String editV2(@Validated(UpdateCheck.class) ..)
    に表示されます.

    フォームを分離してオブジェクトを渡す


    :ただし、通常、実際の操作では、フォームを分離してオブジェクトを転送する方法が使用されます.
    :Itemを直接受信するのではなく、複雑なフォームのデータをコントローラに転送する個別のオブジェクトを作成します.
    たとえば、フォームItemSaveForm@ModelAttributeを渡す専用オブジェクトを作成できます.
    :コントローラからフォームデータを受信し、必要な情報のみを使用してItemを作成します.
    :これらのフォーム転送オブジェクトを作成するときに、ItemSaveFormとItemEditFormを分離して、登録フォームと変更フォームの内容が異なるようにすることができます.

    サンプルコードは次のとおりです。


    :Itemはすべての検証コードを適用する必要はありません.
    @Data
    public class Item{
    	private long id;
        private String itemName;
        ...
    }
    :ITEM保存用!これはフォームです.
    @Data
    public class ItemSaveForm{
    	@NotBlank
        private String itemName;
        
        @NotNull
        @Range(min=1000, max = 1000000)
        pirvate Integer price;
        
        ...
    }
    :ITEMの修正に使用します.これはフォームです.
    @Data
    public class ItemUpdateForm{
    	@NotNull
        private Long id;
        
        @NotBlank
        private String itemName;
        
        ...
    }
    :コントローラを変更してフォームを使用します.
    @Slf4j
    @Controller
    @RequestMapping("/validation/v4/items")
    @RequiredArgsConstructor
    public class ValidationItemController{
    	private final ItemRepository itemrRepository;
        
        @GetMapping("/add")
        public String addForm(Model model){
        	model.addAttribute("item", new Item());
            return "validation/v4/addForm";
        }
        
        @PostMapping("/add")
        public String addItem(@Validated @ModelAttribute("item") ItemSaveForm form, BindingResult bindingResult, RedirectAttributes redirectAttributes){
        
        // 글로벌 예외
        if(form.getPrice() != null && form.getQuantity() != null){
    		int resultPrice = form.getPrice() * form.getQuantity();
            if(resultPrice <10000){
            	bindingResult.reject("totalPriceMin", new Object[]{1000, resultPrice}, null);
                }
                }
       if (bindingResult.hasErrors()) {
    		log.info("errors={}", bindingResult);
    		return "validation/v4/addForm";
    }
    	//성공 로직
    	Item item = new Item();
    	item.setItemName(form.getItemName());
    	item.setPrice(form.getPrice());
    	item.setQuantity(form.getQuantity());
    	Item savedItem = itemRepository.save(item);
    	redirectAttributes.addAttribute("itemId", savedItem.getId());
    	redirectAttributes.addAttribute("status", true);
    	return "redirect:/validation/v4/items/{itemId}";
    }	

    HTTPメッセージ変換器bean Validation


    :@ValidatedはHTTPMessageConverter(@RequestBody)にも使用できます.
    :@RequestBodyは主にAPI JSON要求の処理に用いられる.
    @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;
    }
    }
    コードから3つの結果が得られます.
    1.成功した場合
    2.JSONをオブジェクト自体に作成できませんでした
    (ex.price値に数値以外の文字が含まれている場合)
    (Itemオブジェクトを作成できないため、コントローラ自体は呼び出されず、その前に異常が発生します.)
    3.OSNをオブジェクトとして作成しましたが、検証に失敗しました.
    :2番目のcaseが発生した理由は次のとおりです.これは、フィールド単位で適用される@ModelAttributeコントラストHttpMessageConverterがオブジェクト全体に適用されるためである.@ModelAttributeは無効なフィールドを正常に処理できますが、HttpMessageConverterはサポートされていません.