环境:jdk1.8、idea、Spring Boot 2.0.4
一、非注解写法
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Web Socket依赖 start-->
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>4.3.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<!-- Spring Web Socket依赖 end-->
<!-- commin-lang -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
application.yml
server:
port: 8001
Entity
public class User {
private String phone;
private String name;
private Integer userId;
private Integer id;
……Getter and Setter……
public String toString() {
return "User [phone=" + phone + ", name=" + name + ", userId=" + userId
+ "]";
}
}
Interceptor
import com.zhao.entity.User;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;
import java.util.Map;
/**
* 拦截器
* @author zhaoYang
* @Title: web-socket
* @Package com.zhao.websocket
* @date 2018/10/31 17:01
*/
public class DemoWebSocketInterceptor implements HandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse,
WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {
System.out.println("执行beforeHandshake方法*****拦截器(1)");
if (request instanceof ServletServerHttpRequest) {
System.out.println("执行beforeHandshake方法*****拦截器(2)");
// 保存session中已登录的用户到websocket的上下文环境中。在推送消息的时候,需要根据当前登录用户获取点位权限
User u=new User();
u.setId(1);
u.setName("test");
u.setUserId(1);
// client传Sec-WebSocket-Protocol过来,server必须返回Sec-WebSocket-Protocol回去
serverHttpResponse.getHeaders().add("Sec-WebSocket-Protocol",(request).getHeaders().get("Sec-WebSocket-Protocol").get(0));
map.put("userId",((ServletServerHttpRequest) request).getServletRequest().getParameter("userId"));
map.put("token",(request).getHeaders().get("Sec-WebSocket-Protocol").get(0));
System.out.println("=========拦截器 "+map);
}
return true;
}
@Override
public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse,
WebSocketHandler webSocketHandler, Exception e) {
System.out.println("执行afterHandshake方法*****拦截器");
}
}
Handler
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* @author zhaoYang
* @Title: web-socket
* @Package com.zhao.websocket.handler
* @date 2018/10/31 17:08
*/
@Component
public class DemoWebSocketHandler implements WebSocketHandler {
private static final Map<String,WebSocketSession> userSocketSessionMapThreadLocal = new HashMap<>();
/**
* 建立连接
* @param webSocketSession
* @throws Exception
*/
@Override
public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
System.out.println("=========================建立连接 "+webSocketSession.getAttributes().get("userId").toString());
userSocketSessionMapThreadLocal.put(webSocketSession.getAttributes().get("userId").toString(),webSocketSession);
}
/**
* 接收客户端发来的消息
* @param webSocketSession
* @param webSocketMessage
* @throws Exception
*/
@Override
public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception {
Object payload = webSocketMessage.getPayload();
System.out.println(payload);
}
/**
* 传输错误异常
* @param webSocketSession
* @param throwable
* @throws Exception
*/
@Override
public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
}
/**
* 连接关闭
* 在此刷新页面就相当于断开WebSocket连接,原本在静态变量userSocketSessionMap中的
* WebSocketSession会变成关闭状态(close),但是刷新后的第二次连接服务器创建的
* 新WebSocketSession(open状态)又不会加入到userSocketSessionMap中,所以这样就无法发送消息
* 因此应当在关闭连接这个切面增加去除userSocketSessionMap中当前处于close状态的WebSocketSession,
* 让新创建的WebSocketSession(open状态)可以加入到userSocketSessionMap中
* @param webSocketSession
* @param closeStatus
* @throws Exception
*/
@Override
public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
System.out.println("=========================连接关闭");
}
@Override
public boolean supportsPartialMessages() {
return false;
}
/**
* 广播推送消息,如需点对点发送,即可根据userSocketSessionMapThreadLocal对应的key进行发送
* @throws IOException
*/
public void sendMessage(String message) throws IOException {
System.out.println("=========================sendMessage");
Iterator iter = userSocketSessionMapThreadLocal.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
//String key = (String) entry.getKey();
WebSocketSession ws = (WebSocketSession) entry.getValue();
//发送WebSocket消息
// JSONObject jsonObject = new JSONObject();
// String message=jsonObject.fromObject(result).toString();
// ws.sendMessage(new TextMessage(message.getBytes()));
ws.sendMessage(new TextMessage(message.getBytes()));
}
}
}
Config
import com.zhao.websocket.handler.DemoWebSocketHandler;
import com.zhao.websocket.interceptor.DemoWebSocketInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
/**
* @author zhaoYang
* @Title: web-socket
* @Package com.zhao.websocket.config
* @date 2018/10/31 17:06
*/
@Component
@EnableWebSocket
@EnableWebMvc
public class DemoWebSocketConfig implements WebSocketConfigurer {
@Autowired
DemoWebSocketHandler demoWebSocketHandler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
System.out.println("=========================config");
//添加Web Socket处理器,添加握手拦截器
webSocketHandlerRegistry.addHandler(demoWebSocketHandler, "/demoWebSocket").
setAllowedOrigins("*") // 添加允许跨域访问
.addInterceptors(new DemoWebSocketInterceptor());
}
}
Controller
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zhao.websocket.handler.DemoWebSocketHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* @author zhaoYang
* @Title: web-socket
* @Package com.zhao.websocket.controller
* @date 2018/10/31 17:38
*/
@RestController
public class WebSocketController {
@Autowired
DemoWebSocketHandler demoWebSocketHandler;
@RequestMapping(value = "webSocket",method = RequestMethod.GET)
public String webSocket(){
try {
Map<String,Object> result=new HashMap<>();
result.put("a","1");
result.put("b","2");
result.put("c","3");
JSONObject jsonObject=JSONObject.parseObject(JSON.toJSONString(result));
String message=jsonObject.toJSONString();
demoWebSocketHandler.sendMessage(message);
}catch (Exception e){
e.printStackTrace();
}
return "success";
}
}
html
<!DOCTYPE html>
<html lang="en">
<body>
<div id="msg"></div>
<input type="text" id="text">
<input type="submit" value="send" onclick="send()">
</body>
<script>
var msg = document.getElementById("msg");
var token='dcvuahsdnfajw12kjfasfsdf34';
var websocket = new WebSocket("ws://127.0.0.1:8001/demoWebSocket?userId=1",[token]);
//监听连接打开
websocket.onopen = function (evt) {
console.log("onopen");
msg.innerHTML = "The connection is open";
};
//监听服务器数据推送
websocket.onmessage = function (evt) {
console.log("onmessage ");
msg.innerHTML += "<br>" + evt.data;
};
//监听连接关闭
websocket.onclose = function (evt) {
console.log("onclose ");
//alert("连接关闭");
};
function send() {
var text = document.getElementById("text").value
websocket.send(text);
}
</script>
</html>
启动项目,并打开页面
调用Controller接口,触发服务端主动推送消息给客户端
localhost:8001/webSocket