据的处理方法。
那么这个注解下的方法究竟可以获取哪些数据,其中有什么原理呢?
我大概说一下:
Message,@Payload,@Header,@Headers,MessageHeaders,MessageHeaderAccessor, SimpMessageHeaderAccessor,StompHeaderAccessor
以上这些都是获取消息头,消息体,或整个消息的基本对象模型。
@DestinationVariable
这个注解用于动态监听路径,很想rest中的@PathVariable:
e.g.:
@MessageMapping("/queue/chat/{uid}")
public void chat(@Payload @Validated Message message, @DestinationVariable("uid") String uid, Principal principal) {
String msg = "发送人: " + principal.getName() + " chat ";
simpMessagingTemplate.convertAndSendToUser(uid,"/queue/chat",msg);
}
java.security.Principal
这个对象我需要重点说一下。
他则是spring security认证之后,产生的Token对象,即本例中的UsernamePasswordAuthenticationToken.
不难发现UsernamePasswordAuthenticationToken是Principal的一个实现.
可以将Principal直接转成授权后的token,进行操作:
UsernamePasswordAuthenticationToken user = (UsernamePasswordAuthenticationToken) principal;
正如前边设计章节所说,整个用户设计都是对org.springframework.security.core.userdetails.User进行操作,那如何拿到User对象呢。
很简单,如下:
UsernamePasswordAuthenticationToken user = (UsernamePasswordAuthenticationToken) principal;
User user = (User) user.getPrincipal()
通讯层设计 – 1-1 && 1-n
1-n topic:
此方式,上述消息模型章节已经讲过,此处不再赘述
1-1 queue:
客服-用户沟通为1-1用户交互的案例
前端:
stompClient.subscribe('/user/queue/chat',function(greeting){
showGreeting(greeting.body);
});
后端:
@MessageMapping("/queue/chat/{uid}")
public void chat(@Payload @Validated Message message, @DestinationVariable("uid") String uid, Principal principal) {
String msg = "发送人: " + principal.getName() + " chat ";
simpMessagingTemplate.convertAndSendToUser(uid,"/queue/chat",msg);
}
发送端:
function chat(uid) {
stompClient.send("/app/queue/chat/"+uid,{},JSON.stringify({'title':'hello','content':'message content'}));
}
上述的转化,看上去没有topic那样1-n的广播要流畅,因为代码中采用约定的方式进行开发,当然这是由spring约定的。
约定转化的处理器为UserDestinationMessageHandler。
大概的语义逻辑如下:
“An application can send messages targeting a specific user, and Spring’s STOMP support recognizes destinations prefixed with “/user/“ for this purpose. For example, a client might subscribe to the destination “/user/queue/position-updates”. This destination will be handled by the UserDestinationMessageHandler and transformed into a destination unique to the user session, e.g. “/queue/position-updates-user123”. This provides the convenience of subscribing to a generically named destination while at the same time ensuring no collisions with other users subscribing to the same destination so that each user can receive unique stock position updates.”
大致的意思是说:如果是客户端订阅了/user/queue/position-updates,将由UserDestinationMessageHandler转化为一个基于用户会话的订阅地址,比如/queue/position-updates-user123,然后可以进行通讯。
例子中,我们可以把uid当成用户的会话,因为用户1-1通讯是通过spring security授权的,所以我们可以把会话当做授权后的token.
如登录用户token为: UsernamePasswordAuthenticationToken newToken = new UsernamePasswordAuthenticationToken(“admin”,”user”);
且这个token是合法的,那么/user/queue/chat订阅则为/queue/chat-admin
发送时,如果通过/user/admin/queue/chat,则不通过@MessageMapping直接进行推送。
如果通过/app/queue/chat/admin,则将消息由@MessageMapping注解处理,最终发送给/user/admin/queue/chat终点
追踪代码simpMessagingTemplate.convertAndSendToUser:
@Override
public void convertAndSendToUser(S