无论数据是否有效,是否可以让 JSF 恢复用户输入的值?
Is it possible to make JSF restore user entered values regardless of the data being valid?
我正在开发一个具有表单的 JSF 应用程序:
<h:inputText value="#{model.firstname}" />
<h:inputText value="#{model.employeeNumber}" converter="javax.faces.Integer"/>
...
这是带有 bean 验证的模型:
@NotNull(message="Please enter a surname")
private String firstname;
@Min(value=1)
@Max(value=2000)
private Integer employeeNumber;
...
//setters and getters
除了页面中明确编码的 'back' 按钮(转到上一页/表单)之外,一切都运行良好。
我希望用户输入的值在他们再次 return 到上面的页面时恢复,无论数据是否 valid.for 例如,如果用户输入 abc
employeeNumber
字段此字符串无法存储到模型上的 Integer
。
我知道 JSF 将用户输入的值存储到每个 UIComponent
的 "Request Values" 中。我想恢复的是这些而不是我的模型,因为上面的表格还没有验证它的数据。
我该怎么做?
(用户点击提交时会进行数据验证)。
我过去处理过这个问题 - 通过不使用 @NotNull
、@Min
和 @Max
等验证注释。使用这些注释时,无法将无效数据应用于模型,因此无法在服务器上保存状态。
相反,我不得不在“提交”按钮后面的方法中编写验证逻辑代码。缺点是 JSF 不为您做这些工作;你必须自己做。好处是您可以更好地控制应用验证的确切时间和方式。
My colleague has just mentioned there may be a way to accomplish this using omnifaces
截至目前,有。 OmniFaces 中已经提供了很多东西,只是缺少了一小部分关键部分。我只是 committed a Hacks#getStateHelper()
to 2.3 SNAPSHOT which should expose the protected UIComponent#getStateHelper()
method into public. Then, it's doable together with help of EditableValueHolderStateHelper
already in OmniFaces since 1.0 and with <o:form>
and <o:ignoreValidationFailed>
以便无论如何调用操作,而不管 conversion/validation 错误(正如 "back" 按钮应该做的那样)。
因此,如果您确保至少使用 OmniFaces 2.3(目前仅作为 SNAPSHOT 提供),那么您可以使用以下会话范围的帮助程序 bean 实现要求,利用几个 OmniFaces 实用程序 classes Faces
、Hacks
和 EditableValueHolderStateHelper
:
@Named
@SessionScoped
public class Forms implements Serializable {
private transient Map<String, StateHelper> states = new ConcurrentHashMap<>();
public void saveState(ComponentSystemEvent event) {
UIComponent form = event.getComponent();
FacesContext context = Faces.getContext();
StateHelper state = Hacks.getStateHelper(form);
EditableValueHolderStateHelper.save(context, state, form.getFacetsAndChildren());
states.put(Faces.getViewId(), state);
}
public void restoreState(ComponentSystemEvent event) {
StateHelper state = states.get(Faces.getViewId());
if (state != null) {
UIComponent form = event.getComponent();
FacesContext context = Faces.getContext();
EditableValueHolderStateHelper.restore(context, state, form.getFacetsAndChildren());
}
}
public void removeState() {
states.remove(Faces.getViewId());
}
}
需要在表单组件的postValidate
事件中调用saveState
。 restoreState()
需要在表单组件的postAddToView
事件中被调用。 removeState()
需要在成功操作期间调用。下面是一个示例表格:
<o:form>
<f:event type="postAddToView" listener="#{forms.restoreState}" />
<f:event type="postValidate" listener="#{forms.saveState}" />
<h:inputText value="#{bean.string}" required="true" />
<h:inputText value="#{bean.integer}" required="true" />
<h:commandButton value="save" actionListener="#{forms.removeState()}" action="#{bean.save}" />
<h:commandButton value="back" action="#{bean.back}">
<o:ignoreValidationFailed />
</h:commandButton>
<h:messages />
</o:form>
这种方法的主要优点是不需要对现有的验证规则和支持 bean 进行修改,从而保留了 JSF 和 BV 的所有优点。
确保清除服务器会话状态 and/or 增加 serialVersionUID
的 Forms
class 每当您更改关联表单的组件树结构时,否则您必须进行预检查 and/or 正确处理异常。给表单和输入组件一个固定的 ID 也是 strongly recommended.
我正在开发一个具有表单的 JSF 应用程序:
<h:inputText value="#{model.firstname}" />
<h:inputText value="#{model.employeeNumber}" converter="javax.faces.Integer"/>
...
这是带有 bean 验证的模型:
@NotNull(message="Please enter a surname")
private String firstname;
@Min(value=1)
@Max(value=2000)
private Integer employeeNumber;
...
//setters and getters
除了页面中明确编码的 'back' 按钮(转到上一页/表单)之外,一切都运行良好。
我希望用户输入的值在他们再次 return 到上面的页面时恢复,无论数据是否 valid.for 例如,如果用户输入 abc
employeeNumber
字段此字符串无法存储到模型上的 Integer
。
我知道 JSF 将用户输入的值存储到每个 UIComponent
的 "Request Values" 中。我想恢复的是这些而不是我的模型,因为上面的表格还没有验证它的数据。
我该怎么做?
(用户点击提交时会进行数据验证)。
我过去处理过这个问题 - 通过不使用 @NotNull
、@Min
和 @Max
等验证注释。使用这些注释时,无法将无效数据应用于模型,因此无法在服务器上保存状态。
相反,我不得不在“提交”按钮后面的方法中编写验证逻辑代码。缺点是 JSF 不为您做这些工作;你必须自己做。好处是您可以更好地控制应用验证的确切时间和方式。
My colleague has just mentioned there may be a way to accomplish this using omnifaces
截至目前,有。 OmniFaces 中已经提供了很多东西,只是缺少了一小部分关键部分。我只是 committed a Hacks#getStateHelper()
to 2.3 SNAPSHOT which should expose the protected UIComponent#getStateHelper()
method into public. Then, it's doable together with help of EditableValueHolderStateHelper
already in OmniFaces since 1.0 and with <o:form>
and <o:ignoreValidationFailed>
以便无论如何调用操作,而不管 conversion/validation 错误(正如 "back" 按钮应该做的那样)。
因此,如果您确保至少使用 OmniFaces 2.3(目前仅作为 SNAPSHOT 提供),那么您可以使用以下会话范围的帮助程序 bean 实现要求,利用几个 OmniFaces 实用程序 classes Faces
、Hacks
和 EditableValueHolderStateHelper
:
@Named
@SessionScoped
public class Forms implements Serializable {
private transient Map<String, StateHelper> states = new ConcurrentHashMap<>();
public void saveState(ComponentSystemEvent event) {
UIComponent form = event.getComponent();
FacesContext context = Faces.getContext();
StateHelper state = Hacks.getStateHelper(form);
EditableValueHolderStateHelper.save(context, state, form.getFacetsAndChildren());
states.put(Faces.getViewId(), state);
}
public void restoreState(ComponentSystemEvent event) {
StateHelper state = states.get(Faces.getViewId());
if (state != null) {
UIComponent form = event.getComponent();
FacesContext context = Faces.getContext();
EditableValueHolderStateHelper.restore(context, state, form.getFacetsAndChildren());
}
}
public void removeState() {
states.remove(Faces.getViewId());
}
}
需要在表单组件的postValidate
事件中调用saveState
。 restoreState()
需要在表单组件的postAddToView
事件中被调用。 removeState()
需要在成功操作期间调用。下面是一个示例表格:
<o:form>
<f:event type="postAddToView" listener="#{forms.restoreState}" />
<f:event type="postValidate" listener="#{forms.saveState}" />
<h:inputText value="#{bean.string}" required="true" />
<h:inputText value="#{bean.integer}" required="true" />
<h:commandButton value="save" actionListener="#{forms.removeState()}" action="#{bean.save}" />
<h:commandButton value="back" action="#{bean.back}">
<o:ignoreValidationFailed />
</h:commandButton>
<h:messages />
</o:form>
这种方法的主要优点是不需要对现有的验证规则和支持 bean 进行修改,从而保留了 JSF 和 BV 的所有优点。
确保清除服务器会话状态 and/or 增加 serialVersionUID
的 Forms
class 每当您更改关联表单的组件树结构时,否则您必须进行预检查 and/or 正确处理异常。给表单和输入组件一个固定的 ID 也是 strongly recommended.