쿼리 매개변수와 관련된 변환/검증 실패 시 리디렉션 수행
-
21-12-2019 - |
문제
다음은 간단한 사용 사례입니다. <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을 통해 전달됩니다.다음과 같이 숫자가 아닌 값을 입력하면 변환 오류가 발생합니다. xxx
문제의 URL을 통해 전달되며 viewAction()
리스너와 관련된 메소드 <f:viewAction>
호출되지 않습니다.
의 가치 id
~이다 null
이 경우.다른 페이지로 리디렉션하고 싶은 경우 id
이 경우와 같이 원하는 대상 유형으로 변환할 수 없습니다. id
에서 발생할 수 있는 잠재적인 예외를 피하기 위해 지정된 유효성 검사 기준에 대해 유효성이 검사되지 않습니다. LazyDataModel#load()
해당 관리 Bean에서 이러한 매개변수에 대한 액세스가 시도될 때마다 PrimeFaces의 메소드 또는 연관된 관리 Bean의 다른 위치에 있습니다.그러기 위해서는, viewAction()
메소드를 호출해야 합니다.
어떻게 진행하나요?사용해야 할까요?
<f:event type="preRenderView">
와 함께 <f:viewAction>
?
해결책
이것은 지정된 행동.언제 PROCESS_VALIDATIONS
단계는 다음으로 끝납니다. 검증 실패, 둘 다 UPDATE_MODEL_VALUES
그리고 INVOKE_APPLICATION
단계를 건너뜁니다."일반" 형식과 정확히 동일합니다. <h:form>
.에 대해 생각하다 <f:viewParam>
로서 <h:inputText>
그리고 <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>
그러나 추가적인 Backing 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>
태그는 실제로 새로운 태그에 적합합니다. 옴니페이스 특징.
다른 팁
단순히 검증하지 않는 이유 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);
}
}
}