1. 程式人生 > >springboot整合websocket實現頁面線上客服聊天,並且解決無法注入例項的問題

springboot整合websocket實現頁面線上客服聊天,並且解決無法注入例項的問題

本文采用現在流行的springboot框架整合websocket實現線上客服的聊天功能,程式碼實現如下:

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.zqj</groupId>
	<artifactId>webchat</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<name>webchat</name>
	
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.2.RELEASE</version>
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>1.8</maven.compiler.source>
		<maven.compiler.target>1.8</maven.compiler.target>
	</properties>

	<dependencies>
		<!-- springboot web -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-tomcat</artifactId>
					<scope>compile</scope>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>
		
		<!--spring websocket -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-websocket</artifactId>
		</dependency>
		
		<!-- lombok pojo log -->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.0</version>
		</dependency>
	</dependencies>
	
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
			</plugin>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

springboot入口類:

package com.zqj.chat;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@SpringBootApplication
public class WebChatApplication 
{
    public static void main( String[] args )
    {
        SpringApplication.run(WebChatApplication.class, args);
    }
    
    /**
     * 
    * @Title: serverEndpointExporter  
    * @Description: 檢測服務類實現
    * @return ServerEndpointExporter 
    * @throws
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter (){
        return new ServerEndpointExporter();
    }
}

websocket服務實現WebSocketService

package com.zqj.chat.service;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import lombok.extern.slf4j.Slf4j;

import org.springframework.stereotype.Component;

@ServerEndpoint("/websocket/{userId}")
@Component
@Slf4j
public class WebSocketService {
	
	public static Map<String, Session> sessionMap = new ConcurrentHashMap<String, Session>();
	
	@OnOpen
	public void onOpen(@PathParam("userId") String userId,Session session) {
		log.info("WebSocketService onOpen: "+userId);
		if(sessionMap == null) {
			sessionMap = new ConcurrentHashMap<String, Session>();
		}
		sessionMap.put(userId, session);
	}
	
	@OnClose
	public void OnClose(@PathParam("userId") String userId) {
		log.info("WebSocketService OnClose: "+userId);
		sessionMap.remove(userId);
	}
	@OnMessage
	public void OnMessage(@PathParam("userId") String userId,Session session,String message) {
		log.info("WebSocketService OnMessage: "+message);
		for(Session session_ : sessionMap.values()) {
			session_.getAsyncRemote().sendText(message);
		}
	}
	
	@OnError
	public void error(Session session, Throwable t) {
		
		t.printStackTrace();
	}
}

測試頁面:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
    <title>聊天室</title>
    <link rel="stylesheet" type="text/css" href="css/easyui.css">
		
		<script type="text/javascript" src="js/jquery.min.js"></script>
		<script type="text/javascript" src="js/jquery.easyui.min.js"></script>
		<script type="text/javascript" src="js/json2.js"></script>
		<style type="text/css">
*{font-size: 14px; padding:0; margin:0;}
#chatRecord{
 position: relative;
 margin: 20px auto;
 border: 1px solid steelblue;
 width: 600px;
 height: 500px;
}

.msgContent{
 width:auto;
 max-width: 250px;
 height: auto;
 word-break: break-all;
 margin: 5px;
 padding: 3px;
 border-radius: 5px;
}
 
#chatZone .left{
list-style:none;
 text-align: left;
}
#chatZone .left .p{
 float: left;
 text-align: left;
 background-color: lightgrey;
 font-size: 4ex;
 
}
#chatZone .left .title{
 text-align: left;
 font-size: 5px;
 color:grey;
}
#chatZone .right{
float: right;
 list-style:none;
 text-align: right;
}
#chatZone .right .title{
 text-align: right;
 font-size: 5px;
 color:grey;
 clear:both;
}
 #chatZone .right .p{
 float: right;
 text-align: right;
 background-color: yellowgreen;
 font-size: 4ex;
 
}

 
</style>
</head>
<body>
     <p>
    帳號<input type="text" id="linkAgent" class="easyui-textbox" style="width: 150px" /> 
    暱稱<input type="text" id="nickname" class="easyui-textbox" style="width: 150px" /> 
    <a id="btnLink" href="javascript:void(0)" class="easyui-linkbutton c1">開始聊天</a></p>
    <div data-options="region:'center'" class="easyui-panel" style="width: 50%;height:500px;  padding: 5px;" id="chatRecord">
						<ul class="chatDialog-main clearfix" id="chatZone">
				
						
				
						</ul>
					</div>
		<div class="easyui-panel" style="width: 50%; padding: 5px;">
							<table height="100%" cellpadding="0px" cellspacing="0px">
								<tr>
									<td height="100px">
										<table cellpadding="5px" cellspacing="0" border="0">
											<tr style="vertical-align: middle;">
												<td>
													<textarea
														style="width: 600px; height: 100px; overflow: auto; vertical-align: middle;"
														id="txtMessage" name="txtMessage"></textarea>
												</td>
												<td style="width: 6px"></td>
												<td style="vertical-align: middle;">
													<a id="btnSend" href="javascript:void(0)"
														class="easyui-linkbutton c3" data-options="size:'large'">傳送</a>
												</td>
											</tr>
										</table>
									</td>
								</tr>
							</table>
						</div>						
    
</body>
<script type="text/javascript">
function getNowFormatDate() {
    var date = new Date();
    var seperator1 = "-";
    var seperator2 = ":";
    var month = date.getMonth() + 1;
    var strDate = date.getDate();
   	var hours = date.getHours();
   	var minutes = date.getMinutes();
   	var seconds = date.getSeconds();
    if (month >= 1 && month <= 9) {
        month = "0" + month;
    }
    if (strDate >= 0 && strDate <= 9) {
        strDate = "0" + strDate;
    }
    if (hours >= 0 && hours <= 9) {
    	hours = "0" + hours;
    }
    if (minutes >= 0 && minutes <= 9) {
    	minutes = "0" + minutes;
    }
    if (seconds >= 0 && seconds <= 9) {
    	seconds = "0" + seconds;
    }
    var currentdate = date.getFullYear() + seperator1 + month + seperator1 + strDate
            + " " + hours + seperator2 + minutes
            + seperator2 + seconds;
    return currentdate;
}
$(function() {
	var websocket;
	var nickname;
	$(window).keyup(function(event){
		if(event.keyCode == 13) {
			$("#btnSend").click();
			return true;
        } 
	});
	$("#btnSend").click(function() {
		var from = $("#linkAgent").val();
		var msg = $("#txtMessage").val();
		var obj=new Object();
		obj.from=from;
		obj.message=msg;
		
		obj.nickname=nickname;
		var json = JSON.stringify(obj);
		var result =websocket.send(json);
		var message ="<li class='msgContent right'>"+
						"<p class='msgContent right title'>"+nickname+" ("+getNowFormatDate()+"):</p>"+
		   				"<p class='msgContent right p'>"+msg+"</p></li>"+
		   				"<div style='clear:both'></div>";
		$("#chatZone").append(message);
		$("#txtMessage").val("");
		
	});
	
	$("#btnLink").click(function() {
		var agent = $("#linkAgent").val();
		nickname = $("#nickname").val();
		if('WebSocket' in window){
			
		}else{
			alert("您的瀏覽器版本太低,請升級瀏覽器版本!");
			return;
		}
		if('WebSocket' in window){
			var wsUrl = "ws://"+window.location.host+"/websocket/";
			
			websocket = new WebSocket(wsUrl+agent);
		
		    
		     
		   //連線發生錯誤的回撥方法
		     websocket.onerror = function(){
		         console.log(" websocket.onerror :error");
		     };

		     //連線成功建立的回撥方法
		     websocket.onopen = function(event){
		     	
		     }

		     //接收到訊息的回撥方法
		     websocket.onmessage = function(event){
		    	 msg = eval('(' + event.data + ')');
		    	 if(msg.from != agent) {
		    		 var message ="<li class='msgContent left'>"+
						"<p class='msgContent left title'>"+msg.nickname+" ("+getNowFormatDate()+"):</p>"+
		   				"<p class='msgContent left p'>"+msg.message+"</p></li>"+
		   				"<div style='clear:both'></div>";
						$("#chatZone").append(message);
		    	 }
		     	
		     }

		     //連線關閉的回撥方法
		     websocket.onclose = function(){
		    	console.log(" websocket.onclose :close");
		   		websocket = new WebSocket(wsUrl+agent);
		     }

		     //監聽視窗關閉事件,當視窗關閉時,主動去關閉websocket連線,防止連線還沒斷開就關閉視窗,server端會拋異常。
		     window.onbeforeunload = function(){
		         websocket.close();
		     }
		}
	});
	
});
</script>
</html>

開啟瀏覽器訪問:http://127.0.0.1:8080/webchat.html,介面如下:


在開發過程中遇到了使用註解@ServerEndpoint時,會發生無法自動注入其他例項的情況,解決方案如下:

先寫一個config類:

package com.libang.manage.websocket;

import javax.websocket.server.ServerEndpointConfig.Configurator;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyEndpointConfigure extends Configurator implements
		ApplicationContextAware {

	private static volatile BeanFactory context;

	@Override
	public <T> T getEndpointInstance(Class<T> clazz)
			throws InstantiationException {
		return context.getBean(clazz);
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		System.out.println("auto load" + this.hashCode());
		MyEndpointConfigure.context = applicationContext;
	}

}

將WebsocketService類上的@ServerEndpoint(value="/websocket/{userId}")改成

@ServerEndpoint(value="/websocket/{userId}",configurator=MyEndpointConfigure.class) 

就可以完美的使用@Autowired注入例項。

相關推薦

springboot整合websocket實現頁面線上聊天並且解決無法注入例項的問題

本文采用現在流行的springboot框架整合websocket實現線上客服的聊天功能,程式碼實現如下:pom.xml:<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.

SpringBoot整合WebSocket實現多個服務通訊

import com.test.www.socket.WebSocketServer; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.

springboot整合websocket實現訊息推送.

springboot整合websocket實現訊息推送 1.maven配置 2.書寫後端程式碼 3.書寫前端程式碼 4.測試 1.maven依賴 <dependency> <groupId>org

springboot整合websocket實現一對一訊息推送和廣播訊息推送

springboot基礎環境 請參考springboot文件 maven依賴    

(原創)用.NET Core實現一個線上系統(上篇)

前言 沒有視訊的介紹顯得尤為空白倉促。所以,如果你不趕時間,看看視訊先 → → 戳我看視訊 ← ←  線上演示訪客端:http://role.fuyue.xyz/visitor/index客服端:http://role.fuyue.xyz/

一分鐘讓自己的網頁接入qq線上聊天功能

第一步:登入qq推廣官網  --> http://shang.qq.com/v3/widget.html 第二步:登入之後有3種qq元件樣式可供我們選擇 選擇之後複製下面對應的程式碼到自己的專案所要使用的位置即可使用qq聊天功能了哦~~ 最後即可

一款強大的網站線上聊天系統:whisper搭建教程

簡介 whisper是一個線上客服系統原始碼,採用thinkphp5+Gatewayworker編寫,效能強悍。自己搭建,控制在自己,也無需為您的資料安全擔心,您可以應用在任何的正規的網站,只需要新增一段簡單的js程式碼,就可以使您的網站擁有線上客服功能。 截圖

.net core 和 WPF 開發升訊威線上與營銷系統:使用 WebSocket 實現端通訊

本系列文章詳細介紹使用 .net core 和 WPF 開發 升訊威線上客服與營銷系統 的過程。本產品已經成熟穩定並投入商用。 線上演示環境:[https://kf.shengxunwei.com](https://kf.shengxunwei.com) 注意:演示環境僅供演示交流與評估,不保證 7x24 小

用php+mysql+ajax實現淘寶或阿裏旺旺聊天功能 之 前臺頁面

group -a com 現在 中間 數據 bottom margin -m 首先來看一下我已經實現的效果圖: 消費者頁面:(本篇隨筆) (1)會顯示店主的頭像 (2)當前用戶發送信息顯示在右側,接受的信息,顯示在左側 店主或客服頁面:(下一篇隨筆) (1)在左側有一個列

用php+mysql+ajax實現淘寶或阿裏旺旺聊天功能 之 後臺頁面

聯系人 http esc hold 聊天內容 12px onclick onf pda 在上一篇隨筆中,我們已經看了如何實現前臺的對話功能;前臺我限定了店主只有一人,店鋪只有一個,所有比較單一,但後臺就不一樣了,而後臺更像是我們常見的聊天軟件;當然,前臺也應該實現這種效果,

springboot+websocket實現頁面後臺長連線

    在自己整合websocket時踩了一些坑,給大家分享出來希望可以幫到有需要的小夥伴,我的測試案例中有什麼問題請指出,大家共同學習,現在開始上程式碼; 第一步,新增pom.xml依賴 <?xml version="1.0" encodi

SpringBoot整合websocket並區分不同頁面來源

首先web.xml新增支援 <!-- 新增websocket支援 --> <dependency> <groupId>org.springframework.boot</groupId>

微信小程式、微信公眾號轉私人微訊號實現24小時線上

    現在不少企業都有自己的微信公眾號、服務號、小程式,其中也添加了客服功用。     但據所知,官方提供的僅是網頁版的客服系統,我們的客服人民必須開啟網頁進行“守候”。     我們為什麼不能將

webSocket 實現 聊天邏輯

文章目錄 寫在前面 程式碼 前端 客服端 使用者端 後端 各事件處理類 socket連線管理類 測試類 效果圖 寫在前

websocket實現頁面資料實時載入(Springboot+vue)

在這裡先提供兩種思路。要實現頁面資料的實時載入有兩種方式,第一種是長輪詢的方式。要麼是後臺長輪詢,檢測到資料變化時,通知websocket你該更新一下資料了。要麼是前臺長輪詢,每隔一段時間發起請求獲取資料。結合前後臺長輪詢的方式,這裡想給各位推薦第二種--手動通知。我不頻繁發起請求,我只在當我後臺資

關於微信線上系統的實現(已經證實可用)

1.微信線上客服系統需要認證服務號資格,如果沒有認證是沒辦法完成 和大家分享下我實現的方式: 微信前端接入資訊到資料庫->做一個JSP 頁面定時重新整理(或者在有資料插入的時候涮新)->取使用者發來的資料 主要是openid 和內容(也支援語音和圖片)到JSP

.net core 和 WPF 開發升訊威線上與營銷系統:使用 TCP協議 實現穩定的

本系列文章詳細介紹使用 .net core 和 WPF 開發 升訊威線上客服與營銷系統 的過程。本產品已經成熟穩定並投入商用。 線上演示環境:[https://kf.shengxunwei.com](https://kf.shengxunwei.com) 注意:演示環境僅供演示交流與評估,不保證 7x24 小

.net core 和 WPF 開發升訊威線上系統:怎樣實現拔網線也不丟訊息的高可靠通訊(附視訊)

本系列文章詳細介紹使用 .net core 和 WPF 開發 升訊威線上客服與營銷系統 的過程。本產品已經成熟穩定並投入商用。 線上演示環境:[https://kf.shengxunwei.com](https://kf.shengxunwei.com) 注意:演示環境僅供演示交流與評估,不保證 7x24 小

SpringBoot 4.SpringBoot 整合 devtools 實現熱部署

exce 機制 maven optional 引入 實現 目錄 觸發 exclude 一、添加 devtools 依賴 <!-- Spring boot 熱部署 : 此熱部署會遇到 java.lang.ClassCastException 異常 --

SpringBoot整合Mybatis實現增刪改查的功能

ger 開始 pan ble img 映射 講師 -name date SpringBoot框架作為現在主流框架之一,好多框架都漸漸的移植到SpringBoot中來。前面我給大家介紹過redis,jpa等等的的整合,今天在這裏給大家介紹一下Mybatis的整合過程。 S