首页 > 编程 > Java > 正文

Spring Boot实战之netty-socketio实现简单聊天室(给指定用户推送消息)

2019-11-26 12:48:38
字体:
来源:转载
供稿:网友

网上好多例子都是群发的,本文实现一对一的发送,给指定客户端进行消息推送

1、本文使用到netty-socketio开源库,以及MySQL,所以首先在pom.xml中添加相应的依赖库

<dependency>     <groupId>com.corundumstudio.socketio</groupId>     <artifactId>netty-socketio</artifactId>     <version>1.7.11</version> </dependency> <dependency>     <groupId>org.springframework.boot</groupId>   <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency>   <groupId>mysql</groupId>   <artifactId>mysql-connector-java</artifactId> </dependency> 

2、修改application.properties, 添加端口及主机数据库连接等相关配置,

wss.server.port=8081 wss.server.host=localhost  spring.datasource.url = jdbc:mysql://127.0.0.1:3306/springlearn spring.datasource.username = root spring.datasource.password = root spring.datasource.driverClassName = com.mysql.jdbc.Driver  # Specify the DBMS spring.jpa.database = MYSQL # Show or not log for each sql query spring.jpa.show-sql = true # Hibernate ddl auto (create, create-drop, update) spring.jpa.hibernate.ddl-auto = update # Naming strategy spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy # stripped before adding them to the entity manager) spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect 

3、修改Application文件,添加nettysocket的相关配置信息

