17

Springコントローラーに次のコードがあります。

@Autowired
private javax.validation.Validator validator;

@RequestMapping(value = "/submit", method = RequestMethod.POST)
public String submitForm(CustomForm form) {
    Set<ConstraintViolation<CustomForm>> errors = validator.validate(form);
    ...
}

すべてのエラーを手動で調べて追加することなくerrors、Springのオブジェクトにマップすることは可能ですか?このようなもの:BindingResultBindingResult

// NOTE: this is imaginary code
BindingResult bindingResult = BindingResult.fromConstraintViolations(errors);

CustomFormパラメータに注釈を付けて、@ValidSpringBindingResultに別のメソッドのパラメータとして注入させることは可能ですが、私の場合はオプションではありません。

// I know this is possible, but doesn't work for me
public String submitForm(@Valid CustomForm form, BindingResult bindingResult) {
    ...
}
4

5 に答える 5

10

より簡単なアプローチはorg.springframework.validation.Validator、代わりにSpringの抽象化を使用することです。コンテキストにこのBeanを含めることで、バリデーターを取得できます。

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

@Autowired @Qualifier("jsr303Validator") Validator validator;

この抽象化が適切に行われると、この方法でバリデーターを使用して、bindingResultを渡すことができます。

validator.validate(obj, bindingResult);
于 2013-02-15T11:19:27.353 に答える
5

Springは、SpringValidatorAdapterを使用して、バインディング結果にあるように、javax.validation.ConstraintViolationオブジェクトをObjectErrorまたはFieldErrorオブジェクトに変換します。次に、BindStatusはメッセージソース(Webアプリケーションコンテキスト自体など)を使用してエラーを変換します。要するに、あなたはすることができます:

SpringValidatorAdapter springValidator = new SpringValidatorAdapter(validator);
BindingResult bindingResult= new BeanPropertyBindingResult(myBeanToValidate, "myBeanName");
springValidator.validate(myBeanToValidate, bindingResult);

Springコンテキストを作成する必要さえないため、単体テストを作成するときにこれは簡単です。

于 2017-06-14T14:26:15.540 に答える
1
@RequestMapping(value = "/submit", method = RequestMethod.POST)
public String submitForm(CustomForm form) {
    Set<ConstraintViolation<CustomForm>> errors = validator.validate(form);

    BindingResult bindingResult = toBindingResult(errors, form, "form");
    ...
}

private BindingResult toBindingResult(ConstraintViolationException e, Object object, String objectName) {
    BindingResult bindingResult = new BeanPropertyBindingResult(object, objectName);
    new AddConstraintViolationsToErrors().addConstraintViolations(e.getConstraintViolations(), bindingResult);
    return bindingResult;
}

private static class AddConstraintViolationsToErrors extends SpringValidatorAdapter {
    public AddConstraintViolationsToErrors() {
        super(Validation.buildDefaultValidatorFactory().getValidator()); // Validator is not actually used
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    public void addConstraintViolations(Set<? super ConstraintViolation<?>> violations, Errors errors) {
        // Using raw type since processConstraintViolations specifically expects ConstraintViolation<Object>
        super.processConstraintViolations((Set) violations, errors);
    }
}

Set<ConstraintViolation<?>>この質問に対する他の回答とは異なり、このソリューションは、に変換する必要のあるがすでに存在する場合を処理しBindingResultます。

説明

Springは、SpringValidatorAdapterBean検証を実行するクラスを提供し、結果をインスタンスに格納します( extendsErrorsに注意してください)。このクラスの通常の手動使用は、次のメソッドを介して検証を実行するために使用することです。BindingResultErrorsvalidate

Validator beanValidator = Validation.buildDefaultValidatorFactory().getValidator();
SpringValidatorAdapter validatorAdapter = new SpringValidatorAdapter(beanValidator);

BindException bindException = new BindException(form, "form");
validatorAdapter.validate(form, bindException);

Set<ConstraintViolation<?>>ただし、これは、に変換する必要のあるがすでに存在する場合には役立ちませんBindingResult

この目標を達成することはまだ可能ですが、いくつかの追加のフープをジャンプする必要があります。 オブジェクトを適切なSpringサブタイプに変換し、それらをオブジェクトに格納SpringValidatorAdapterするメソッドが含まれています。ただし、このメソッドは保護されているため、アクセスがサブクラスに制限されます。processConstraintViolationsConstraintViolationObjectErrorErrors

SpringValidatorAdapterこの制限は、保護されたメソッドに委任または公開するカスタムサブクラスを作成することで回避できます。これは一般的な使用法ではありませんが、機能します。

public class AddConstraintViolationsToErrors extends SpringValidatorAdapter {
    public AddConstraintViolationsToErrors() {
        super(Validation.buildDefaultValidatorFactory().getValidator()); // Validator is not actually used
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    public void addConstraintViolations(Set<? super ConstraintViolation<?>> violations, Errors errors) {
        // Using raw type since processConstraintViolations specifically expects ConstraintViolation<Object>
        super.processConstraintViolations((Set) violations, errors);
    }
}

このカスタムクラスを使用して、新しく作成されたを設定し、からBindingResultを作成するという目標を達成できます。BindingResultSet<ConstraintViolation<?>>

private BindingResult toBindException(ConstraintViolationException e, Object object, String objectName) {
    BindingResult bindingResult = new BeanPropertyBindingResult(object, objectName);
    new AddConstraintViolationsToErrors().addConstraintViolations(e.getConstraintViolations(), bindingResult);
    return bindingResult;
}
于 2021-02-05T20:08:33.237 に答える
0

Kristiaanの回答を拡張すると、テストの目的で、SpringのbindingResultを使用して検証するSpringコンテキストを作成する必要はありません。次に例を示します。

public class ValidatorTest {

    javax.validation.Validator javaxValidator = Validation.buildDefaultValidatorFactory().getValidator();
    org.springframework.validation.Validator springValidator = new SpringValidatorAdapter(javaxValidator);

    @Test
    public void anExampleTest() {

    JSR303AnnotatedClassToTest   ctt  = new JSR303AnnotatedClassToTest( ..init vars..)

    ... test setup...

    WebDataBinder dataBinder = new WebDataBinder(ctt);
    dataBinder.setValidator(springValidator);
    dataBinder.validate();
    BindingResult bindingResult = dataBinder.getBindingResult(); 

    ... test analysis ...

    }
}

このアプローチでは、事前にバインディング結果を作成する必要はありません。dataBinderは適切な結果を作成します。

于 2018-12-16T21:28:13.140 に答える
0

私は同様の問題に遭遇しました、そしてこれは私がそれを解決した方法です。

あなたの例を考えると、これは私がそれを実装した方法です

まず、スマートバリデーターを使用し、このメソッドでSpringにBindingResultを注入させました

@Autowired
private org.springframework.validation.SmartValidator validator;

@RequestMapping(value = "/submit", method = RequestMethod.POST)
public String submitForm(CustomForm form, BindingResult bindingResult) {
    Set<ConstraintViolation<CustomForm>> errors = validator.validate(form);
    ...
}

次に、そのバインディング結果を使用して、SmartValidatorに渡し、エラーがBindingResultにバインドされるようにします。

validator.validate(form, bindingResult);
if(bindingResult.hasErrors()) {
     throw new BindException(bindingResult);
}
于 2021-09-22T04:54:54.250 に答える