SSE は、サーバーがフロントエンドにデータを積極的にプッシュするテクノロジーです。これは一方向であり、フロントエンドがサーバーにデータを送信できないことを意味します。 SSE は、メッセージ プッシュ、監視、およびサーバー プッシュ データのみを必要とするその他のシナリオに適しています。次は、Spring Boot を使用して進行状況データをフロント エンドにプッシュする簡単なシミュレーションです。フロント エンド ページがそれを受け入れると、進行状況バーが表示されます。
Spring Boot で使用する場合は注意が必要です。Spring Web が提供する SseEmitter クラスを使用して動作させるのが最適です。最初は Content-Type を使用しましたtext-stream に設定すると、フロントエンドが毎回接続を再作成することがわかります。最後に、この記事を参照することで、最終的に望ましい効果を達成しました。
SSEServer.java
package vip.huhailong.catchat.sse; import lombok.extern.slf4j.Slf4j; import org.springframework.http.MediaType; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; /** * @author Huhailong */ @Slf4j public class SSEServer { /** * 当前连接数 */ private static AtomicInteger count = new AtomicInteger(0); private static Map<String, SseEmitter> sseEmitterMap = new ConcurrentHashMap<>(); public static SseEmitter connect(String userId){ //设置超时时间,0表示不过期,默认是30秒,超过时间未完成会抛出异常 SseEmitter sseEmitter = new SseEmitter(0L); //注册回调 sseEmitter.onCompletion(completionCallBack(userId)); sseEmitter.onError(errorCallBack(userId)); sseEmitter.onTimeout(timeOutCallBack(userId)); sseEmitterMap.put(userId,sseEmitter); //数量+1 count.getAndIncrement(); log.info("create new sse connect ,current user:{}",userId); return sseEmitter; } /** * 给指定用户发消息 */ public static void sendMessage(String userId, String message){ if(sseEmitterMap.containsKey(userId)){ try{ sseEmitterMap.get(userId).send(message); }catch (IOException e){ log.error("user id:{}, send message error:{}",userId,e.getMessage()); e.printStackTrace(); } } } /** * 想多人发送消息,组播 */ public static void groupSendMessage(String groupId, String message){ if(sseEmitterMap!=null&&!sseEmitterMap.isEmpty()){ sseEmitterMap.forEach((k,v) -> { try{ if(k.startsWith(groupId)){ v.send(message, MediaType.APPLICATION_JSON); } }catch (IOException e){ log.error("user id:{}, send message error:{}",groupId,message); removeUser(k); } }); } } public static void batchSendMessage(String message) { sseEmitterMap.forEach((k,v)->{ try{ v.send(message,MediaType.APPLICATION_JSON); }catch (IOException e){ log.error("user id:{}, send message error:{}",k,e.getMessage()); removeUser(k); } }); } /** * 群发消息 */ public static void batchSendMessage(String message, Set<String> userIds){ userIds.forEach(userId->sendMessage(userId,message)); } public static void removeUser(String userId){ sseEmitterMap.remove(userId); //数量-1 count.getAndDecrement(); log.info("remove user id:{}",userId); } public static List<String> getIds(){ return new ArrayList<>(sseEmitterMap.keySet()); } public static int getUserCount(){ return count.intValue(); } private static Runnable completionCallBack(String userId) { return () -> { log.info("结束连接,{}",userId); removeUser(userId); }; } private static Runnable timeOutCallBack(String userId){ return ()->{ log.info("连接超时,{}",userId); removeUser(userId); }; } private static Consumer<Throwable> errorCallBack(String userId){ return throwable -> { log.error("连接异常,{}",userId); removeUser(userId); }; } }
上記のクラスは次のようになります。 SSE ツール クラスを作成します。以下で使用してみましょう
package vip.huhailong.catchat.controller; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import vip.huhailong.catchat.sse.SSEServer; /** * @author Huhailong */ @Slf4j @RestController @CrossOrigin @RequestMapping("/sse") public class SSEController { @GetMapping("/connect/{userId}") public SseEmitter connect(@PathVariable String userId){ return SSEServer.connect(userId); } @GetMapping("/process") public void sendMessage() throws InterruptedException { for(int i=0; i<=100; i++){ if(i>50&&i<70){ Thread.sleep(500L); }else{ Thread.sleep(100L); } SSEServer.batchSendMessage(String.valueOf(i)); } } }
上記の接続は sse に接続するために使用され、SseEmitter インスタンスを返します。今回は接続が作成され、以下のプロセス インターフェイスを使用してデータをプッシュします。フロントエンドにプログレス バーの効果を認識させるつもりなので、プッシュされるのは数字です。明らかな効果を得るには、50 から 70 まで押します。ゆっくりにして、残りは 100 ミリ秒です。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Home</title> <script> let data = new EventSource("/cat-chat/sse/connect/huhailong") data.onmessage = function(event){ console.log("test=>",event) document.getElementById("result").innerText = event.data+'%'; document.getElementById("my-progress").value = event.data; } </script> </head> <body> <div id="result"></div> <progress id="my-progress" value="0" max="100"></progress> </body> </html>
最終効果:
以上がSpring Boot が SSE を使用してデータをフロントエンドにプッシュする方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。