如何解决vaadin 和 spring boot 中的最佳实践推送通知
我正在开发一个使用 vaadin 作为前端、使用 spring-boot 作为后端的项目。在这个应用程序中,我有一个特定的用例,其中一组用户(操作员)在不同的站点上工作,在这些站点中,他们可以生成应通知另一组不同用户(主管)的事件 - 但仅限于分配给他们的站点。 通常没什么大不了的,但我想使用网络推送通知在新事件发生时通知主管。
我开始阅读有关 Notification API 的一些内容,并设法在 vaadin 中创建了一个视图,用于检查浏览器是否被授予发送通知的权限(在我的 Windows 10 示例中)以及该权限是否没有授予尚未显示一个按钮来要求它。如果权限被授予,按钮将被隐藏,一个标签确认权限被授予。同时发送测试通知(让我测试它是否有效)。 到目前为止一切正常。
我使用 java/vaadin 和原生 java 脚本的混合实现了一切
window.sendNotification = function(element,body,icon,title,type,id) {
var options = {
body: body,icon: icon
}
var notification = new Notification(title,options);
notification.onclick = (e) => element.$server.notificationClicked(type,id);
}
window.checkNotificationPermission = function() {
return Notification.permission;
}
window.askNotificationPermission = function(element) {
function handlePermission(permission) {
element.$server.permissionAsked(permission);
}
// Let's check if the browser supports notifications
if (!('Notification' in window)) {
console.log("This browser does not support notifications.");
} else {
if (checkNotificationPromise()) {
Notification.requestPermission()
.then((permission) => {
handlePermission(permission);
})
} else {
Notification.requestPermission(function(permission) {
handlePermission(permission);
});
}
}
}
function checkNotificationPromise() {
// safari supported permission or all other browsers?
try {
Notification.requestPermission().then();
} catch (e) {
return false;
}
return true;
}
这是js方面,在java/vaadin中,我用@PWA(使用生成的sw.js和manifest)、@Push和@JsModule注释了视图以包含js代码。另外我使用 page.executeJs() 调用每个 js 函数,例如像这样:
Page page = UI.getCurrent().getPage();
page.executeJs("askNotificationPermission($0)",this.getElement());
我还提供回调方法,用于处理授予权限或单击通知的时间。例如:
@ClientCallable
private void permissionAsked(String permission) {
sendSuccessNotification();
permissionChecked(permission);
}
直到这里一切正常。
现在我的大问题是如何自动通知每个用户(其中一些甚至可能登录到不同的机器,例如 PC 和智能手机)。我想过让另一个线程在视图上运行并让它轮询后端以获取新通知:
像这样:
@Override
protected void onAttach(AttachEvent attachEvent) {
// Start the data feed thread
thread = new NotificationThread();
thread.start();
}
@Override
protected void onDetach(DetachEvent detachEvent) {
// Cleanup
thread.interrupt();
thread = null;
}
private class NotificationThread extends Thread {
@Override
public void run() {
try {
while (true) {
Thread.sleep(10000); // update every 10 seconds
List<ResponseNotification> findNewNotifications = notificationController.findNewNotifications();
if (findNewNotifications.size() > 1) {
sendGeneralNotification("You have new notifications","New Notifications!",NavigationTarget.NOTIFICATIONS,"");
} else if (findNewNotifications.size() == 1) {
sendGeneralNotification("An operator requires your attention","Operator",NavigationTarget.OPERATOR,notification.operator.id);
}
}
} catch (InterruptedException e) {
// ...
// handle
}
}
}
这种方法的最大问题是身份验证在后端不再可用,因为它是从另一个线程调用的,因此 SecurityContextHolder.getContext().getAuthentication()
将返回 null。
但我也不确定一般方法是否合理,因为视图总是需要打开的,而且我觉得每 10 秒轮询一次可能会给后端带来一些不必要的负载,一旦有超过一堆主管。>
事件存储在我的数据库中,除了通知之外,我还想发送一封电子邮件,因此如果有一种方法可以在处理事件的同时从后端发送通知并推送到客户端,那就太完美了. 也许有人已经有经验,可以帮助我找到解决此问题的方法。
提前致谢!
解决方法
如果您需要在应用程序未打开时通知用户,则需要查看 Web Push。不幸的是,这需要 Safari 上的自定义(但类似)解决方案,并且是 not available on iOS,这是 Vaadin 还没有内置解决方案的主要原因。 Marcus Hellberg made a prototype 几年前,这可能会提供一些提示。
要通知当前已打开应用程序的用户,请考虑这是否适用于您的情况: 不是每个用户每 10 秒轮询一次相关事件,而是考虑“订阅”关于用户感兴趣的每个站的事件,然后在事件发生时向所有订阅者发送“事件”。用户只有在登录后才会保持订阅状态,因此发布线程不需要跟踪权限。
这需要您为发布/订阅机制使用某种事件总线,为此您可以查看 Collaboration Engine - 主要是因为它与 Vaadin 集成,并带来了您可能会觉得有用的其他协作功能(可能是事件日志,或者每个站的聊天,以便每个操作员可以添加一些额外的细节)。当您使用高级 API 和组件时,它是最强大的,但您可以使用低级 API 做很多漂亮的事情。
您可以通过多种方式进行设置,例如创建一个名为“通知”的主题,使用 CollaborativeMap 共享每个站的更新。 (或者,您可以根据需要为每个站创建一个单独的主题。)
对于每个用户来说都是这样的:
CollaborationEngine.getInstance().openTopicConnection(this,"notifications",localUser,topic -> {
CollaborationMap stations = topic.getNamedMap("stations");
return stations.subscribe(event -> {
if (MY_STATIONS.contains(event.getKey())) {
Notification notification = new Notification(event.getValue(String.class));
notification.setDuration(5000);
notification.open();
}
});
});
然后当一个站有更新时,同样的方式获取stationMap,但要更新:
stationMap.put(STATION_ID,STATION_ID + “: An update at " + new Date());
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。