一、使用Spring的低层级WebSocket API
- 为了在Spring使用较低层级的API来处理消息,我们必须编写一个实现WebSocketHandler的类,或继承AbstractWebSocketHandler类。
public class MyWebSocket extends AbstractWebSocketHandler{
@Override//当新连接建立的时候,会调用
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
LOG.debug("打开链接");
}
@Override//接受文本消息
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
LOG.info("收到消息:{}",message.getPayload());
Thread.sleep(2000);
session.sendMessage(new TextMessage("响应"));
}
@Override
protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
super.handleBinaryMessage(session, message);
}
@Override
protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
super.handlePongMessage(session, message);
}
@Override//当连接关闭时,会调用
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
LOG.debug("关闭链接");
super.afterConnectionClosed(session, status);
}
private Logger LOG=LoggerFactory.getLogger(getClass());
}
2.配置启用WebSocket映射处理器
@Configuration
@EnableWebSocket//启用webSocket的功能
public class RootConfig implements WebSocketConfigurer{
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
//registry.addHandler(myWebSocket(), "/mySocket")
//将myWebSocket映射到/mySocket路径,withSockJS()表示当有的浏览器或服务端不支持websocket时,SockJS在底层会提供备用方案,客户端要使用要使用sockjs创建sock
registry.addHandler(myWebSocket(), "/mySocket").withSockJS();
}
@Bean //生命MyWebSocket的bean
public MyWebSocket myWebSocket(){
return new MyWebSocket();
}
}
xml配置
3.jsp页面客户端编写
<script type="text/javascript" src="//cdn.jsdelivr.net/sockjs/1/sockjs.min.js"></script>
<script type="text/javascript">
//当客户段和服务段都支持websock时
//var url="ws://"+window.location.host+"/SpringMVC/mySocket";
//var sock=new WebSocket(url);
//当客户点不支持websocket时
var url="<c:url value="/mySocket" />";
var sock= new SockJS(url);
var i=0;
sock.onopen=function(){
console.log("打开链接");
sayMarco();
}
sock.onmessage=function(e){
console.log("处理信息"+e.data)
if(i==5){
console.log("关闭链接");
sock.close();
}else{
setTimeout(function(){
sayMarco("请求"+i);
},2000);
i++;
}
}
sock.onclose=function(e){
console.log("wasClean:"+e.wasClean+"code:"+e.code+"reason:"+e.reason);
console.log("关闭连接");
}
function sayMarco(a){
console.log("发送消息");
sock.send(a);
}
</script>
二、使用STOMP消息
1.配置@EnableWebSocketMessageBroker注解能够在WebSocket之上启用STOMP
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketMessageBrokerConfig extends AbstractWebSocketMessageBrokerConfigurer{
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
//将“/sockt”注册为STOMP端点,客户端在订阅或发布消息到目的地路径前,要连接该端点
//在客户端链接时使用
registry.addEndpoint("/sockt").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
//代理将会处理前缀为“/topic”和“/queue”的消息
//(以“/topic”和“/queue”作为前缀)发送到代理上的消息,其中也包括@MessageMapping注解方法的返回值所形成的消息,将会路由到代理上,并最终发送到订阅这些目的地的客户端。
registry.enableSimpleBroker("/queue","/topic");
//发往应用程序的消息将会带有“/app”前缀。
//(/app前缀)以应用程序为目的地的消息将会直接路由到带有@MessageMapping注解的控制器方法中
registry.setApplicationDestinationPrefixes("/app");
//处理指定用户发送消息
registry.setUserDestinationPrefix("/user");
}
registry.enableSimpleBroker(“/queue”,”/topic”);
启用简单代理,
registry.enableStompBrokerRelay(“/queue”,”/topic”);启用真正支持STOMP的代理来支撑WebSocket消息,如RabbitMQ或ActiveMQ
2.处理来自客户端的STOMP消息
@MessageMapping(“/marco”) 接受/app/marco的socket请求
@SubscribeMapping(“/subscribe”) 接受订阅请求/topic/subscribe
@SendTo(“/topic/geting”) 发送到订阅该路径的客户端
@SendToUser(“/topic/nitoifcation”) 发送到单个用户
@MessageMapping("/geting")
public Shout geting(Shout message){
System.out.println("123"+message.getMessage());
Shout s=new Shout();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
s.setMessage(message.getMessage());
return s;
}
<script type="text/javascript" src="//cdn.jsdelivr.net/sockjs/1/sockjs.min.js"></script>
<script type="text/javascript" src="//cdn.bootcss.com/stomp.js/2.3.3/stomp.js"></script>
<script type="text/javascript">
var url="<c:url value="/sockt" />";
var sock= new SockJS(url);
var stomp=Stomp.over(sock);
var abc=JSON.stringify({'message':'你好','user':"123"});
stomp.connect({},function(frame){
stomp.send('/app/geting',{},abc);
stomp.subscribe("/topic/geting",function(resp){
var a=JSON.parse(resp.body);
console.log(a);
});
});
@SubscribeMapping("/subscribe")
public Shout subscribe(){
System.out.println(123);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Shout s=new Shout();
s.setMessage("响应");
return s;
}
stomp.connect({},function(frame){
//订阅
stomp.subscribe("/app/subscribe",function(resp){
var a=JSON.parse(resp.body);
console.log(a);
});
});
@MessageMapping("/login")
@SendToUser("/topic/nitoifcation")
public Notification login(){
return new Notification("登陆成功");
}
stomp.connect({},function(frame){
stomp.send('/app/login',{},abc);
stomp.subscribe("/user/topic/nitoifcation",function(resp){
var a=JSON.parse(resp.body);
console.log(a);
});
});
@Service("homeService")
public class HomeService{
@Autowired //注入SimpMessageSendingOperations可以在任何时间发送消息
private SimpMessageSendingOperations message;
public void send(Shout str){
message.convertAndSend("/topic/nitoifcation", str);
message.convertAndSendToUser("123","/topic/nitoifcation", str);
}
}