websocket通信主要来自两个类以及一个测试的html页面。
MyHandler 和 WebSocketH5Config,下面全部代码
MyHandler类全部代码:
package com.union.common.config; import java.io.IOException;import java.util.HashMap;import java.util.Map;import java.util.Set;import com.alibaba.fastjson.JSONObject;import org.springframework.stereotype.Service;import org.springframework.web.socket.CloseStatus;import org.springframework.web.socket.TextMessage;import org.springframework.web.socket.WebSocketHandler;import org.springframework.web.socket.WebSocketMessage;import org.springframework.web.socket.WebSocketSession; @Servicepublic class MyHandler implements WebSocketHandler { //在线用户列表 private static final MapwebSocketUsers; static { webSocketUsers = new HashMap<>(); } //新增socket @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { String ID = session.getUri().toString().split("uid=")[1]; if (ID != null) { webSocketUsers.put(ID, session); session.sendMessage(new TextMessage("成功建立socket连接")); } } //接收socket信息 @Override public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage webSocketMessage) throws Exception { try{ JSONObject jsonobject = JSONObject.parseObject((String) webSocketMessage.getPayload()); String message = (String) jsonobject.get("message"); if (message == null) { message = "服务器收到了,hello!"; } sendMessageToUser(jsonobject.get("id")+"",message); }catch(Exception e){ e.printStackTrace(); } } /** * 发送信息给指定用户 * @param clientId * @param message * @return */ public boolean sendMessageToUser(String clientId, String message) { if(webSocketUsers.get(clientId) == null){ return false; } WebSocketSession session = webSocketUsers.get(clientId); if(!session.isOpen()) { return false; } try { session.sendMessage(new TextMessage(message)); } catch (IOException e) { e.printStackTrace(); return false; } return true; } /** * 广播信息 * @param message * @return */ public boolean sendMessageToAllUsers(String message) { boolean allSendSuccess = true; Set clientIds = webSocketUsers.keySet(); WebSocketSession session = null; for (String clientId : clientIds) { try { session = webSocketUsers.get(clientId); if (session.isOpen()) { session.sendMessage(new TextMessage(message)); } } catch (IOException e) { e.printStackTrace(); allSendSuccess = false; } } return allSendSuccess; } /** * 关闭连接 * @param clientId * @return */ public void afterConnectionClosed(String clientId) { try { if(webSocketUsers.get(clientId) != null){ WebSocketSession session = webSocketUsers.get(clientId); afterConnectionClosed(session,CloseStatus.NORMAL); } webSocketUsers.remove(clientId); }catch (Exception e){ e.printStackTrace(); } } @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { String uid = session.getUri().toString().split("uid=")[1]; webSocketUsers.remove(uid); if (session.isOpen()) { session.close(); } } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { String uid = session.getUri().toString().split("uid=")[1]; webSocketUsers.remove(uid); session.close(status); } @Override public boolean supportsPartialMessages() { return false; }}
WebSocketH5Config 类全部代码:
package com.union.common.config;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;//实现接口来配置Websocket请求的路径和拦截器。@Configuration@EnableWebSocketpublic class WebSocketH5Config implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { //handler是webSocket的核心,配置入口 registry.addHandler(new MyHandler(), "/myHandler/{uid}").setAllowedOrigins("*"); }}
测试用的html页面:
socket.html Welcome登录的uid:发送出去的信息:发送送给谁的uid:收到的信息:
因为websocket使用的是ws协议。所以我在nginx上做了一个请求转发,这样服务器就可以使用:
在nginx.conf文件里面的http部分加入如下代码。
map $http_upgrade $connection_upgrade { default upgrade; '' close; }
在server{}部分加了如下代码。放在最前面,就可以在ws部分使用域名访问了:
ws和wss就像http和https一样的
wss://api.****.com/union-front/myHandler/uid=
location ~* /union-front/myHandler { proxy_pass http://127.0.0.1:8080; proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header Origin ""; }
当使用websocket的时候,再使用定时任务,则会报错,在Application启动类上加上如下代码即可解决这个问题
@Bean public TaskScheduler taskScheduler() { //使用 websockt注解的时候,使用@EnableScheduling注解启动的时候一直报错,增加这个bean 则报错解决。 ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); taskScheduler.setPoolSize(10); taskScheduler.initialize(); return taskScheduler; }