在Spring Boot中使用Web套接字通知特定用户

时间:2019-03-26 07:08:16

标签: java spring-boot spring-security spring-websocket stomp

我正在Spring Boot中创建任务管理应用程序。以下是我的模型:

public class Task {

    private String name;
    private String description;
    private User assignee;

    //getters and setters
}

public class User {

    private String name;
    private String email;
    private String password;

    //getters and setters
}

我正在为用户使用spring security。现在说有三个Users A,B和C。A创建一个Task并将其分配给B。我现在尝试使用websocket仅向B发送通知。为此,我创建了一个WebSocketConfiguration

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer {
    @Override
    public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
        stompEndpointRegistry.addEndpoint("/socket").setAllowedOrigins("*").withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic");
        registry.setApplicationDestinationPrefixes("/app");
    }
}

要分配此任务的控制器:

@RestController
@RequestMapping("/api/task")
public class TaskController {

    @PostMapping("/assign")
    public void assign(@RequestBody Task task) {
        taskService.assign(task);
    }
}

最后在服务中,我有:

@Service
public class TaskService {

    @Autowired
    private SimpMessagingTemplate template;

    @Override
    public void assign(Task task) {
        //logic to assign task
        template.convertAndSendToUser(task.getAssignee().getEmail(), "/topic/notification",
            "A task has been assigned to you");
    }
}

在客户端,我使用Angular,订阅部分如下所示:

stompClient.subscribe('/topic/notification'+logged_user_email, notifications => {
    console.log(notifications); 
})

当前,任何用户都不会在控制台中打印任何内容。

我遵循了this教程,该教程非常适合广播消息。

我还使用this answer作为使用logging_user_email的参考,但这不起作用。

我已经尝试在客户端添加/user前缀以订阅/user/topic/notification/,如this answer中所述。我也尝试使用queue代替同一答案中说明的主题,但没有成功。

我找到的其他答案提到在控制器中使用@MessageMapping,但我需要能够从服务发送通知。

所以问题是,如何区分通知的目标用户以及如何在服务器端和客户端定义此通知?

1 个答案:

答案 0 :(得分:0)

这可能会有点晚,但是对于遇到相同问题的任何人,我都可以通过执行以下操作使其起作用:

我没有发送用户的电子邮件,而是将其转换为Base64并发送。

@Service
public class TaskService {

    @Autowired
    private SimpMessagingTemplate template;

    @Override
    public void assign(Task task) {
        //logic to assign task
        String base64EncodedEmail = Base64.getEncoder().encodeToString(task.getAssignee().getEmail().getBytes(StandardCharsets.UTF_8));
        template.convertAndSendToUser(base64EncodedEmail, "/topic/notification",
            "A task has been assigned to you");
    }
}

然后在客户端的this tutorial的WebSocketService中,我将connect方法替换为以下内容:

public connect() {
    const encodedEmail = window.btoa(email);
    const socket = new SockJs(`http://localhost:8080/socket?token=${encodedEmail}`);
    const stompClient = Stomp.over(socket);
    return stompClient;
}

在订阅部分,我做了以下事情:

stompClient.subscribe("/user/topic/notification", notification => {
    //logic to display notification
});

其他所有与tututial中相同。