当与查询参数关联的转换/验证失败时执行重定向 [英] Performing a redirect, when conversion / validation associated with query parameters fails
问题描述
以下是
的一个简单用例.
The following is a simple use case of <f:viewAction>
.
<f:metadata>
<f:viewParam name="id" value="#{testManagedBean.id}" maxlength="20"/>
<f:viewAction action="#{testManagedBean.viewAction}"/>
</f:metadata>
所涉及的托管 bean.
The managed bean involved.
@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 和与 < 的侦听器关联的
未调用.viewAction()
方法传递像 xxx
这样的非数字值时,会出现转换错误;f: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
未根据指定的验证标准进行验证时避免在 LazyDataModel#load()
PrimeFaces 方法或相关托管 bean 中的其他地方,只要访问在相应的托管 bean 中尝试使用这些参数.为此,应该调用 viewAction()
方法.
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.
如何处理?我应该使用
<f:event type="preRenderView">
与
结合?
推荐答案
这是指定一>行为.当 PROCESS_VALIDATIONS
阶段以 验证失败,UPDATE_MODEL_VALUES
和 INVOKE_APPLICATION
阶段都被跳过.就像在带有
的常规"表单中一样.把
想象成一个
和一个
作为一个 <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:
如您所见,添加一个
.我宁愿挂钩postValidate
事件,而不是为了更好的自我记录性.
As you found out, add a
<f:event listener>
. I'd rather hook onpostValidate
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);
}
}
}
如有必要,您可以在
中使用
来传递"参数给转换器.
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);
创建一个自定义标记处理程序,它的作用与
基本相同,但不需要额外的支持 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屋!