首页 文章

JSF 2.0必需的字段标签装饰器,用于具有@NotNull约束的属性

提问于
浏览
9

我有一个JSF 2.0应用程序,它也使用Primefaces 3.3 . 目前有一个很好的功能,如果相关的 <p:inputText> 使用 required="true" 属性,标签用星号装饰 .

此字段绑定到bean属性,该属性使用 @NotNull 验证约束进行批注 . 当bean属性已经使用@NotNull注释时,在XHTML中添加 required="true" 似乎是多余的并且容易出错 .

是否有一个钩子或某种方法来自动装饰与@NotNull绑定到属性的组件的标签?

任何想法或建议都非常感谢 .

2 回答

  • 3

    注意:这是一个黑客 . 由于它使用了内省,它可能会对性能产生影响

    • 在基本级别,如果字段使用_2595348注释,则需要知道的内容 . 对于视图范围的bean,在 @PostConstruct 等合理的位置执行此检查 . 声明一个全局变量以确定所需的属性
    boolean  requiredAttribute;        
    
    @PostConstruct
    public void init{ 
    Field theField = this.getClass().getField("theField");
    NotNull theAnnotation = theField.getAnnotation(NotNull.class);
    if(theAnnotation != null){
       requiredAttribute = true;
       }
    }
    
    • required 属性绑定到辅助bean中的变量
    <p:inputText id="inputit" required="#{myBean.requiredAttribute}"/>
    
  • 3

    此解决方案基于PF 6.0,我不记得以前版本中是否有 BeanValidationMetadataExtractor . 无论如何,创建一个DIY提取器是一项简单的任务 .

    我遇到了类似的问题 . 在我的具体情况中:

    • 应通知用户需要某个字段(读取 UIInput

    • 我不想在comp上重复 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 将使用 data-required passthrough属性进行渲染:

    <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 s

    • 获取 UIInput 与标签的 for / forValue ValueExpression相关联

    • 检查 UIInput 是否有验证约束

    • 最终调用 UIInput.setRequired(true)

    性能影响可以忽略不计,因为我测试了大约3000个组件的复杂页面 .

相关问题