JSF和Bean Validation组

时间:2014-12-15 14:07:24

标签: jsf jsf-2 bean-validation

我在WildFly 8.1运行时使用JavaEE 7(JSF 2.2,Bean Validation 1.1 ...)和primefaces 5.1

我想根据按下的按钮使用不同的验证组。与少量约束相关联的保存按钮和与大量约束相关联的提交按钮。

bean验证组似乎是我需要的,但我对Web界面有一些问题。

根据验证模式,我不认为无效输入显示为红色:保存或提交

所以我做了3个接口:

public interface LifeCycleValidation {}
public interface Save extends LifeCycleValidation {}
public interface Submit extends Save {}

我使用BeanVal使用模型对象中的适当组

注释字段
@Size(min=3, max = 300, groups = Save.class)
@NotNull(groups = Save.class)
private String title ;

@Size(min = 3, max = 5, groups = Submit.class)
private List<String> keywords ;

我在JSF托管bean中创建了一些方法

private final String formIdPrefix = "bookEditForm:" ;

public void save() {
    save(Save.class) ;
}

public void submit() {
    save(Submit.class) ;
}

private void save(Class<? extends LifeCycleValidation> groupClass) {
    ValidatorFactory factory = Validation.buildDefaultValidatorFactory() ;
    Validator validator = factory.getValidator();
    Set<ConstraintViolation<Book>> violations = validator.validate(this, groupClass);
    violations.stream()
            .forEach(violation -> addErrorMessage(formIdPrefix+violation.getPropertyPath().toString(), violation.getMessage()));
    if(violations.isEmpty()) {
        // save
        addInfoMessage("","sucess") ;
    } else {
        addErrorMessage("",violations.size()+" error(s)") ;
    }
}

private void addErrorMessage(String id, String msg) {
    addMessage(id,FacesMessage.SEVERITY_ERROR,"Error",msg) ;
}

private void addInfoMessage(String id, String msg) {
    addMessage(id,FacesMessage.SEVERITY_INFO,"Info",msg) ;
}

private void addMessage(String clientId, FacesMessage.Severity severity, String summary, String detail) {
    FacesMessage message = new FacesMessage(severity, summary, detail);
    FacesContext.getCurrentInstance().addMessage(clientId, message);
}

如果输入的id对应于属性的路径但输入不是红色,则消息会正确显示

    <h:form id="bookEditForm">
        <p:messages showDetail="true" showSummary="true"/>
        <p:panelGrid columns="3">

            <p:outputLabel value="title" for="title"/>
            <p:inputText value="#{book.title}" id="title"/>
            <p:message showDetail="true" showSummary="true" for="title"/>

            <p:outputLabel value="keywords" for="keywords"/>
            <p:inputText value="#{book.keywords}" id="keywords" converter="converter.ListString"/>
            <p:message showDetail="true" showSummary="true" for="keywords"/>

        </p:panelGrid>

        <p:commandButton value="save" action="#{book.save()}" update="@form"/>
        <p:commandButton value="submit" action="#{book.submit()}" update="@form"/>

    </h:form>

(在我的例子中,模型和控制器属于同一类,它只是一个测试)

我使用f:validateBean validationGroups尝试其他解决方案 所以我做了ValidationMode枚举:

public enum ValidationMode {
    SAVE(Save.class), SUBMIT(Submit.class);

    public final Class<? extends LifeCycleValidation> cl ;

    private ValidationMode(Class<? extends LifeCycleValidation> cl) {
        this.cl = cl ;
    }
}

并将其放在JSF托管bean中:

private ValidationMode validationMode ;

public void setValidationMode(String validationModeTitle) {
    this.validationMode = ValidationMode.valueOf(validationModeTitle);
}

public String getValidationGroups() {
    if(validationMode==null) {
        return ValidationMode.SAVE.cl.getCanonicalName() ;
    }
    return validationMode.cl.getCanonicalName() ;
}

并尝试在ther commandButton

的actionListener中设置适当的模式
    <h:form id="bookEditForm">
        <p:messages showDetail="true" showSummary="true"/>
        <p:panelGrid columns="3">

            <p:outputLabel value="title" for="title"/>
            <p:inputText value="#{book.title}" id="title">
                <f:validateBean validationGroups="#{book.validationGroups}"/>
            </p:inputText>
            <p:message showDetail="true" showSummary="true" for="title"/>

            <p:outputLabel value="keywords" for="keywords"/>
            <p:inputText value="#{book.keywords}" id="keywords" converter="converter.ListString">
                <f:validateBean validationGroups="#{book.validationGroups}"/>
            </p:inputText>
            <p:message showDetail="true" showSummary="true" for="keywords"/>

        </p:panelGrid>

        <p:commandButton value="save" action="#{book.save()}" actionListener="#{book.setValidationMode('SAVE')}" update="@form"/>
        <p:commandButton value="submit" action="#{book.submit()}" actionListener="#{book.setValidationMode('SUBMIT')}" update="@form"/>

    </h:form>

