欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2024-03-05 08:47:12
网上好多例子都是群发的,本文实现一对一的发送,给指定客户端进行消息推送 1、本文使用到netty-socketio开源库,以及mysql,所以首先在pom.xml中添加相...

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

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、工程结构

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

10、运行测试

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

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

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

运行结果如下

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

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

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

上一篇: Java基础--反射机制

下一篇: