3

HibernateValidator4.3.1を使用しています。検証は、アプリケーション全体で意図したとおりに実行されます。

テキストフィールドの数値(など)を確認したり、 Joda-Time APIに関する有効な日付を確認したりするなどdouble、グローバルに検証を実行するカスタムエディタをいくつか登録しました。int

このタイプの検証では、allowEmptyパラメータをfalse通常どおりに設定してnull /空の値を許可し、特にそのようなフィールドが空白のままの場合に個別のユーザーフレンドリーなエラーメッセージを表示するために個別に検証します。

したがって、HibernateValidatorとカスタムエディターを使用した検証に加えて、次の検証戦略を使用しようとしています。繰り返しになりますが、この種の検証は、カスタムエディタに登録されているフィールドが空白のままになっている場合にのみ適用されます。

org.springframework.validation.Validator以下は、インターフェースを実装するクラスです。

package test;

import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import validatorbeans.TempBean;

@Component
public final class TempValidator implements Validator {

    @Override
    public boolean supports(Class<?> clazz) {
        System.out.println("supports() invoked.");
        return TempBean.class.isAssignableFrom(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        TempBean tempBean = (TempBean) target;

        System.out.println("startDate = " + tempBean.getStartDate() + " validate() invoked.");
        System.out.println("doubleValue = " + tempBean.getDoubleValue() + " validate() invoked.");
        System.out.println("stringValue = " + tempBean.getStringValue() + " validate() invoked.");

        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "startDate", "java.util.date.nullOrEmpty.error");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "doubleValue", "java.lang.double.nullOrEmpty.error");
    }
}

クラスは@Componentアノテーションで指定されているため、特定のSpringコントローラークラスに自動配線できます。デバッグステートメントは、ユーザーから提供された入力に正確に基づいて表示されます。

以下はコントローラークラスです。

package controller;

import customizeValidation.CustomizeValidation;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.groups.Default;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.DataBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import test.TempValidator;
import validatorbeans.TempBean;

@Controller
public final class TempController {

    @Autowired
    private TempService tempService;

    private TempValidator tempValidator;

    public TempValidator getTempValidator() {
        return tempValidator;
    }

    @Autowired
    public void setTempValidator(TempValidator tempValidator) {
        this.tempValidator = tempValidator;
    }

    @RequestMapping(method = {RequestMethod.GET}, value = {"admin_side/Temp"})
    public String showForm(@ModelAttribute("tempBean") @Valid TempBean tempBean, BindingResult error, Map model, HttpServletRequest request, HttpServletResponse response) {
        return "admin_side/Temp";
    }

    @RequestMapping(method = {RequestMethod.POST}, value = {"admin_side/Temp"})
    public String onSubmit(@ModelAttribute("tempBean") @Valid TempBean tempBean, BindingResult errors, Map model, HttpServletRequest request, HttpServletResponse response) {
        //tempValidator.supports(TempBean.class);
        //tempValidator.validate(tempBean, errors);

        DataBinder dataBinder = new DataBinder(tempBean);
        dataBinder.setValidator(tempValidator);
        dataBinder.validate();

        //errors=dataBinder.getBindingResult();
        if (CustomizeValidation.isValid(errors, tempBean, TempBean.ValidationGroup.class, Default.class) && !errors.hasErrors()) {
            System.out.println("Validated");
        }

        return "admin_side/Temp";
    }
}

私はSpringコントローラークラス自体からバリデーターを呼び出しています(私は本当に欲しいです)

DataBinder dataBinder = new DataBinder(tempBean);
dataBinder.setValidator(tempValidator);
dataBinder.validate();

バリデーターが呼び出されますが、期待される検証は実行されません

次のステートメント(上記でコメント化されています)を使用してバリデーターを手動で呼び出すだけの場合、

tempValidator.validate(tempBean, errors);

次に、検証が実行されます。したがって、バリデーターが正しく機能しているとは思いません。なぜそれがうまくいかないのDataBinderですか?

私のapplication-context.xmlファイルでは、このBeanは単純に次のように構成されています。

<bean id="tempValidator" class="test.TempValidator"/>

testクラスが含まれているパッケージを含む、以下のような多くのパッケージTempValidatorは自動検出されます。

<context:component-scan base-package="controller spring.databinder validatorbeans validatorcommands test" use-default-filters="false">
    <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
    <context:include-filter expression="org.springframework.web.bind.annotation.ControllerAdvice" type="annotation"/>  
</context:component-scan>

私も入れようとしました

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>

私のdispatcher-servlet.xmlファイルで。

私はここで何を見落としていますか?

4

2 に答える 2

4

あなたが達成しようとしていることをよく理解している場合(空白のフィールドと入力された誤った値を区別する)、はるかに単純なアプローチを使用できます。

