spring websocket 使用@SendToUser


spring websocket 使用@SendToUser

原文鏈接:https://blog.csdn.net/yingxiake/article/details/51224569

之前我們利用@SendTo在方法上進行注解,方法的返回值會被messageconverter轉化並推送到消息代理器中,由消息代理器廣播到訂閱路徑去

@MessageMapping("bar") //@MessageMapping接收客戶端消息
@SendTo("/topic/brocast") //@SendTo廣播消息出去
public String handle1(String msg) {
return msg;
}

上面msg會被廣播到”/topic/brocast”這個訂閱路徑中,只要客戶端訂閱了這條路徑,不管是哪個用戶,都會接收到消息

那么需求來了,如果我只是想簡單的用websocket向服務器請求資源而已,然后服務器你就把資源給我就行了,別的用戶就不用你廣播推送了,簡單點,就是我請求,你就推送給我。

spring websocket 可以使用@SendToUser做到這一點,在使用@SendToUser之前,我們需要明白以下幾點:

1.spring webscoket通道的建立最開始還是源於http協議的第一次握手,握手成功之后,就打開了瀏覽器和服務器的webscoket通過,這時,httprequest中的登錄授權信息即javax.security.Principal會被綁定到websocket的session中

2.spring webscoket能識別帶”/user”的訂閱路徑並做出處理,例如,如果瀏覽器客戶端,訂閱了’/user/topic/greetings’這條路徑,

stompClient.subscribe('/user/topic/greetings', function(data) {
//...
});

就會被spring websocket利用UserDestinationMessageHandler進行轉化成”/topic/greetings-usererbgz2rq”,”usererbgz2rq”中,user是關鍵字,erbgz2rq是sessionid,這樣子就把用戶和訂閱路徑唯一的匹配起來了

3.spring webscoket在使用@SendToUser廣播消息的時候,

@MessageMapping("handle")
@SendToUser("/topic/greetings")
public String handle(String msg) {
//...
return msg;
}
 
“/topic/greetings”會被UserDestinationMessageHandler轉化成”/user/role1/topic/greetings”,role1是用戶的登錄帳號,這樣子就把消息唯一的推送到請求者的訂閱路徑中去,這時候,如果一個帳號打開了多個瀏覽器窗口,也就是打開了多個websocket session通道,這時,spring webscoket默認會把消息推送到同一個帳號不同的session,你可以利用broadcast = false把避免推送到所有的session中

@MessageMapping("handle")
@SendToUser(value = "/topic/greetings",broadcast = false)
public String handle(String msg) {
//...
return name;
}

下面來做個demo,首先是服務器要配置登錄驗證權限,這里利用tomcat的basic安全驗證,在web.xml里面配置

<security-constraint>
<web-resource-collection>
<web-resource-name>protect resources </web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>HEAD</http-method>
<http-method>GET</http-method>
<http-method>POST</http-method>
<http-method>PUT</http-method>
<http-method>DELETE</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>role1</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<security-role>
<description>Role1</description>
<role-name>role1</role-name>
</security-role>  


role1是登錄的角色名,其中驗證信息可以在tomcat-users.xml里面配置

<role rolename="tomcat"/>
<role rolename="role1"/>
<user username="tomcat" password="tomcat" roles="tomcat"/>
<user username="both" password="tomcat" roles="tomcat,role1"/>
<user username="role1" password="tomcat" roles="role1"/>



這里有倆個帳號,role1和both,角色都有role1,password都是tomcat,我們可以利用這倆個帳號在IE9和谷歌瀏覽器進行登錄

 

然后服務器,我們分別使用@SendTo和@SendToUser進行廣播推送和精准推送

首先我們注冊下spring webscoket服務器

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketMessageBrokerConfig implements WebSocketMessageBrokerConfigurer {

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {

//portfolio-stomp就是websocket的端點,客戶端需要注冊這個端點進行鏈接,withSockJS允許客戶端利用sockjs進行瀏覽器兼容性處理
registry.addEndpoint("/portfolio-stomp").withSockJS();

}

@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic"); //設置服務器廣播消息的基礎路徑
registry.setApplicationDestinationPrefixes("/app"); //設置客戶端訂閱消息的基礎路徑
registry.setPathMatcher(new AntPathMatcher(".")); //可以已“.”來分割路徑,看看類級別的@messageMapping和方法級別的@messageMapping
}

@Override
public boolean configureMessageConverters(List<MessageConverter> messageConverters) {

return true;
}

@Override
public void configureWebSocketTransport(WebSocketTransportRegistration registry) {
// TODO Auto-generated method stub
registry.addDecoratorFactory(new MyWebSocketHandlerDecoratorFactory());
}

@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.setInterceptors(new MyChannelInterceptor());
}

@Override
public void configureClientOutboundChannel(ChannelRegistration registration) {
// TODO Auto-generated method stub

}

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
// TODO Auto-generated method stub

}

@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
// TODO Auto-generated method stub

}

}
 

 

 

然后寫下服務的的接收和發送

@Controller
@RequestMapping("/webSocket")
@MessageMapping("foo")
public class WebSocketController {

/**
* 精准推送
* @param msg
* @param principal
* @return
*/
@MessageMapping("handle1") 
@SendToUser(value = "/topic/greetings1",broadcast = false)
public String handle1(String msg,Principal principal) {

return "精准推送,只推送到" + principal.getName();
}


/**
* 廣播推送
* @param msg
* @param principal
* @return
*/
@MessageMapping("handle2") 
@SendTo("topic/greetings2")
public String handle2(String msg,Principal principal) {

return "廣播推送,所有用戶都收得到";

}

 最后在瀏覽器客戶端,我們利用sockjs和stomp.js鏈接並發送和訂閱消息,其中在websocket.js代碼就是這樣子的

var socket = new SockJS('/whats/portfolio-stomp');
var stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {

stompClient.subscribe('/user/topic/greetings1', function(data) {
$("#ret").text(data.body);
});

stompClient.subscribe('/topic/greetings2', function(data) {
$("#ret").text(data.body);
});
});

/**
* 精准推送
*/
document.getElementById("ws1").onclick = function() {
stompClient.send("/app/foo.handle2",{},{
msg : "精准推送"
});
}

/**
* 廣播推送
*/
document.getElementById("ws").onclick = function() {

stompClient.send("/app/foo.handle1",{},{
msg : "廣播推送"
});

}
 

 jsp頁面其實就是這樣子的

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html >
<html>
<head>
<meta charset="UTF-8">
<title>websocket</title>

</head>
<body>

<h1>hello websocket client !!</h1>

<button id = "ws">精准推送</button>
<button id = "ws1">廣播推送</button>

<span id ="ret"></span>

<script type="text/javascript" src="${pageContext.request.contextPath}/content/uilib/websocket/sockjs-1.0.3.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/content/uilib/websocket/stomp.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/content/js/websocket/websocket.js"></script>
</body>
</html>

到這里就完成了功能了

精准推送

 

 

 

廣播推送 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM