1、先來看看效果吧
這個項目是spring boot的裡搞的,隻要把類放到項目裡就可以運作了
1、pom.xml 添加依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2、添加一個java檔案(websocket 的預設服務)
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
3、在添加一個接收資料的工具類
@ServerEndpoint(value = "/websocket/{userId}")
@Component
public class WebSocketServer {
private static int onlineCount = 0;
private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
private static ConcurrentHashMap<String,Session> webSocketMap = new ConcurrentHashMap<String,Session>();
private Session session;
/**
* 連接配接建立成功調用的方法
*/
@OnOpen
public void onOpen(Session session,@PathParam("userId")String userId) {
this.session = session;
webSocketSet.add(this); // 加入set中
webSocketMap.put(userId, session);
addOnlineCount(); // 線上數加1
System.out.println("有新連接配接加入!目前線上人數為" + getOnlineCount());
//推送我到所有人清單裡
// try {
// sendMessage("連結已經建立!");
// } catch (IOException e) {
// System.out.println("IO異常");
// }
sendUserList(session);
}
public void sendUserList(Session session) {
Map<String, String> map = session.getPathParameters();
Enumeration<String> sets= webSocketMap.keys();
while(sets.hasMoreElements()) {
String userid= sets.nextElement();
Enumeration<String> sett= webSocketMap.keys();
while (sett.hasMoreElements()) {
String string = (String) sett.nextElement();
webSocketMap.get(userid).getAsyncRemote().sendText("list:"+string);
}
}
}
/**
* 連接配接關閉調用的方法
*/
@OnClose
public void onClose(Session session) {
Map<String, String> map = session.getPathParameters();
webSocketSet.remove(this); // 從set中删除
webSocketMap.remove(map.get("userId"));
subOnlineCount(); // 線上數減1
System.out.println("有一連接配接關閉!目前線上人數為" + getOnlineCount());
//告訴所有人我退出了
Enumeration<String> sets= webSocketMap.keys();
while (sets.hasMoreElements()) {
String str = (String) sets.nextElement();
webSocketMap.get(str).getAsyncRemote().sendText("clist:"+map.get("userId"));
}
}
/**
* 收到用戶端消息後調用的方法
*
* @param message
* 用戶端發送過來的消息
*/
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("來自用戶端的消息:" + message);
// 群發消息
// for (WebSocketServer item : webSocketSet) {
// try {
// item.sendMessage(message);
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
//發給個人
String[] msg= message.split("\\^");
Map<String, String> map = session.getPathParameters();
Session sessi=webSocketMap.get(msg[0]);
if(sessi==null) {
//接入電話中心
session.getAsyncRemote().sendText("error:使用者已下線!");
}else {
sessi.getAsyncRemote().sendText(map.get("userId")+"^"+msg[1]);
}
}
/**
* 發生錯誤時調用
*/
@OnError
public void onError(Session session, Throwable error) {
System.out.println("發生錯誤");
error.printStackTrace();
}
public void sendMessage(String message) throws IOException {
this.session.getAsyncRemote().sendText(message);
}
/**
* 群發自定義消息
* */
public static void sendInfo(String message) throws IOException {
for (WebSocketServer item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
continue;
}
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocketServer.onlineCount--;
}
}
3、建立一個html
<!DOCTYPE HTML>
<html>
<head>
<title>My WebSocket</title>
<style type="text/css">
.main{
display:flex;
}
#windows{
flex:0 0 auto;
}
.main > div{
margin-left: 15px;
flex:1;
}
.chat-bottom input{
display: inline-block;
padding: 5px 10px;
border: 1px solid #ccc;
border-radius: 4px;
margin: 0 10px;
width: 80%;
}
.chat-bottom button{
padding: 5px 10px;
border-radius: 4px;
color:#fff;
background-color: green;
border:none;
}
.chat-main{
overflow: auto;
box-sizing:border-box;
padding: 10px 15px;
margin-bottom: 15px;
}
.chat-main .people-say{
margin: 15px 0;
}
.other-say,.i-say{
overflow: auto;
}
.other-say > div:not(.other-name){
float:left;
padding: 5px 10px;
background: #ccc;
border-radius: 4px;
}
.i-say > div{
float: right;
padding: 5px 10px;
background: green;
color:#fff;
border-radius: 4px;
}
.other-name{
width: 100%;
}
.msg-tip{
position: absolute;
top:50%;
right:5px;
transform:translateY(-50%);
background: red;
border-radius: 10px;
height: 15px;
line-height: 15px;
color: #fff;
padding: 1px 3px;
font-size: 12px;
min-width: 11px;
text-align: center;
}
</style>
</head>
<body>
<div class="main">
<div id="windows" style="width: 200px; height: 400px; border: solid 1px #FFCC00;">
<div data='-1' id="title"
style="width: 100%; height: 50px; background-color: #DDDDDD; text-align: center; line-height: 50px;">
</div>
</div>
<div style="width: 300px;height: 400px;border: solid 1px #FFCC00; ">
<div data='-1' id="titles"
style="width: 100%; height: 50px; background-color: #DDDDDD; text-align: center; line-height: 50px;">
</div>
<input type="hidden" id="cuser"/>
<div class="chat-main" style="height: 300px;width: 100%">
</div>
<div class="chat-bottom" style="height: 50px;width: 100%">
<input id="msgtext" type="text" /><button οnclick="sendMsg()">發送</button>
</div>
</div>
</div>
</body>
<script type="text/javascript"
src="/static/hui/lib/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript">
var msgArr=[];
var chatbox = $('.chat-main')
//判斷是消息還是清單
String.prototype.startWith = function(str) {
var reg = new RegExp("^" + str);
return reg.test(this);
}
var websocket = null;
var timestamp = Date.parse(new Date());
//判斷目前浏覽器是否支援WebSocket
if ('WebSocket' in window) {
websocket = new WebSocket("ws://10.130.87.227:8081/websocket/" + timestamp);
} else {
alert('Not support websocket');
}
//連接配接發生錯誤的回調方法
websocket.onerror = function() {
setMessageInnerHTML("error");
};
//連接配接成功建立的回調方法
websocket.onopen = function(event) {
$("#title").html("建立連結");
}
//接收到消息的回調方法
websocket.onmessage = function(event) {
//setMessageInnerHTML(event.data);
if(event.data.startWith("list")){
var uid=event.data.replace("list:","");
userList(uid);
}else if(event.data.startWith("clist")){
var uid=event.data.replace("clist:","");
cuserList(uid);
}else if(event.data.startWith("error")){
var error=event.data.replace("error:","");
alert(error);
}else {
userMsg(event.data);
}
}
//連接配接關閉的回調方法
websocket.onclose = function() {
setMessageInnerHTML("close");
}
//監聽視窗關閉事件,當視窗關閉時,主動去關閉websocket連接配接,防止連接配接還沒斷開就關閉視窗,server端會抛異常。
window.onbeforeunload = function() {
websocket.close();
}
//将消息顯示在網頁上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
//關閉連接配接
function closeWebSocket() {
websocket.close();
}
//發送消息
function sendMsg(){
var message= $("#msgtext").val();
if(message==""){
return;
}
var cuser= $("#cuser").val();
if(cuser==""){
alert("請選擇會話人員!");
return;
}
$(".chat-main").append(`<div class="i-say people-say">
<div>`+message+`</div>
</div>`);
chatbox.scrollTop(chatbox[0].scrollHeight);
websocket.send(cuser+"^"+message);
$("#msgtext").val("");
}
//使用者替換
function cuserList(uid){
$.each($("#windows").children(),function(index,item){
var d= $(item).attr("data");
if(uid==d){
//校驗是否在目前會話
var cuser= $("#cuser").val();
if(uid==cuser){
$("#cuser").val("");
$("#titles").html("目前使用者已下線。");
}
$(item).remove();
}
})
}
function userList(uid){
if(timestamp==uid){
return;
}
var b=false;
$.each($("#windows").children(),function(index,item){
var d= $(item).attr("data");
if(uid==d){
b=true;
}
})
if(!b){
$("#windows").append(`
<div οnclick="msgWindow(this,`+uid+`)" data="`+uid+`" style="position:relative;width: 100%;height: 40px;border-bottom: solid 1px #DDDDDD;line-height: 40px; " >
`+uid+`
</div>`);
}
}
function msgWindow(obj,uid){
var cu= $("#cuser").val();
if(cu==uid){
return;
}
$("#cuser").val(uid);
$("#titles").html("您正在和"+uid+"聊天中!");
$(".chat-main").html("");
$.each(msgArr,function(index,item){
if(item.key==uid){
$.each(item.value,function(ins,it){
$(".chat-main").append(`<div class="other-say people-say">
<div class="other-name">`+uid+`</div>
<div>`+it+`</div>
</div>`);
chatbox.scrollTop(chatbox[0].scrollHeight);
})
msgArr.splice(index);
}
});
$(obj).children(".msg-tip").remove();
}
//消息處理
function userMsg(msg){
var msgs=msg.split("^");
var cu= $("#cuser").val();
if(cu==msgs[0]){
$(".chat-main").append(`<div class="other-say people-say">
<div class="other-name">`+cu+`</div>
<div>`+msgs[1]+`</div>
</div>`);
chatbox.scrollTop(chatbox[0].scrollHeight);
}else{
var obj=[];
$.each(msgArr,function(index,item){
if(item.key==msgs[0]){
obj=item.value;
msgArr.splice(index);
obj.push(msgs[1]);
msgArr.push({key:msgs[0],value:obj});
}
});
if(obj.length==0){
//新增
obj.push(msgs[1]);
msgArr.push({key:msgs[0],value:obj});
}
//找到清單資料
$.each($("#windows").children(),function(index,item){
var d= $(item).attr("data");
if(msgs[0]==d){
$(item).append(`<span class="msg-tip">`+obj.length+`</span>`);
}
})
}
}
</script>
</html>
到此,這個聊天的就可以用了。大家試試吧
注意:在這個(接收資料的工具類)裡是無法進行其他spring 管理的類注入的,因為被@ServerEndpoint 修飾的類是不歸spring 管理的。如果要注入其他類可以使用一下辦法(加入紅色部分即可)
@ServerEndpoint(value = "/websocket/{userId}",configurator = SpringConfigurator.class)