代码之家  ›  专栏  ›  技术社区  ›  Wolkenarchitekt

在视图中显示要使用的@asynchronous函数的当前进度

  •  1
  • Wolkenarchitekt  · 技术社区  · 16 年前

    在我的jee6应用程序(运行在glassfish 3.0.1上)中,我有一个emailejb,它必须发送大量邮件。邮件是异步发送的,因此它用新的ejb3.1@asynchronous进行了注释,允许它在单独的线程中运行。现在我想让用户知道方法的当前状态:已经发送了多少邮件?

    异步发送邮件很好,但我不知道如何让进度从外部访问。似乎我这样做的方法是非常错误的,但不知何故,它必须是可能的(可能是另一种方法)。这就是我的emailejb当前的样子(它是一种伪代码,但解释了我想要的东西):

    @Stateful
    public class EmailEJB {
    
      @Asynchronous
      public Future<Integer> sendMails() {
        for (int i=0; i<mails.size; i++) {
          sendMail(mails[i])
          // i want to return the progress without returning ;)
          return new AsyncResult<Integer>(i)
        }
      }
    }
    
    //Just for the completeness... from outside, i'm accessing the progress like this:
    Future<Integer> progress = emailEJB.sendEmails();
    Integer currentvalue = progress.get();
    

    如何在异步函数中返回当前进度,而不使用返回来取消它?如何向用户显示函数内循环的进度?我需要另一个异步方法吗?有什么暗示吗?

    3 回复  |  直到 9 年前
        1
  •  3
  •   Wolkenarchitekt    16 年前

    没人?好的,这就是我的解决方案。我不确定这是一个巨大的解决方案,还是一种完成这项工作的方法。

    由于@asynchronous方法无法访问会话上下文,因此也没有会话bean(至少我不知道如何访问,我总是得到ConcurrentModificationErrors或类似的bean),所以我创建了一个singleton progressEJB,其中包含一个哈希映射:

    @Singleton @LocalBean @Startup
    public class ProgressEJB {
      private HashMap<String, Integer> progressMap = new HashMap<String, Integer>
      // getters and setters
    }
    

    此哈希映射应将sessionid(字符串)映射为整数值(进度0->100)。因此,用户会话与进度相关联。 在我的emailejb中,我正在注入这个progressejb,在我的@asynchronous方法中,每次发送电子邮件时,我都会增加值:

    @Stateful @LocalBean
    public class EmailEJB {
    @Inject
    private ProgressEJB progress;
    // Mail-Settings
    ...
    @Asynchronous
    public void sendEmails(user:User, message:Message, sessionId:String) {
      progress.progressMap.put(sessionId, 0);
      for (int i=0; i<mails.size; i++) {
        sendMail(mails[i])
        progress.getProgressMap().put(sessionId, (i / mails.size) * 100)
      }
      progress.getProgressMap().remove(sessionId);
    }
    

    当调用函数时,sessionid来自我的托管(weld)bean:

    @SessionScoped
    @Named
    public class EmailManager {
      @Inject 
      private ProgressEJB progress;
      @Inject
      private FacesContext facesContext;
    
      private String sessionId;
    
      @PostConstruct
      private void setSessionId() {
        this.sessionId = ((HttpSession)facesContext.getExternalContext().getSession(false)).getId();
      }
    
      public Integer getProgress() {
        if (progress.getProgressMap().get(sessionId) == null)
          return 100;
        else 
          return progress.getProgressMap().get(sessionId);
      }
    }
    

    现在,我可以通过Ajax轮询从我的JSF视图访问emailManager的进度,告诉用户已经发送了多少邮件。刚用2个用户测试过,似乎可以用。

        2
  •  0
  •   aholbreich Stephen C    13 年前

    我也只看到@singleton解决方案。 但这意味着需要在ProgressEJB中进行内务管理。例如,需要做一些努力从hashmap中删除旧会话。

        3
  •  0
  •   Manuel Drieschmanns    9 年前

    另一个解决方案在 Is there any way to know the progress of a EJB Asynchronous process?

    此解决方案不需要有状态bean。

    @Stateless
    public class EmailEJB {
        // Mail-Settings
        ...
        @Asynchronous
        public void sendEmails(User user, Message message, WorkContext context) {
          progress.progressMap.put(sessionId, 0);
          for (int i=0; i<mails.size; i++) {
            sendMail(mails[i])
            context.setProgress((i / mails.size) * 100)
          }
          context.setRunning(false);
        }
    }
    

    保存进度的上下文对象。

    public class WorkContext {
        //volatile is important!
        private volatile Integer progress = 0;
        private volatile boolean running = false;    
        // getters & setters
    }
    

    使用非常简单。

    @SessionScoped
    @Named
    public class EmailManager {
      @Inject 
      private EmailEJB emailEJB;
      private WorkContext workContext;
    
      public void doStuff() {
            workContext = new WorkContext();
            emailEJB.sendEmails(user, message, workContext)
      }
    
      public Integer getProgress() {
            return workContext.getProgress();
      }
      ....
    }
    
    推荐文章