【发布时间】:2021-05-04 13:32:23
【问题描述】:
我正在做一个项目,它使用 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 和清单)、@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 秒轮询一次可能会给后端带来一些不必要的负载,一旦有多个主管。
事件存储在我的数据库中,除了通知之外,我还想发送一封电子邮件,所以如果有办法从后端发送通知并在处理事件时推送给客户端,那将是完美的. 也许有人已经有经验并且可以帮助我找到解决这个问题的方法。
提前致谢!
【问题讨论】:
-
你检查过这个其他问题吗:stackoverflow.com/questions/67356031/…
-
@TatuLund 感谢您的提示,不,这在我的研究过程中没有出现。这可能是第一个解决方案,但它是否正确?如果 vaadin 是一个独立于后端运行并通过 rest 访问它的无状态服务会怎样。如何验证登录?
-
Vaadin Flow(不是 Fusion)不能运行“无状态”——它总是会运行一个会话,因为它保存了每个 UI 的场景图。您将始终必须在您的 UI/客户端/用户和您的事件源之间建立关系。如果你正在投票,你可以为这些人创造一个长期运行的代币。或者您可以信任您的 vaadin 服务并发送所有更新或允许轮询所有更新以提高效率,然后发送到例如用户名,例如推出自己的发布/订阅。然后当然你可以使用一些已建立的 pub/sub。没有灵丹妙药。
-
其实Vaadin push就是使用websocket。
-
Websocket 是一个有状态的协议。 REST 是无状态的,我认为您不能使用 REST 服务推送通知。
标签: spring-boot push-notification vaadin web-push vaadin-flow