我有一个按钮从调用Bean调用方法。此方法允许从解析html代码中提取数据。当该方法运行时,我有一个显示进度条和命令按钮的对话框 Cancel
。我需要当用户单击取消按钮时,提取按钮调用的方法停止。
这是我的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>
这是我的sessionScoped Bean中的searchEmails方法
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");
}
如何通过取消命令按钮停止searchEmails方法的运行?
具有中断友好任务的ExecutorService
ExecutorService
文件
而不是直接调用该方法,将方法转换为 ExecutorService
的任务。
public class SearchEmailsTask implements Runnable {
private EmailSearcher emailSearcher;
public SearchEmailsTask(EmailSearcher emailSearcher) {
this.emailSearcher = emailSearcher;
}
@Override
public void run() {
emailSearcher.searchEmails();
}
}
您可以使用 Callable<Object>
如果你想要归还某些东西。
如果要调用方法,请将该任务提交给 ExecutorService
。
ExecutorService executorService = Executors.newFixedThreadPool(4);
SearchEmailsTask searchEmailsTask = new SearchEmailsTask(new EmailSearcher());
Future<?> future = executorService.submit(searchEmailsTask);
保留对任务的引用。
private static Map <String, Future<Object>> results = new HashMap <String, Future<Object>>();
存储多个地图应该是一个好主意 Future
对象。如果你愿意,你当然可以选择更好的东西。
必要时,呼叫取消任务。
future.cancel(true);
注意:
任务应该有适当的线程中断检查以正确取消。
要实现此目的,请参阅
- ExecutorService的未来任务并未真正取消
- 如何使用线程的id挂起线程?
祝你好运。
具有中断友好任务的ExecutorService
ExecutorService
文件
而不是直接调用该方法,将方法转换为 ExecutorService
的任务。
public class SearchEmailsTask implements Runnable {
private EmailSearcher emailSearcher;
public SearchEmailsTask(EmailSearcher emailSearcher) {
this.emailSearcher = emailSearcher;
}
@Override
public void run() {
emailSearcher.searchEmails();
}
}
您可以使用 Callable<Object>
如果你想要归还某些东西。
如果要调用方法,请将该任务提交给 ExecutorService
。
ExecutorService executorService = Executors.newFixedThreadPool(4);
SearchEmailsTask searchEmailsTask = new SearchEmailsTask(new EmailSearcher());
Future<?> future = executorService.submit(searchEmailsTask);
保留对任务的引用。
private static Map <String, Future<Object>> results = new HashMap <String, Future<Object>>();
存储多个地图应该是一个好主意 Future
对象。如果你愿意,你当然可以选择更好的东西。
必要时,呼叫取消任务。
future.cancel(true);
注意:
任务应该有适当的线程中断检查以正确取消。
要实现此目的,请参阅
- ExecutorService的未来任务并未真正取消
- 如何使用线程的id挂起线程?
祝你好运。
使用您当前的架构并不容易。通过查看您的代码,您似乎在调用两个不能在中间中止的大型操作。您必须将工作分解为小单元并使处理中止。
使用当前代码的最简单的解决方案可能看起来像这样。
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;
}
}
在JSF中:
<p:commandButton value="Cancel" title="Cancel" actionListener="#{mailMB.abortSearch()}" />
这就是说我建议使用执行器和基于期货的方法来实现更清洁的架构。然后你也可以实现一个真正的进度条而不仅仅是一个动画GIF微调器。
在命令处理程序中执行长操作的另一个问题是最终HTTP请求将超时。
一个更干净的解决方案将如下所示:
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);
}
}
然后使用AJAX轮询组件轮询getPending以确定何时完成并隐藏窗口。
也可以看看: