以下是<f:viewAction>
的简单用例.
<f:metadata>
<f:viewParam name="id" value="#{testManagedBean.id}" maxlength="20"/>
<f:viewAction action="#{testManagedBean.viewAction}"/>
</f:metadata>
涉及的托管 bean。
@ManagedBean
@ViewScoped
public final class TestManagedBean implements Serializable {
private static final long serialVersionUID = 1L;
private Long id; //Getter and setter.
public void viewAction() {
System.out.println("viewAction() called : " + id);
}
}
参数
id
通过 URL 传递。当非数字值如 xxx
时,会出现转换错误通过有问题的 URL 和 viewAction()
传递与 <f:viewAction>
的监听器关联的方法不被调用。id
的值是 null
在这种情况下。我想重定向到另一个页面,当 id
无法转换为所需的目标类型(如本例)或 id
未针对指定的验证标准进行验证,以避免可能在 LazyDataModel#load()
中引发的潜在异常只要在相应的托管 bean 中尝试访问这些参数,PrimeFaces 或相关托管 bean 中的其他位置的方法。为此,viewAction()
方法应该被调用。如何进行?我应该使用
<f:event type="preRenderView">
结合
<f:viewAction>
?
最佳答案
这是 specified行为。当PROCESS_VALIDATIONS
阶段以 validation failure 结束, 双方 UPDATE_MODEL_VALUES
和 INVOKE_APPLICATION
阶段被跳过。与 <h:form>
的“常规”形式完全一样.想想<f:viewParam>
作为 <h:inputText>
和一个 <f:viewAction>
作为 <h:commandButton>
并且会变得更加清晰。
对于您的特定要求,在转换/验证失败时执行重定向,至少有 3 种解决方案:
<f:event listener>
.我宁愿上钩 postValidate
事件而不是更好的自我记录性。<f:metadata>
<f:viewParam name="id" value="#{bean.id}" maxlength="20" />
<f:event type="postValidate" listener="#{bean.redirectIfNecessary}" />
<f:viewAction action="#{bean.viewAction}" />
</f:metadata>
public void redirectIfNecessary() throws IOException {
FacesContext context = FacesContext.getCurrentInstance();
if (!context.isPostback() && context.isValidationFailed()) {
context.getExternalContext().redirect("some.xhtml");
}
}
支票在
FacesContext#isPostback()
防止在同一 View (如果有)中对“常规”表单的验证失败执行重定向。LongConverter
您可以在 getAsObject()
中执行重定向(验证器不适合,因为 Long
的默认转换器在非数字输入上已经失败;如果转换器失败,则永远不会触发验证器)。然而,这是糟糕的设计(紧耦合)。<f:metadata>
<f:viewParam name="id" value="#{bean.id}" converter="idConverter" />
<f:viewAction action="#{bean.viewAction}" />
</f:metadata>
@FacesConverter("idConverter")
public class IdConverter extends LongConverter {
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || !value.matches("[0-9]{1,20}")) {
try {
context.getExternalContext().redirect("some.xhtml");
return null;
}
catch (IOException e) {
throw new FacesException(e);
}
}
else {
return super.getAsObject(context, component, value);
}
}
}
如有必要,您可以使用
<f:attribute>
内<f:viewParam>
将参数“传递”给转换器。<f:viewParam name="id" value="#{bean.id}" converter="idConverter">
<f:attribute name="redirect" value="some.xhtml" />
</f:viewParam>
String redirect = (String) component.getAttributes().get("redirect");
context.getExternalContext().redirect(redirect);
<f:event listener>
基本相同的自定义标签处理程序但不需要额外的支持 bean 方法。<html ... xmlns:my="http://example.com/ui">
<f:metadata>
<f:viewParam name="id" value="#{bean.id}" maxlength="20" />
<my:viewParamValidationFailed redirect="some.xhtml" />
<f:viewAction action="#{bean.viewAction}" />
</f:metadata>
com.example.taghandler.ViewParamValidationFailed
public class ViewParamValidationFailed extends TagHandler implements ComponentSystemEventListener {
private String redirect;
public ViewParamValidationFailed(TagConfig config) {
super(config);
redirect = getRequiredAttribute("redirect").getValue();
}
@Override
public void apply(FaceletContext context, UIComponent parent) throws IOException {
if (parent instanceof UIViewRoot && !context.getFacesContext().isPostback()) {
((UIViewRoot) parent).subscribeToEvent(PostValidateEvent.class, this);
}
}
@Override
public void processEvent(ComponentSystemEvent event) throws AbortProcessingException {
FacesContext context = FacesContext.getCurrentInstance();
if (context.isValidationFailed()) {
try {
context.getExternalContext().redirect(redirect);
}
catch (IOException e) {
throw new AbortProcessingException(e);
}
}
}
}
/WEB-INF/my.taglib.xml
<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
version="2.0"
>
<namespace>http://example.com/ui</namespace>
<tag>
<tag-name>viewParamValidationFailed</tag-name>
<handler-class>com.example.taghandler.ViewParamValidationFailed</handler-class>
</tag>
</facelet-taglib>
/WEB-INF/web.xml
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/my.taglib.xml</param-value>
</context-param>
确实,这是一些代码,但它最终是干净且可重用的
<my:viewParamValidationFailed>
标签,实际上非常适合新的 OmniFaces特征。 关于jsf - 当与查询参数关联的转换/验证失败时执行重定向,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23049930/