websocket是全双工、长连接的网络通信协议,通过websocket可以实现即时通信,服务器推送消息给客户端等业务情况。
spring boot实现websocket
spring boot框架是为我们提供了实现websocket的方法的,在该过程中大概可以分为三步。
- 引入依赖
- 配置websocket
- 编写websocket的相关逻辑控制
首先我们需要在pom文件中添加如下依赖:
<!-- 引入websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
然后maven update我们的项目,从而自动添加spring-boot-starter-websocket.jar到我们的项目中。
引入websocket的jar包后我们需要在spring boot中配置websocket的使用。
配置文件比较简单:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
//声明该类是配置文件
@Configuration
public class WebSocketConf {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
在该配置文件中,主要使用了@Configuration和@Bean注解,@Configuration告诉spring boot容器这是一个配置文件,这样到初始化spring boot容器的过程中该类就会被自动加载执行,而@Bean注解是对该方法的说明,当调用该方法的时候将返回一个bean;
注:该配置文件位置并不固定,形式内容比较固定,直接粘贴复制就可以了。
在上面准备工作完成后,就需要我们对websocket链接的基本逻辑做出处理。在一个链接建立到结束的过程中大概可以分为以下几种情况:
- 链接建立成功
- 链接开
- 双方通信
- 发生异常
因此我们的基本逻辑处理需要针对以上四种情况做出处理。
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSONObject;
/**
* @author XVX
* webSocket的controller层可以接受到客户端的请求
*
* websocket链接不同于http链接,spring boot为所有http链接提供单一的controll,但是为每个websocket链接都提供了一个controller
* 也就是说WebSocketController并不是单例模式的。不能使用autowrite进行依赖注入
*
* 解决方法:实现ApplicationContextAware接口,通过接口对成员变量进行赋值
*/
//声明为bean
@Component
//通过该注解可以让spring boot容器知道该bean是一个webSocket的控制器 其中{sid}是客户端回传的信息
@ServerEndpoint("/websocket")
public class WebSocketController {
private static final Logger log = LoggerFactory.getLogger(WebSocketController.class);
private Session session = null;
private static CopyOnWriteArraySet<Session> sessions = new CopyOnWriteArraySet<Session>();
private String flag = "not connect";
public WebSocketController() {
System.out.println("create");
}
/**
* @param session ----- 客户端和服务器之间的会话,客户端通过session发送信息给客户端
* @param sid ----- 客户端建立链接的过程中回传的信息,一般可以用于身份识别
* 连接建立成功调用的方法,需要@OnOpen声明
*/
@OnOpen
public void onOpen(Session session, @PathParam("sid") String sid) {
this.session = session;
sessions.add(session);
System.out.println(flag);
System.out.println("code:"+this.hashCode()+"\n"+"class:"+this.getClass());
flag = "connect";
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("data", "thank");
sendMessage(jsonObject.toJSONString());
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 当客户端主动断开链接时调用
*/
@OnClose
public void onClose() {
sessions.remove(session);
}
/**
* @param message ---- 客户端发送的请求
* @param session ---- 会话
* 接受到客户端请求时调用
*/
@OnMessage
public void onMessage(String message, Session session) {
System.out.println(message);
}
/**
* @param session
* @param error
* 处理发生错误时调用
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误");
error.printStackTrace();
sessions.remove(session);
}
/**
* @param message --- 将要发送的信息
* @throws IOException
* 服务器主动向客户端发送信息
*/
public static void sendMessage(String message) throws IOException {
sessions.forEach(e->{
try {
e.getBasicRemote().sendText(message);
} catch (IOException e1) {
e1.printStackTrace();
}
});
}
}
一般的逻辑控制器如上所示。需要注意的是该类并不是单例模式被运用,他并不像spring boot种的基本的contraller层一样,针对每个链接都会对应一个上面类的实例。通过静态成员变量可以实现数据共享。此外,由于该类不是单例模式,因此不可以使用@autowire注释来实现依赖注入,如果想要获取到spring boot容器的dao接口,那需要实现ApplicationContextAware接口,并重现下面的代码:
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//你的赋值代码
}
spring boot实现websocet的源码:
链接:https://pan.baidu.com/s/1tMeCyMGsiTAXfWsC9SDsUg
提取码:ripl