Весенний валидатор: наличие аннотации и реализации валидатора

Возможно ли иметь как валидатор для формы, так и ограничения аннотаций?

Например, чтобы в объекте формы было такое поле:

@NotEmpty
private String date;

но затем проверьте шаблон даты в валидаторе.

Я знаю, что есть аннотация шаблона, но я просто хочу посмотреть, смогу ли я использовать оба типа проверки.


person Marius    schedule 16.08.2011    source источник


Ответы (2)


Вот ссылка на очень хороший сайт, где объясняется, как можно комбинировать валидатор JSR-303 с валидатором spring.

Далее я представлю свое решение, которое работает. Надеюсь, поможет.

Мой абстрактный валидатор:

import java.util.Map;
import java.util.Set;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorFactory;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.validation.Errors;


public abstract class AbstractValidator implements org.springframework.validation.Validator, ApplicationContextAware,
    ConstraintValidatorFactory {

@Autowired
private Validator validator;

private ApplicationContext applicationContext;

public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.applicationContext = applicationContext;
}

public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) {
    Map<String, T> beansByNames = applicationContext.getBeansOfType(key);
    if (beansByNames.isEmpty()) {
        try {
            return key.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException("Could not instantiate constraint validator class '" + key.getName() + "'", e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Could not instantiate constraint validator class '" + key.getName() + "'", e);
        }
    }
    if (beansByNames.size() > 1) {
        throw new RuntimeException("Only one bean of type '" + key.getName() + "' is allowed in the application context");
    }
    return (T) beansByNames.values().iterator().next();
}

public boolean supports(Class<?> c) {
    return true;
}

public void validate(Object objectForm, Errors errors) {
    Set<ConstraintViolation<Object>> constraintViolations = validator.validate(objectForm);
    for (ConstraintViolation<Object> constraintViolation : constraintViolations) {
        String propertyPath = constraintViolation.getPropertyPath().toString();
        String message = constraintViolation.getMessage();
        errors.rejectValue(propertyPath, "", message);
    }
    addExtraValidation(objectForm, errors);
}

protected abstract void addExtraValidation(Object objectForm, Errors errors);

}

Фактический валидатор:

import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;

import ro.scorpionsoftware.demo3.dao.AbstractValidator;


@Component(value="doctorValidator")
public class DoctorValidator extends AbstractValidator {

    @Override
    protected void addExtraValidation(Object objectForm, Errors errors) {
        //perform typical validation
        //can autowire to context
    }


}

Контроллер: (в конце это привязка @Valid к валидатору)

@Controller
public class DoctorEditController {

@Autowired
    private DoctorValidator doctorValidator;

@RequestMapping(value = "/doctorEdit", method = RequestMethod.POST)
    public String processSubmit(
            @ModelAttribute("doctorForm") @Valid DoctorForm df,
            BindingResult result,
            ModelMap model) {
     ...
}
@InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.setValidator(doctorValidator);
    }
}

В контексте объявите валидатор JSR-303:

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

При таком подходе вы можете получить контекст как в фактическом валидаторе, так и в любой другой пользовательской аннотации, которую вы хотите реализовать.

person Marius    schedule 20.08.2011

Вы можете составить вместе аннотации для использования нескольких валидаторов, так что это будет примерно так.

@NotEmpty
@Pattern("") // not sure of syntax here
@Target(ElementType.METHOD)
@Retention( RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {})
@Documented
public @interface DatePattern {
    String message() default "";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}
person Ransom Briggs    schedule 16.08.2011