1

I am currently working on a Spring Boot application that uses WebSockets for real-time communication. I have set up a notification system where notifications are sent to a specific user via WebSocket. However, I am facing an issue where the notifications are not being received by the client. Here's what I have done so far: I have a NotificationListener class that listens for notifications on a specific topic. The handleNotification method in this class is annotated with @SubscribeMapping and @SendToUser annotations. The destination in the @SubscribeMapping annotation matches the destination to which the notifications are being sent.

-I have a NotificationService class that handles the creation and sending of notifications. The sendNotification method in this class saves the notification in the database and then sends it to the user via WebSocket.

I have a WebSocketConfig class that configures the WebSocket connection. The broker is enabled for the correct prefix and the endpoints are correctly registered. -I have a JwtAuthenticationFilter class that extracts the JWT token from the request and sets the authentication for the user. -I have a SecurityConfig class that configures the security aspects of the application, including the role hierarchy and CORS settings.

@Controller
public class NotificationListener {
    private static final Logger logger = LoggerFactory.getLogger(NotificationListener.class);

    @SubscribeMapping("/user/[email protected]/queue/notifications")
    @SendToUser("/queue/notifications")
    public Notification handleNotification(Notification notification) {
        logger.info("Received notification: {}", notification);
        return notification;
    }
}
@RestController
@RequestMapping("/api/notifications")
public class NotificationController {
    private final NotificationService notificationService;

    @Autowired
    public NotificationController(NotificationService notificationService) {
        this.notificationService = notificationService;
    }

    @PostMapping("/send")
    public ResponseEntity<Void> sendNotification(@RequestParam String message, @RequestParam String userEmail) {
        notificationService.sendNotification(message, userEmail);
        return ResponseEntity.ok().build();
    }

    @GetMapping("/recipient")
    public ResponseEntity<List<Notification>> getLatestNotificationsForRecipient(@RequestParam String email, @RequestParam int page, @RequestParam int size) {
        List<Notification> notifications = notificationService.getLatestNotificationsForRecipient(email, page, size);
        return ResponseEntity.ok(notifications);
    }
}
@Service
public class NotificationService {
    private final SimpMessagingTemplate messagingTemplate;
    private final NotificationRepository notificationRepository;
    private static final Logger logger = LoggerFactory.getLogger(NotificationService.class);

    @Autowired
    public NotificationService(SimpMessagingTemplate messagingTemplate, NotificationRepository notificationRepository) {
        this.messagingTemplate = messagingTemplate;
        this.notificationRepository = notificationRepository;
    }

    public Notification sendNotification(String message, String userEmail) {
        Notification notification = new Notification();
        notification.setMessage(message);
        notification.setTimestamp(LocalDateTime.now());
        notification.setRecipient(userEmail);  // Use email as recipient

        Notification savedNotification = notificationRepository.save(notification);
        logger.info("Notification saved: " + savedNotification);
        messagingTemplate.convertAndSendToUser(userEmail, "/queue/notifications", savedNotification);
        logger.info("Notification sent via WebSocket to user " + userEmail);
        return savedNotification;
    }

