Ответ 1
Это указано. Когда фаза PROCESS_VALIDATIONS
заканчивается валидацией, обе фазы UPDATE_MODEL_VALUES
и INVOKE_APPLICATION
пропускаются. Точно так же, как в "обычных" формах с <h:form>
. Подумайте <f:viewParam>
как <h:inputText>
и a <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()
предотвращает выполнение перенаправления при ошибках проверки правильных форм в одном и том же представлении (если есть). -
Расширьте встроенный
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.