You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Exchange流式通知回调时向UI返回JSON响应?

How to Return JSON Responses to UI When EWS Streaming Notification Callback Triggers

Great question! Since your EWS streaming notification callback runs asynchronously in the backend, you can't directly return an HTTP response to the UI from this callback (it's not tied to any incoming HTTP request). Instead, you need a real-time communication channel to actively push JSON updates to the UI whenever a new mail event is detected. Below are two practical, widely-used solutions:

Solution 1: Use WebSocket (Bidirectional Communication)

WebSocket is ideal if you need two-way communication (e.g., UI can send commands to the backend later). Here's how to integrate it with your EWS code using Spring WebSocket (adjust for your framework if needed):

Step 1: Configure WebSocket in Backend

First, set up a WebSocket handler and config to manage client connections:

import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class MailNotificationWebSocketHandler extends TextWebSocketHandler {
    // Track active client sessions (thread-safe)
    private static final Set<WebSocketSession> activeSessions = Collections.synchronizedSet(new HashSet<>());

    @Override
    public void afterConnectionEstablished(WebSocketSession session) {
        activeSessions.add(session);
        System.out.println("Client connected: " + session.getId());
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, org.springframework.web.socket.CloseStatus status) {
        activeSessions.remove(session);
        System.out.println("Client disconnected: " + session.getId());
    }

    // Static method to send JSON to all connected UIs
    public static void pushNotification(String jsonPayload) {
        for (WebSocketSession session : activeSessions) {
            if (session.isOpen()) {
                try {
                    session.sendMessage(new TextMessage(jsonPayload));
                } catch (IOException e) {
                    e.printStackTrace();
                    // Clean up invalid sessions if needed
                    activeSessions.remove(session);
                }
            }
        }
    }
}

Add the WebSocket config class:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new MailNotificationWebSocketHandler(), "/mail-notifications")
                .setAllowedOrigins("*"); // Restrict to your UI domain in production
    }
}

Step 2: Update EWS Callback to Push JSON

Modify your EWS callback to convert notification events to JSON and send via WebSocket:

import com.fasterxml.jackson.databind.ObjectMapper;
import microsoft.exchange.webservices.data.NotificationEvent;
import microsoft.exchange.webservices.data.ItemEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

// ... your existing EWS setup code ...

streamingConn.addOnNotificationEvent((sender, notification) -> {
    // 1. Convert EWS NotificationEvents to a serializable structure
    List<Map<String, Object>> eventDataList = new ArrayList<>();
    for (NotificationEvent event : notification.getEvents()) {
        Map<String, Object> eventMap = new HashMap<>();
        eventMap.put("eventType", event.getEventType().name());
        eventMap.put("folderId", event.getFolderId().getUniqueId());

        // Add item-specific details if it's an item event (like new mail)
        if (event instanceof ItemEvent) {
            ItemEvent itemEvent = (ItemEvent) event;
            eventMap.put("itemId", itemEvent.getItemId().getUniqueId());
            eventMap.put("subject", itemEvent.getItemSubject()); // Include subject if available
        }
        eventDataList.add(eventMap);
    }

    // 2. Convert to JSON string using Jackson
    ObjectMapper objectMapper = new ObjectMapper();
    String jsonResponse;
    try {
        jsonResponse = objectMapper.writeValueAsString(eventDataList);
    } catch (Exception e) {
        e.printStackTrace();
        return;
    }

    // 3. Push JSON to all connected UIs
    MailNotificationWebSocketHandler.pushNotification(jsonResponse);
});

Step 3: UI WebSocket Client (JavaScript)

Connect to the backend and handle incoming notifications:

const socket = new WebSocket('ws://your-backend-domain:port/mail-notifications');

socket.onmessage = (event) => {
    const notifications = JSON.parse(event.data);
    console.log('New mail events received:', notifications);
    // Update your UI here (e.g., show a toast, refresh inbox list)
};

socket.onerror = (error) => {
    console.error('WebSocket error:', error);
};

Solution 2: Use Server-Sent Events (SSE) (Unidirectional Push)

If you only need the backend to push updates to the UI (no reverse communication), SSE is simpler than WebSocket. Here's how to implement it with Spring MVC:

Step 1: Create SSE Controller

import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;

@RestController
@RequestMapping("/sse")
public class MailNotificationSseController {
    // Reusable SSE emitter (adjust timeout as needed)
    private final SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);

    @GetMapping("/mail-updates")
    public SseEmitter getMailUpdates() {
        return emitter;
    }

    // Method to send JSON updates to UI
    public void sendNotification(String jsonPayload) {
        try {
            emitter.send(SseEmitter.event().data(jsonPayload));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Step 2: Update EWS Callback

Inject the SSE controller (if using Spring) and push JSON:

import org.springframework.beans.factory.annotation.Autowired;
// ... other imports ...

@Autowired
private MailNotificationSseController sseController;

// ... your EWS setup code ...

streamingConn.addOnNotificationEvent((sender, notification) -> {
    // Same JSON conversion logic as WebSocket example
    List<Map<String, Object>> eventDataList = new ArrayList<>();
    // ... populate eventDataList ...

    ObjectMapper objectMapper = new ObjectMapper();
    String jsonResponse = objectMapper.writeValueAsString(eventDataList);

    // Push via SSE
    sseController.sendNotification(jsonResponse);
});

Step 3: UI SSE Client (JavaScript)

const eventSource = new EventSource('/sse/mail-updates');

eventSource.onmessage = (event) => {
    const notifications = JSON.parse(event.data);
    console.log('New mail updates:', notifications);
    // Update your UI accordingly
};

eventSource.onerror = (error) => {
    console.error('SSE error:', error);
    eventSource.close();
};

Key Notes

  • Thread Safety: Ensure your communication channel (WebSocket sessions/SSE emitter) is accessed safely, as the EWS callback runs in a background thread.
  • User Specificity: If you have multiple users, add logic to map sessions to user IDs (e.g., authenticate WebSocket connections) so notifications go to the correct user's UI.
  • Error Handling: Always handle IO exceptions when sending messages (clients may disconnect unexpectedly).

内容的提问来源于stack exchange,提问作者Asif Ansari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:23:02