当与查询参数关联的转换/验证失败时,执行重定向 [英] Performing a redirect, when conversion / validation associated with query parameters fails

查看:53
本文介绍了当与查询参数关联的转换/验证失败时,执行重定向的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是<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传递.当通过所讨论的URL传递诸如xxx的非数字值并且未调用与<f:viewAction>的侦听器关联的viewAction()方法时,会发生转换错误.

The parameter id is passed through a URL. There is a conversion error, when a non-numeric value like xxx is passed through the URL in question and the viewAction() method associated with the listener of <f:viewAction> is not invoked.

在这种情况下,id的值是null.我想重定向到另一页,当id无法转换为所需的目标类型(如本例)或id未根据指定的验证标准进行验证时,避免可能抛出的异常

The value of id is null in this case. I would like to redirect to another page, when id is not convertible to a desired target type (like in this case) or id is not validated against the specified validation criteria to avoid potential exceptions which are likely to be thrown in the LazyDataModel#load() method of PrimeFaces or somewhere else in the associated managed bean whenever access to these parameters is attempted in the corresponding managed bean. For this to be so, the viewAction() method should be invoked.

如何进行此操作?我应该使用

How to proceed with this? Should I use

<f:event type="preRenderView">

<f:viewAction>一起使用?

推荐答案

这是指定的行为.当PROCESS_VALIDATIONS阶段以验证失败,将同时跳过UPDATE_MODEL_VALUESINVOKE_APPLICATION阶段.与<h:form>的常规"形式完全相同.将<f:viewParam>视为<h:inputText>,将<f:viewAction>视为<h:commandButton>,它将变得更加清晰.

This is specified behavior. When PROCESS_VALIDATIONS phase ends with a validation failure, both the UPDATE_MODEL_VALUES and INVOKE_APPLICATION phases are skipped. Exactly like as in "regular" forms with <h:form>. Think of <f:viewParam> as a <h:inputText> and a <f:viewAction> as a <h:commandButton> and it will become more clear.

对于您的特定要求,当转换/验证失败时执行重定向,至少有3种解决方案:

For your particular requirement, performing a redirect when conversion/validation has failed, there are at least 3 solutions:

  1. 如您所知,添加一个<f:event listener>.我宁愿挂在postValidate事件上,也可以更好地实现自我记录.

  1. As you found out, add a <f:event listener>. I'd rather hook on postValidate event instead for better self-documentability.

<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()的检查可防止在同一视图(如果有)中对常规"表单的验证失败执行重定向.

The check on FacesContext#isPostback() prevents the redirect being performed on validation failures of "regular" forms in the same view (if any).

扩展内置的 LongConverter ,从而在getAsObject()中执行重定向(验证器不适合,因为Long的默认转换器在非数字输入上已经失效;如果转换器失败,则永远不会触发验证器).但是,这是较差的设计(紧密耦合).

Extend the builtin LongConverter whereby you perform the redirect in getAsObject() (a validator is insuitable as the default converter for Long would already fail on non-numeric inputs; if a converter fails, the validators are never fired). This is however poor design (tight-coupling).

<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:viewParam>中使用<f:attribute>进行操作,以将参数传递"到转换器.

You could if necessary play around with <f:attribute> inside <f:viewParam> to "pass" parameters to the converter.

<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方法.


  • Create a custom taghandler which does basically the same as <f:event listener> but without the need for an additional backing bean method.

    <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 功能.

    True, it's a bit of code, but it ends up in clean and reusable <my:viewParamValidationFailed> tag and is actually a good fit for a new OmniFaces feature.

    这篇关于当与查询参数关联的转换/验证失败时,执行重定向的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