最近因为业务需求,需要进行长连接开发,所以对websocket进行了了解,入坑好几天,下面是一点点总结。
websocket后端java的开发主要有两种方式,一个基于javax的开发,一个是基于spring框架的开发。我这个使用的是基于spring框架进行开发的。话不多说,直接上代码。
首先需要导入依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${spring.version}</version>
</dependency>
首先是websocket的配置类:
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(),"/webSocketServer").addInterceptors(new WebSocketInterceptor()).setAllowedOrigins("*");
}
@Bean
public WebSocketHandler myHandler(){
return new MyHandler();
}
}
编写websocket的拦截器
public class WebSocketInterceptor implements HandshakeInterceptor {
final Logger logger = Logger.getLogger(WebSocketInterceptor.class);
/**
* 当客户端与服务器端握手之前之前执行的方法
* 取出当前存在session的用户信息将openid,封装到WebSocket对象中的map中;
* 由Handler处理器中获取openid
* @return
*/
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {
ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request;
HttpSession session = serverHttpRequest.getServletRequest().getSession();
HttpServletResponse httpServletResponse = ((ServletServerHttpResponse)response).getServletResponse();
String openId = ((ServletServerHttpRequest) request).getServletRequest().getParameter("openId");
logger.info("openid is:" + openId);
logger.info(JSONObject.toJSONString(((ServletServerHttpRequest) request).getServletRequest().getParameterMap()));
map.put("openId", openId);
System.out.println(map.get("openId") + " $$$$$$$$");
((ServletServerHttpRequest) request).getServletRequest().getSession().setAttribute("openId",openId);
if (StringUtils.isNotEmpty(((ServletServerHttpRequest) request).getServletRequest().
getHeader("Sec-WebSocket-Protocol"))) {
httpServletResponse.addHeader("Sec-WebSocket-Protocol",
((ServletServerHttpRequest) request).getServletRequest().getHeader("Sec-WebSocket-Protocol"));
}
return true;
}
//与服务器websoket建立握手之后执行的方法
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler webSocketHandler, @Nullable Exception e) {
}
}
最后是websocket的各种功能实现
public class MyHandler extends TextWebSocketHandler {
//在线用户列表
private static final Map<String, WebSocketSession> users;
private static final String OPEN_ID = "openId"; //用户标识
//类加载初始化一个map集合,存放用户的websocket对象
static{
users = new HashMap<String, WebSocketSession>();
}
/**
* 获取用户标识,获取websocekt对象的map集合
* @param session
* @return
*/
private String getClientId(WebSocketSession session) {
try {
//获取存入websocket的openId
String openId = (String) session.getAttributes().get(OPEN_ID);
return openId;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 成功建立连接触发的方法,
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
//取出拦截器放入的openid,为当前的websoket绑定用户到map
String openId = getClientId(session);
System.out.println(openId+":链接获得id");
if (openId != null) {
users.put(openId, session);
session.sendMessage(new TextMessage("成功建立socket连接"));
System.out.println(openId +"%%%%%%%%%%%%%%");
System.out.println(session + "********");
}
}
/**
* 当接收到客户端浏览器后接收的方法
*/
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
System.out.println(message.getPayload());
WebSocketMessage message1 = new TextMessage("server:"+message);
try {
session.sendMessage(message1);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 发送信息给指定用户
* @param openid
* @param message
* @return
* map中根据用户的id获取对应得websoket,发送信息
*/
public boolean sendMessageToUser(String openid, TextMessage message) {
//获取当前的
if (users.get(openid) == null) return false;
WebSocketSession session = users.get(openid);
System.out.println("sendMessage:" + session);
if (!session.isOpen()) return false;
try {
session.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 广播信息(发送给所有人)
* @param message
* @return
* 遍历出map中所有的websocket发送在线消息
*/
public boolean sendMessageToAllUsers(TextMessage message) {
boolean allSendSuccess = true;
Set<String> openids = users.keySet();
WebSocketSession session = null;
for (String openid : openids) {
try {
session = users.get(openid);
if (session.isOpen()) {
session.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
allSendSuccess = false;
}
}
return allSendSuccess;
}
/**
* 当链接发生异常后触发的方法,关闭出错会话的连接,和删除在Map集合中的记录
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
//判断当前的链接是否在继续,关闭连接
if (session.getAttributes().get(OPEN_ID) == null) {
session.close();
}
System.out.println("连接出错");
users.remove(getClientId(session));
}
/**
* 当链接关闭后触发的方法,连接已关闭,移除在Map集合中的记录。
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
System.out.println("连接已关闭:" + status); //当前的状态码,并删除存储在map中的websocket的链接对象
users.remove(getClientId(session));
}
@Override
public boolean supportsPartialMessages() {
return false;
}
}
可以写一个前端的html页面进行测试,这里也附上一个吧
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script> </head> <body> </body> <script type="application/javascript"> var host = "localhost:9100"; var websocket; if ('WebSocket' in window) { websocket = new WebSocket("ws://" + host + "/webSocketServer?openId=oo41c5ZrJE8hf_dVKFZDnnkq5Na4", "a", {debug:true, maxReconnectAttempts:4}); } else if ('MozWebSocket' in window) { websocket = new MozWebSocket("ws://" + host + "/webSocketServer"); } else { websocket = new SockJS("http://" + host + "/sockjs/webSocketServer"); } websocket.onopen = function(evnt) { console.log("websocket连接上"); }; websocket.onmessage = function(evnt) { messageHandler(evnt.data); }; websocket.onerror = function(evnt) { console.log("websocket错误"); }; websocket.onclose = function(evnt) { console.log("websocket关闭"); } </script> </html>水平有限,如果有什么错误之处,希望路过的大神基于指正,谢谢!