0.pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
1.启动器(Application)或者webConfig中
/**
* 如果不是spring boot项目,那就不需要进行这样的配置,因为如果在tomcat中运行的话,tomcat会扫描带有@ServerEndpoint的注解成为websocket,而spring boot项目中需要由这个bean来提供注册管理。
* @return
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
2.服务器端
package com.uniview.gdp.websocket;
import com.fasterxml.jackson.core.type.TypeReference;
import com.uniview.gdp.utils.JacksonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Component
/**
* @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
* 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
* 使用websocket的核心,就是一系列的websocket注解,@ServerEndpoint是注册在类上面开启。
*/
@ServerEndpoint("/websocket/{user}")
public class websocket {
private static String user;
//连接时执行
@OnOpen
public void onOpen(@PathParam("user") String user, Session session) throws IOException {
System.out.println("新连接:" + user);
}
//关闭时执行
@OnClose
public void onClose(){
System.out.println(user+" is close");
}
//收到消息时执行
@OnMessage
public void onMessage(String message, Session session) throws IOException {
System.out.println("来自客户端的消息:" + message);
/* Map<String,Object> result = new HashMap<>();
result.put("message", message);
session.getBasicRemote().sendText(JacksonUtil.mapToJSon(result));*/
// websocket sesion发送消息
//通过这两个方法 可以实现服务器主动推送
session.getBasicRemote().sendText(message);
session.getAsyncRemote().sendText(message);
/*session.close();*/
}
//连接错误时执行
@OnError
public void onError(Session session, Throwable error){
System.out.println("用户id为:{}的连接发送错误"+this.user);
error.printStackTrace();
}
}
3.html页面
<!DOCTYPE HTML>
<html>
<head>
<title>首页</title>
<script type="text/javascript">
var websocket = null;
function startWebSocket(){
//判断当前浏览器是否支持WebSocket
if('WebSocket' in window){
//访问路径 端口号+定义的websocket地址
websocket = new WebSocket("ws://localhost:8080/websocket/333");
console.log("link success")
}else{
alert('Not support websocket')
}
//连接发生错误的回调方法
websocket.onerror = function(){
setMessageInnerHTML("error");
};
//连接成功建立的回调方法
websocket.onopen = function(event){
setMessageInnerHTML("open");
}
console.log("-----")
//接收到消息的回调方法
websocket.onmessage = function(event){
setMessageInnerHTML(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 send(){
var message = document.getElementById('text').value;
websocket.send(message);
}
</script>
</head>
<body>
<section class="Hui-article-box">
<nav class="breadcrumb"><i class="Hui-iconfont"></i> webSocket
<a class="btn btn-success radius r" style="line-height:1.6em;margin-top:3px"
href="javascript:location.replace(location.href);" title="刷新"><i class="Hui-iconfont"></i></a>
</nav>
<div class="Hui-article">
<article class="cl pd-20">
websocket Demo---- user000 <br />
<input id="text" type="text" />
<button οnclick="startWebSocket()"> connect </button>
<button οnclick="send()"> Send </button>
<button οnclick="closeWebSocket()"> Close </button>
<div id="message"> </div>
</article>
</div>
</section>
<script>
</script>
</body>
</html>
4.控制器
@GetMapping("/webSocket")
public String webSocket(){
return "internal/system/webSocket";
}
springboot使用websocket时,打成war包,发布到服务器,项目启动报错问题
如果用外置 tomcat ,要注释掉以下代码,否则启动项目会报错,用 springboot 内置 tomcat 就得放开以下代码@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
websocket通信failed to execute 'send'问题的解决
在建立web socket通信后,发送数据时,出现下图所示现象:
问题代码演示
function TestSockets() {
//实例化一个WebSocket对象
var socket = new WebSocket("ws://127.0.0.1:8000/ws");
//声明一个消息
var message = {
nickname: "benben_2015",
email: "123456@qq.com",
content: "I love programming"
};
//web sockets只能通过连接发送纯文本数据,所以对于复杂的数据结构,在通过连接发送之前,必须进行序列化。
socket.send(JSON.stringify(message));
}
要明白这个问题产生的原因,就需要了解websocket的几个状态。通常在实例化一个websocket对象之后,客户端就会与服务器进行连接。但是连接的状态是不确定的,于是用readyState属性来进行标识。它有四个值,分别对应不同的状态:
- CONNECTING:值为0,表示正在连接;
- OPEN:值为1,表示连接成功,可以通信了;
- CLOSING:值为2,表示连接正在关闭;
- CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
这样问题的原因就很明显了,之所以数据不能发送出去,是因为websocket还处在“CONNECTING”状态下,连接还没有成功。
解决办法
只要在函数中添加对状态的判断,在状态为OPEN时,执行send方法即可。方法一代码如下:
function TestSockets() {
var socket = new WebSocket("ws://127.0.0.1:8000/ws");
var message = {
nickname: "benben_2015",
email: "123456@qq.com",
content: "I love programming"
};
//添加状态判断,当为OPEN时,发送消息
if (socket.readyState===1) {
socket.send(JSON.stringify(message));
}else{
//do something
}
}
也可以设置事件监听,当为OPEN时,执行send操作。方案二代码如下:
function TestSockets() {
var socket = new WebSocket("ws://127.0.0.1:8000/ws");
var message = {
nickname: "benben_2015",
email: "123456@qq.com",
content: "I love programming"
};
message = JSON.stringify(message);
//添加事件监听
socket.addEventListener('open', function () {
socket.send(message)
});
}
实例对象websocket的onopen属性,可以用来指定连接成功后的回调函数。方案三代码如下:
function TestSockets() {
var socket = new WebSocket("ws://127.0.0.1:8000/ws");
//设置连接成功后的回调函数
socket.onopen=function () {
console.log("socket has been opened");
var message = {
nickname: "benben_2015",
email: "123456@qq.com",
content: "I love programming"
};
message = JSON.stringify(message);
socket.send(message);
};
}
转载文章:
https://blog.csdn.net/benben_2015/article/details/79294547
https://blog.csdn.net/qq_18649209/article/details/79529434