网上个人认为写的比较好的网址:
https://www.ibm.com/developerworks/cn/web/1112_huangxa_websocket/
https://www.cnblogs.com/zhang-bo/p/7844062.html
https://www.cnblogs.com/roy-blog/p/7211761.html
https://blog.csdn.net/u014042066/article/details/76702120
自己测试比较好用的两个工具类:
第一种(springboot方式):
参考网址:https://www.cnblogs.com/zhang-bo/p/7844062.html
①引入maven的jar包依赖
<!--添加websocket依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> <version>1.3.5.RELEASE</version> </dependency>
②服务端代码
package com.ah.fuzhou.riverchief.controller.check; /** * @author wph * @date 2018/8/16 10:34 */ import org.springframework.stereotype.Component; import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.ConcurrentHashMap; /** * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端, * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端 * @ServerEndpoint 可以把当前类变成websocket服务类 */ @ServerEndpoint("/websocket/{userno}") @Component public class WebSocketTest { //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 private static int onlineCount = 0; //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识 private static ConcurrentHashMap<String, WebSocketTest> webSocketSet = new ConcurrentHashMap<String, WebSocketTest>(); //与某个客户端的连接会话,需要通过它来给客户端发送数据 private Session session; //当前发消息的人员编号 private String userno = ""; /** * 连接建立成功调用的方法 * * @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据 */ @OnOpen public void onOpen(@PathParam(value = "userno") String param, Session session, EndpointConfig config) { System.out.println(param); userno = param;//接收到发送消息的人员编号 this.session = session; webSocketSet.put(param, this);//加入map中 addOnlineCount(); //在线数加1 System.out.println("有新连接加入!当前在线人数为" + getOnlineCount()); } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { if (!userno.equals("")) { webSocketSet.remove(userno); //从set中删除 subOnlineCount(); //在线数减1 System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount()); } } /** * 收到客户端消息后调用的方法 * * @param message 客户端发送过来的消息 * @param session 可选的参数 */ @OnMessage public void onMessage(String message, Session session) { System.out.println("来自客户端的消息:" + message); // session.get //群发消息 if (2>1) { sendAll(message); } else { //给指定的人发消息 sendToUser(message); } } /** * 给指定的人发送消息 * @param message */ private void sendToUser(String message) { String sendUserno = message.split("[|]")[1]; String sendMessage = message.split("[|]")[0]; String now = getNowTime(); try { if (webSocketSet.get(sendUserno) != null) { webSocketSet.get(sendUserno).sendMessage(now + "用户" + userno + "发来消息:" + " <br/> " + sendMessage); } else { System.out.println("当前用户不在线"); } } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args){ WebSocketTest t =new WebSocketTest(); t.sendToUser("服务的推送消息|5678"); } /** * 给所有人发消息 * @param message */ private void sendAll(String message) { String now = getNowTime(); String sendMessage = message.split("[|]")[0]; //遍历HashMap for (String key : webSocketSet.keySet()) { try { //判断接收用户是否是当前发消息的用户 if (!userno.equals(key)) { webSocketSet.get(key).sendMessage(now + "用户" + userno + "发来消息:" + " <br/> " + sendMessage); System.out.println("key = " + key); } } catch (IOException e) { e.printStackTrace(); } } } /** * 获取当前时间 * * @return */ private String getNowTime() { Date date = new Date(); DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String time = format.format(date); return time; } /** * 发生错误时调用 * * @param session * @param error */ @OnError public void onError(Session session, Throwable error) { System.out.println("发生错误"); error.printStackTrace(); } /** * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。 * * @param message * @throws IOException */ public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); //this.session.getAsyncRemote().sendText(message); } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { WebSocketTest.onlineCount++; } public static synchronized void subOnlineCount() { WebSocketTest.onlineCount--; } }
③客户端代码
<!DOCTYPE html>
<html>
<head>
<title>Java后端WebSocket的Tomcat实现</title>
</head>
<body>
Welcome<br/><input id="text" type="text"/>
<button οnclick="send()">发送消息</button>
<hr/>
<!--userno:发送消息人的编号-->
<div id="userno">1234</div>
<button οnclick="closeWebSocket()">关闭WebSocket连接</button>
<hr/>
<div id="message"></div>
</body><script type="text/javascript">
var websocket = null;
var userno=document.getElementById('userno').innerHTML;
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8080/websocket/"+userno);
}
else {
alert('当前浏览器 Not support websocket')
}//连接发生错误的回调方法
websocket.onerror = function () {
setMessageInnerHTML("WebSocket连接发生错误");
};//连接成功建立的回调方法
websocket.onopen = function () {
setMessageInnerHTML("WebSocket连接成功");
}//接收到消息的回调方法
websocket.onmessage = function (event) {
setMessageInnerHTML(event.data);
}//连接关闭的回调方法
websocket.onclose = function () {
setMessageInnerHTML("WebSocket连接关闭");
}//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
closeWebSocket();
}//将消息显示在网页上
function setMessageInnerHTML(sendMessage) {
document.getElementById('message').innerHTML += sendMessage + '<br/>';
}//关闭WebSocket连接
function closeWebSocket() {
websocket.close();
}//发送消息
function send() {
var message = document.getElementById('text').value;//要发送的消息内容
var now=getNowFormatDate();//获取当前时间
document.getElementById('message').innerHTML += (now+"发送人:"+userno+'<br/>'+"---"+message) + '<br/>';
document.getElementById('message').style.color="red";
var ToSendUserno="5678";//接收人编号:4567
message=message+"|"+ToSendUserno//将要发送的信息和内容拼起来,以便于服务端知道消息要发给谁
websocket.send(message);
}
//获取当前时间
function getNowFormatDate() {
var date = new Date();
var seperator1 = "-";
var seperator2 = ":";
var month = date.getMonth() + 1;
var strDate = date.getDate();
if (month >= 1 && month <= 9) {
month = "0" + month;
}
if (strDate >= 0 && strDate <= 9) {
strDate = "0" + strDate;
}
var currentdate = date.getFullYear() + seperator1 + month + seperator1 + strDate
+ " " + date.getHours() + seperator2 + date.getMinutes()
+ seperator2 + date.getSeconds();
return currentdate;
}
</script>
</html>
④直接运行服务端项目就可测试
第二种方式(普通javaweb项目):
参考网址:https://www.cnblogs.com/roy-blog/p/7211761.html
①引入依赖
<dependency> <groupId>org.java-websocket</groupId> <artifactId>Java-WebSocket</artifactId> <version>1.3.0</version> </dependency>
②WebSocket连接池工具类
package com.ah.fuzhou.riverchief.controller.check; import org.java_websocket.WebSocket; import java.util.*; /** * @author wph * @date 2018/8/16 15:55 */ public class WsPool { private static final Map<WebSocket, String> wsUserMap = new HashMap<WebSocket, String>(); /** * 通过websocket连接获取其对应的用户 * * @param conn * @return */ public static String getUserByWs(WebSocket conn) { return wsUserMap.get(conn); } /** * 根据userName获取WebSocket,这是一个list,此处取第一个 * 因为有可能多个websocket对应一个userName(但一般是只有一个,因为在close方法中,我们将失效的websocket连接去除了) * * @param user */ public static WebSocket getWsByUser(String userName) { Set<WebSocket> keySet = wsUserMap.keySet(); synchronized (keySet) { for (WebSocket conn : keySet) { String cuser = wsUserMap.get(conn); if (cuser.equals(userName)) { return conn; } } } return null; } /** * 向连接池中添加连接 * * @param inbound */ public static void addUser(String userName, WebSocket conn) { wsUserMap.put(conn, userName); // 添加连接 } /** * 获取所有连接池中的用户,因为set是不允许重复的,所以可以得到无重复的user数组 * * @return */ public static Collection<String> getOnlineUser() { List<String> setUsers = new ArrayList<String>(); Collection<String> setUser = wsUserMap.values(); for (String u : setUser) { setUsers.add(u); } return setUsers; } /** * 移除连接池中的连接 * * @param inbound */ public static boolean removeUser(WebSocket conn) { if (wsUserMap.containsKey(conn)) { wsUserMap.remove(conn); // 移除连接 return true; } else { return false; } } /** * 向特定的用户发送数据 * * @param user * @param message */ public static void sendMessageToUser(WebSocket conn, String message) { if (null != conn && null != wsUserMap.get(conn)) { conn.send(message); } } /** * 向所有的用户发送消息 * * @param message */ public static void sendMessageToAll(String message) { Set<WebSocket> keySet = wsUserMap.keySet(); synchronized (keySet) { for (WebSocket conn : keySet) { String user = wsUserMap.get(conn); if (user != null) { conn.send(message); } } } } }
③服务类
package com.ah.fuzhou.riverchief.controller.check; import org.java_websocket.WebSocket; import org.java_websocket.WebSocketImpl; import org.java_websocket.handshake.ClientHandshake; import org.java_websocket.server.WebSocketServer; import java.net.InetSocketAddress; /** * @author wph * @date 2018/8/16 15:58 */ public class WsServer extends WebSocketServer { public WsServer(int port) { super(new InetSocketAddress(port)); } public WsServer(InetSocketAddress address) { super(address); } @Override public void onOpen(WebSocket conn, ClientHandshake handshake) { // ws连接的时候触发的代码,onOpen中我们不做任何操作 } @Override public void onClose(WebSocket conn, int code, String reason, boolean remote) { //断开连接时候触发代码 userLeave(conn); System.out.println(reason); } @Override public void onMessage(WebSocket conn, String message) { System.out.println(message); if(null != message &&message.startsWith("online")){ String userName=message.replaceFirst("online", message);//用户名 userJoin(conn,userName);//用户加入 }else if(null != message && message.startsWith("offline")){ userLeave(conn); } } @Override public void onError(WebSocket conn, Exception ex) { //错误时候触发的代码 System.out.println("on error"); ex.printStackTrace(); } /** * 去除掉失效的websocket链接 * @param conn */ private void userLeave(WebSocket conn){ WsPool.removeUser(conn); } /** * 将websocket加入用户池 * @param conn * @param userName */ private void userJoin(WebSocket conn,String userName){ WsPool.addUser(userName, conn); } public static void main(String args[]){ WebSocketImpl.DEBUG = false; int port = 8887; // 端口 WsServer s = new WsServer(port); s.start(); } //http://www.blue-zero.com/WebSocket/ 在线测试地址 }
④直接运行就行