如何记录在servlet过滤器中调用的托管bean名称和操作方法 [英] How to log managed bean name and action method being invoked in a servlet filter
问题描述
我正在开发基于JSF 2 Mojarra的Web应用程序.我需要通过我的servlet过滤器记录一些检测信息.为此,我还需要知道正在调用哪个ManagedBean和哪个方法.
I am working on a web application built on JSF 2 Mojarra. I have a requirement to log some instrumentation information through my servlet filter. To do this I also need to know which ManagedBean and which method is being invoked.
是否有获取此信息的方法?我无法访问FacesContext
,因为在请求到达Faces Servlet之前调用了过滤器.
Is there a way to get this information? I can't access FacesContext
as filter is invoked before the request reaches Faces Servlet.
推荐答案
我认为您想记录正在调用的UICommand
组件. servlet筛选器不适合该操作,因为它无法访问FacesContext
,更不用说您最终需要遍历的UIViewRoot
了. FacesContext
(以及UIViewRoot
等)也由FacesServlet
创建,因为它是一个体面的servlet,完全符合方式可以创建您自己的
I gather that you want to log the UICommand
component being invoked. A servlet filter is insuitable for that as it has no access to the FacesContext
, let alone the UIViewRoot
which you ultimately need to traverse. The FacesContext
(and inherently also the UIViewRoot
, et.al) are created by the FacesServlet
which is as being a decent servlet completely conform the servlet spec invoked after all filters. It's therefore impossible to get a hand of the FacesContext
inside a servlet filter. True, there are ways to create your own FacesContext
instance, but this is absolutely not recommended if there exist a "right way" to achieve the requirement.
您应该为该作业使用正确的工具,在这种情况下,它是一个阶段侦听器.这是一个阶段监听器的外观示例,应该如何注册:
You should be using the right tool for the job, which is in this particular case a phase listener. Here's a kickoff example of how a phase listener look like and should be registered:
public class MyPhaseListener implements PhaseListener {
@Override
public PhaseId getPhaseId() {
return PhaseId.RESTORE_VIEW;
}
@Override
public void beforePhase(PhaseEvent event) {
// Do your job here which should run right before the RESTORE_VIEW phase.
}
@Override
public void afterPhase(PhaseEvent event) {
// Do your job here which should run right after the RESTORE_VIEW phase.
}
}
要使其运行,请在faces-config.xml
中进行如下注册:
To get it to run, register it as follows in faces-config.xml
:
<lifecycle>
<phase-listener>com.example.MyPhaseListener</phase-listener>
</lifecycle>
您可以根据自己的见解更改getPhaseId()
结果,例如PhaseId.RENDER_RESPONSE
,则阶段侦听器将在渲染响应阶段之前和之后启动.
You can change the getPhaseId()
outcome to your insight, e.g. PhaseId.RENDER_RESPONSE
, then the phase listener will kick in on before and after the render response phase.
这是一个具体的启动示例,它可以完成您正在寻找的工作(查找正在调用的命令组件并记录其操作方法表达式):
Here's a concrete kickoff example which does the job you're looking for (finding the command component being invoked and logging its action method expression):
public class InvokedCommandComponentLogger implements PhaseListener {
@Override
public PhaseId getPhaseId() {
return PhaseId.RESTORE_VIEW;
}
@Override
public void beforePhase(PhaseEvent event) {
// NOOP. The view hasn't been restored yet at that point, so the component tree wouldn't be available anyway.
}
@Override
public void afterPhase(PhaseEvent event) {
FacesContext context = event.getFacesContext();
if (context.isPostback()) {
UICommand component = findInvokedCommandComponent(context);
if (component != null) {
String methodExpression = component.getActionExpression().getExpressionString();
System.out.println("Method expression of the action being invoked: " + methodExpression);
}
}
}
private UICommand findInvokedCommandComponent(FacesContext context) {
Map<String, String> params = context.getExternalContext().getRequestParameterMap();
Set<String> clientIds = new HashSet<>();
if (context.getPartialViewContext().isAjaxRequest()) {
clientIds.add(params.get("javax.faces.source")); // This covers <f:ajax> inside UICommand.
} else {
for (Entry<String, String> entry : params.entrySet()) {
if (entry.getKey().equals(entry.getValue())) { // This covers UIForm and UICommand components.
clientIds.add(entry.getKey());
}
}
}
EnumSet<VisitHint> hints = EnumSet.of(VisitHint.SKIP_UNRENDERED);
final UICommand[] found = new UICommand[1];
context.getViewRoot().visitTree(VisitContext.createVisitContext(context, clientIds, hints), new VisitCallback() {
@Override
public VisitResult visit(VisitContext context, UIComponent target) {
if (target instanceof UICommand) {
found[0] = (UICommand) target;
return VisitResult.COMPLETE;
} else {
return VisitResult.ACCEPT;
}
}
});
return found[0];
}
}
这篇关于如何记录在servlet过滤器中调用的托管bean名称和操作方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!