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 @Override //portfolio-stomp就是websocket的端點,客戶端需要注冊這個端點進行鏈接,withSockJS允許客戶端利用sockjs進行瀏覽器兼容性處理 } @Override @Override return true; @Override @Override @Override } @Override } @Override } } |
然后寫下服務的的接收和發送
@Controller /** return "精准推送,只推送到" + principal.getName();
return "廣播推送,所有用戶都收得到"; |
最后在瀏覽器客戶端,我們利用sockjs和stomp.js鏈接並發送和訂閱消息,其中在websocket.js代碼就是這樣子的
var socket = new SockJS('/whats/portfolio-stomp'); stompClient.subscribe('/user/topic/greetings1', function(data) { stompClient.subscribe('/topic/greetings2', function(data) { /** /** stompClient.send("/app/foo.handle1",{},{ } |
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>
到這里就完成了功能了
精准推送
廣播推送