(java)websocket服务的两种实现方式

humannoid 2024-07-31 12:05:03 阅读 60

1.基于java注解实现websocket服务器端

1.1需要的类

1.1.1服务终端类

用java注解来监听连接@ServerEndpoint、连接成功@OnOpen、连接失败@OnClose、收到消息等状态@OnMessage

1.1.2配置类

把spring中的ServerEndpointExporter对象注入进来

2.1代码示例

2.1.1 maven配置

<code><?xml version="1.0" encoding="UTF-8"?>code>

<project xmlns="http://maven.apache.org/POM/4.0.0"code>

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"code>

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">code>

<modelVersion>4.0.0</modelVersion>

<groupId>com.heima</groupId>

<artifactId>ws-demo</artifactId>

<version>1.0-SNAPSHOT</version>

<properties>

<maven.compiler.source>8</maven.compiler.source>

<maven.compiler.target>8</maven.compiler.target>

<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

</properties>

<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter</artifactId>

<version>2.7.3</version>

</dependency>

<dependency>

<groupId>org.projectlombok</groupId>

<artifactId>lombok</artifactId>

<version>1.16.22</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-websocket -->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-websocket</artifactId>

<version>2.7.14</version>

</dependency>

</dependencies>

</project>

2.1.2 WsServerEndpoint类

package com.heima;

import lombok.extern.slf4j.Slf4j;

import org.springframework.scheduling.annotation.EnableScheduling;

import org.springframework.scheduling.annotation.Scheduled;

import org.springframework.stereotype.Component;

import javax.websocket.OnClose;

import javax.websocket.OnMessage;

import javax.websocket.OnOpen;

import javax.websocket.Session;

import javax.websocket.server.ServerEndpoint;

import java.io.IOException;

import java.util.HashMap;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

/***

* 监听websocket地址 /myWs

*/

@ServerEndpoint("/myWs")

@Component

@Slf4j

@EnableScheduling

public class WsServerEndpoint {

static Map<String,Session> map = new ConcurrentHashMap<String,Session>();

/***

* 连接建立时执行的操作

* @param session

*/

@OnOpen

public void onOpen(Session session)

{

map.put(session.getId(),session);

log.info("websocket is open");

}

/***

* 收到客户端消息执行的操作

* @param text

*/

@OnMessage

public String OnMessage(String text)

{

log.info("收到了一条信息"+text);

return "已收到你的信息" ;

}

/***

* 连接关闭时执行的操作

* @param session

*/

@OnClose

public void OnClose(Session session)

{

map.remove(session.getId());

log.info("连接关闭时执行的操作");

}

/***

* 向客户端发送信息

*/

@Scheduled(fixedRate = 2000)

public void sendMsg() throws IOException {

for (String key : map.keySet())

{

map.get(key).getBasicRemote().sendText("你好,你好");

}

}

}

2.1.3 WebSocketConfig

package com.heima;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration

public class WebSocketConfig {

@Bean

public ServerEndpointExporter serverEndpointExporter()

{

return new ServerEndpointExporter();

}

}

2.1.3 前端测试代码

<!DOCTYPE html>

<html lang="en">code>

<head>

<meta charset="UTF-8">code>

<title>wsClient</title>

</head>

<body>

<script>

// 创建websocket

let ws = new WebSocket("ws://localhost:8080/myWs")

//向服务器发送hello

ws.onopen=function (){

ws.send("hello")

}

//监听数据ws://localhost:8080/myWs

ws.onmessage=function (message){

console.log(message.data)

}

</script>

</body>

</html>

2.1.4测试结果

2.1.4.1 当打开浏览器时

2.1.4.2 当关闭浏览器时

2.1.4.3 当刷新浏览器的时候

2.基于spring提供的类和接口刷新websocket服务器端

2.1:HttpSessionHandShakeInter 握手拦截器

<code>package com.spring;

import lombok.extern.slf4j.Slf4j;

import org.springframework.context.annotation.Configuration;

import org.springframework.http.server.ServerHttpRequest;

import org.springframework.http.server.ServerHttpResponse;

import org.springframework.stereotype.Component;

import org.springframework.web.socket.WebSocketHandler;

