赞
踩
目录结构如下
0.创建基础springboot项目,此处不再赘述
1.在pom文件中导入socket相关依赖
<!-- web 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- lombok插件,可以自动生成getter、setter等方法,简化代码 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- 主要依赖 socket通信 --> <dependency> <groupId>com.corundumstudio.socketio</groupId> <artifactId>netty-socketio</artifactId> <version>1.7.15</version> </dependency> <!-- 日志打印 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.26</version> </dependency>
以下代码仅供参考,完整代码地址: https://github.com/Szwget/springboot-socket.git
1.在application.properties 中编写socket相关配置文件
# netty-socket-io
nettySocketIO.port=10089
nettySocketIO.linkedCount=200
nettySocketIO.allowRequest=true
# 协议升级超时时间(毫秒),默认10秒,HTTP握手升级为ws协议超时时间
nettySocketIO.upgradeTimeOut=10000
# 60s内未接受到消息发送超时事件
nettySocketIO.pingTimeOut=60000
nettySocketIO.pingSpace=25000
#设置交互内容长度
nettySocketIO.contextLength=2071738
#设置每帧处理数据大小(防注入攻击)
nettySocketIO.payloadLength=2071738
2.编写相关java代码
0) 注入配置文件的配置信息
@Configuration @Slf4j public class SocketConfig { @Value("${nettySocketIO.port}") private int port; @Value("${nettySocketIO.linkedCount}") private int linkedCount; @Value("${nettySocketIO.allowRequest}") private Boolean allowRequest; @Value("${nettySocketIO.upgradeTimeOut}") private Integer upgradeTimeOut; @Value("${nettySocketIO.pingTimeOut}") private Integer pingTimeOut; @Value("${nettySocketIO.pingSpace}") private Integer pingSpace; @Value("${nettySocketIO.contextLength}") private Integer contextLength; @Value("${nettySocketIO.payloadLength}") private Integer payloadLength; //把socketServer注册为一个bean @Bean("socketIOServer") public SocketIOServer socketIOServer(){ com.corundumstudio.socketio.Configuration configuration = new com.corundumstudio.socketio.Configuration(); configuration.setPort(port); com.corundumstudio.socketio.SocketConfig socketConfig = new com.corundumstudio.socketio.SocketConfig(); socketConfig.setReuseAddress(true); configuration.setSocketConfig(socketConfig); configuration.setWorkerThreads(linkedCount); configuration.setAllowCustomRequests(allowRequest); configuration.setUpgradeTimeout(upgradeTimeOut); configuration.setPingTimeout(pingTimeOut); configuration.setPingInterval(pingSpace); configuration.setMaxHttpContentLength(contextLength); configuration.setMaxFramePayloadLength(payloadLength); return new SocketIOServer(configuration); } //开启socketIO注解 // @Bean // public SpringAnnotationScanner springAnnotationScanner(SocketIOServer socketIOServer){ // return new SpringAnnotationScanner(socketIOServer); // } }
1)定义消息和房间实体bean
a. 定义消息相关实体类 ===>MessageBean.java
@Data //lombok注解,可自动生成getter、setter、构造方法等 public class MessageBean implements Serializable { private static final long serialVersionUID = 1L; //房间的标识 private String roomName; //用户标识 public String userName; public String token; //消息内容 public String message; //操作类型 public String option; }
b.定义房间相关实体类 ===>
@Data
public class RoomBean implements Serializable {
private static final long serialVersionUID = 1L;
//房间的标识
private String roomName;
//用户标识
private String userId;
private String userName;
//动作类型 用户进入/退出房间
private String option;
}
2)定义事件常量
public class Config {
public static final String CHATEVENT = "chatevent";
public static final String ROOMEVENT = "roomevent";
public static final String TARGETEVENT = "target";
//系统消息
public static final String SYSTEM_ROOM_MESSAGE = "system-message";
//房间消息
public static final String SYSTEM_MESSAGE = "system-room-message";
}
3) 编写事件监听器
a.连接事件监听器
@Slf4j public class AppConnectListener implements ConnectListener { @Autowired private SocketIOServer server; public AppConnectListener (SocketIOServer server){ this.server = server; } @Override public void onConnect(SocketIOClient client) { log.info("{}进入连接...",client.getSessionId()); } }
b.断开连接监听事件
@Slf4j public class AppDisconnectListener implements DisconnectListener { @Autowired private SocketIOServer server; public AppDisconnectListener (SocketIOServer server){ this.server = server; } @Override public void onDisconnect(SocketIOClient client) { log.info("{} 断开连接.", client.getSessionId()); } }
c.进入房间监听器
@Component @Slf4j public class RoomListener implements DataListener<RoomBean> { @Autowired private SocketIOServer server; public RoomListener(SocketIOServer server){ this.server = server; } @Override public void onData(SocketIOClient client, RoomBean data, AckRequest ackSender) throws Exception { String roomName = data.getRoomName(); BroadcastOperations bo = server.getRoomOperations(roomName); String option = data.getOption(); if("join".equals(option)){ //客户端加入房间 client.joinRoom(data.getRoomName()); //发送进入房间消息到所有在线的客户端 bo.sendEvent(Config.ROOMEVENT,data.getToken().concat("进入房间")); }else{ server.getClient(client.getSessionId()).sendEvent(Config.TARGETEVENT, "走错了,小老弟~"); } } }
d. 发送消息监听器
@Component @Slf4j public class SendMessageListener implements DataListener<MessageBean> { @Autowired private SocketIOServer server; public SendMessageListener (SocketIOServer server){ this.server = server; } @Override public void onData(SocketIOClient client, MessageBean data, AckRequest ackSender) throws Exception { String roomName = data.getRoomName(); String option = data.getOption(); BroadcastOperations bo = server.getRoomOperations(roomName); if ("send".equals(option)) { bo.sendEvent(Config.TARGETEVENT, data); } else { bo.sendEvent(Config.TARGETEVENT,"这是什么操作???"); } } }
4)编写socketServer启动类,当springboot项目启动的时候,启动socketServer
@Component @Order(1) @Slf4j public class Server implements CommandLineRunner { private final SocketIOServer server; @Autowired public Server(SocketIOServer socketIOServer) { this.server = socketIOServer; } public void init() { // Configuration config = new Configuration(); // config.setPort(prot); // final SocketIOServer server = new SocketIOServer(config); // 连接监听器 server.addConnectListener(new AppConnectListener(server)); // 断开连接监听器 server.addDisconnectListener(new AppDisconnectListener(server)); // 消息发送监听器 server.addEventListener(Config.CHATEVENT, MessageBean.class, new SendMessageListener(server)); server.addEventListener(Config.ROOMEVENT, RoomBean.class, new RoomListener(server)); // 服务启动 log.info("socket服务准备启动"); server.startAsync(); log.info("socket启动完成"); } @Override public void run(String... args) throws Exception { this.init(); } }
客户端1和客户端2的代码本质上是一样的,因为本例的代码的用户信息是在页面写死的,所以有两套代码
<!doctype html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdn.bootcss.com/vue/2.5.22/vue.min.js"></script> <script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.slim.js"></script> </head> <title>User1</title> <body class="luck-draw-input-box"> <div id="luck_login" class="luck-draw-input"> <div> <input id="uid" name="uid" type="text" placeholder="请输入消息" class="name" v-model="msg"> <a href="javascript:;" class="draw-btn" v-on:click="subMsg">发送</a> </div> <div v-for="(item,index) in content" style="display: flex;"> <p :key="index" style="margin-right: 10px;">{{item.userName}}:</p> <p :key="index">{{item}}</p> </div> </div> <script> var mv = new Vue({ el: '#luck_login', data: { username: '', socket:'', msg:'', content:[] }, created(){ //生命周期钩子,在实例创建完成后被立即调用 this.join() }, methods: { //加入房间 join(event) { let self = this; //开始连接server self.socket = io('ws://192.168.1.190:10099', {transports: ['websocket']}); //debugger self.socket.on('connect', function (data) { self.socket.emit('roomevent', {// roomDataListener roomName: "001", userId: "001", userName:"AAA", option: "join" }); }); //点对点的消息 self.socket.on('target', function (data) { console.log(data); mv.content.push(data); }); }, //发送消息 subMsg(){ this.socket.emit('chatevent',{ roomName: "001", userName:"AAA", token: "001", message:this.msg, option:'send' }) } } }) </script> </body> </html>
2.客户端2
<!doctype html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdn.bootcss.com/vue/2.5.22/vue.min.js"></script> <script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.slim.js"></script> </head> <title>User2</title> <body class="luck-draw-input-box"> <div id="luck_login" class="luck-draw-input"> <div> <input id="uid" name="uid" type="text" placeholder="请输入消息" class="name" v-model="msg"> <a href="javascript:;" class="draw-btn" v-on:click="subMsg">发送</a> </div> <div v-for="(item,index) in content" style="display: flex;"> <p :key="index" style="margin-right: 10px;">{{item.userName}}:</p> <p :key="index">{{item}}</p> </div> </div> <script> var mv = new Vue({ el:'#luck_login', data:{ uid:'', username:'', socket:'', msg:'', content:[] }, created(){ //生命周期钩子,在实例创建完成后被立即调用 this.join() }, methods:{ join(event){ let self = this; //开始连接server self.socket = io('http://192.168.1.190:10099',{transports:['websocket']}); //debugger self.socket.on('connect', function(data){ self.socket.emit('roomevent', {//roomDataListener roomName: "001", userId: "002", userName:"BBB", option: "join" }); }); //点对点的消息 self.socket.on('target', function(data) { console.log(data); mv.content.push(data); }); self.socket.on('chatevent', function(data) { console.log("chatevent"); console.log(data); if(data){ mv.content.push(data); } }); }, subMsg(){ this.socket.emit('chatevent',{ roomName: "001", userName:"BBB", token: "002", message:this.msg, option:'send' }) } } }) </script> </body> </html>
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。