前后端分离之使用websocket,springboot+vue
---前言提要---
在百度、谷歌、CSDN、博客园...几经折腾之后,终于达到了我想要的结果。springboot+vue,前后端分离项目,网上的大多不是前后端分离,所以排错怎么也排不出,说到底我产生了依赖,只想从网上寻找答案,然后简单的一了百了,而忘记了思考,为什么出错。
其实错误很简单,我是前后端分离,前后端项目的端口都不一样,一个是8080,一个是自定义的63000,在前端发起的请求到了前端,而前端没有启动websocket这个服务,所以连接超时,无关配置无关代码,只是请求错了而已。
这个教训告诉我们,遇到事先自己想一想,想不通的时候再抱着疑问 一边想一边去查资料。
---正确配置---
后端pom:(可参考网上其他教程pom导包)
<!--ws(start)-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>1.3.5.RELEASE</version>
</dependency>
<!--ws(end)-->
后端websock配置文件:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
后端websock具体实现:
注意@ServerEndpoint("/websocket")是你连接时的url,如果后端为127.0.0.1:8080,那么前端websocket连接url写为: 127.0.0.1:8080/websocket
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import lombok.extern.slf4j.Slf4j;
@Slf4j
// @ServerEndpoint("/websocket/{username}")
@ServerEndpoint("/websocket")
@Component // 此注解千万千万不要忘记,它的主要作用就是将这个***纳入到Spring容器中进行管理
public class WebSocketServer {
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
/**
* 连接建立成功调用的方法*/
@OnOpen
public void onOpen(Session session) {
this.session = session;
webSocketSet.add(this); //加入set中
addOnlineCount(); //在线数加1
log.info("有新连接加入!当前在线人数为" + getOnlineCount());
try {
sendMessage("有新连接加入!当前在线人数为" + getOnlineCount());
} catch (IOException e) {
log.error("websocket IO异常");
}
}
// //连接打开时执行
// @OnOpen
// public void onOpen(@PathParam("user") String user, Session session) {
// currentUser = user;
// System.out.println("Connected ... " + session.getId());
// }
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
webSocketSet.remove(this); //从set中删除
subOnlineCount(); //在线数减1
log.info("有一连接关闭!当前在线人数为" + getOnlineCount());
}
/**
* 收到客户端消息后调用的方法
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("来自客户端的消息:" + message);
//群发消息
for (WebSocketServer item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 发生错误
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误");
error.printStackTrace();
}
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 群发自定义消息
* */
public static void sendInfo(String message) throws IOException {
log.info(message);
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--;
}
}
这里要注意的是:
- 用onMessage()接收前端用户发来的消息。
- 用sendMessage()给前端用户发送消息。
前端vue主要js:(实际使用可以将我的部分自定义方法去掉)
created() {
this.webSocket(); // 连接WebSocket
},
destroyed :function() {
this.websocketclose();
},
methods: {
say() {
if (this.websock == null) {
alert("连接异常:null");
return 'null'
}
if(this.userInput===""){
this.tips('请输入聊天内容');
}else{
this.tips('');
}
this.websocketsend(this.userInput);
this.userInput = '';
},
webSocket :function() {
// 建立socket连接
if ('WebSocket' in window) {//判断当前浏览器是否支持webSocket
this.websock = new WebSocket("ws://localhost:63000/websocket");//与后端服务建立连接
} else {
alert('你的浏览器暂不支持websocket :(');
}
console.log(this.websock);
this.websock.onopen = this.websocketonopen;
this.websock.onerror = this.websocketonerror;
this.websock.onmessage = this.websocketonmessage;
this.websock.onclose = this.websocketclose;
},
websocketonopen :function() {
console.log("WebSocket连接成功");
// let data = {
// code: 0,
// msg: '这是client:初次连接'
// }
var data = '这是'+'user'+',加入了连接';
this.websocketsend(data)
},
websocketonerror :function(e) {
this.tips("WebSocket连接发生错误");
// console.log("WebSocket连接发生错误");
},
websocketonmessage :function(e) { // 数据接收
// 显示消息内容
this.setMessageInnerHTML(e.data);
},
websocketsend :function (data) { // 数据发送
// this.tips("数据发送中...");
this.websock.send(this.niming+": "+data)
},
websocketclose :function(e) {
this.websock.close();
this.tips("WebSocket连接关闭");
console.log("connection closed (" + e + ")");// e.code
},
//将消息显示在网页上
setMessageInnerHTML(msg) {
document.getElementById('message').innerHTML += msg + '<br/>';
},
//提示信息显示在网页上
tips (msg) {
document.getElementById('ts').innerHTML = msg ;
}
}
这里要注意的是:
- this.websock = new WebSocket("ws://localhost:63000/websocket");//建立连接,这里的63000是我后端自定义的端口号,请自行改成后端的端口。
- 页面created时建立连接,页面close时断开连接。
---写在最后---
可能遇到的错误及注意事项:
- 检查new WebSocket("ws://localhost:8080/websocket");的路径是否正确、是否以ws://开头
- url是否和后端配置的一致,单词是否拼写正确,导包是否正确
- 前后端端口号是否重复占用
- pom引包是否正确
- tomcat是否使用7以上版本,建议使用tomcat8以及较新的springboot版本
- 后端配置文件是否注入spring
- 是否设置了拦截器
参考博文:https://blog.csdn.net/eieiei438/article/details/82879887