前言:最近在做弹幕的需求,考虑用到websocket。搭建过程做记录分享。
1、pom.xml依赖,spring请用4.0以上
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${spring.version}</version>
</dependency>
<!--jackson用于json操作 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.3.0</version>
</dependency>
2、服务初始化类,spring官网还有xml的配置方法
@Configuration
@EnableWebMvc
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic", "/user");
config.setApplicationDestinationPrefixes("/msg");
config.setUserDestinationPrefix("/user/");
}
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/webServer").setAllowedOrigins("*").withSockJS();
}
}
说明:
a、config.enableSimpleBroker("/topic","/user");
//这句表示在topic和user这两个域上可以向客户端发消息。
b、config.setUserDestinationPrefix("/user/");
//这句表示给指定用户发送(一对一)的主题前缀是“/user/”。
c、config.setApplicationDestinationPrefixes("/msg");
//这句表示客户端向服务端广播发送时的主题上面需要加"/msg"作为前缀。
d、registry.addEndpoint("/webServer").setAllowedOrigins("").withSockJS();
//这个和客户端创建连接时的url有关,后面在客户端的代码中可以看到。
//setAllowedOrigins("")处理跨域访问问题。
e、如果spring不配扫包,可以手动配一下
<bean name="WebSocketConfig" class="com.xxx.WebSocketConfig" />
3、服务类**
@Controller
public class WebSocketController {
private static int SIZE = 3;
private Queue<Object> queue = new ArrayDeque<Object>();
public SimpMessagingTemplate template;
@Autowired
public WebSocketController(SimpMessagingTemplate template) {
this.template = template;
}
@SubscribeMapping("/init/{coordinationId}")
public Map<String,Object> init(@DestinationVariable("coordinationId") int coordinationId) {
System.out.println("------------新用户 " + coordinationId + " 进入,空间初始化---------");
Map<String, Object> document = new HashMap<String, Object>();
document.put("chat",queue);
return document;
}
// 广播
@MessageMapping("/live")
@SendTo("/topic/live")
public TopicMessage sendTopic(TopicMessage msg) {
if (queue.size() >= SIZE) {
queue.poll();
}
queue.offer(msg);
return msg;
}
// 广播 方式写点对点
@MessageMapping("/point")
public void sendPoint(UserMessage userMessage) {
String dest = "/topic/point" + userMessage.getCoordinationId();
this.template.convertAndSend(dest, userMessage);
}
//点对点
@MessageMapping("/message")
//@SendToUser("/message")
public void userMessage(UserMessage userMessage) throws Exception {
this.template.convertAndSendToUser(userMessage.getCoordinationId(), "/message", userMessage);
}
}
说明:
a、queue 为消息缓存队列,简单放到jvm中,实际项目请放到Redis等缓存中。
b、广播方式用的@SendTo注解。
c、正常的点对点应该采用@SendToUser,但实际上并没调通,表现就是仅仅js端发,js端就能触发回调,根本不走controller中的userMessage方法(stompClient.send("/user/{userId}/message"),有哪位大神知道为什么请赐教。
d、据spring官网意思,@MessageMapping、@RequestMapping是共存的,所以把它当做平常我们用的controller就行了,一毛一样。
4、js端
<script type="text/javascript" src="../static/scripts/jquery/jquery-1.7.1.js"></script>
<script type="text/javascript" src="../static/scripts/stomp.js"></script>
<script type="text/javascript" src="../static/scripts/sockjs.js"></script>
</head>
<script>
var stompClient = null;
$(function() {
startServer();
})
function startServer() {
var url = 'http://IP:端口/项目名/webServer'
var socket = new SockJS(url);
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
//初始化
stompClient.subscribe('/msg/init/' + userId, function (initData) {
console.log(initData);
var body = JSON.parse(initData.body);
var chat = body.chat;
chat.forEach(function(item) {
showChat(item);
});
});
//广播回调
stompClient.subscribe('/topic/live', function(message){
var json = JSON.parse(message.body);
showChat(json);
});
//广播方式实现点对点回调
stompClient.subscribe('/topic/point' + userId, function (message) {
var json = JSON.parse(message.body);
showChat(json);
});
//点对点方式回调
stompClient.subscribe('/user/' + userId + '/message', function(message){
var json = JSON.parse(message.body);
showChat(json);
});
});
//强制关闭浏览器断开连接
window.onbeforeunload = function() {
if (stompClient != null) {
stompClient.disconnect();
}
}
}
function closeServer() {
if (stompClient != null) {
stompClient.disconnect();
}
}
function sendTopic() {
var input = $('#topic_input');
var inputValue = input.val();
input.val("");
stompClient.send("/msg/live", {}, JSON.stringify({
'name' : encodeURIComponent('广播'),
'msg' : encodeURIComponent(inputValue)
}));
}
function sendPoint() {
var input = $('#point_input');
var inputValue = input.val();
input.val("");
stompClient.send("/msg/point", {}, JSON.stringify({
'name' : encodeURIComponent('广播点对点'),
'msg': encodeURIComponent(inputValue),
'coordinationId': 1
}));
}
function sendUser() {
var input = $('#user_input');
var inputValue = input.val();
input.val("");
stompClient.send("/msg/message", {}, JSON.stringify({
'name' : encodeURIComponent('点对点'),
'msg': encodeURIComponent(inputValue),
'coordinationId': 'a'
}));
}
function showChat(message) {
var value = decodeURIComponent(message.name) + ':' + decodeURIComponent(message.msg) + '\n';
var content = $("#topic_content").val() + value;
$("#topic_content").val(content);
}
</script>
<body>
<div>
<input id="topic_input" type="text">
<input type="button" onclick="sendTopic();" value="send广播">
</div>
<div>
<input id="point_input" type="text">
<input type="button" onclick="sendPoint();" value="send广播点对点">
</div>
<div>
<input id="user_input" type="text">
<input type="button" onclick="sendUser();" value="send点对点">
</div>
<div>
<textarea id="topic_content" style="width:200px;height:80px;"></textarea>
</div>
</body>
</html>
记得引入sockjs-0.3.4.js,stomp.js
5、附两个上面用到的pojo
public class TopicMessage {
private String name;
private String msg;
set/get
}
public class UserMessage {
private String name;
private String msg;
private String coordinationId;
set/get
}
参考资料:
http://www.lxway.com/4002114921.htm
http://blog.csdn.net/xjyzxx/article/details/38542665?utm_source=tuicool&utm_medium=referral
http://docs.spring.io/spring/docs/4.1.9.RELEASE/spring-framework-reference/htmlsingle/#_websocket_sockjs_and_stomp_messaging
网友评论