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
    ?它会导致PrimeFaces
    LazyDataModel
    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>