SpringBoot+Maven+前后端分离+WebSocket+nginx
Maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
后端代码
WebSocketServer文件:
import com.xad.util.TimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@Slf4j
@Component
@ServerEndpoint("/websocket/chat/{roomName}")
public class WebSocketServer {
// 使用map来收集session,key为roomName,value为同一个房间的用户集合
// concurrentMap的key不存在时报错,不是返回null
private static final Map<String, Set<Session>> rooms = new ConcurrentHashMap<>();
//注入聊天的service方法
@OnOpen
public void connect(@PathParam("roomName") String roomName, Session session) {
log.info("roomName={}", roomName);
// 将session按照房间名来存储,将各个房间的用户隔离
if (!rooms.containsKey(roomName)) {
// 创建房间不存在时,创建房间
Set<Session> room = new HashSet<>();
//添加用户
room.add(session);
rooms.put(roomName, room);
} else {
// 房间已存在,直接添加用户到相应的房间
rooms.get(roomName).add(session);
}
log.info("客户端已连接");
}
@OnClose
public void disConnect(@PathParam("roomName") String roomName, Session session) {
rooms.get(roomName).remove(session);
System.out.println("客户端已断开连接");
}
@OnMessage
public void sendMessage(@PathParam("roomName") String roomName, String msg, Session session) {
//创建时间
String time = TimeUtil.getNowTime();
String message;
for (Session session1 : rooms.get(roomName)) {
//判断是否发送给自己
if (session1.equals(session)) {
//发送给自己
message = msg;
} else {
//发送给别人
message = msg;
}
//可以在此保存数据到数据库
// 注意存储到数据库
// 根据roomId查询用户的全部信息
// 数据库聊天字段
// 你的id,别人的id,message,内容
//发送
try {
session1.getBasicRemote().sendText(message);
} catch (IOException e) {
log.error("websocket消息发送异常");
e.printStackTrace();
}
log.info("websocket消息发送成功");
}
}
}
WebSocketConfig文件:
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();
}
}
前端代码JS部分
websocket.html文件:
var websocket = null;
if ('WebSocket' in window) {
websocket = new WebSocket("ws://域名(IP):20006/demo/websocket/chat/"+roomName);
} else {
alert('该浏览器不支持websocket');
}
//连接发生错误的回调方法
websocket.onerror = function () {
console.log('连接失败');
};
//连接成功建立的回调方法
websocket.onopen = function (event) {
console.log('建立连接');
};
//接收到消息的回调方法
websocket.onmessage = function (event) {
console.log('收到消息:' + event.data);
var str = '<p>' + event.data + ' ' + date + '</p>';
$('.message').append(str);
};
//连接关闭的回调方法
websocket.onclose = function () {
console.log('连接关闭');
};
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
websocket.close();
};
//关闭连接
function closeWebSocket() {
websocket.close();
}
//发送消息
function send() {
var chat = $('.chat').val();
if (chat) {
websocket.send(chat);
}
$('.chat').val("");
}
nginx配置
上面是项目配置,下面是websocket配置
location /demo/ {
proxy_pass http://localhost:20006;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /demo/websocket/ {
proxy_pass http://localhost:20006;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_connect_timeout 4s;
proxy_read_timeout 7200s;
proxy_send_timeout 12s;
}
注:添加websocket依赖后,@SpringBootTest运行可能报错
改为:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)