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

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

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

运行结果如下

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

以上是 Spring Boot实战之netty-socketio实现简单聊天室(给指定用户推送消息) 的全部内容, 来源链接: utcz.com/p/211944.html

回到顶部