大概目录结构

依赖只引入了JSP 和SpringBoot整合WebSocket Spring Web

index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="${pageContext.request.contextPath}/js/jquery.min.js"></script>
<title>SpringBoot+WebSocket+JSP</title>
</head>
<body style="margin: 45px;">
<h4>在线聊天室</h4>
<div class="form-group">
<label for="content"></label>
<textarea id="content" readonly="readonly" cols="80" rows="15"></textarea>
</div>
<div class="form-group" style="margin-top: 8px">
<textarea id="message" cols="80" rows="5" placeholder="请输入消息"></textarea>
<div style="margin-top: 10px">
<button id="toSend" class="btn btn-info">发送</button>
<button id="user_exit" class="btn btn-danger">离开</button>
<input id="username" value="${username}" style="display: none">
</div>
</div>
<script type="text/javascript">
$(function () {
var ws;
if ("WebSocket" in window) {
var baseUrl = 'ws://localhost:8080/websocket/';
var userName = $('#username').val();
ws = new WebSocket(baseUrl + userName);
// 连通之后的回调事件,建立连接
ws.onopen = function () {
console.log("建立 websocket 连接...");
};
// 接收后台服务端的消息
ws.onmessage = function (event) {
$('#content').append(event.data + '\n\n');
console.log("接收到服务端发送的消息..." + event.data + '\n');
};
ws.onerror = function (event) {
console.log("websocket发生错误..." + event + '\n');
}
// 连接关闭的回调事件
ws.onclose = function () {
$('#content').append('[' + userName + '] 已离开!');
console.log("关闭 websocket 连接...");
};
} else {
// 浏览器不支持 WebSocket
alert("您的浏览器不支持WebSocket!");
}
// 客户端发送消息到服务器
$('#toSend').click(function () {
sendMsg();
});
$(document).keyup(function (event) {
// 回车键事件
if (event.keyCode == 13) {
sendMsg();
}
});
// 发送消息
function sendMsg() {
//websocket发送消息
ws.send($('#message').val());
$('#message').val("");
}
// 退出
$('#user_exit').click(function () {
if (ws) {
ws.close();
}
});
});
</script>
</body>
</html>
控制器
@Controller
public class ChatController {
private AtomicInteger idProducer = new AtomicInteger();
@RequestMapping("/")
public String index(Model model) {
model.addAttribute("username","user" + idProducer.getAndIncrement());
return "index";
}
}
配置类
@EnableWebSocket //启用WebSocket支持
@Configuration //表示配置类
public class WebSocketConfig {
/**
* 配置ServerEndpointExporter的bean
*
* 该Bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
/**
* 说明:
* 1、@ServerEndpoint注解中指定WebSocket协议的地址;
* 2、@OnOpen、@OnMessage、@OnClose、@OnError注解与WebSocket中监听事件对应
*
**/
@Slf4j //lombok jar包,帮我们自动生成一些代码:@Data
@Component
@ServerEndpoint("/websocket/{username}")
public class ChatServerEndpoint {
/**
* 连接建立时触发
*/
@OnOpen
public void openSession(@PathParam("username") String username, Session session) {
log.info("用户{}登录", username);
String message = "用户[" + username + "] 已进入聊天室!";
// 发送登录消息给其他人
WebSocketUtils.sendMessageAll(message);
// 获取当前在线人数,发给自己
String onlineInfo = WebSocketUtils.getOnlineInfo();
//发送消息
WebSocketUtils.sendMessage(session, onlineInfo);
// 添加自己到map中
WebSocketUtils.CLIENTS.put(username, session);
}
/**
* 客户端接收服务端数据时触发
*/
@OnMessage
public void onMessage(@PathParam("username") String username, String message) {
log.info("发送消息:{}, {}", username, message);
//广播,把消息同步给其他客户端
WebSocketUtils.sendMessageAll("[" + username + "] : " + message);
}
/**
* 连接关闭时触发
*/
@OnClose
public void onClose(@PathParam("username") String username, Session session) {
// 当前的Session移除某个用户
WebSocketUtils.CLIENTS.remove(username);
// 离开消息通知所有人
WebSocketUtils.sendMessageAll("[" + username + "] 已离开!");
try {
//关闭WebSocket Session会话
session.close();
log.info("{} 已退出, onclose", username);
} catch (IOException e) {
e.printStackTrace();
log.error("onClose error", e);
}
}
/**
* 通信发生错误时触发
*/
@OnError
public void onError(Session session, Throwable throwable) {
try {
//关闭WebSocket Session会话
session.close();
} catch (IOException e) {
e.printStackTrace();
log.error("onError Exception", e);
}
log.info("Throwable msg " + throwable.getMessage());
}
}
public final class WebSocketUtils {
private static final Logger logger = LoggerFactory.getLogger(WebSocketUtils.class);
/**
* 存储WebSocket session
* <p>
* 用户名为key,WebSocket Session对象为value
*/
public static final Map<String, Session> CLIENTS = new ConcurrentHashMap<>();
/**
* 使用连接发送数据
*
* @param session 用户session
* @param message 发送内容
*/
public static void sendMessage(Session session, String message) {
if (session == null) {
return;
}
final RemoteEndpoint.Basic basic = session.getBasicRemote();
if (basic == null) {
return;
}
try {
//发送
basic.sendText(message);
} catch (IOException e) {
e.printStackTrace();
logger.error("sendMessage IOException ", e);
}
}
/**
* 发送消息给其他所有人
*
* @param message
*/
public static void sendMessageAll(String message) {
CLIENTS.forEach((sessionId, session) -> sendMessage(session, message));
}
/**
* 获取所有在线用户
*/
public static String getOnlineInfo() {
Set<String> userNames = CLIENTS.keySet();
if (userNames.size() == 0) {
return "当前无人在线...";
}
return CLIENTS.keySet().toString() + "在线";
}
}


















