gpt4 book ai didi

spring - 将 Spring 的 LocalValidatorFactoryBean 与 JSF 一起使用

转载 作者:行者123 更新时间:2023-12-01 05:25:07 25 4
gpt4 key购买 nike

我正在尝试将 bean 注入(inject)自定义 ConstraintValidator .我遇到了一些事情:

  • 在 validation-api-1.1.0 中支持 CDI(提供 Beta 版)
  • Hibernate Validator 5 似乎实现了validation-api-1.1.0(Alpha 可用)
  • 使用 Seam 验证模块
  • 使用 Spring 的 LocalValidatorFactoryBean

  • 最后一个似乎最适合我的情况,因为我们已经在使用 Spring (3.1.3.Release)。

    我已将验证器工厂添加到 XML 应用程序上下文并启用了注释:
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.1.xsd">

    <context:component-scan base-package="com.example" />
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
    </beans>

    验证者:
    public class UsernameUniqueValidator implements
    ConstraintValidator<Username, String>
    {
    @Autowired
    private PersonManager personManager;

    @Override
    public void initialize(Username constraintAnnotation)
    {
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context)
    {
    if (value == null) return true;
    return personManager.findByUsername(value.trim()) != null;
    }
    }

    验证应用于 Person :
    public class Person
    {
    @Username
    private String username;
    }

    和支持bean:
    @Named
    @Scope("request")
    public class PersonBean
    {
    private Person person = new Person();
    @Inject
    private PersonManager personManager;

    public create()
    {
    personManager.create(person);
    }
    }

    在 JSF 页面中,我有:
    <p:inputText value="#{personBean.person.username}" />

    验证器被调用,但该字段未 Autowiring /注入(inject)并保持为空。这当然会引发 NullPointerException。

    我正在使用 Hibernate 验证器 4.2 对此进行测试(因为我认为 LocalValidatorFactoryBean 应该能够做到这一点)。

    最佳答案

    我也面临同样的问题。在我的例子中,使用了 Spring+MyFaces+RichFaces。在应用程序启动期间,Spring 创建了 LocalValidatorFactoryBean,但 MyFaces 不使用该 bean 作为验证工厂。相反,MyFaces 和 RichFaces 都使用了自己的验证器,即使是 spring-faces 模块。

    为了弄清楚如何使用 LocalValidatorFactoryBean 制作面孔,我查看了 javax.faces.validator.BeanValidator createValidatorFactory 方法。每次需要验证时,MyFaces 都会使用此方法创建 ValidatorFactory。在该方法中,您可以看到以下内容:

    Map<String, Object> applicationMap = context.getExternalContext().getApplicationMap();
    Object attr = applicationMap.get(VALIDATOR_FACTORY_KEY);
    if (attr instanceof ValidatorFactory)
    {
    return (ValidatorFactory) attr;
    }
    else
    {
    synchronized (this)
    {
    if (_ExternalSpecifications.isBeanValidationAvailable())
    {
    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    applicationMap.put(VALIDATOR_FACTORY_KEY, factory);
    return factory;
    }
    else
    {
    throw new FacesException("Bean Validation is not present");
    }
    }
    }

    如您所见,它首先尝试从上下文加载 ValidatorFactory,然后再创建一个新实例。所以我实现了以下解决方案来使用 Spring LocalValidatorFactoryBean:我创建了一个在 PostConstructApplicationEvent 上运行的 SystemEventListener。此监听器从 servlet 上下文中获取 Spring WebApplicationContext,从中检索 LocalValidatorFactoryBean 的实例并将其存储在 ExternalContext ApplicationMap 中。
    public class SpringBeanValidatorListener implements javax.faces.event.SystemEventListener {
    private static final long serialVersionUID = -1L;

    private final Logger logger = LoggerFactory.getLogger(SpringBeanValidatorListener.class);

    @Override
    public boolean isListenerForSource(Object source) {
    return true;
    }

    @Override
    public void processEvent(SystemEvent event) {
    if (event instanceof PostConstructApplicationEvent) {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    onStart(facesContext);
    }
    }

    private void onStart(FacesContext facesContext) {
    logger.info("--- onStart ---");

    if (facesContext == null) {
    logger.warn("FacesContext is null. Skip further steps.");
    return;
    }

    ServletContext context = getServletContext(facesContext);

    if (context == null) {
    logger.warn("ServletContext is not available. Skip further steps.");
    return;
    }

    WebApplicationContext webApplicationContext = (WebApplicationContext) context.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

    if (webApplicationContext == null) {
    logger.warn("Spring WebApplicationContext was not set in ServletContext. Skip further steps.");
    return;
    }

    LocalValidatorFactoryBean validatorFactory = null;

    try {
    validatorFactory = webApplicationContext.getBean(LocalValidatorFactoryBean.class);
    } catch (BeansException ex){
    logger.warn("Cannot get LocalValidatorFactoryBean from spring context.", ex);
    }

    logger.info("LocalValidatorFactoryBean loaded from Spring context.");

    Map<String, Object> applicationMap = facesContext.getExternalContext().getApplicationMap();
    applicationMap.put(BeanValidator.VALIDATOR_FACTORY_KEY, validatorFactory);

    logger.info("LocalValidatorFactoryBean set to faces context.");
    }

    private ServletContext getServletContext(FacesContext facesContext) {
    return (ServletContext) facesContext.getExternalContext().getContext();
    }
    }

    因此,当 MyFaces 第一次尝试获取 ValidatorFactory 时,LocalValidatorFactoryBean 已经存在并且 MyFaces 不会创建新实例。

    关于spring - 将 Spring 的 LocalValidatorFactoryBean 与 JSF 一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14361037/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com