在线WebSocket客户端工具
Maven依赖
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
<version>5.7.16</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.7.RELEASE</version>
<configuration>
<mainClass>com.hwl.socket.SocketApplication</mainClass>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 用于将当前项目当成war包-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
四个类 启动类 websocket具体处理类 websocket拦截器类 websocket注册类
启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
// ws://localhost:5000/websocket?key=A 开发时
// ws://192.168.110.6:8080/socket/websocket?key=A 部署到tomcat时
@SpringBootApplication
@EnableWebSocket
public class SocketApplication extends SpringBootServletInitializer {
// 使用SpringBoot内置tomcat启动项目的启动方法
public static void main(String[] args) {
SpringApplication.run(SocketApplication.class, args);
}
// 使用外置Tomcat启动项目的棋类方法 继承SpringBootServletInitializer 重写 configure
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(SocketApplication.class);
}
}
webSocket具体处理类
// Handler 这个类是单例的。交由SpringBoot管理是单例的不交也是单例的
@Slf4j
//@Component 这个类注入也行不注入野心。
public class Handler extends TextWebSocketHandler {
//静态变量,用来记录当前在线连接数。
private static final AtomicInteger onlineCount = new AtomicInteger(0);
//concurrent包的线程安全
private static final ConcurrentHashMap<String, WebSocketSession> map = new ConcurrentHashMap<String, WebSocketSession>();
// 由于这个类是单例的所以这样写是有问题的。 应用时要另行处理
private String key;
// 连接建立成功调用的方法
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
this.key = String.valueOf(session.getAttributes().get("key"));
addOnlineCount();
map.put(key, session);
log.info("[WebSocket] 新的连接加入:{}\t当前有{}个连接", key, getOnlineCount());
}
// 收到客户端消息后调用的方法
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
log.info("[WebSocket] 来自 {}-{} 的消息:{}", this.hashCode(), key, message);
try {
sendMessage(new SimpleDateFormat("yy-MM:dd HH:mm:ss").format(new Date()));
} catch (IOException e) {
e.printStackTrace();
}
}
// 连接关闭调用的方法
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
map.remove(key);
subOnlineCount(); //在线数减1
log.info("[WebSocket] 连接关闭:{}\t当前有{}个连接", key, getOnlineCount());
}
/*
*/
/**
* 发生错误时调用
*
* @param session
* @param error
*//*
@OnError
public void onError(Session session, Throwable error) {
log.error("[WebSocket] 异常:{}", error.getMessage());
}
*/
/**
* 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
*/
public void sendMessage(String message) throws IOException {
// 这个处理是有问题的。 key 一直是最后一个连接用户的key. 这个对象是单例的
map.get(key).sendMessage(new TextMessage(message));
//this.session.getAsyncRemote().sendText(message);
}
public static synchronized int getOnlineCount() {
return onlineCount.get();
}
public static synchronized void addOnlineCount() {
onlineCount.getAndIncrement();
}
public static synchronized void subOnlineCount() {
onlineCount.getAndDecrement();
}
}
webSocket拦截器类
import cn.hutool.http.HttpUtil;
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.HandshakeInterceptor;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.UUID;
@Component
public class HandlerInterceptor implements HandshakeInterceptor {
@Override // 握手前
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
Map<String, String> paramMap = HttpUtil.decodeParamMap(request.getURI().getQuery(), StandardCharsets.UTF_8);
attributes.put("key", paramMap.getOrDefault("key","default")+ UUID.randomUUID().toString().substring(0,5));
return true;
}
@Override // 握手后
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Exception exception) {
}
}
webSocket注册类
import com.hwl.socket.interceptor.HandlerInterceptor;
import com.hwl.socket.server.Handler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
public class WebSocketRegister implements WebSocketConfigurer {
@Autowired
private HandlerInterceptor handlerInterceptor;
// @Autowired
// private Handler handler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new Handler(), "websocket") # 访问的path
.addInterceptors(handlerInterceptor) # 拦截器
.setAllowedOrigins("*"); # 跨域
}
}
|