一、实现目标
- 1、在线聊天,客服聊天,聊天室
- 2、业务数据实时展示,自动更新
二、实践步骤
以下是为了实现:业务数据实时展示,自动更新
1. Maven引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2. 创建配置文件
WebSocketConfig
/**
* 开启WebSocket支持
* @author zhengkai
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
3. 创建服务端
@ServerEndpoint(value = "/websocket")
@Component
public class WebSocketServer {
private final Logger log = LoggerFactory.getLogger(this.getClass());
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session) {
this.session = session;
webSocketSet.add(this);
sendMessage("连接成功");
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
webSocketSet.remove(this);
log.info("有一连接关闭!");
}
/**
* 收到客户端消息后调用的方法
*
* @param queryType 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String queryType) {
log.info("收到信息:" + queryType);
//群发消息
for (WebSocketServer item : webSocketSet) {
item.sendMessage("hello");
}
}
/**
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误");
error.printStackTrace();
}
/**
* 实现服务器主动推送
*/
public void sendMessage(Object message) {
try {
this.session.getBasicRemote().sendText(JSON.toJSONString(message));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 实现服务器主动群发消息
*/
public static void sendInfo(Object message) {
for (WebSocketServer item : webSocketSet) {
item.sendMessage(message);
}
}
}
4. 前端发起websocket请求
<script>
var socket;
if(typeof(WebSocket) == "undefined") {
console.log("您的浏览器不支持WebSocket");
}else{
console.log("您的浏览器支持WebSocket");
//实现化WebSocket对象,指定要连接的服务器地址与端口 建立连接
socket = new WebSocket("ws://localhost:8080/webscoket");
//打开事件
socket.onopen = function() {
console.log("Socket 已打开");
//socket.send("这是来自客户端的消息" + location.href + new Date());
};
//获得消息事件
socket.onmessage = function(msg) {
console.log(msg.data);
//发现消息进入 开始处理前端触发逻辑
};
//关闭事件
socket.onclose = function() {
console.log("Socket已关闭");
};
//发生了错误事件
socket.onerror = function() {
alert("Socket发生了错误");
//此时可以尝试刷新页面
}
}
</script>
三、实践中会遇到的问题
1. 前端发起websocket请求, 却无法连接websocket
- 错误一:被权限拦截,例如spring security
解决方式:放开权限或允许访问
// spring security
.antMatchers(
"/websocket"
)
.permitAll()
- 错误二:请求的websocket地址错误
@ServerEndpoint(value = "/websocket")
对应的地址是:ws://localhost:8080/webscoket
- 错误三:被AOP拦截
@Pointcut("execution(public * com.xxx.xxx.controller..*(..))")
public void webLog() {
}
解决办法
// 排除拦截
@Pointcut("execution(public * com.xxx.xxx.controller..*(..)) && !execution(public * com.xxx.xxx.controller.xxx*(..))")
public void webLog() {
}
2. 在WebSocketServer中,无法注入Bean,无法使用@Autowired
即你按如下方式直接使用@Autowired,会报错
@ServerEndpoint(value = "/websocket")
@Component
public class WebSocketServer {
@Autowired
ChartDataService chartDataService;
}
在WebSocket中, 因 SpringBoot+WebSocket 对每个客户端连接都会创建一个 WebSocketServer(@ServerEndpoint 注解对应的) 对象,Bean 注入操作会被直接略过,因而手动注入一个全局变量(即你需要注入的bean)
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
// 在这里注入你需要的bean
@Autowired
public void setMessageService(ChartDataService chartDataService) {
WebSocketServer.chartDataService = chartDataService;
// ...
}
}
使用你注入的bean
@ServerEndpoint(value = "/websocket")
@Component
public class WebSocketServer {
public static ChartDataService chartDataService;
此方式经实践,有效
其他解决方式: https://stackoverflow.com/questions/29306854/serverendpoint-and-autowired
- 1.使用@Inject
@ServerEndpoint("/ws")
public class MyWebSocket {
@Inject
private ObjectMapper objectMapper;
}
- 2.使用SpringConfigurator
@ServerEndpoint(value = "/ws", configurator = SpringConfigurator.class)
- 3.使用@PostConstruct
@PostConstruct
public void init(){
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
经过实践,上述三种方式,对于我而言,均无效
参考链接:https://blog.csdn.net/moshowgame/article/details/80275084
网友评论