답변:
사용 actionListener
하면 훅이 원한다면 전에 실제 비즈니스 동작이 실행 얻을, 예를 들어 그것을 로그 및 / 또는 (기준 추가 속성을 설정 <f:setPropertyActionListener>
), 및 / 또는으로 사용할 수있는 조치를 (호출 구성 요소에 액세스 할 수 있도록를 ActionEvent
논의). 따라서 실제 비즈니스 활동이 시작되기 전에 목적을 준비하기위한 것입니다.
이 actionListener
방법에는 기본적으로 다음과 같은 서명이 있습니다.
import javax.faces.event.ActionEvent;
// ...
public void actionListener(ActionEvent event) {
// ...
}
그리고 메소드 괄호없이 다음과 같이 선언해야합니다.
<h:commandXxx ... actionListener="#{bean.actionListener}" />
EL 2.2에서는 추가 인수를 전달할 수 없습니다 . 그러나 ActionEvent
사용자 정의 인수를 전달하고 지정 하여 인수를 모두 대체 할 수 있습니다 . 다음 예가 유효합니다.
<h:commandXxx ... actionListener="#{bean.methodWithoutArguments()}" />
<h:commandXxx ... actionListener="#{bean.methodWithOneArgument(arg1)}" />
<h:commandXxx ... actionListener="#{bean.methodWithTwoArguments(arg1, arg2)}" />
public void methodWithoutArguments() {}
public void methodWithOneArgument(Object arg1) {}
public void methodWithTwoArguments(Object arg1, Object arg2) {}
인수없는 메소드 표현식에서 괄호의 중요성에 유의하십시오. 이들이 없으면 JSF는 여전히 ActionEvent
인수가 있는 메소드를 기대합니다 .
EL 2.2+를 사용하는 경우을 통해 여러 액션 리스너 메소드를 선언 할 수 있습니다 <f:actionListener binding>
.
<h:commandXxx ... actionListener="#{bean.actionListener1}">
<f:actionListener binding="#{bean.actionListener2()}" />
<f:actionListener binding="#{bean.actionListener3()}" />
</h:commandXxx>
public void actionListener1(ActionEvent event) {}
public void actionListener2() {}
public void actionListener3() {}
binding
속성 에서 괄호의 중요성에 유의하십시오 . 속성 이 없으면 EL은 속성을 기본적으로 메소드 표현식이 아닌 값 표현식으로 해석 javax.el.PropertyNotFoundException: Property 'actionListener1' not found on type com.example.Bean
하기 때문에 혼란스럽게을 던질 것 binding
입니다. EL 2.2+ 스타일 괄호를 추가하면 값 표현식이 메소드 표현식으로 투명하게 바뀝니다. JSF가 지원하지 않는 <f : actionListener>를 임의의 메소드에 바인딩 할 수있는 이유 는 무엇입니까?
action
비즈니스 조치를 실행하고 필요한 경우 탐색을 처리 할 때 사용하십시오 . 이 action
메소드는 String
탐색 케이스 결과 (대상보기)로 사용될 a 를 리턴 할 수 있습니다 (따라서는 안 됨 ). null
또는 의 반환 값은 void
동일한 페이지로 돌아가 현재 뷰 범위를 유지합니다. 빈 문자열 또는 동일한 뷰 ID의 리턴 값도 동일한 페이지로 리턴되지만 뷰 범위를 다시 작성하여 현재 활성 인 뷰 범위 Bean을 삭제하고 해당하는 경우 다시 작성하십시오.
이 action
방법은 유효 MethodExpression
하며 다음과 같은 EL 2.2 인수를 사용하는 것도 가능합니다.
<h:commandXxx value="submit" action="#{bean.edit(item)}" />
이 방법으로 :
public void edit(Item item) {
// ...
}
액션 메소드가 문자열 만 반환 할 때, action
속성 에서 해당 문자열을 정확하게 지정할 수도 있습니다 . 따라서 이것은 완전히 서투른 것입니다.
<h:commandLink value="Go to next page" action="#{bean.goToNextpage}" />
이 의미없는 방법으로 하드 코드 된 문자열을 반환합니다.
public String goToNextpage() {
return "nextpage";
}
대신 하드 코딩 된 문자열을 속성에 직접 넣으십시오.
<h:commandLink value="Go to next page" action="nextpage" />
이는 POST로 탐색하는 디자인이 잘못되었음을 나타냅니다. 이것은 사용자 나 SEO 친화적이지 않습니다. 이 모든 것은 h : commandLink 대신 h : outputLink를 사용해야하는시기에 설명되어 있습니다. 로 해결되어야합니다
<h:link value="Go to next page" outcome="nextpage" />
JSF에서 탐색하는 방법을 참조하십시오 . URL이 현재 페이지를 반영하도록하는 방법 (이전 페이지는 아님) .
JSF 2.x부터 세 번째 방법이 <f:ajax listener>
있습니다.
<h:commandXxx ...>
<f:ajax listener="#{bean.ajaxListener}" />
</h:commandXxx>
이 ajaxListener
방법에는 기본적으로 다음과 같은 서명이 있습니다.
import javax.faces.event.AjaxBehaviorEvent;
// ...
public void ajaxListener(AjaxBehaviorEvent event) {
// ...
}
Mojarra에서 AjaxBehaviorEvent
인수는 선택 사항이며 아래에서 잘 작동합니다.
public void ajaxListener() {
// ...
}
그러나 MyFaces에서는을 던집니다 MethodNotFoundException
. 아래는 인수를 생략하려는 경우 두 JSF 구현에서 작동합니다.
<h:commandXxx ...>
<f:ajax execute="@form" listener="#{bean.ajaxListener()}" render="@form" />
</h:commandXxx>
Ajax 리스너는 명령 컴포넌트에서 실제로 유용하지 않습니다. 그들은 입력 및 선택 구성 요소에 대한 자세한 유용하다 <h:inputXxx>
/ <h:selectXxx>
. 명령 구성 요소에서 단지에 충실 action
및 / 또는 actionListener
선명도와 더 나은 자기 문서화 코드. 또한, 같은 actionListener
의는 f:ajax listener
탐색 결과 반환을 지원하지 않습니다.
<h:commandXxx ... action="#{bean.action}">
<f:ajax execute="@form" render="@form" />
</h:commandXxx>
속성 execute
및 render
속성 에 대한 설명은 PrimeFaces 프로세스 / 업데이트 이해 및 JSF f : ajax 실행 / 렌더 속성으로 이동하십시오 .
actionListener
들 항상 호출 하기 전에action
그들이보기에 선언하고 구성 요소에 첨부 된대로 같은 순서로. 는 f:ajax listener
항상 호출 하기 전에 모든 액션 청취자. 따라서 다음 예제는
<h:commandButton value="submit" actionListener="#{bean.actionListener}" action="#{bean.action}">
<f:actionListener type="com.example.ActionListenerType" />
<f:actionListener binding="#{bean.actionListenerBinding()}" />
<f:setPropertyActionListener target="#{bean.property}" value="some" />
<f:ajax listener="#{bean.ajaxListener}" />
</h:commandButton>
다음 순서로 메소드를 호출합니다.
Bean#ajaxListener()
Bean#actionListener()
ActionListenerType#processAction()
Bean#actionListenerBinding()
Bean#setProperty()
Bean#action()
이 actionListener
특별한 예외를 지원합니다 : AbortProcessingException
. 이 예외가 actionListener
메소드 에서 발생하면 JSF는 나머지 조치 리스너 및 조치 메소드를 건너 뛰고 응답을 직접 렌더링합니다. 오류 / 예외 페이지가 표시되지 않지만 JSF가이를 기록합니다. 또한 다른 예외가에서 발생할 때마다 암시 적으로 수행됩니다 actionListener
. 따라서 비즈니스 예외의 결과로 오류 페이지별로 페이지를 차단하려는 경우 action
메소드 에서 작업을 수행해야합니다 .
를 사용하는 유일한 이유는 경우 actionListener
하는 것입니다 void
같은 페이지로 돌아 방법을, 그 나쁜 일입니다. 이 action
방법은 void
일부 IDE에서 EL 유효성 검사를 통해 믿을 수있는 것과는 반대로 완벽하게 반환 할 수 있습니다 . 있습니다 PrimeFaces 쇼케이스 예는 이런 종류의 산재하는 actionListener
모든 장소에 걸쳐들. 이것은 실제로 잘못입니다. 이것을 스스로 핑계로 사용하지 마십시오.
그러나 아약스 요청에서는 특별한 예외 처리기가 필요합니다. 이는 listener
속성 사용 여부에 관계없이 적용 <f:ajax>
됩니다. 설명과 예를 보려면 JSF ajax requests의 Exception handling으로 이동하십시오 .
actionListener
,하지만 여전히 남용 할 수있는 좋은 변명하지 않습니다 actionListener
에 대한 사업 활동.
action
해당 조치 만 해당됩니다. actionListener
보조적인 물건입니다. actionListener
필요한 경우 s의 예외 가 전파 될 수 있음 을 분명히하고 싶었습니다 .)
actionListener
속성 에서 사용될 때 메소드 이름을 자유롭게 선택할 수 public
있으며 역시 있어야 합니다. processAction
사용중인 경우 이름은 필수 <f:actionListener type>
유형 구현이 간단하기 때문에, ActionListener
메소드 이름은 정확히이 인터페이스 processAction
definied합니다.
<f:ajax>
명령 구성 요소의 경우 action
비즈니스 조치에 속성을 사용하는 것을 선호합니다 . 예 <h:commandButton action="#{bean.businessAction}"><f:ajax/></h:commandButton>
.
BalusC가 지적했듯이, actionListener
기본적으로 예외를 삼키지 만 JSF 2.0에는 이것에 조금 더 있습니다. 즉, 그것은 삼키고 기록하는 것이 아니라 실제로 예외를 게시 합니다.
이것은 다음과 같은 호출을 통해 발생합니다.
context.getApplication().publishEvent(context, ExceptionQueuedEvent.class,
new ExceptionQueuedEventContext(context, exception, source, phaseId)
);
이 이벤트의 기본 리스너는 ExceptionHandler
Mojarra 의 기본 리스너입니다 com.sun.faces.context.ExceptionHandlerImpl
. 이 구현은 기본적으로 기록 된 AbortProcessingException과 관련된 경우를 제외하고는 예외를 다시 발생시킵니다. ActionListener는 클라이언트 코드에 의해 발생 된 예외를 이러한 AbortProcessingException에 랩하여 항상 기록되는 이유를 설명합니다.
이것은 ExceptionHandler
사용자 정의 구현 얼굴-config.xml 파일에서 그러나 교체 할 수 있습니다 :
<exception-handlerfactory>
com.foo.myExceptionHandler
</exception-handlerfactory>
하나의 Bean이 전체적으로 청취하는 대신 이러한 이벤트를 청취 할 수도 있습니다. 다음은 이에 대한 개념 증명입니다.
@ManagedBean
@RequestScoped
public class MyBean {
public void actionMethod(ActionEvent event) {
FacesContext.getCurrentInstance().getApplication().subscribeToEvent(ExceptionQueuedEvent.class, new SystemEventListener() {
@Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
ExceptionQueuedEventContext content = (ExceptionQueuedEventContext)event.getSource();
throw new RuntimeException(content.getException());
}
@Override
public boolean isListenerForSource(Object source) {
return true;
}
});
throw new RuntimeException("test");
}
}
(이것은 일반적으로 리스너를 코딩하는 방법이 아니며 데모 목적으로 만 사용됩니다!)
다음과 같이 Facelet에서 이것을 호출하십시오.
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:body>
<h:form>
<h:commandButton value="test" actionListener="#{myBean.actionMethod}"/>
</h:form>
</h:body>
</html>
오류 페이지가 표시됩니다.
Action이 호출되기 전에 응답을 수정하는 옵션과 함께 ActionListener가 먼저 시작되고 다음 페이지의 위치를 결정합니다.
같은 페이지에 여러 곳의 버튼이 있지만 같은 위치로 이동해야하지만 약간 다른 작업을 수행하는 경우 각 버튼에 대해 동일한 Action을 사용할 수 있지만 다른 ActionListener를 사용하여 약간 다른 기능을 처리 할 수 있습니다.
관계를 설명하는 링크는 다음과 같습니다.
TL; DR :
ActionListener
들 (다수 존재할 수있다)들이 전에 등록 된 순서대로 수행action
긴 답변 :
비즈니스는 action
일반적으로 EJB 서비스를 호출하고, 필요도 다른보기로 최종 결과 및 / 또는 탐색합니다를 설정하면 그것은 당신이 무슨 일을하지 않은 경우 actionListener
에 더 적합한 즉 때와 같은 구성 요소와 사용자의 상호 작용, h:commandButton
또는 h:link
그들이 할 수있는 actionListener
UI 컴포넌트의 속성에 관리 Bean 메소드의 이름을 전달 하거나 ActionListener
인터페이스 를 구현 하고 구현 클래스 이름을 actionListener
UI 컴포넌트의 속성에 전달하여 처리됩니다 .