package com.xiaofangtech.sunt;  import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean;  import com.corundumstudio.socketio.AuthorizationListener; import com.corundumstudio.socketio.Configuration; import com.corundumstudio.socketio.HandshakeData; import com.corundumstudio.socketio.SocketIOServer; import com.corundumstudio.socketio.annotation.SpringAnnotationScanner;  @SpringBootApplication public class NettySocketSpringApplication {    @Value("${wss.server.host}")   private String host;    @Value("${wss.server.port}")   private Integer port;      @Bean   public SocketIOServer socketIOServer()    {     Configuration config = new Configuration();     config.setHostname(host);     config.setPort(port);          //该处可以用来进行身份验证     config.setAuthorizationListener(new AuthorizationListener() {       @Override       public boolean isAuthorized(HandshakeData data) {         //http://localhost:8081?username=test&password=test         //例如果使用上面的链接进行connect,可以使用如下代码获取用户密码信息,本文不做身份验证 //       String username = data.getSingleUrlParam("username"); //       String password = data.getSingleUrlParam("password");         return true;       }     });          final SocketIOServer server = new SocketIOServer(config);     return server;   }      @Bean   public SpringAnnotationScanner springAnnotationScanner(SocketIOServer socketServer) {     return new SpringAnnotationScanner(socketServer);   }      public static void main(String[] args) {     SpringApplication.run(NettySocketSpringApplication.class, args);   } } 

4、添加消息结构类MessageInfo.java

package com.xiaofangtech.sunt.message;  public class MessageInfo {   //源客户端id   private String sourceClientId;   //目标客户端id   private String targetClientId;   //消息类型   private String msgType;   //消息内容   private String msgContent;      public String getSourceClientId() {     return sourceClientId;   }   public void setSourceClientId(String sourceClientId) {     this.sourceClientId = sourceClientId;   }   public String getTargetClientId() {     return targetClientId;   }   public void setTargetClientId(String targetClientId) {     this.targetClientId = targetClientId;   }   public String getMsgType() {     return msgType;   }   public void setMsgType(String msgType) {     this.msgType = msgType;   }   public String getMsgContent() {     return msgContent;   }   public void setMsgContent(String msgContent) {     this.msgContent = msgContent;   } } 

5、添加客户端信息,用来存放客户端的sessionid

package com.xiaofangtech.sunt.bean;  import java.util.Date;  import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; import javax.validation.constraints.NotNull;  @Entity @Table(name="t_clientinfo") public class ClientInfo {   @Id   @NotNull   private String clientid;   private Short connected;   private Long mostsignbits;   private Long leastsignbits;   private Date lastconnecteddate;   public String getClientid() {     return clientid;   }   public void setClientid(String clientid) {     this.clientid = clientid;   }   public Short getConnected() {     return connected;   }   public void setConnected(Short connected) {     this.connected = connected;   }   public Long getMostsignbits() {     return mostsignbits;   }   public void setMostsignbits(Long mostsignbits) {     this.mostsignbits = mostsignbits;   }   public Long getLeastsignbits() {     return leastsignbits;   }   public void setLeastsignbits(Long leastsignbits) {     this.leastsignbits = leastsignbits;   }   public Date getLastconnecteddate() {     return lastconnecteddate;   }   public void setLastconnecteddate(Date lastconnecteddate) {     this.lastconnecteddate = lastconnecteddate;   }    } 

6、添加查询数据库接口ClientInfoRepository.java

package com.xiaofangtech.sunt.repository;  import org.springframework.data.repository.CrudRepository;  import com.xiaofangtech.sunt.bean.ClientInfo;  public interface ClientInfoRepository extends CrudRepository<ClientInfo, String>{   ClientInfo findClientByclientid(String clientId); } 

7、添加消息处理类MessageEventHandler.Java

package com.xiaofangtech.sunt.message;  import java.util.Date; import java.util.UUID;  import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;  import com.corundumstudio.socketio.AckRequest; import com.corundumstudio.socketio.SocketIOClient; import com.corundumstudio.socketio.SocketIOServer; import com.corundumstudio.socketio.annotation.OnConnect; import com.corundumstudio.socketio.annotation.OnDisconnect; import com.corundumstudio.socketio.annotation.OnEvent; import com.xiaofangtech.sunt.bean.ClientInfo; import com.xiaofangtech.sunt.repository.ClientInfoRepository;  @Component public class MessageEventHandler  {   private final SocketIOServer server;      @Autowired   private ClientInfoRepository clientInfoRepository;      @Autowired   public MessageEventHandler(SocketIOServer server)    {     this.server = server;   }   //添加connect事件,当客户端发起连接时调用,本文中将clientid与sessionid存入数据库   //方便后面发送消息时查找到对应的目标client,   @OnConnect   public void onConnect(SocketIOClient client)   {     String clientId = client.getHandshakeData().getSingleUrlParam("clientid");     ClientInfo clientInfo = clientInfoRepository.findClientByclientid(clientId);     if (clientInfo != null)     {       Date nowTime = new Date(System.currentTimeMillis());       clientInfo.setConnected((short)1);       clientInfo.setMostsignbits(client.getSessionId().getMostSignificantBits());       clientInfo.setLeastsignbits(client.getSessionId().getLeastSignificantBits());       clientInfo.setLastconnecteddate(nowTime);       clientInfoRepository.save(clientInfo);     }   }      //添加@OnDisconnect事件,客户端断开连接时调用,刷新客户端信息   @OnDisconnect   public void onDisconnect(SocketIOClient client)   {     String clientId = client.getHandshakeData().getSingleUrlParam("clientid");     ClientInfo clientInfo = clientInfoRepository.findClientByclientid(clientId);     if (clientInfo != null)     {       clientInfo.setConnected((short)0);       clientInfo.setMostsignbits(null);       clientInfo.setLeastsignbits(null);       clientInfoRepository.save(clientInfo);     }   }      //消息接收入口,当接收到消息后,查找发送目标客户端,并且向该客户端发送消息,且给自己发送消息   @OnEvent(value = "messageevent")   public void onEvent(SocketIOClient client, AckRequest request, MessageInfo data)    {     String targetClientId = data.getTargetClientId();     ClientInfo clientInfo = clientInfoRepository.findClientByclientid(targetClientId);     if (clientInfo != null && clientInfo.getConnected() != 0)     {       UUID uuid = new UUID(clientInfo.getMostsignbits(), clientInfo.getLeastsignbits());       System.out.println(uuid.toString());       MessageInfo sendData = new MessageInfo();       sendData.setSourceClientId(data.getSourceClientId());       sendData.setTargetClientId(data.getTargetClientId());       sendData.setMsgType("chat");       sendData.setMsgContent(data.getMsgContent());       client.sendEvent("messageevent", sendData);       server.getClient(uuid).sendEvent("messageevent", sendData);     }        } } 

8、添加ServerRunner.java

package com.xiaofangtech.sunt.message;  import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component;  import com.corundumstudio.socketio.SocketIOServer;  @Component public class ServerRunner implements CommandLineRunner {   private final SocketIOServer server;    @Autowired   public ServerRunner(SocketIOServer server) {     this.server = server;   }    @Override   public void run(String... args) throws Exception {     server.start();   } } 

9、工程结构

10、运行测试

1) 添加基础数据,数据库中预置3个客户端testclient1,testclient2,testclient3

2) 创建客户端文件index.html,index2.html,index3.html分别代表testclient1 testclient2 testclient3三个用户

本文直接修改的https://github.com/mrniko/netty-socketio-demo/tree/master/client 中的index.html文件

其中clientid为发送者id, targetclientid为目标方id,本文简单的将发送方和接收方写死在html文件中

使用 以下代码进行连接

io.connect('http://localhost:8081?clientid='+clientid); 

index.html 文件内容如下

<!DOCTYPE html> <html> <head>      <meta charset="utf-8" />      <title>Demo Chat</title>      <link href="bootstrap.css" rel="external nofollow" rel="stylesheet">    <style>     body {       padding:20px;     }     #console {       height: 400px;       overflow: auto;     }     .username-msg {color:orange;}     .connect-msg {color:green;}     .disconnect-msg {color:red;}     .send-msg {color:#888}   </style>     <script src="js/socket.io/socket.io.js"></script>     <script src="js/moment.min.js"></script>     <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>    <script>      var clientid = 'testclient1';     var targetClientId= 'testclient2';          var socket = io.connect('http://localhost:8081?clientid='+clientid);      socket.on('connect', function() {       output('<span class="connect-msg">Client has connected to the server!</span>');     });      socket.on('messageevent', function(data) {       output('<span class="username-msg">' + data.sourceClientId + ':</span> ' + data.msgContent);     });      socket.on('disconnect', function() {       output('<span class="disconnect-msg">The client has disconnected!</span>');     });          function sendDisconnect() {             socket.disconnect();         }      function sendMessage() {             var message = $('#msg').val();             $('#msg').val('');              var jsonObject = {sourceClientId: clientid,                      targetClientId: targetClientId,                      msgType: 'chat',                      msgContent: message};             socket.emit('messageevent', jsonObject);     }      function output(message) {             var currentTime = "<span class='time'>" + moment().format('HH:mm:ss.SSS') + "</span>";             var element = $("<div>" + currentTime + " " + message + "</div>");       $('#console').prepend(element);     }      $(document).keydown(function(e){       if(e.keyCode == 13) {         $('#send').click();       }     });   </script> </head>  <body>    <h1>Netty-socketio Demo Chat</h1>    <br/>    <div id="console" class="well">   </div>      <form class="well form-inline" onsubmit="return false;">       <input id="msg" class="input-xlarge" type="text" placeholder="Type something..."/>       <button type="button" onClick="sendMessage()" class="btn" id="send">Send</button>       <button type="button" onClick="sendDisconnect()" class="btn">Disconnect</button>     </form>  </body>  </html> 

3、本例测试时

testclient1 发送消息给 testclient2

testclient2 发送消息给 testclient1

testclient3发送消息给testclient1

运行结果如下


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表