所有 ajax 请求中 JSF ViewScoped bean 的唯一 ID?

Unique ID for a JSF ViewScoped bean across all ajax requests?

我(主要)使用 @ViewScoped @Named Faces bean(javax.faces.view.ViewScopedjavax.inject.Named)并且想知道我是否可以从 ServletRequest(或 HttpServletRequest)中区分两者javax.servlet.Filter

中同一 bean 的不同实例化

例如,用户在两个不同的选项卡中打开同一个页面,但是这两个选项卡通过调用 httpRequest.getSession().getId() 具有相同的 SessionID。目前这对我没有帮助。

或者,我可以访问线程 ID,但这会随着每次 ajax 调用而改变,我需要在所有调用中为支持 bean 的实例保留一些独特的东西。直到 bean被摧毁了。

所以,像这样(这不起作用,但希望能说明我的需要)

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 
{
    try 
    {
        HttpServletRequest httpRequest = (HttpServletRequest) request;

        // not real code, but this is what I'm looking for; 
        // get a unique identifier for just this instance of the bean that stays the same across all ajax requests
        String beanId = request.getCurrentBackingBean.getInstanceId(); 
        ...

您可以通过 FacesContext 获得它,但 不能 ServletFilter.ServletFilter 的 运行 上获得到 JSF 所在的 Servlet,因此在到达 de Servlet 之前无法访问 FacesContext(您的入口点将是任何托管 bean)。

但是,如果您设法重塑业务逻辑以便能够在托管 bean 中执行您想要的操作,则可以通过以下方式获取视图 ID:

    FacesContext.getCurrentInstance().getViewRoot().getViewId();

或者如果您使用的是 JSF 2.3,您可以在任何托管 bean 中注入 FacesContext

@Inject
FacesContext facesContext;
...
public void anyMethod() {
    facesContext.getViewRoot().getViewId();
}

为了 FacesContext 的注入工作,您必须通过 CDI Bean 中的特殊注释激活 JSF 2.3 版特定功能,例如:


import javax.enterprise.context.ApplicationScoped;
import javax.faces.annotation.FacesConfig;

@FacesConfig(version = FacesConfig.Version.JSF_2_3)
@ApplicationScoped
public class JSF23ActivationBean {
}

正如@BalusC 在评论中提到的,servlet 过滤器可能不是解决此问题的最佳位置,但我正在使用可能不允许重构的现有代码.

他的其他评论让我想到了这个解决方案:

在过滤器中:使用HttpServletRequest,获取参数“javax.faces.ViewState”。这包含跨 Ajax 个请求的我的 (ViewScoped) 支持 bean 的视图的唯一 ID。它将为支持 bean 的每个新实例创建一个新的唯一 ID。

请注意,它似乎在第一次调用过滤器时不可用,我假设是因为尚未在新的支持 bean 上调用 @PostConstruct。我最初尝试解决这个问题是通过以下调用将其从 FacesContext(在@PostConstruct 中)中拉出来:

String viewState = FacesContext.getCurrentInstance().getApplication().getStateManager().getViewState(FacesContext.getCurrentInstance());
ThreadContext.put("viewState", viewState);

虽然这似乎获得了 viewState,但它似乎以某种方式破坏了生命周期,并且我的页面没有呈现。我想知道在页面呈现之前是否无法 'grab' viewState?

现在,Filter 中的工作代码现在看起来像这样(截断):

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 
{
    try 
    {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String viewState = httpRequest.getParameter("javax.faces.ViewState");
        ...
        ThreadContext.put("viewState", viewState);
        ...