您的位置:首页 > 教程文章 > 编程开发

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

:0 :2021-05-09 12:52:31

网上好多例子都是群发的,本文实现一对一的发送,给指定客户端进行消息推送
1、本文使用到netty-socketio开源库,以及MySQL,所以首先在pom.xml中添加相应的依赖库

com.corundumstudio.socketio
netty-socketio
1.7.11



org.springframework.boot
spring-boot-starter-data-jpa



mysql
mysql-connector-java


2、修改application.properties, 添加端口及主机数据库连接等相关配置,
wss.server.port=8081
wss.server.host=localhost

spring.datasource.url = jdbc:
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) {
//
//例如果使用上面的链接进行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 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三个用户
本文直接修改的 中的index.html文件
其中clientid为发送者id, targetclientid为目标方id,本文简单的将发送方和接收方写死在html文件中
使用 以下代码进行连接
io.connect('
index.html 文件内容如下








<link href="bootstrap.css" rel="external nofollow" />

<style type="text/css">
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 connect-msg="" src=" <br /> <br /> <script> <br /> <br /> var clientid = 'testclient1'; <br /> var targetClientId= 'testclient2'; <br /> <br /> var socket = io.connect(' <br /> <br /> socket.on('connect', function() { <br /> output('<span class=">Client has connected to the server!');
});

socket.on('messageevent', function(data) {
output('' + data.sourceClientId + ': ' + data.msgContent);
});

socket.on('disconnect', function() {
output('The client has disconnected!');
});

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 = "" + moment().format('HH:mm:ss.SSS') + "";
var element = $("

" + currentTime + " " + message + "
");
$('#console').prepend(element);
}

$(document).keydown(function(e){
if(e.keyCode == 13) {
$('#send').click();
}
});
</script>




 

Netty-socketio Demo Chat






 
 


 







3、本例测试时
testclient1 发送消息给 testclient2
testclient2 发送消息给 testclient1
testclient3发送消息给testclient1
运行结果如下

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

Java中JDBC连接数据库详解
java 可变参数详解及实例