一种方法是将Future<String> 句柄写入ApplicationScoped bean(可能是它们的列表)。然后在您的页面中有一个“检查”按钮,当您按下该按钮时,客户端应用程序会检查应用程序 bean 中列出的每个 Future<String> 句柄。如果作业现在已完成(或取消),它会从列表中删除句柄并显示一条消息。
如果这过于被动,请考虑在页面模板上添加一些内容或对每个页面导航进行检查。如果您想要即时弹出通知,请研究 JSF 2.3 Push 功能和 f:websocket。或者在异步作业结束时总是会生成一封无聊的旧电子邮件。您需要考虑如何收到通知,以及如果异步作业失败和/或作业完成后您不再使用应用程序或应用程序重新启动时会发生什么。
客户端视图
@Named
@ViewScoped
public class AsyncClientController implements java.io.Serializable {
@Inject
private FacesContext facesContext;
@Inject
private AsyncJobController jobController;
@Inject
private AsyncEJBStatelessBean asyncBean;
public void startAsync() {
String name = "Job " +
LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
Future<String> handle = asyncBean.longRunningJob(name);
jobController.add(handle);
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Submitted", null));
}
public void checkResults() {
String res = jobController.getNewResults();
if (res == null || res.isBlank()) {
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO,
"No new results", "Jobs logged: " + Integer.toString(jobController.size())));
} else {
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "New results", res));
}
}
}
应用程序 Bean
@Named
@ApplicationScoped
public class AsyncJobController implements java.io.Serializable {
private final List<Future<String>> handlesList = new ArrayList<>();
public void add(Future<String> handle) {
handlesList.add(handle);
}
public String getNewResults() {
StringBuilder builder = new StringBuilder();
List<Future<String>> finishedList = new ArrayList<>();
handlesList.stream()
.filter(handle -> (handle.isDone()))
.forEachOrdered(handle -> {
finishedList.add(handle);
});
for (Future<String> handle : finishedList) {
try {
builder.append(builder.length() == 0 ? "" : "'\n'")
.append(handle.get());
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(AsyncJobController.class.getName()).log(Level.SEVERE, null, ex);
}
handlesList.remove(handle);
}
return builder.toString();
}
public int size() {
return handlesList.size();
}
}
异步无状态 EJB
@Stateless
@Asynchronous
public class AsyncEJBStatelessBean {
@Inject
private Logger log;
public Future<String> longRunningJob(String name) {
long sleepTime = (long) (Math.random()*60 + 0.5); // 1 .. 60
log.log(Level.INFO, "Starting job ''{0}'' with duration {1}",
new Object[]{name, Long.toString(sleepTime)});
try {
Thread.sleep(sleepTime * 1000); // milliseconds
} catch (InterruptedException e) {
// do nothing
}
String res = "Job '" + name + "' finished after " + Long.toString(sleepTime) + " seconds";
log.log(Level.INFO, "{0}", res);
return new AsyncResult<>(res);
}
}