2013-02-08 13 views
8

我有一個JSF 2.0應用程序它也使用Primefaces 3.3。目前,如果相關<p:inputText>使用required="true"屬性,則標籤上帶有星號的裝飾很有用。JSF 2.0必填字段標籤裝飾器屬性的@NotNull約束

該字段綁定到一個bean屬性,該屬性註釋爲@NotNull驗證約束。當bean屬性已經用@NotNull註解時,似乎冗餘且容易出錯的還必須在XHTML中添加required="true"

是否有鉤子或某種方式來自動修飾綁定到@NotNull屬性的組件的標籤?

任何想法或建議,非常感謝。

+1

@dforce:你使用哪個PF版本?由於PF 4.0有內置設施。然而,這個問題提到PF 3.3本身並不支持這一點。 – BalusC 2017-05-22 12:04:18

+0

嗨,我們正在使用5.3.5。它如何被使用?謝謝 – dforce 2017-05-22 14:43:29

+0

@dforce我不知道你是否收到新答案的通知,所以這是一個提醒:) – 2017-05-29 08:17:46

回答

3

注意:這是一個破解。這可能會影響性能,由於它的使用內省

  1. 的在基本層面,你需要知道什麼,如果該字段與@NotNull註解。在@PostConstruct這樣一個明智的地方爲視圖範圍的bean執行此檢查。聲明一個全局變量來確定所需的屬性

    boolean requiredAttribute;   
    
    @PostConstruct 
    public void init{ 
    Field theField = this.getClass().getField("theField"); 
    NotNull theAnnotation = theField.getAnnotation(NotNull.class); 
    if(theAnnotation != null){ 
        requiredAttribute = true; 
        } 
    } 
    
  2. 綁定required屬性變量的支持Bean

    <p:inputText id="inputit" required="#{myBean.requiredAttribute}"/> 
    
3

該解決方案基於PF 6.0,我不請記住,如果BeanValidationMetadataExtractor在以前的版本中可用。無論如何,創建DIY提取器是一項簡單的任務。

我有一個類似的問題。在我的具體情況:

  • 用戶應告知某一領域(讀UIInput)需要
  • 我不想在補償重複required="true",因爲它已經綁定到@NotNull/@NotBlank財產/現場
  • 對我來說,一個標籤組件可能不存在(我不喜歡帶星號的標籤)

所以,這裏是我做了什麼:

import java.util.Set; 
import javax.el.ValueExpression; 
import javax.faces.component.UIInput; 
import javax.faces.context.FacesContext; 
import javax.faces.event.AbortProcessingException; 
import javax.faces.event.PreRenderComponentEvent; 
import javax.faces.event.SystemEvent; 
import javax.faces.event.SystemEventListener; 
import javax.validation.constraints.NotNull; 
import javax.validation.metadata.ConstraintDescriptor; 
import org.hibernate.validator.constraints.NotBlank; 
import org.hibernate.validator.constraints.NotEmpty; 
import org.omnifaces.util.Faces; 
import org.primefaces.context.RequestContext; 
import org.primefaces.metadata.BeanValidationMetadataExtractor; 


public class InputValidatorConstraintListener implements SystemEventListener 
{ 
    @Override 
    public boolean isListenerForSource(Object source) 
    { 
     return source instanceof UIInput; 
    } 

    @Override 
    public void processEvent(SystemEvent event) throws AbortProcessingException 
    { 
     if(event instanceof PreRenderComponentEvent) 
     { 
      UIInput component = (UIInput) event.getSource(); 

      component.getPassThroughAttributes().computeIfAbsent("data-required", k -> 
      { 
       ValueExpression requiredExpression = component.getValueExpression("required"); 
       if(requiredExpression != null || !component.isRequired()) 
       { 
        FacesContext context = Faces.getContext(); 
        ValueExpression valueExpression = component.getValueExpression("value"); 
        RequestContext requestContext = RequestContext.getCurrentInstance(); 

        try 
        { 
         Set<ConstraintDescriptor<?>> constraints = BeanValidationMetadataExtractor.extractAllConstraintDescriptors(context, requestContext, valueExpression); 
         if(constraints != null && !constraints.isEmpty()) 
         { 
          return constraints.stream() 
           .map(ConstraintDescriptor::getAnnotation) 
           .anyMatch(x -> x instanceof NotNull || x instanceof NotBlank || x instanceof NotEmpty); 
         } 
        } 
        catch(Exception e) 
        { 
         return false; 
        } 
       } 

       return false; 
      }); 
     } 
    } 
} 

並在faces-config中聲明它。XML:

<?xml version="1.0" encoding="utf-8"?> 
<faces-config version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"> 

    <application> 
     <system-event-listener> 
      <system-event-listener-class>it.shape.core.jsf.listener.InputValidatorConstraintListener</system-event-listener-class> 
      <system-event-class>javax.faces.event.PreRenderComponentEvent</system-event-class> 
     </system-event-listener> 
    </application> 

</faces-config> 

此偵聽UIInput s的渲染與data-required直通屬性:

<input 
    id="form:editPanelMain:j_idt253" 
    name="form:editPanelMain:j_idt253" 
    type="text" 
    value="Rack Assemply" 
    size="80" 
    data-required="true" <============================ NOTE THIS!! 
    data-widget="widget_form_editPanelMain_j_idt253" 
    class="ui-inputfield ui-inputtext ui-widget ui-state-default ui-corner-all" 
    role="textbox" 
    aria-disabled="false" 
    aria-readonly="false"> 

現在,我使用的CSS規則來突出這些領域:

input[data-required='true'], 
.ui-inputfield[data-required='true'], 
*[data-required='true'] .ui-inputfield { 
    box-shadow: inset 0px 2px 2px #bf8f8f; 
} 

你可以讓聽衆根據需要設置組件或使用另一種適合您特定需求的方法。

另一種方法可以是:

  • UILabel!而非UIInput小號
  • 獲得與標籤的for/forValue ValueExpression相關的UIInput
  • 檢查UIInput爲驗證約束
  • 最終調用UIInput.setRequired(true)

性能影響可以忽略不計,因爲我測試了具有〜3000組件的複雜頁面。