如何记录在servlet过滤器中调用的托管bean名称和操作方法 [英] How to log managed bean name and action method being invoked in a servlet filter

查看:88
本文介绍了如何记录在servlet过滤器中调用的托管bean名称和操作方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发基于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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