public class MyBean {

    @NotNull
    @DateTimeFormat(pattern="dd.MM.yyyy HH:mm") 
    private DateTime date;

    @NotNull
    @Max(value=5)
    private Integer max;

    @NotNull
    @Size(max=20)
    private String name;

    // getters, setters ... 
} 

コントローラのマッピング:

public void submitForm(@ModelAttribute @Valid MyBean myBean, BindingResult result) {

    if (result.hasErrors){
       // do something}
    else{
       // do something else
    }        
}

検証メッセージ:

NotNull=Required field.
NotNull.date=Date is required field.
NotNull.max=Max is required field.
Size=Must be between {2} and {1} letters.
Max=Must be lower than {1}.
typeMismatch.java.lang.Integer=Must be number.
typeMismatch.org.joda.time.DateTime=Required format dd.mm.yyyy HH:mm

スプリング構成:

@Configuration
public class BaseValidatorConfig {

    @Bean
    public LocalValidatorFactoryBean getValidator() {

        LocalValidatorFactoryBean lvfb = new LocalValidatorFactoryBean();
        lvfb.setValidationMessageSource(getValidationMessageSource());
        return lvfb;
    }

    protected MessageSource getValidationMessageSource() {// return you validation messages ...}
}

必要に応じて、詳細と説明を提供できます。

于 2013-02-27T07:58:32.767 に答える
0

質問で述べたアプローチがうまくいかなかった理由はわかりません。私はそれを機能させませんでしたが、このドキュメントを読んで、私の要件に従って私のために機能する別のアプローチを見つけました。

@InitBinderアノテーションで指定されたメソッド内にバリデーターを設定しました。

ドキュメントから

@Validメソッド引数が検出されたときに呼び出されるValidatorインスタンスは、2つの方法で構成できます。まず、@ Controllerの@InitBinderコールバック内でbinder.setValidator(Validator)を呼び出すことができます。これにより、@ControllerクラスごとにValidatorインスタンスを構成できます。

具体的には、私の要件では、データをデータベースに更新または挿入している間、つまり、これらの操作に関連付けられた送信ボタンが押されたときにのみ検証を実行する必要があります(アプリケーションにはこれらのタスク(挿入と更新)の両方に共通のボタンがあります)その名前はbtnSubmit)です。

それ以外の場合(たとえば、削除ボタンが押された場合)は、検証をミュートする必要があります。この要件を満たすために、私は次のようにバリデーターを登録しました。

@InitBinder
protected void initBinder(WebDataBinder binder, WebRequest webRequest) {
    if (webRequest.getParameter("btnSubmit") != null) {
        binder.setValidator(new TempValidator());
    } else {
        binder.setValidator(null);
    }
}

この状況では、バリデーター-TempValidatorは、名前属性がクライアントによってクリックされた送信ボタンの場合にのみ設定さbtnSubmitれます。

自動配線だけでなく、どこでもxml構成の必要はありません。

例示的なコントローラクラスは、次のようになります。

@Controller
public final class TempController {

    @Autowired
    private TempService tempService;

    @InitBinder
    protected void initBinder(WebDataBinder binder, WebRequest webRequest) {
        if (webRequest.getParameter("btnSubmit") != null) {
            binder.setValidator(new TempValidator());
        } else {
            binder.setValidator(null);
        }
    }

    //Removed the @Valid annotation before TempBean, since validation is unnecessary on page load.
    @RequestMapping(method = {RequestMethod.GET}, value = {"admin_side/Temp"})
    public String showForm(@ModelAttribute("tempBean") TempBean tempBean, BindingResult error, Map model, HttpServletRequest request, HttpServletResponse response) {
        return "admin_side/Temp";
    }

    @RequestMapping(method = {RequestMethod.POST}, value = {"admin_side/Temp"})
    public String onSubmit(@ModelAttribute("tempBean") @Valid TempBean tempBean, BindingResult errors, Map model, HttpServletRequest request, HttpServletResponse response) {
        if (CustomizeValidation.isValid(errors, tempBean, TempBean.ValidationGroup.class, Default.class) && !errors.hasErrors()) {
            System.out.println("Validated");
        }
        return "admin_side/Temp";
    }
}

WebRequestメソッド内のパラメンターは、initBinder()明らかなようにHttpリクエスト全体を処理するためのものではありません。汎用のリクエストメタデータを使用するためだけのものです。

についてのJavadoc WebRequest

Webリクエストの汎用インターフェース。主に一般的なWebリクエストインターセプターを対象としており、リクエストを実際に処理するためではなく、一般的なリクエストメタデータにアクセスできるようにします。

私がフォローしている可能性のある問題がある場合は、それを明確にするか、別の回答を追加してください。

于 2013-02-21T18:29:29.390 に答える