Was würde ich wirklich tun möchte, ist log, was die Ajax-Anforderung ist eigentlich für.
Diese Information ist nur in dem JSF-Komponentenbaum zur Verfügung: wie der Name des Verfahrens, mit der Ajax (<p:ajax process="contactDetails" update="@form" listener="#{aboutYouController.findAddress}" ....
zB „Findaddress“ in diesem Aufruf) aufgerufen wird. Die JSF-Komponentenstruktur ist nur nach der Build-Zeit verfügbar. Eine Sicht wird nur erstellt, wenn die Anforderung von FacesServlet
bedient wurde. Daher ist ein Servlet-Filter viel zu früh, bevor er vor einem Servlet ausgeführt wird.
Sie sollten den Code nach der Wiederherstellungsansichtsphase eines Postbacks ausführen. Der JSF-Komponentenbaum ist in diesem Moment garantiert verfügbar. Sie können FacesContext#isPostback()
verwenden, um zu überprüfen, ob die aktuelle Anfrage ein Postback ist. Sie können PartialViewContext#isAjaxRequest()
verwenden, um zu überprüfen, ob die aktuelle Anfrage eine Ajax-Anfrage ist. Sie können den vordefinierten Request-Parameter javax.faces.source
verwenden, um die Client-ID der Quellkomponente der Ajax-Anforderung abzurufen. Sie können den vordefinierten Request-Parameter javax.faces.behavior.event
verwenden, um den Ajax-Ereignisnamen zu erhalten (z. B. change
, click
, action
, usw.).
Erhalten das zugehörige Verhalten Listeners ist wiederum eine Geschichte auseinander. Dies ist einfach für ActionSource2
Komponenten (z. B. <h|p:commandButton action="#{...}">
), da die MethodExpression
nur von ActionSource2#getActionExpression()
verfügbar ist. Dies ist jedoch für BehaviorBase
Tag-Handler (z. B. <f|p:ajax listener="#{...}">
) nicht einfach, da diese API keine Methode wie getBehaviorListeners()
hat. Es gibt nur Methoden zum Hinzufügen und Entfernen von ihnen, aber nicht zum Abrufen einer Liste von ihnen. Es ist also eine fiese Reflektionstrickerei erforderlich, um auf das private
-Feld mit den Listenern zuzugreifen, deren Name JSF-spezifisch ist. In Mojarra ist es listeners
und in MyFaces ist es _behaviorListeners
. Beide sind glücklicherweise zuweisbar von List
und es ist das einzige Feld dieses Typs, also könnten wir einfach nachsehen. Sobald Sie die Hand der BehaviorListener
Instanz haben, dann müssen Sie immer noch müssen eine weitere Reflexion Trickserei, um die MethodExpression
Feld dieser Instanz zu erhalten. Jawohl.
Alles in allem ist hier, wie die Tricks im Geschmack eines PhaseListener
aussehen wie auf afterPhase
von RESTORE_VIEW
hören:
public class AjaxActionLoggerPhaseListener implements PhaseListener {
@Override
public PhaseId getPhaseId() {
return PhaseId.RESTORE_VIEW;
}
@Override
public void beforePhase(PhaseEvent event) {
// NOOP.
}
@Override
public void afterPhase(PhaseEvent event) {
FacesContext context = event.getFacesContext();
if (!(context.isPostback() && context.getPartialViewContext().isAjaxRequest())) {
return; // Not an ajax postback.
}
Map<String, String> params = context.getExternalContext().getRequestParameterMap();
String sourceClientId = params.get("javax.faces.source");
String behaviorEvent = params.get("javax.faces.behavior.event");
UIComponent source = context.getViewRoot().findComponent(sourceClientId);
List<String> methodExpressions = new ArrayList<>();
if (source instanceof ClientBehaviorHolder && behaviorEvent != null) {
for (ClientBehavior behavior : ((ClientBehaviorHolder) source).getClientBehaviors().get(behaviorEvent)) {
List<BehaviorListener> listeners = getField(BehaviorBase.class, List.class, behavior);
if (listeners != null) {
for (BehaviorListener listener : listeners) {
MethodExpression methodExpression = getField(listener.getClass(), MethodExpression.class, listener);
if (methodExpression != null) {
methodExpressions.add(methodExpression.getExpressionString());
}
}
}
}
}
if (source instanceof ActionSource2) {
MethodExpression methodExpression = ((ActionSource2) source).getActionExpression();
if (methodExpression != null) {
methodExpressions.add(methodExpression.getExpressionString());
}
}
System.out.println(methodExpressions); // Do your thing with it.
}
private static <C, F> F getField(Class<? extends C> classType, Class<F> fieldType, C instance) {
try {
for (Field field : classType.getDeclaredFields()) {
if (field.getType().isAssignableFrom(fieldType)) {
field.setAccessible(true);
return (F) field.get(instance);
}
}
} catch (Exception e) {
// Handle?
}
return null;
}
}
Um wie unten um es zu bekommen zu laufen, registrieren in faces-config.xml
:
<lifecycle>
<phase-listener>com.example.AjaxActionLoggerPhaseListener</phase-listener>
</lifecycle>
Oben ist getestet und kompatibel mit Mojarra und PrimeFaces und theoretisch auch kompatibel mit MyFaces.
aktualisieren: falls Sie sich mit JSF-Utility-Bibliothek OmniFaces oder sind offen, da die Version 2.4 die neue Components#getCurrentActionSource()
Dienstprogramm-Methode verwenden, kann die aktuelle Aktion Quellenkomponente, um herauszufinden, und Components#getActionExpressionsAndListeners()
zu bekommen eine Liste aller Aktionsmethoden und Listener, die für eine bestimmte Komponente registriert sind. Dies ist auch bei regulären (Nicht-Ajax-) Anfragen verwendbar. Damit kann die obige PhaseListener
Beispiel wie unten reduziert werden:
public class FacesActionLoggerPhaseListener implements PhaseListener {
@Override
public PhaseId getPhaseId() {
return PhaseId.PROCESS_VALIDATIONS;
}
@Override
public void beforePhase(PhaseEvent event) {
// NOOP.
}
@Override
public void afterPhase(PhaseEvent event) {
if (!event.getFacesContext().isPostback())) {
return;
}
UIComponent source = Components.getCurrentActionSource();
List<String> methodExpressions = Components.getActionExpressionsAndListeners(source);
System.out.println(methodExpressions); // Do your thing with it.
}
}
speziell über den Hörer Methodennamen, tale ein Blick auf sich bitte hier an: http://stackoverflow.com/questions/11860550/jsf-get-current -action-in-managed-bean –
@tt_dev Interessant. Ich könnte dies möglicherweise verwenden, aber der facesContext ist in meinem Filter nicht verfügbar, da es keine Bean ist. Ich glaube, dass ich den facesContext von irgendwo innerhalb der Standardanfrage/Session holen kann, aber ich erinnere mich nicht wo. Ich habe meine App im Debug suchen, um es vergebens zu suchen. –
Es gibt keinen Grund, diese Frage abzustimmen. – Tiny