如何阻止java代码使用stop按钮运行

时间:2021-05-03 07:12:53

I have a button that calls a method from the backing Bean. This method allows to extract data from parsing html code. While the method is running i have a dialog showing a progress bar and a command button Cancel. I need when the user click the cancel button the method called by the extract button stops.

我有一个从后台Bean调用方法的按钮。该方法允许从解析html代码中提取数据。当方法运行时,我有一个显示进度条和命令按钮取消的对话框。当用户单击cancel按钮时,提取按钮调用的方法将停止。

This is my html code:

这是我的html代码:

<p:commandButton
    value="Start" style="width: 12%;height: 100%"
    update=":confirmPurchase, :confirmPurchaseTest, :mainform" id="extractbutton"
    ajax="true" widgetVar="ButtonExtract"
    actionListener="#{mailMB.searchEmails()}" 
    icon="ui-icon-disk" styleClass="ui-priority-primary"
    onstart="blockUIWidget1.show();" oncomplete=" blockUIWidget1.hide();" />

<p:dialog  widgetVar="blockUIWidget1" header="Hitonclick" modal="true"
    resizable="false" closable="false">
    <table border="0" style="width: 500px">
        <tbody > 
            <tr>  
                <td>
                    <p:graphicImage url="pictures/loading81.gif" width="200" height="200" alt="animated-loading-bar"/>
                </td>
                <td>
                    <h:outputLabel value="Extracting is in progress. Please wait..."/>
                    <div align="center">
                        <p:commandButton value="Cancel" title="Cancel" />
                    </div>
                </td>
            </tr>
            <div align="right">

            </div>
        </tbody>
    </table>
</p:dialog>

And here is my searchEmails method in my sessionScoped Bean

这是我的sessionScoped Bean中的searchemail方法。

 public void searchEmails() throws Exception {
        idCustomer = (String) session.getAttribute("idCustomer");
        System.out.println(idCustomer + " this is it");
        Customer customer = customerBusinessLocal.findById(idCustomer);
        data = dataBusinessLocal.createData(new Date(), number, keyword, moteur, customer, State.REJECTED);
        mails = mailBusinessLocal.createEmails(keyword, number, moteur, data);
        System.out.println("Method was invoked");    
 }

How can i stop the searchEmails method from running via the cancel command button?

如何阻止searchEmails方法通过“取消命令”按钮运行?

2 个解决方案

#1


12  

ExecutorService with interrupt friendly tasks

ExecutorService documentation

ExecutorService文档


  • Instead of directly calling the method, convert the method into an ExecutorService's task.

    与其直接调用方法,不如将方法转换为ExecutorService的任务。

    public class SearchEmailsTask implements Runnable {
    
        private EmailSearcher emailSearcher;
    
        public SearchEmailsTask(EmailSearcher emailSearcher) {
            this.emailSearcher = emailSearcher;
        }
    
        @Override
        public void run() {
            emailSearcher.searchEmails();
        }
    }
    

    You can use Callable<Object> if you want to return something.

    如果您想要返回某些东西,可以使用Callable


  • When you want call the method, submit that task to an ExecutorService.

    当您希望调用该方法时,将该任务提交给ExecutorService。

    ExecutorService executorService = Executors.newFixedThreadPool(4);
    
    SearchEmailsTask searchEmailsTask = new SearchEmailsTask(new EmailSearcher());
    
    Future<?> future = executorService.submit(searchEmailsTask);
    

  • Keep a reference to the task.

    保持对任务的引用。

    private static Map <String, Future<Object>> results = new HashMap <String, Future<Object>>();
    

    A map should be a good idea to store multiple Future objects. You can of course go for something better if you want.

    映射应该是存储多个未来对象的好主意。如果你愿意的话,当然可以选择更好的。


  • Call cancel on the task whenever required.

    在需要时调用cancel。

    future.cancel(true);
    

Note:
Task should have suitable checks for thread interruption for proper cancellation.
To achieve this, refer to

注意:任务应该对线程中断进行适当的检查,以便进行适当的取消。要实现这一点,请参考。

  1. Future task of ExecutorService not truly cancelling
  2. 未来的执行任务并没有真正取消
  3. how to suspend thread using thread's id?
  4. 如何使用线程id挂起线程?

Good luck.

祝你好运。

#2


3  

With your current architecture it's not going to be easy. By looking at your code it seems that you are calling two big operations that can't be aborted in the middle. You must break the work into small units and make the processing abortable.

有了当前的架构,这就不容易了。通过查看代码,您似乎正在调用两个不能在中间中止的大型操作。您必须将工作分解成小单元,并使处理可中止。

The easiest solution that uses your current code could look something like this.

使用当前代码的最简单的解决方案可以如下所示。

 public class SessionScopedMailBean {
     volatile boolean searchAborted;

     public void searchEmails() throws Exception {
         searchAborted = false;
         while(!searchAborted) {
             // Process a single unit of work
         }
     }

     public void abortSearch() {
         searchAborted = true;
     }
}

In JSF:

在JSF中:

<p:commandButton value="Cancel" title="Cancel" actionListener="#{mailMB.abortSearch()}" />

That said I'd recommend using executors and futures based approach for cleaner architecture. Then you can also implement a real progress bar not just an animated GIF spinner.

也就是说,我建议使用执行器和基于期货的方法来实现更清洁的体系结构。然后你也可以实现一个真正的进度条,而不仅仅是一个动画GIF旋转器。

Another problem with performing a long operation in command handler is that eventually the HTTP request will time out.

在命令处理程序中执行长期操作的另一个问题是,HTTP请求最终将超时。

A cleaner solution will look like this:

一个更干净的解决方案会是这样的:

public class SessionScopedBean {
    ExecutorService pool;
    List<Future<Void>> pendingWork;

