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

首先给大家推荐一下我老师大神的人工智能教学网站。教学不仅零基础,通俗易懂,而且非常风趣幽默,还时不时有内涵黄段子!点这里可以跳转到网站

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=8081wss.server.host=localhost spring.datasource.url = jdbc:mysql://127.0.0.1:3306/springlearnspring.datasource.username = rootspring.datasource.password = rootspring.datasource.driverClassName = com.mysql.jdbc.Driver # Specify the DBMSspring.jpa.database = MYSQL# Show or not log for each sql queryspring.jpa.show-sql = true# Hibernate ddl auto (create, create-drop, update)spring.jpa.hibernate.ddl-auto = update# Naming strategyspring.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; @SpringBootApplicationpublic 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; @Componentpublic 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; @Componentpublic 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="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="https://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" οnsubmit="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

运行结果如下

点这里可以跳转到人工智能网站

发表评论