2

사용자 정의 ConstraintValidator에 bean을 주입하려고합니다. 나는 몇 가지를 가로 질러 온 :Spring의 LocalValidatorFactoryBean을 JSF와 함께 사용하기

  • CDI는
  • 최대 절전 모드 검사기 5 검증-API-1.1.0 (사용 가능한 알파)를 구현하는 것 같다 검증-API-1.1.0 (사용 가능한 베타) 지원
  • 우리는 이미 봄 (3.1.3.Release)를 사용하고 있기 때문에
  • 사용 솔기 검증 모듈
  • 사용 봄의 LocalValidatorFactoryBean

마지막 하나는 내 상황에 가장 적합한 것 같다.

나는 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> 

유효성 검사기 : 검증은 Person에 적용되는

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; 
    } 
} 

:

public class Person 
{ 
    @Username 
    private String username; 
} 

그리고 뒷받침 콩 :

@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}" /> 

유효성 검사기가 호출되지만 필드/autowire가 주입 null이 유지되지 않습니다. 이것은 물론 NullPointerException을 발생시킵니다.

Hibernate validator 4.2로 이것을 테스트하고 있습니다. (LocalValidatorFactoryBean이 이것을 수행 할 수 있어야합니다).

+0

동일한 문제가 있습니다. 해결책을 찾았습니까? – citress

+0

@citress 아니, 나는이 일을 결코 얻지 못했다. 다행히도 저에게 우선 순위가 아니 었습니다. 해결할 수 있다면 알려주세요. ;-) – siebz0r

답변

0

저는 봄 전문가는 아니지만, beans.xml에 PersonManager을 정의하거나 @Component로 주석을 달 것을 기대합니다. 또한 Autowiring Unmanaged Beans Annotated With @Component

+0

'PersonManager'는'@ Named'으로 주석 처리됩니다. 다른 Spring 관리 빈에 잘 주입된다. ;-)'beans.xml' 파일을 정의 할 수 없습니다. 왜냐하면 Spring과 충돌을 일으키기 때문입니다. – siebz0r

0

나는 또한 동일한 문제에 직면했다. 내 경우에는 Spring + MyFaces + RichFaces가 사용됩니다. 응용 프로그램을 시작하는 동안 Spring은 LocalValidatorFactoryBean을 만듭니다. 그러나 MyFaces는 해당 bean을 유효성 검사 팩토리로 사용하지 않습니다. 대신 MyFaces와 RichFaces는 스프링 페이스 모듈을 사용하여 자체 유효성 검사기를 사용했습니다.

Face를 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를로드하려고합니다. 그래서 Face를 Spring LocalValidatorFactoryBean으로 사용하기 위해 다음과 같은 솔루션을 구현했습니다. PostConstructApplicationEvent에서 실행되는 SystemEventListener를 만들었습니다. 이 리스너는 서블릿 컨텍스트에서 Spring WebApplicationContext를 가져 와서 LocalValidatorFactoryBean의 인스턴스를 가져 와서 ExternalContext ApplicationMap에 저장한다.에서 MyFaces 처음 ValidatorFactory을 얻을 때

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(); 
    } 
} 

그래서, LocalValidatorFactoryBean 이미 존재하고에서 MyFaces는 새로운 인스턴스를 생성하지 않습니다.

0

BeanValidator.VALIDATOR_FACTORY_KEY 키를 사용하여 사용자 지정 ValidatorFactory를 응용 프로그램 맵에 추가하는 방법을 찾아야합니다. 그러나 javax.faces.event.SystemEventListener를 사용하는 대신 스프링 측에서 접근 할 수도 있습니다. ValidatorFactory를 ServletContext의 속성으로 등록하면 응용 프로그램 맵 (ServletContext 또는 PortletContext의 추상화)에 추가되어 응용 프로그램 맵에 추가 될 수 있습니다.

그래서 질문은 : Spring 빈을 ServletContext에 속성으로 추가하는 방법입니다. 당신이 ServletContext를 추가 할 빈의 모든 유형이 클래스를 사용할 수

public class ServletContextAttributePopulator implements ServletContextAware { 

    Map<String,Object> attributes; 

    public Map<String, Object> getAttributes() { 
     return attributes; 
    } 

    public void setAttributes(Map<String, Object> attributes) { 
     this.attributes = attributes; 
    } 

    @Override 
    public void setServletContext(ServletContext servletContext) { 
     for (Map.Entry<String,Object> entry : attributes.entrySet()) { 
      servletContext.setAttribute(entry.getKey(), entry.getValue()); 
     } 
    } 

} 

참고 : 내 솔루션 ServletContextAware를 구현하는 도우미 빈을 사용하는 것이 었습니다. 당신의 봄의 맥락에서
, 당신은 다음 추가합니다 :

<bean id="servletContextPopulator" class="my.package.ServletContextAttributePopulator"> 
    <property name="attributes"> 
    <map> 
     <entry key="javax.faces.validator.beanValidator.ValidatorFactory" value-ref="validator"/> 
    </map> 
    </property> 
</bean> 

"검증은"당신의 LocalValidatorFactoryBean의 ID입니다.