WebSocket是HTML5的一种新的协议,它实现了浏览器与服务器的全双工通信的推送技术
全双工和半双工
- 全双工:指的是可以在同一时间段同时进行信号的双向传输,即A->B的同时B->A
- 半双工:指的是在同一时间段只能有一个动作进行传输,即A->B结束后才可以B->A
项目地址
SpringBoot使用
引入
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
|
创建拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| package jtxyh.top.chat.sys.interceptor;
import com.alibaba.fastjson.JSON; import jtxyh.top.chat.sys.enetity.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.server.HandshakeInterceptor; import java.util.Map;
@Component public class ChatInterceptor implements HandshakeInterceptor {
@Autowired private StringRedisTemplate rs;
private String key = "INLINE_USER";
@Override public boolean beforeHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception { HashOperations<String, Object, Object> ops = rs.opsForHash(); Object loginUser = ops.get(key, "loginUser"); if (loginUser != null) { User user = JSON.parseObject((String) loginUser, User.class); map.put("loginUser", user); ops.put(key, user.getUsername(), JSON.toJSONString(user)); } return true; }
@Override public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {
} }
|
创建处理器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
| package jtxyh.top.chat.sys.controller;
import com.alibaba.fastjson.JSON; import jtxyh.top.chat.sys.enetity.Message; import jtxyh.top.chat.sys.enetity.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; import org.springframework.web.socket.*;
import java.io.IOException; import java.util.*;
@Component public class ChatWebSocketHandler implements WebSocketHandler {
@Autowired private StringRedisTemplate rs;
private String key = "INLINE_USER";
private static final Map<String, WebSocketSession> IN_LINE_USER;
static { IN_LINE_USER = new HashMap<>(); }
@Override public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception { User user = (User) webSocketSession.getAttributes().get("loginUser"); IN_LINE_USER.put(user.getUsername(), webSocketSession); noticeMessage("欢迎【" + user.getUsername() + "】来到聊天室!"); }
@Override public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception { if (webSocketMessage.getPayloadLength() == 0) return; Message msg = JSON.parseObject(webSocketMessage.getPayload().toString(), Message.class); User user = (User) webSocketSession.getAttributes().get("loginUser"); msg.setUsername(user.getUsername()); sendMessageToAll(new TextMessage(JSON.toJSONBytes(msg))); }
@Override public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception { }
@Override public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception { User user = (User) webSocketSession.getAttributes().get("loginUser"); IN_LINE_USER.remove(user.getUsername()); rs.opsForHash().delete(key, user.getUsername()); noticeMessage("【" + user.getUsername() + "】离开了聊天室!"); }
@Override public boolean supportsPartialMessages() { return false; }
private void sendMessageToAll(TextMessage message) { IN_LINE_USER.forEach((s, webSocketSession) -> { if (webSocketSession.isOpen()) { new Thread(() -> { try { webSocketSession.sendMessage(message); } catch (IOException e) { e.printStackTrace(); } }).start(); } }); }
private void noticeMessage(String message) { Message msg = new Message(); msg.setMsg(message); msg.setLoginUser(new ArrayList<>()); IN_LINE_USER.forEach((s, webSocketSession) -> { msg.getLoginUser().add((User) webSocketSession.getAttributes().get("loginUser")); }); msg.setUsername("系统消息"); sendMessageToAll(new TextMessage(JSON.toJSONBytes(msg))); } }
|
创建配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package jtxyh.top.chat.sys.ws;
import jtxyh.top.chat.sys.controller.ChatWebSocketHandler; import jtxyh.top.chat.sys.interceptor.ChatInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Component @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer {
@Autowired private ChatWebSocketHandler chatWebSocketHandler;
@Autowired private ChatInterceptor chatInterceptor;
@Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(chatWebSocketHandler, "/ws").addInterceptors(chatInterceptor).setAllowedOrigins("*"); } }
|
前端JS代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| var webSocket;
connectWebSocket();
$("#close").on("click", () => { webSocket.close(); });
function connectWebSocket() { webSocket = new WebSocket("ws://localhost:8080/ws"); webSocket.onopen = function (event) { }; webSocket.onmessage = function (event) { }; webSocket.onclose = function (event) { } }
function sendMessage() { let message = $("#message"); if (message.val() === "") return; let msg = {"msg": message.val(), "username": localStorage.getItem("username")}; webSocket.send(JSON.stringify(msg)); message.val(""); }
|
相关文章
数据库连接池
SpringIOC
Junit和Spring
Tomcat
Servlet
Request,Response和ServletContext
Cookie和Session
JSP和EL和Jstl
Filter和Listener
Mybatis