1

我正在使用 Java(Servlet,JSP) 开发 Web 应用程序。

我有一个发送电子邮件的课程。

类看起来像:

public class EmailSender
{
    String SendEmail(String from,Session session,String To,String CC, String BCC, String Subject,String Body)
    {
        //Actual code for sending emails
    }
}

EmailSender从另一个类调用类:

public class InvokeSender
{
    public InvokeSender(String dbFileName)
    {
        //get emails from database for sending who has STATUS='NOTSENT'
        //statements to get all required parameter to pass to SendEmail()
        EmailSender sender = new EmailSender();
        String msg = sender.SendEmail(fromEmail,session,To,CC,BCC,SUBJECT,BODY);
    }
}

InvokeSender在用户单击按钮时从 servlet 调用。

当用户单击按钮时,调用 InvokeSender,它将电子邮件从数据库发送并形成它们,然后将这些参数传递给SendEmail()EmailSender

如果按钮被按下两次,我希望一次只InvokeSender运行一个实例以避免相同的电子邮件发送两次。如何处理?multithreading在这种情况下有用吗?

任何建议将不胜感激。

Update1 用户单击后我无法禁用该按钮。因为如果用户刷新页面,则默认情况下将启用该按钮。

Update2 第一个用户选择客户、模板等来发送电子邮件,然后将电子邮件参数存储在数据库中。InvokeSender类获取所有要发送的电子邮件。无法预测要发送的电子邮件数量。它可以是 1 或 500 或更多。我只希望InvokeSender运行一个实例,直到前一个实例完成发送电子邮件。功能(生成和发送电子邮件的按钮)将向 5-7 个用户公开。

4

4 回答 4

2

我认为,可以通过创建一个唯一的令牌来完成,该令牌的会话范围适用于页面,无论哪个页面具有电子邮件发件人和 Servlet 类中的 Singleton Map 来维护令牌。

  1. 创建一个 servlet 过滤器来为页面生成一个会话范围的令牌。

  2. 如果映射中不存在令牌,则将令牌添加到映射中并调用邮件发件人。

  3. 如果包含,则不调用邮件发件人

于 2013-11-06T05:51:14.633 回答
1

您可以使用队列数据结构对发送电子邮件请求进行排队,并在单独的线程中对其进行处理。该线程将在启动期间产生一次并处理队列。邮件发送后STATUS='NOTSENT'会被清空,这样就解决了多发邮件的问题。队列可以定期处理,也可以轮询数据,或者有一些信号机制在队列中有数据时向线程发出信号。

编辑:我认为这个解决方案适合Update1Update2

于 2013-11-06T05:19:59.870 回答
1

使用同步块

        public InvokeSender(String dbFileName)
        {
           synchronized(InvokeSender.class){ 
           //get emails from database for sending who has STATUS='NOTSENT'
            //statements to get all required parameter to pass to SendEmail()
            EmailSender sender = new EmailSender();
            String msg = sender.SendEmail(fromEmail,session,To,CC,BCC,SUBJECT,BODY);
          }
        }
于 2013-11-06T08:13:24.477 回答
1

我会在 InvokeSender 中使用 AtomicBoolean 然后执行以下操作:

public class InvokeSender
{
  static AtomicBoolean sendInProgress = new AtomicBoolean(false);

  public InvokeSender(String dbFileName)
  {
    if (sendInProgress.compareAndSet(false, true)) {

      //get emails from database for sending who has STATUS='NOTSENT'
      //statements to get all required parameter to pass to SendEmail()
      EmailSender sender = new EmailSender();
      String msg = sender.SendEmail(fromEmail,session,To,CC,BCC,SUBJECT,BODY);

      sendInProgress.set(false); 
    }
  }
}

当然,这是一个非常简单的解决方案,如果您想要更复杂的行为,例如限制上一封电子邮件和下一封电子邮件之间的时间,您必须为此添加更多逻辑。

于 2013-11-06T05:22:01.043 回答