1. Предпосылки
Все мы знаем, что протокол http может только в одностороннем порядке инициировать запрос от браузера к серверу для получения ответа, и сервер не может активно отправлять сообщения в браузер. Есть два основных способа добиться активного нажатия браузером:
- Опрос: много недостатков, но просто реализовать
- websocket: устанавливает TCP-соединение между браузером и сервером для обеспечения полнодуплексной связи.
springboot использует веб-сокет двумя способами: один — реализовать простой веб-сокет, другой — реализоватьSTOMPпротокол. В этой статье реализован простой веб-сокет, а STOMP будет обсуждаться в следующей статье.
Примечание. Следующее предназначено для использования встроенного контейнера springboot.
2. Реализация
1. Введение зависимости
Ключ к использованию websocket@ServerEndpoint
Эта аннотация является аннотацией в стандарте javaee, которая была реализована в tomcat 7 и выше.Если вы используете традиционный метод для развертывания пакета war на tomcat, вам нужно только ввести следующие стандартные зависимости javaee:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
Если вы используете встроенный контейнер Springboot, вам не нужно его импортировать, Springboot уже включил его. Нам нужно только ввести следующие зависимости:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>1.5.3.RELEASE</version>
<type>pom</type>
</dependency>
2. Внедрить боб
Сначала введитеServerEndpointExporterBean, bean-компонент автоматически зарегистрирует конечную точку веб-сокета, объявленную с помощью аннотации @ServerEndpoint. код показывает, как показано ниже:
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
3. Объявить конечную точку
УчреждатьMyWebSocket.javaКласс, в котором обрабатывается логика веб-сокета
@ServerEndpoint(value = "/websocket") //接受websocket请求路径
@Component //注册到spring容器中
public class MyWebSocket {
//保存所有在线socket连接
private static Map<String,MyWebSocket> webSocketMap = new LinkedHashMap<>();
//记录当前在线数目
private static int count=0;
//当前连接(每个websocket连入都会创建一个MyWebSocket实例
private Session session;
private Logger log = LoggerFactory.getLogger(this.getClass());
//处理连接建立
@OnOpen
public void onOpen(Session session){
this.session=session;
webSocketMap.put(session.getId(),this);
addCount();
log.info("新的连接加入:{}",session.getId());
}
//接受消息
@OnMessage
public void onMessage(String message,Session session){
log.info("收到客户端{}消息:{}",session.getId(),message);
try{
this.sendMessage("收到消息:"+message);
}catch (Exception e){
e.printStackTrace();
}
}
//处理错误
@OnError
public void onError(Throwable error,Session session){
log.info("发生错误{},{}",session.getId(),error.getMessage());
}
//处理连接关闭
@OnClose
public void onClose(){
webSocketMap.remove(this.session.getId());
reduceCount();
log.info("连接关闭:{}",this.session.getId());
}
//群发消息
//发送消息
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
//广播消息
public static void broadcast(){
MyWebSocket.webSocketMap.forEach((k,v)->{
try{
v.sendMessage("这是一条测试广播");
}catch (Exception e){
}
});
}
//获取在线连接数目
public static int getCount(){
return count;
}
//操作count,使用synchronized确保线程安全
public static synchronized void addCount(){
MyWebSocket.count++;
}
public static synchronized void reduceCount(){
MyWebSocket.count--;
}
}
4. Реализация клиента
Клиент использует собственный веб-сокет h5, который может не поддерживаться некоторыми браузерами. код показывает, как показано ниже:
<html>
<head>
<title>websocket测试</title>
<meta charset="utf-8" />
</head>
<body>
<button onclick="sendMessage()">测试</button>
<script>
let socket = new WebSocket("ws://localhost:8080/websocket");
socket.onerror = err => {
console.log(err);
};
socket.onopen = event => {
console.log(event);
};
socket.onmessage = mess => {
console.log(mess);
};
socket.onclose = () => {
console.log("连接关闭");
};
function sendMessage() {
if (socket.readyState === 1) socket.send("这是一个测试数据");
else alert("尚未建立websocket连接");
}
</script>
</body>
</html>
3. Тест
Создайте группу тестирования контроллера, код выглядит следующим образом:
@RestController
public class HomeController {
@GetMapping("/broadcast")
public void broadcast(){
MyWebSocket.broadcast();
}
}
Затем откройте приведенный выше HTML-код, и вы увидите, что и браузер, и сервер выводят информацию об успешном подключении:
浏览器:
Event {isTrusted: true, type: "open", target: WebSocket, currentTarget: WebSocket, eventPhase: 2, …}
服务端:
2018-08-01 14:05:34.727 INFO 12708 --- [nio-8080-exec-1] com.fxb.h5websocket.MyWebSocket : 新的连接加入:0
Нажмите кнопку тестирования, и вы увидите следующий вывод на сервере:
2018-08-01 15:00:34.644 INFO 12708 --- [nio-8080-exec-6] com.fxb.h5websocket.MyWebSocket : 收到客户端2消息:这是一个测试数据
Снова откройте html-страницу, чтобы было два клиента веб-сокетов, а затем зайдите в браузерlocalhost:8080/broadcastПротестируйте функцию групповой отправки, каждый клиент выведет следующую информацию:
MessageEvent {isTrusted: true, data: "这是一条测试广播", origin: "ws://localhost:8080", lastEventId: "", source: null, …}
Исходный код доступен по адресугитхаб скачатьЗагружайте и скачивайте, не забывайте ставить лайки и звездочки
Эта статья была первоначально опубликована на:Уууу, она этого заслуживает? top/blog/detail…