    public List<Notification> getLatestNotificationsForRecipient(String email, int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "timestamp"));
        return notificationRepository.findByRecipientOrderByTimestampDesc(email, pageable).getContent();
    }
}
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    private static final Logger logger = LoggerFactory.getLogger(WebSocketConfig.class);

    @Autowired
    private JwtTokenProvider jwtTokenProvider;

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/queue");
        config.setApplicationDestinationPrefixes("/app");
        config.setUserDestinationPrefix("/user");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws")
                .setAllowedOrigins("http://localhost:4200")
                .withSockJS()
                .setInterceptors(new HandshakeInterceptor() {
                    @Override
                    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
                        if (request instanceof ServletServerHttpRequest) {
                            ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
                            String token = extractToken(servletRequest);
                            if (token != null && jwtTokenProvider.validateToken(token)) {
                                String userEmail = jwtTokenProvider.getUserEmailFromToken(token);
                                attributes.put(Principal.class.getName(), new Principal() {
                                    @Override
                                    public String getName() {
                                        return userEmail;
                                    }
                                });
                                return true;
                            } else {
                                return false;
                            }
                        }
                        return false;
                    }

                    @Override
                    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {}
                });
    }

    private String extractToken(ServletServerHttpRequest request) {
        String bearerToken = request.getServletRequest().getHeader("Authorization");
        if (bearerToken == null || !bearerToken.startsWith("Bearer ")) {
            bearerToken = request.getServletRequest().getParameter("token");
        } else {
            bearerToken = bearerToken.substring(7);
        }
        return bearerToken;
    }

    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.interceptors(new ChannelInterceptor() {
            @Override
            public Message<?> preSend(Message<?> message, MessageChannel channel) {
                StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
                if (StompCommand.SUBSCRIBE.equals(accessor.getCommand())) {
                    String destination = accessor.getDestination();
                    logger.info("Client subscribed to topic: {}", destination);
                } else if (StompCommand.UNSUBSCRIBE.equals(accessor.getCommand())) {
                    String destination = accessor.getDestination();
                    logger.info("Client unsubscribed from topic: {}", destination);
                }
                return message;
            }
        });
    }
}`

Here's my logs everything is fine the prob is I don't receive the notification :


02:38:13.126 [clientInboundChannel-2] DEBUG o.s.m.s.b.SimpleBrokerMessageHandler - Processing CONNECT session=oxb0cqmx
02:38:13.140 [clientOutboundChannel-1] INFO  c.e.m.n.WebSocketEventListener - Received a new web socket connection
02:38:13.199 [http-nio-8080-exec-9] INFO  c.e.m.notification.WebSocketConfig - Client subscribed to topic: /user/[email protected]/queue/notifications
02:38:15.423 [http-nio-8080-exec-2] INFO  c.e.m.config.JwtTokenProvider - Token is valid
02:38:15.424 [http-nio-8080-exec-2] INFO  c.e.m.config.JwtTokenProvider - Extracted email from token: [email protected]
Hibernate: select u1_0.matricule,u1_0.adresse,u1_0.civilite,u1_0.departement,u1_0.email,u1_0.emailpersonnel,u1_0.first_time,u1_0.nom,u1_0.password,u1_0.prenom,u1_0.tel from user u1_0 where u1_0.email=?
Hibernate: select r1_0.user_id,r1_1.id,r1_1.name,p1_0.role_id,p1_1.id,p1_1.name from user_roles r1_0 join user_role r1_1 on r1_1.id=r1_0.role_id left join role_permissions p1_0 on r1_1.id=p1_0.role_id left join permission p1_1 on p1_1.id=p1_0.permission_id where r1_0.user_id=?
02:38:15.433 [http-nio-8080-exec-2] INFO  c.e.m.config.JwtAuthenticationFilter - Authorities from token: [ASSIGN_TASKS, VIEW_PROJECT, REQUEST_LEAVE, CHAT_MESSAGE, VIEW_USERS, MANAGE_TASKS]
02:38:15.433 [http-nio-8080-exec-2] INFO  c.e.m.config.JwtAuthenticationFilter - Set authentication for user: [email protected]
Hibernate: select u1_0.matricule,u1_0.adresse,u1_0.civilite,u1_0.departement,u1_0.email,u1_0.emailpersonnel,u1_0.first_time,u1_0.nom,u1_0.password,u1_0.prenom,u1_0.tel from user u1_0 where u1_0.matricule=?
Hibernate: insert into notification (message,recipient,timestamp) values (?,?,?)
02:38:15.517 [http-nio-8080-exec-2] INFO  c.e.m.n.NotificationService - Notification saved: com.example.managementsystem.notification.Notification@f4810f8
02:38:15.518 [http-nio-8080-exec-2] INFO  c.e.m.n.NotificationService - Notification sent via WebSocket to user [email protected]
Hibernate: update task set user_matricule=?,description=?,sprint_id=?,status=? where id=?

: Spring Boot :: (v3.2.4)

Here's my github repository :

https://github.com/Hamzaafroukh321/notif

Folder : notification

Sorry for all of this but I hope you can understand me , but I'm still a junior and I have a project to deliver and it's been 3 weeks that I'm stuck in this problem

-I have checked the WebSocket connection and it is open when the notification is sent. -I have checked the destination to which the notification is sent and it matches the destination to which the client is subscribed. -I have checked the user to which the notification is sent and it matches the user that is connected to the WebSocket. -I have checked the database and the notification is saved correctly. -I have added logging statements in my code and the sendNotification method in NotificationService.java is being called. Despite all these checks, I am still not receiving the notifications at the client end. I would appreciate any help or suggestions on how to debug this issue (I did post on StackOverflow no answer and its been 3 weeks that I'm struggling that why I did create a ticket). Thank you in advance.

0