10

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

@NotNull该字段绑定到一个带有验证约束注释的 bean 属性。required="true"当 bean 属性已经用 @NotNull 注释时,还必须在 XHTML 中添加似乎是多余且容易出错的。

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

非常感谢任何想法或建议。

4

2 回答 2

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}"/>
    
于 2013-02-08T21:26:47.047 回答
3

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

我有一个类似的问题。在我的具体情况下:

  • 应告知用户某个字段(读取UIInput)是必需的
  • 我不想required="true"在 comp 上重复,因为它已经绑定到@NotNull/ @NotBlankproperty/field
  • 在我的情况下,标签组件可能不存在(而且我不喜欢星号标签)

所以,这就是我所做的:

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>

使用这个 listener s 会使用passthrough 属性UIInput进行渲染: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;
}

您可以调整此侦听器以根据需要设置组件或使用适合您特定需求的其他方法。

另一种方法可能是:

  • UILabels 而不是UIInputs
  • 获取UIInput与标签的for/ forValueValueExpression 关联的
  • 检查UIInput验证约束
  • 最终调用UIInput.setRequired(true)

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

于 2017-05-27T10:01:50.263 回答