1.基于java注解实现websocket服务器端
1.1需要的类
1.1.1服务终端类
用java注解来监听连接@serverendpoint、连接成功@onopen、连接失败@onclose、收到消息等状态@onmessage
1.1.2配置类
把spring中的serverendpointexporter对象注入进来
2.1代码示例
2.1.1 maven配置
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/pom/4.0.0"
xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<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">
<head>
<meta charset="utf-8">
<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 握手拦截器
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">
<head>
<meta charset="utf-8">
<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>
发表评论