Tha*_*ham 3 java validation jsf viewparams omnifaces
我有这个f:viewParam,我尝试绑定验证,并转换userId成Player和我得到了一个意想不到的结果.
<f:metadata>
<f:viewParam name="userId" value="#{myBean.selectedPlayer}" converter="pConverter"
converterMessage="Bad Request. Unknown User" required="true"
requiredMessage="Bad Request. Please use a link from within the system" />
</f:metadata>
<h:body>
<p:messages id="msgs"/>
<h:form>
<ul>
<li><a href="index2.xhtml?userId=1">Harry</a></li>
<li><a href="index2.xhtml?userId=2">Tom</a></li>
<li><a href="index2.xhtml?userId=3">Peter</a></li>
</ul>
</h:form>
<h:form>
<h:panelGrid columns="2" rendered="#{not empty myBean.selectedPlayer}">
<h:outputText value="Id: #{myBean.selectedPlayer.id}"/>
<h:outputText value="Name: #{myBean.selectedPlayer.name}"/>
</h:panelGrid>
</h:form>
<h:form id="testForm">
<h:inputText value="#{myBean.text}"/>
<p:commandButton value="Switch" update=":msgs testForm"/>
<h:outputText value="#{myBean.text}" rendered="#{not empty myBean.text}"/>
</h:form>
</h:body>
Run Code Online (Sandbox Code Playgroud)
我的转换器看起来像这样
@FacesConverter(value="pConverter")
public class PConverter implements Converter {
private static final List<Player> playerList;
static{
playerList = new ArrayList<Player>();
playerList.add(new Player(1, "Harry"));
playerList.add(new Player(2, "Tom"));
playerList.add(new Player(3, "Peter"));
}
@Override
public Object getAsObject(FacesContext fc, UIComponent uic, String value) {
if(value == null || !value.matches("\\d+")){
return null;
}
long id = Long.parseLong(value);
for(Player p : playerList){
if(p.getId() == id){
return p;
}
}
throw new ConverterException(new FacesMessage("Unknown userId: " + value));
}
@Override
public String getAsString(FacesContext fc, UIComponent uic, Object value) {
if(!(value instanceof Player) || value == null){
return null;
}
return String.valueOf(((Player)value).getId());
}
}
Run Code Online (Sandbox Code Playgroud)
当我点击三个链接(哈利,汤姆,彼得)时,转换器工作得很好.它转换id并将其绑定player到我的托管bean.然后我在文本框中键入内容,然后单击Switch,第一次它正常工作,我键入的内容出现在按钮旁边,但随后我更改了我键入的内容,然后Switch再次单击,然后出现错误消息Bad Request. Please use a link from within the system,这是错误消息为required对f:viewParam.如果我把f:viewParam拿出去,那么一切正常.令人惊讶的是,如果我从f:viewParam切换到o:viewParam(OmniFaces),那么它工作得很好.
那是因为<f:viewParam>每次HTTP请求都会运行,也会在回发上运行.对于普通的GET链接,它适用于您的情况,因为您在链接中传递了该参数.对于POST表单,它会失败,因为您没有在按钮中传递该参数.因此,它变为null请求参数映射,required验证器启动,因此验证错误.
为了保持<f:viewParam required="true">对POST表单的满意,您基本上需要<f:param>在命令按钮/链接中保留初始请求参数.
<p:commandButton value="Switch" update=":msgs testForm">
<f:param name="userId" value="#{param.userId}" />
</p:commandButton>
Run Code Online (Sandbox Code Playgroud)
OmniFaces <o:viewParam>设计用于与视图范围的bean结合使用,在isRequired()getter中有一个额外的检查(源代码在这里):
@Override
public boolean isRequired() {
// The request parameter get lost on postbacks, however it's already present in the view scoped bean.
// So we can safely skip the required validation on postbacks.
return !FacesContext.getCurrentInstance().isPostback() && super.isRequired();
}
Run Code Online (Sandbox Code Playgroud)
因此,这会required在每次回发时跳过验证器(此外,由于其无状态特性,它还会跳过在每个回发上设置模型值).这就是为什么你没有看到验证错误,你仍然有适当的模型值(每次回发都没有重置).