SocketJS学习总结
关于WebSocket的介绍和相关API,网上有很多文档,感觉下面这个说得比较细:WebSocket介绍WebSocket APISockJS FallbackWebSocket STOMP这个是SpringBoot整合 WebSocket的文档,前端用的SocketJS/Stomp。后端用的是Spring所支持的...
关于WebSocket的介绍和相关API,网上有很多文档,感觉下面这个说得比较细:
这个是SpringBoot整合 WebSocket的文档,前端用的SocketJS/Stomp。后端用的是Spring所支持SocketJS:springboot websocket 一篇足够了
前端用的Stomp来获取client进行SocketJS的API操作:Stomp Over Websocket文档
我们知道SocketJS对Cookie的兼容性不好,网上有看到可以把Cookie信息放到Header中进行传输及获取,这是相关的整合文档:
Spring+WebSocket+SockJS实现实时聊天
关于为什么不直接用原生的WebSocket而用SocketJS应该不用我多说,就是IE10以下不支持ws协议,为了它的兼容性,需要在不支持websocket浏览器下降级成长轮询的方式。而SocketJS和SocketIO都封装了WebSocket。而SocketIO后端官方是用NodeJS实现的,如果要用Java当服务器端,可以使用基于Netty实现的netty-socketio:githup地址,它官方也提供了相应的demo,提出了namespace/room的概念,比较适合当聊天工具的开发,只是要开启新的端口来监听连接(socketJS就不需要)
补充一下:SocketJS中有个
registry.setUserDestinationPrefix("/user");
有点不容易被理解,看了源码,在convertAndSendToUser和convertAndSend方法时体现了他们的不同之处
SimpMessagingTemplate.class
// convertAndSendToUser方法底层调用的convertAndSend方法,只不过参数添加了config中的destinationPrefix及点对点的接收人
super.convertAndSend(this.destinationPrefix + user + destination, payload, headers, postProcessor);
另附上后端调用api时主要的代码及注释:
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.annotation.SendToUser;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.socket.WebSocketSession;
import top.fissile.manager.SocketManager;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
import java.util.HashMap;
import java.util.Map;
/**
* demo地址:http://123.56.157.29:3333/html/index.html
* @Author duln
* @Date 2019/12/27 11:27
* @Version 1.0
*/
@RestController
@Slf4j
public class TestController {
@Autowired
private SimpMessagingTemplate template;
/**
* @Description 接收客户端的消息
* @param principal 这是在拦截器中设置的数据,之前只用token给设置个name值
* @param msg 客户端发送过来的消息(也可以用map接收,前端就需要obj转json)
*/
// 只和前端的发送参数相关,类似RequestMapping,前端直接clent.send('/sendAllUser',...)就可以
@MessageMapping("/sendAllUser")
// 貌似得和@MessageMapping连用才生效,也就限制了一般只能用在controller中
// 区别于@SendToUser,@SendTo是用来服务器给客户端群发的:value就是群发的destination,方法返回值就是群发数据
// 如果返回值为Map,则客户端收到的是application/json格式;如果返回值是String,则收到的是xxx/text格式
// @SendTo同template.convertAndSend(),只是template可用于任何地方
@SendTo("/topic/receiveMsg")
public Map<String, Object> sendAllUser(Principal principal, String msg) {
Map<String, Object> map = new HashMap<>();
map.put("type", "公开");
map.put("userName", principal.getName());
map.put("message", msg);
return map;
}
/**
* 客户端请求获取当前人数信息
*/
@MessageMapping("/getCount")
public void getCount(Principal principal) {
Map<String, Object> map = SocketManager.get();
// 与convertAndSend不同的是:this.destinationPrefix + user
// super.convertAndSend(this.destinationPrefix + user + destination, payload, headers, postProcessor);
template.convertAndSendToUser(principal.getName(), "/queue/count", map);
}
/**
* 点对点用户聊天
*/
@MessageMapping("/sendOneUser")
public void sendOneUser(Principal principal, Map<String, String> map) {
log.info("map = {}", map);
String toName = map.get("userName");
String fromName = principal.getName();
WebSocketSession webSocketSession = SocketManager.get(toName);
if (webSocketSession != null) {
Map<String, Object> toMap = new HashMap<>();
toMap.put("type", "私聊");
toMap.put("message", map.get("message"));
Map<String, Object> fromMap = new HashMap<>(toMap);
toMap.put("fromName", fromName);
toMap.put("toName", "你");
fromMap.put("fromName", "你");
fromMap.put("toName", toName);
template.convertAndSendToUser(toName, "/queue/sendUser", toMap);
template.convertAndSendToUser(fromName, "/queue/sendUser", fromMap);
}
}
}
更多推荐
所有评论(0)