    @PostConstruct
    public void startPool() {
        pool = Executors.newFixedThreadPool(1);
    }

    @PreDestroy
    public void stopPool() {
        if(executor != null)
            pool.shutdownNow();
    }

    public void startSearch() {
        pendingWork = new ArrayList<Future<Void>>();

        // Prepare units of work (assuming it can be done quickly)
        while(/* no more work found */) {
            final MyType unit = ...; // Determine next unit of work
            Callable<Void> worker = new Callable<Void>() {
                @Override
                public Void call() throws Exception {
                    // Do whatever is needed to complete unit
                }
            };
            pendingWork.add(pool.submit(worker));
        }
    }

    public int getPending() {
        int nPending = 0;

        for(Future<MyResultType> i: pendingWork)
            if(!i.isDone()) nPending++;

        return nPending;
    }

    public void stopSearch() {
        for(Future<Void> i: pendingWork)
            if(!i.isDone()) i.cancel(true);
    }
}

Then use an AJAX polling component to poll getPending to determine when it's done and hide the window.

然后使用AJAX轮询组件轮询getPending,以确定何时完成,并隐藏窗口。

See also:

参见:

#1


12  

ExecutorService with interrupt friendly tasks

ExecutorService documentation

ExecutorService文档


  • Instead of directly calling the method, convert the method into an ExecutorService's task.

    与其直接调用方法,不如将方法转换为ExecutorService的任务。

    public class SearchEmailsTask implements Runnable {
    
        private EmailSearcher emailSearcher;
    
        public SearchEmailsTask(EmailSearcher emailSearcher) {
            this.emailSearcher = emailSearcher;
        }
    
        @Override
        public void run() {
            emailSearcher.searchEmails();
        }
    }
    

    You can use Callable<Object> if you want to return something.

    如果您想要返回某些东西,可以使用Callable


  • When you want call the method, submit that task to an ExecutorService.

    当您希望调用该方法时,将该任务提交给ExecutorService。

    ExecutorService executorService = Executors.newFixedThreadPool(4);
    
    SearchEmailsTask searchEmailsTask = new SearchEmailsTask(new EmailSearcher());
    
    Future<?> future = executorService.submit(searchEmailsTask);
    

  • Keep a reference to the task.

    保持对任务的引用。

    private static Map <String, Future<Object>> results = new HashMap <String, Future<Object>>();
    

    A map should be a good idea to store multiple Future objects. You can of course go for something better if you want.

    映射应该是存储多个未来对象的好主意。如果你愿意的话,当然可以选择更好的。


  • Call cancel on the task whenever required.

    在需要时调用cancel。

    future.cancel(true);
    

Note:
Task should have suitable checks for thread interruption for proper cancellation.
To achieve this, refer to

注意:任务应该对线程中断进行适当的检查,以便进行适当的取消。要实现这一点,请参考。

  1. Future task of ExecutorService not truly cancelling
  2. 未来的执行任务并没有真正取消
  3. how to suspend thread using thread's id?
  4. 如何使用线程id挂起线程?

Good luck.

祝你好运。

#2


3  

With your current architecture it's not going to be easy. By looking at your code it seems that you are calling two big operations that can't be aborted in the middle. You must break the work into small units and make the processing abortable.

有了当前的架构,这就不容易了。通过查看代码,您似乎正在调用两个不能在中间中止的大型操作。您必须将工作分解成小单元,并使处理可中止。

The easiest solution that uses your current code could look something like this.

使用当前代码的最简单的解决方案可以如下所示。

 public class SessionScopedMailBean {
     volatile boolean searchAborted;

     public void searchEmails() throws Exception {
         searchAborted = false;
         while(!searchAborted) {
             // Process a single unit of work
         }
     }

     public void abortSearch() {
         searchAborted = true;
     }
}

In JSF:

在JSF中:

<p:commandButton value="Cancel" title="Cancel" actionListener="#{mailMB.abortSearch()}" />

That said I'd recommend using executors and futures based approach for cleaner architecture. Then you can also implement a real progress bar not just an animated GIF spinner.

也就是说,我建议使用执行器和基于期货的方法来实现更清洁的体系结构。然后你也可以实现一个真正的进度条,而不仅仅是一个动画GIF旋转器。

Another problem with performing a long operation in command handler is that eventually the HTTP request will time out.

在命令处理程序中执行长期操作的另一个问题是,HTTP请求最终将超时。

A cleaner solution will look like this:

一个更干净的解决方案会是这样的:

public class SessionScopedBean {
    ExecutorService pool;
    List<Future<Void>> pendingWork;

    @PostConstruct
    public void startPool() {
        pool = Executors.newFixedThreadPool(1);
    }

    @PreDestroy
    public void stopPool() {
        if(executor != null)
            pool.shutdownNow();
    }

    public void startSearch() {
        pendingWork = new ArrayList<Future<Void>>();

        // Prepare units of work (assuming it can be done quickly)
        while(/* no more work found */) {
            final MyType unit = ...; // Determine next unit of work
            Callable<Void> worker = new Callable<Void>() {
                @Override
                public Void call() throws Exception {
                    // Do whatever is needed to complete unit
                }
            };
            pendingWork.add(pool.submit(worker));
        }
    }

    public int getPending() {
        int nPending = 0;

        for(Future<MyResultType> i: pendingWork)
            if(!i.isDone()) nPending++;

        return nPending;
    }

    public void stopSearch() {
        for(Future<Void> i: pendingWork)
            if(!i.isDone()) i.cancel(true);
    }
}

Then use an AJAX polling component to poll getPending to determine when it's done and hide the window.

然后使用AJAX轮询组件轮询getPending,以确定何时完成,并隐藏窗口。

See also:

参见: