简述:支持发送公告、发送指定用户及异地登录。
spring mvc需要的jar包:
使用spring boot 可以集成websocket库,如果少了其他库,可以在启动spring boot项目看控制台报什么错,再添加相对应的库即可。
需要的JavaScript库:
sockjs.js
stomp.js
定义收发消息实体类:
package com.test.springWebsocket;
public class WebMessage {
/**
* 用户id
*/
private Long userId;
/**
* 用户名
*/
private String username;
/**
* 客户端标记
*/
private String clientMark;
/**
* 内容
*/
private String contents;
/**
* 消息类型,1.公告,2.点对点发消息,3.检查异地登录
*/
private String type;
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getClientMark() {
return clientMark;
}
public void setClientMark(String clientMark) {
this.clientMark = clientMark;
}
public String getContents() {
return contents;
}
public void setContents(String contents) {
this.contents = contents;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
定义WebSocket配置:
package com.test.springWebsocket;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
//客户端与服务器端建立连接的点,允许使用sockJs方式访问,允许跨域
stompEndpointRegistry.addEndpoint("/any-socket").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry messageBrokerRegistry) {
//订阅Broker名称
messageBrokerRegistry.enableSimpleBroker("/topic", "/user");
//全局使用的订阅前缀(客户端订阅路径上会体现出来)
messageBrokerRegistry.setApplicationDestinationPrefixes("/app");
//点对点使用的订阅前缀(客户端订阅路径上会体现出来),不设置的话,默认也是/user/
//注意:enableSimpleBroker方法里的某个参数路径必须和该方法的路径要一样,不然指定用户发送消息将会失败
messageBrokerRegistry.setUserDestinationPrefix("/user/");
}
}
定义WebSocketController:
package com.test.springWebsocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
@Controller
public class WebSocketController {
@Autowired
private SimpMessagingTemplate template;
/**
* 发送公告
*
* @param msg WebMessage
*/
@MessageMapping("/to-all")
public void toAll(WebMessage msg) {
template.convertAndSend("/topic/to-all", msg);
}
/**
* 发送指定用户
*
* @param msg WebMessage
*/
@MessageMapping("/to-one")
public void toOne(WebMessage msg) {
Long userId = msg.getUserId();
if (userId != null) {
template.convertAndSendToUser(userId.toString(), "/to-one", msg);
}
}
}
定义jsp页面RequestMapping:
/**
* spring WebSocket 页面
*
* @param request HttpServletRequest
* @return String
*/
@RequestMapping("/spring-websocket.xhtm")
public String springWebsocket(HttpServletRequest request) {
String clientMark = (String) request.getSession().getAttribute("clientMark");
if (clientMark == null) {
clientMark = GenerateUtil.getUUID();
request.getSession().setAttribute("clientMark", clientMark);
}
Admin admin = (Admin) request.getSession().getAttribute("admin");
request.setAttribute("userId", admin.getId());
request.setAttribute("username", admin.getAdmin());
request.setAttribute("clientMark", clientMark);
return "springWebsocket/springWebsocket";
}
定义jsp页面:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%
String rootPath = request.getContextPath();
String basePath = request.getScheme() + "://" +
request.getServerName() + ":" +
request.getServerPort() + rootPath + "/";
%>
Spring WebSocket
用户id:${userId}
用户名:${username}
公告:
用户id:
内容:
公告列表:
消息列表:
定义JavaScript脚本:
var socket = null;
var stompClient = null;
function closeSocket() {
if (socket == null || socket.readyState == 2 || socket.readyState == 3) {
return true;
}
socket.close();
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常.
window.onbeforeunload = function () {
closeSocket();
};
function showMsg(webMsg) {
switch (webMsg['type']) {
//公告
case '1': {
var noticeHtm = '' + webMsg['contents'] + '';
$('#noticeList').append(noticeHtm);
$("#noticeList").scrollTop($("#noticeList")[0].scrollHeight);
break;
}
//点对点发消息
case '2': {
var msgHtm = '' + webMsg['contents'] + '';
$('#msgList').append(msgHtm);
$("#msgList").scrollTop($("#msgList")[0].scrollHeight);
break;
}
//检查异地登录
case '3': {
if (webMsg['clientMark'] != clientMark) {
closeSocket();
alert('您的账号在另一处登录');
}
break;
}
default: {
alert("WebSocket接收到未知消息...");
break;
}
}
}
function connect() {
socket = new SockJS(rootPath + '/any-socket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
// 订阅 /topic/to-all 实现公告
stompClient.subscribe(rootPath + '/topic/to-all', function (dd) {
showMsg(JSON.parse(dd.body));
});
// 订阅 /user/userId/to-one 实现点对点
stompClient.subscribe(rootPath + '/user/' + userId + '/to-one', function (dd) {
showMsg(JSON.parse(dd.body));
});
var webMsg = {
'userId': userId,
'username': username,
'clientMark': clientMark,
'type': '3'
};
stompClient.send(rootPath + "/app/to-one", {}, JSON.stringify(webMsg));
});
}
connect();
$(function () {
$('#notice').on('click', function () {
if (socket == null) {
alert('WebSocket连接未打开');
return true;
}
if (socket.readyState == 0) {
alert('WebSocket正在连接中,请稍后再发送消息');
return true;
}
if (socket.readyState == 2) {
alert('WebSocket连接正在关闭中,无法发送消息');
return true;
}
if (socket.readyState == 3) {
alert('WebSocket连接已关闭,无法发送消息');
return true;
}
var webMsg = {
'contents': $('input[name="notice"]').val(),
'type': '1'
};
stompClient.send(rootPath + "/app/to-all", {}, JSON.stringify(webMsg));
});
$('#sendToUser').on('click', function () {
if (socket == null) {
alert('WebSocket连接未打开');
return true;
}
if (socket.readyState == 0) {
alert('WebSocket正在连接中,请稍后再发送消息');
return true;
}
if (socket.readyState == 2) {
alert('WebSocket连接正在关闭中,无法发送消息');
return true;
}
if (socket.readyState == 3) {
alert('WebSocket连接已关闭,无法发送消息');
return true;
}
var webMsg = {
'userId': $('input[name="userId"]').val(),
'username': username,
'contents': $('input[name="contents"]').val(),
'type': '2'
};
stompClient.send(rootPath + "/app/to-one", {}, JSON.stringify(webMsg));
});
});