import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

import java.util.Map;

/***

* 握手拦截器

*/

@Component

@Slf4j

public class MyWsInterceptor extends HttpSessionHandshakeInterceptor {

@Override

public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {

log.info(request.getRemoteAddress().toString()+"开始握手");

return super.beforeHandshake(request, response, wsHandler, attributes);

}

@Override

public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) {

log.info(request.getRemoteAddress().toString()+"完成握手");

super.afterHandshake(request, response, wsHandler, ex);

}

}

2.2  MyWsHandler 主处理程序

sessionbean封装类

import lombok.AllArgsConstructor;

import lombok.Data;

import org.springframework.web.socket.WebSocketSession;

@Data

@AllArgsConstructor

public class SessionBean {

private WebSocketSession webSocketSession;

private Integer clientId;

}

 主处理程序

package com.spring;

import lombok.extern.slf4j.Slf4j;

import org.springframework.boot.web.servlet.server.Session;

import org.springframework.scheduling.annotation.EnableScheduling;

import org.springframework.scheduling.annotation.Scheduled;

import org.springframework.stereotype.Component;

import org.springframework.web.socket.CloseStatus;

import org.springframework.web.socket.TextMessage;

import org.springframework.web.socket.WebSocketSession;

import org.springframework.web.socket.handler.AbstractWebSocketHandler;

import java.io.IOException;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

import java.util.concurrent.atomic.AtomicInteger;

/***

* webSocket 主处理程序

*/

@Component

@Slf4j

@EnableScheduling

public class MyWsHandler extends AbstractWebSocketHandler {

//map有并发线程问题 所以用ConcurrentHashMap

private static Map<String, SessionBean> map ;

//id有并发问题 所以用Integer的安全类型

private static AtomicInteger clientIdMaker;

static {

map = new ConcurrentHashMap<>();

clientIdMaker=new AtomicInteger(0);

}

//连接建立

@Override

public void afterConnectionEstablished(WebSocketSession session) throws Exception {

super.afterConnectionEstablished(session);

//将session 进一步封装 id采用的是自增

SessionBean sessionBean = new SessionBean(session, clientIdMaker.getAndIncrement());

map.put(session.getId(),sessionBean);

log.info(map.get(session.getId()).getClientId()+"建立了连接");

}

//收到消息

@Override

protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

super.handleTextMessage(session, message);

log.info(map.get(session.getId()).getClientId()+":"+message.getPayload());

}

//传输异常

@Override

public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {

super.handleTransportError(session, exception);

if (session.isOpen())

{

session.close();

}

map.remove(session.getId());

}

//连接关闭

@Override

public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {

super.afterConnectionClosed(session, status);

log.info(map.get(session.getId()).getClientId()+"关闭连接");

}

/***

* 向客户端发送信息

*/

@Scheduled(fixedRate = 2000)

public void sendMsg() throws IOException {

for (String key : map.keySet())

{

map.get(key).getWebSocketSession().sendMessage(new TextMessage("hello," +

"spring socket"));

}

}

}

2.3 WebSocketConfigurer 注册拦截器和主处理程序以及监听路径

package com.spring;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.socket.config.annotation.EnableWebSocket;

import org.springframework.web.socket.config.annotation.WebSocketConfigurer;

import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

import javax.annotation.Resource;

@Configuration

@EnableWebSocket

public class MyWsConfig implements WebSocketConfigurer {

@Resource

private MyWsHandler wsHandler;

@Resource

private MyWsInterceptor wsInterceptor;

@Override

public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

registry.addHandler(wsHandler,"/myWs1").addInterceptors(wsInterceptor).setAllowedOriginPatterns("*");

}

}

2.4 前端测试

<!DOCTYPE html>

<html lang="en">code>

<head>

<meta charset="UTF-8">code>

<title>wsClient</title>

</head>

<body>

<script>

// 创建websocket

let ws = new WebSocket("ws://localhost:8080/myWs1")

//向服务器发送hello

ws.onopen=function (){

ws.send("hello")

}

//监听数据ws://localhost:8080/myWs

ws.onmessage=function (message){

console.log(message.data)

}

</script>

</body>

</html>



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。