Jsf 当与查询参数关联的转换/验证失败时,执行重定向
下面是Jsf 当与查询参数关联的转换/验证失败时,执行重定向,jsf,primefaces,jsf-2.2,Jsf,Primefaces,Jsf 2.2,下面是的一个简单用例 参数id通过URL传递。当像xxx这样的非数值通过所讨论的URL传递,并且未调用与的侦听器关联的viewAction()方法时,存在转换错误 在这种情况下,id的值为null。当id无法转换为所需的目标类型时(如本例中),我想重定向到另一个页面或者,id未根据指定的验证标准进行验证,以避免在试图访问相应托管bean中的这些参数时,可能在PrimeFaces方法中或关联托管bean中的其他地方引发的潜在异常。为此,应调用viewAction()方法 如何进行这项工作?我应该用
的一个简单用例
参数id
通过URL传递。当像xxx
这样的非数值通过所讨论的URL传递,并且未调用与
的侦听器关联的viewAction()
方法时,存在转换错误
在这种情况下,id
的值为null
。当id
无法转换为所需的目标类型时(如本例中),我想重定向到另一个页面或者,id
未根据指定的验证标准进行验证,以避免在试图访问相应托管bean中的这些参数时,可能在PrimeFaces方法中或关联托管bean中的其他地方引发的潜在异常。为此,应调用viewAction()
方法
如何进行这项工作?我应该用吗
<f:event type="preRenderView">
结合
?为什么不自己验证id
@ManagedBean
@ViewScoped
public final class TestManagedBean implements Serializable
{
private String id; //Getter and setter.
private Long validId; //Getter and setter.
public void viewAction() {
try {
validId = Long.parseLong(id);
} catch (NumberFormatException ex) {
FacesContext facesContext = FacesContext.getCurrentInstance();
String outcome = "redirect.xhtml";
facesContext.getApplication().getNavigationHandler().handleNavigation(facesContext, null, outcome);
}
}
}
这就是行为。当PROCESS\u VALIDATIONS
阶段以结束时,将跳过UPDATE\u MODEL\u值
和INVOKE\u应用程序
阶段。与带有
的“常规”表单完全相同。将
视为
,将
视为
,它将变得更加清晰
对于您的特定需求,在转换/验证失败时执行重定向,至少有3种解决方案:
。我宁愿挂在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>
检查FacesContext#isPostback()
可防止在同一视图(如果有)中的“常规”表单验证失败时执行重定向
getAsObject()
中执行重定向(验证程序不适用于Long
的默认转换器,因为该转换器在非数字输入时已经失败;如果转换器失败,则验证程序永远不会启动)。然而,这是一个糟糕的设计(紧密耦合)
如有必要,您可以在
内部使用
将参数“传递”到转换器
<f:viewParam name="id" value="#{bean.id}" converter="idConverter">
<f:attribute name="redirect" value="some.xhtml" />
</f:viewParam>
相同,但不需要额外的支持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>
/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>
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/my.taglib.xml</param-value>
</context-param>
诚然,这是一点代码,但它最终以干净且可重用的
标记结束,并且实际上非常适合新功能此时,如果
id
为null
,则不会调用viewAction
?否,则会调用它。例如,如果URL看起来像这样,www.example.com/abc.jsf?id=
(id
在这里没有给出值),就会调用它。当通过URL提供的id
的值无法转换为java.lang.Long
时,它不会被调用,例如,www.example.com/abc.jsf?id=xxx
。抱歉,侦听器方法,viewAction()
本身不会被调用,当作为查询字符串参数传递的id
的值不能转换为java.lang.Long
时,如xxx
。然后如何在viewAction()
方法中验证id
?它会导致PrimeFacesLazyDataModel
的load()
方法中出现NullPointerException
。在我的测试用例(Mojarra 2.2.6)中,viewAction()
总是被调用。请注意,我已将id
的类型更改为String。虽然我没有显示实际的代码以避免代码干扰,但是id
实际上使用自定义JSF转换器转换为JPA实体。我目前正在
中使用一个额外的
标记(可能完全没有必要)在其侦听器方法中进行重定向,只要id
为空。如果没有添加更多答案,我将在几天后接受此答案。仅供参考:
已添加到OmniFaces,将在2.0版中提供。另请参见上一个示例或
中的内容,当转换或验证失败时,是否可以阻止相关视图/请求范围的托管bean中的@PostConstruct
方法执行?有时,一个@PostConstruct
方法被设计为调用一个或多个业务方法,即使转换或验证失败,这些方法也会不必要地执行昂贵的数据库调用。@Tiny:否。请使用
或选中isValidationFailed()
。
<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>
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);
}
}
}
}
<?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>
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/my.taglib.xml</param-value>
</context-param>