1 根据我的另一篇博客创建一个web框架的maven工程
https://blog.csdn.net/u014377655/article/details/81332959
2 在工程中添加文件
结构如下图
3 配置spring-mvc.xml
4 jsp以及类内容
index.jsp
<!DOCTYPE html>
<html>
<body>
<h2>Hello World!</h2>
<body>
<form action="websocket/login.do">
username:<input type="text" name="userName"/>
<input type="submit" value="login"/>
</form>
</body>
</body>
</html>
ws.jsp
<!DOCTYPE html>
<html>
<head>
<title>WebSocket测试页</title>
<script type="text/javascript" src="http://cdn.bootcss.com/jquery/3.1.0/jquery.min.js"></script>
<script type="text/javascript" src="http://cdn.bootcss.com/sockjs-client/1.1.1/sockjs.js"></script>
<script type="text/javascript">
var websocket = null;
if ('WebSocket' in window) {
var host = window.location.host;
var url = "ws://"+host+"/chat/websocket/socketServer.do";
websocket = new WebSocket(url);
}
else if ('MozWebSocket' in window) {
websocket = new MozWebSocket("ws://localhost:8080/chat/websocket/socketServer.do");
}
else {
websocket = new SockJS("http://localhost:8080/chat/sockjs/socketServer.do");
}
websocket.onopen = onOpen;
websocket.onmessage = onMessage;
websocket.onerror = onError;
websocket.onclose = onClose;
function onOpen(openEvt) {
alert("connection status: success");
}
function onMessage(evt) {
//收到服务器消息,使用evt.data提取
evt.stopPropagation()
evt.preventDefault()
writeToScreen(evt.data);
}
function onError() {
//产生异常
writeToScreen(evt.message)
}
function onClose() {
alert("connection status: closed");
}
function closeWebSocket() {
websocket.close();
}
//浏览器刷新前关闭websocket
function fnUnloadHandler() {
websocket.onclose();
}
function doSend() {
if (websocket.readyState == websocket.OPEN) {
var msg = document.getElementById("inputMsg").value;
//后台将调用handleTextMessage方法接收该消息
websocket.send(msg);
alert("send success!");
} else {
alert("send failed!\nconnection is closed!");
}
}
function writeToScreen(message) {
var pre = document.createElement("p");
pre.style.wordWrap = "break-word";
pre.innerHTML += message;
document.body.appendChild(pre);
}
</script>
</head>
<body onbeforeunload="fnUnloadHandler();">
<div>
Input:<textarea rows="3" cols="30" id="inputMsg" name="inputMsg"></textarea>
<button onclick="doSend();">send</button>
<button onclick="closeWebSocket();">close</button>
</div>
</body>
</html>
SpringWebSocketConfig
public class SpringWebSocketConfig extends WebMvcConfigurerAdapter implements
WebSocketConfigurer {
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(webSocketHandler(),"/websocket/socketServer.do").addInterceptors(new SpringWebSocketHandlerInterceptor());
registry.addHandler(webSocketHandler(), "/sockjs/socketServer.do").addInterceptors(new SpringWebSocketHandlerInterceptor()).withSockJS();
}
@Bean
public TextWebSocketHandler webSocketHandler(){
return new SpringWebSocketHandler();
}
}
SpringWebSocketHandler
public class SpringWebSocketHandler extends TextWebSocketHandler {
//在线用户列表
private static final Map<String, WebSocketSession> users;
static {
users = new HashMap<>();
}
public SpringWebSocketHandler() { }
/**
* 建立连接后触发的回调
* 记录用户的连接标识,便于后面发信息,
* 这里我是记录将id记录在Map集合中。
* 一个Map中不能包含相同的key,每个key只能映射一个value,根据先后put的顺序覆盖
* @param session
* @throws Exception
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("成功建立连接");
String userName = getClientId(session);
if (userName != null) {
System.out.println("用户"+userName+"登录!");
users.put(userName, session);
session.sendMessage(new TextMessage("server:成功建立socket连接"));
System.out.println("当前在线用户"+users.size()+": "+users);
}
//userName为空时,不存储该用户,不与该用户交互
}
/**
* 断开连接后触发的回调
* 连接已关闭,移除在Map集合中的记录。
* @param session
* @param closeStatus
* @throws Exception
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
String userName = getClientId(session);
System.out.println("\n用户"+userName+"已退出: " + closeStatus);
users.remove(userName);
System.out.println("剩余在线用户"+users.size()+": "+users);
}
/**
* 收到消息时触发的回调
* 对H5 Websocket的send方法进行处理
* @param session
* @param message
*/
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
//显示客户端发送过来的消息内容
System.out.println("client:"+message.getPayload());
WebSocketMessage message1 = new TextMessage("server:"+message);
try {
session.sendMessage(message1);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 传输消息出错时触发的回调
* 连接出错处理,主要是关闭出错会话的连接,和删除在Map集合中的记录
* @param session
* @param exception
* @throws Exception
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
if (session.isOpen()) {
session.close();
}
System.out.println("连接出错");
users.remove(getClientId(session));
}
/**
* 是否处理分片消息
* @return
*/
public boolean supportsPartialMessages() {
return false;
}
/**
* 发送信息给指定用户
* 传入用户标识和消息体
* @param clientId
* @param message
* @return
*/
public boolean sendMessageToUser(String clientId, TextMessage message) {
if (users.get(clientId) == null) return false;
WebSocketSession session = users.get(clientId);
System.out.println("sendMessage:" + session);
if (!session.isOpen()) return false;
try {
session.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 广播信息
* 只需要传入消息体
* @param message
* @return
*/
public boolean sendMessageToAllUsers(TextMessage message) {
boolean allSendSuccess = true;
Set<String> clientIds = users.keySet();
WebSocketSession session = null;
for (String clientId : clientIds) {
try {
session = users.get(clientId);
if (session.isOpen()) {
session.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
allSendSuccess = false;
}
}
return allSendSuccess;
}
/**
* 获取用户标识
* @param session
* @return
*/
private String getClientId(WebSocketSession session) {
try {
String clientId = (String)session.getAttributes().get(Const.CLIENT_NAME);
return clientId;
} catch (Exception e) {
return null;
}
}
}
SpringWebSocketHandlerInterceptor
public class SpringWebSocketHandlerInterceptor extends HttpSessionHandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception
System.out.println("Before Handshake");
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
HttpSession session = servletRequest.getServletRequest().getSession(false);
if (session != null) {
//使用userName区分WebSocketHandler,以便定向发送消息
String userName = (String) session.getAttribute("userName");
if (userName==null) {
userName="default-system";
}
attributes.put("userName",userName);
}else{
System.out.println("beforeHandshake 没有获取到 session");
}
}
return super.beforeHandshake(request, response, wsHandler, attributes);
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Exception ex) {
System.out.println("After Handshake");
super.afterHandshake(request, response, wsHandler, ex);
}
}
controller
@Controller
public class WebsocketController {
@Bean
public SpringWebSocketHandler infoHandler() {
return new SpringWebSocketHandler();
}
@RequestMapping("/websocket/login")
public ModelAndView login(HttpServletRequest request, HttpServletResponse response) throws Exception {
String userName = request.getParameter("userName");
System.out.println(userName+"登录");
HttpSession session = request.getSession(false);
session.setAttribute(Const.CLIENT_NAME, userName);
ModelAndView mv = new ModelAndView();
mv.setViewName("ws");
return mv;
}}
5 测试
输入用户名,点击login
跳转至
发送消息测试
参考博文
spring配置websocket并实现群发/单独发送消息
https://blog.csdn.net/u014520745/article/details/62046396