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

Posted

技术标签:

【中文标题】JSF ViewScoped bean 在所有 ajax 请求中的唯一 ID?【英文标题】:Unique ID for a JSF ViewScoped bean across all ajax requests? 【发布时间】:2021-12-29 12:20:43 【问题描述】:

我正在(主要)使用@ViewScoped @Named Faces bean(javax.faces.view.ViewScopedjavax.inject.Named)并且想知道是否可以从 ServletRequest(或 HttpServletRequest)中区分同一个 bean 的两个不同实例在javax.servlet.Filter

例如,用户在两个不同的选项卡中打开同一个页面,但通过调用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(); 
        ...

【问题讨论】:

您确定 servlet 过滤器首先是您心目中工作的正确工具吗? xyproblem.info @BalusC 目前在过滤器中,我正在使用 ThreadContext 为 log4j2 添加键/值,例如ThreadContext.put("sessionId", session.getId()); 并希望为支持 bean ID 提供一个简单的类似解决方案。我对其他方式持开放态度,但不确定如何处理。 我认为您可以使用相位侦听器,@BalusC 在其他答案***.com/questions/8388854/… 中解释了如何实现它 啊。如果您使用服务器端状态保存,javax.faces.ViewState 请求参数可能就足够了。 【参考方案1】:

您可以通过FacesContext 获取它,但不能ServletFilter.ServletFilter 运行之前运行到JSF 所在的Servlet,因此无法访问@987654324 @ 直到您到达 de Servlet(您的入口点将是任何托管 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 


【讨论】:

【参考方案2】:

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

他的其他 cmets 让我找到了这个解决方案:

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

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

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

虽然这似乎获得了 viewState,但它似乎以某种方式打破了生命周期,并且我的页面没有呈现。我想知道在呈现页面之前是否无法“抓取”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);
        ...

【讨论】:

以上是关于JSF ViewScoped bean 在所有 ajax 请求中的唯一 ID?的主要内容,如果未能解决你的问题,请参考以下文章

JSF 2.2 ViewScoped Bean 被多次创建

JSF 2.x @ViewScoped 托管 bean 线程安全吗?

即使在刷新页面后,Firefox 也会在 JSF-Viewscoped-Managed-Bean 中保留数组的内容

@ViewScoped JSF bean 被多次初始化

JSF 2.2 内存消耗:为啥 Mojarra 将最后 25 个视图的 ViewScoped Beans 保留在内存中?

无法将 JSF ViewScoped bean 作为 ManagedProperty 注入 Validator