但这不起作用

我想编写自己的jsf验证器,但我不知道如何根据正确的组实现验证器验证字段

1 个答案:

答案 0 :(得分:0)

我终于找到了一些东西,当一个onmouseover发生时触发了setValidationMode,就像在操作之前设置了验证模式:save或submit被称为

        <h:panelGroup layout="span">
            <p:ajax event="mouseover" listener="#{book.setValidationMode('SAVE')}"/>
            <p:commandButton value="save" action="#{book.save()}" update="@form"/>
        </h:panelGroup>            
        <h:panelGroup layout="span">
            <p:ajax event="mouseover" listener="#{book.setValidationMode('SUBMIT')}"/>
            <p:commandButton value="submit" action="#{book.submit()}" update="@form"/>
        </h:panelGroup>

所以你在控制器中无所事事

private ValidationMode validationMode = ValidationMode.SAVE ;

public void setValidationMode(String validationModeTitle) {
    this.validationMode = ValidationMode.valueOf(validationModeTitle);
}

public String getValidationGroups() {
    return validationMode.cl.getCanonicalName() ;
}

public void save() {
    // save
    addInfoMessage("","saved") ;
}

public void submit() {
    // submit
    addInfoMessage("","submited") ;
}

修改

这是干净完整的MVC解决方案,其中进度条以奖金计算:

观点:

    <h:form id="bookEditForm">

        <p:progressBar value="#{bookBean.progress}" labelTemplate="{value}%" id="progress"/>

        <p:messages showDetail="true" showSummary="true"/>

        <p:panelGrid columns="3">

            <p:outputLabel value="title" for="title"/>
            <p:inputText value="#{bookBean.book.title}" id="title">
                <f:validateBean validationGroups="#{bookBean.validationGroups}"/>
            </p:inputText>
            <p:message showDetail="true" showSummary="true" for="title"/>

            <p:outputLabel value="keywords" for="keywords"/>
            <p:inputText value="#{bookBean.book.keywords}" id="keywords" converter="converter.ListString">
                <f:validateBean validationGroups="#{bookBean.validationGroups}"/>
            </p:inputText>
            <p:message showDetail="true" showSummary="true" for="keywords"/>

        </p:panelGrid>

        <h:panelGroup layout="span">
            <p:ajax event="mouseover" listener="#{bookBean.setValidationMode('SAVE')}"/>
            <p:commandButton value="save" action="#{bookBean.save()}" update="@form"/>
        </h:panelGroup>            
        <h:panelGroup layout="span">
            <p:ajax event="mouseover" listener="#{bookBean.setValidationMode('SUBMIT')}"/>
            <p:commandButton value="submit" action="#{bookBean.submit()}" update="@form"/>
        </h:panelGroup>

    </h:form>

控制器:

@Named
@ViewScoped
public class BookBean implements Serializable {

    private ValidationMode validationMode = ValidationMode.SAVE;

    private Book book ;

    public BookView() {
        book = new Book() ;
    }

    public void setValidationMode(String validationModeTitle) {
        this.validationMode = ValidationMode.valueOf(validationModeTitle);
    }

    public String getValidationGroups() {
        return validationMode.cl.getCanonicalName() ;
    }

    public Book getBook() {
        return book;
    }

    public void save() {
        // save...
        addMessage("",FacesMessage.SEVERITY_INFO,"Success","Infos saved") ;
    }

    public void submit() {
        //submit...
        addMessage("",FacesMessage.SEVERITY_INFO,"Success","Infos submitted") ;
    }

    private void addMessage(String clientId, FacesMessage.Severity severity, String summary, String detail) {
        FacesMessage message = new FacesMessage(severity, summary, detail);
        FacesContext.getCurrentInstance().addMessage(clientId, message);
    }

    public int getProgress() {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory() ;
        Validator validator = factory.getValidator();
        int nbConstraints = validator.getConstraintsForClass(Book.class).getConstrainedProperties().size() ;
        int nbViolations = validator.validate(book, Submit.class).size();
        return 100 - (nbViolations*100) / (nbConstraints) ;
    }
}

模特:

public class Book implements Serializable {

    @NotNull(groups = Save.class)
    @Size(min=1, max = 140, groups = Save.class)
    private String title ;

    @NotNull(groups = Submit.class)
    @Size(min = 3, max = 5, groups = Submit.class)
    private List<String> keywords ;

    // getters and setters
}

ValidationMode,LifeCycleValidation,Save and Submit与问题中的相同

OmniFaces似乎有一个很好的解决方案: http://showcase.omnifaces.org/validators/validateBean 可能很有趣......