【问题标题】:@Schedule could not fetch data from @SessionScoped CDI bean@Schedule 无法从 @SessionScoped CDI bean 获取数据
【发布时间】:2020-03-16 16:37:42
【问题描述】:

登录后存储在 SessionScoped bean 中的用户数据。 我希望每 5 秒获取存储在会话中的每个帐户并发送到后端。 我的计时器

@Singleton
@Startup
public class FrontendTimer {

    @Inject
    private UserContext userContext;

    @Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
    @Asynchronous
    public void atSchedule() throws InterruptedException {
        System.out.println("Get Logged user stored in the session each 5 seconds ");
        System.out.println("FR " + userContext.getAccount().toString());
    }

}

启动调度程序的唯一方法是创建@Startup 和@Singleton 类。 将用户数据保存在前端的唯一方法,将帐户保存到 SessionScoped CDI bean,不推荐使用 JSF 原生 bean。

你会得到如下错误: WELD-001303:范围类型 javax.enterprise.context.SessionScoped 没有活动上下文

项目地址在这里https://github.com/armdev/eap 自己上课https://github.com/armdev/eap/blob/master/eap-web/src/main/java/io/project/app/beans/FrontendTimer.java

基本上我想要一个可以从 Session Scope 获取数据的标准计时器。

【问题讨论】:

  • 抱歉,您的问题完全不清楚。小心澄清。最好用minimal reproducible example
  • 假设 UserContext 是 sessionscoped,如果没有活动用户并且调用了 atSchedule(),它应该选择哪个 UserContext?或者如果有两个用户处于活动状态,因此存在两个 UserContext - 如果两者都应该选择?会话范围仅在处理 servlet 请求的线程中可用。计划的后台作业中没有用户会话上下文。
  • @Selaron:哇...阅读帖子(不是代码链接)这个问题对我来说完全没有意义。你的评论(问题)说得很清楚。赞美你确实得到了它。
  • @kukeltje 谢谢。我想我只是快速阅读关键字、代码和错误消息,而不是试图逐字理解所有内容。有时会有所帮助,有时会严重失败._.

标签: jsf jakarta-ee wildfly cdi


【解决方案1】:

您当前的方法将无法按预期工作,因为每个调度程序调用都将在与会话完全隔离的上下文中发生(因此出现No active contexts... 错误消息)。

我建议你在这里使用一个简单的反转。在你的应用范围单例中,添加一个简单的List<String> currentSessions 和对应的方法到void add(String account)void remove(String account)。然后@Inject 单例进入会话范围的bean(而不是相反)。最后,添加@WebListener 来处理会话事件。

@Singleton
public class SessionManager {

    private List<String> currentSessions;

    @Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
    @Asynchronous
    public void atSchedule() throws InterruptedException {
        //Do something with currentSessions
    }

    public void add(String account){
        currentSessions.add(account);
    }

    public void remove(String account){
        currentSessions.remove(account);
    }

}
@SessionScoped
public class UserContext implements Serializable {

    @Inject
    private SessionManager sessionManager;

    /*
    ...
    */

    public void sessionCreated(){
        sessionManager.add(account.toString());
    }

    public void sessionDestroyed(){
        sessionManager.remove(account.toString());
    }

}
@WebListener
    public class SessionListener implements HttpSessionListener {

        @Override
        public void sessionCreated(HttpSessionEvent se) {
            HttpSession session = se.getSession();

            FacesContext context = FacesContext.getCurrentInstance();
            UserContext userContext = (UserContext) session.getAttribute("userContext");
            userContext.sessionCreated();
        }

        @Override
        public void sessionDestroyed(HttpSessionEvent se) {
            HttpSession session = se.getSession();

            FacesContext context = FacesContext.getCurrentInstance();
            UserContext userContext = (UserContext) session.getAttribute("userContext");
            userContext.sessionDestroyed();

        } 
    }

【讨论】:

  • 是的,完全同意。我使用同样的技术确实能够通过 websockets 向所有登录用户发送消息。
  • 谢谢,我认为这是一个真正的解决方案。
猜你喜欢
  • 1970-01-01
  • 2011-12-10
  • 2011-07-11
  • 1970-01-01
  • 1970-01-01
  • 2019-08-04
  • 1970-01-01
  • 2016-08-02
  • 1970-01-01
相关资源
最近更新 更多