RequestScoped Bean使用required或@NotNull导致viewParam丢失的问题
解决JSF表单验证失败时丢失viewParam主键的问题
问题根源
当你给<p:inputText>设置required="true"或者用@NotNull注解时,一旦必填字段为空触发验证失败,页面会回发,但你的termsid这个viewParam参数并没有被包含在表单的POST请求里。因为你的Bean是RequestScoped,每次请求都会重新实例化,回发时没有termsid,ARTermsEditBean.termsID就会为空,执行initializeExisting自然会报错。
不用加大量额外代码的解决办法
办法1:在表单里加隐藏字段存主键
直接在<h:form>里加一个隐藏输入框,把termsID的值带在表单提交请求中,这样不管验证成功还是失败,回发时主键都会跟着传回去:
<h:form id="artermsform"> <!-- 新增隐藏字段,传递主键 --> <h:inputHidden value="#{ARTermsEditBean.termsID}" /> <!-- 原表单内容不变 --> <h:panelGrid columns="3" columnClasses="formLabel"> <h:outputLabel value="Terms" for="terms" /> <p:inputText id="terms" value="#{ARTermsEditBean.terms}" required="true" maxlength="60" /> <p:message for="terms" /> <h:outputLabel value="Due Date Days" for="duedatedays" /> <p:inputText id="duedatedays" value="#{ARTermsEditBean.dueDateDays}" maxlength="3" /> <p:message for="duedatedays" /> </h:panelGrid> <p:commandButton value="Save" ajax="false" action="#{ARTermsEditBean.submit}" /> </h:form>
这样不管验证是否失败,termsID都会被提交到后台,Bean重建时能拿到正确的主键值,不会触发错误。
办法2:优化初始化逻辑,避免回发时重复初始化
把原来的<f:event type="preRenderView">换成<f:viewAction>,设置只在非回发请求时执行初始化,这样验证失败回发时不会重新调用initializeExisting,就算万一主键没传(配合办法1就不会有这情况),也不会因为重复初始化报错:
<f:metadata> <f:viewParam name="termsid" value="#{ARTermsEditBean.termsID}" /> <!-- 替换preRenderView,仅首次加载页面时执行初始化 --> <f:viewAction action="#{ARTermsEditBean.initializeExisting}" if="#{not facesContext.postback}" /> </f:metadata>
两个办法一起用效果最佳,既保证主键不会丢,又避免不必要的重复初始化。
关于其他页面的差异说明
那些主键在只读字段里的页面能正常工作,是因为只读输入框(比如<h:inputText readonly="true">)会把主键值作为表单字段一起提交到后台;而你当前页面没把termsid放进表单里,所以验证失败回发时就丢了这个参数。
内容的提问来源于stack exchange,提问作者Kevin Rahe
相关产品推荐
相关产品推荐

