对于本篇博文主要从以下两部分介绍简易聊天室的实现:
1.介绍redis发布订阅模式
2.java代码实现订阅发布模式
一、redis发布订阅模式
redis订阅分为订阅频道和订阅模式
1.订阅频道
打开一个客户端1,订阅电影直播频道: 127.0.0.1:6379> subscribe "movie::live::room"
在电影直播频道发布信息A 127.0.0.1:6379> publish movie::live::room "Does someone like snow white?"
在消息发布后,订阅消息的客户端1就会收到发布的信息。如果我们想要订阅多个频道,可以使用订阅模式。
2.订阅模式
重新打开一个启客户端2,并订阅有关电影的模式: 127.0.0.1:6379> psubscribe "movie*"
此时在电影直播频道重新发布消息A,客户端1和客户端2都会收到发布的消息。
如果在电影历史频道发布消息B, 127.0.0.1:6379> publish movie::history::room "Does someone like snow white?"
此时只有客户端2会收到消息。
订阅模式支持* 、? 、 []三种模式
*匹配后面所有的字符
?匹配一个字符
[]匹配中括号里的字符 h[eo]llo 匹配hello和hollo
二、java代码实现订阅发布模式
接下来使用Jedis实现一个简单的聊天室
我们用redis作为服务转发,所以没有服务端代码,只需要写客户端就可以了:
定义客户端,功能比较简单,进入房间提示、离开房间提示、在房间说话:
package redis.publishandsubscribe;
import java.util.Scanner;
import redis.RedisUtil;
public class Client {
private String name ;
private ChatSubscribe roomSubListerner;
public Client(){
roomSubListerner = new ChatSubscribe();
}
public void setName(String name){
this.name =name;
}
public String getName(){
return name;
}
/* 进入房间*/
public void subscribe(final String[] room){
ChatSubscribe roomSub = roomSubListerner;
roomSub.setClientName(name);
roomSub.setRoom(room);
RedisUtil.subscribe(room, roomSub);
}
/* 退出房间*/
public void unSubscribe(final String[] room){
roomSubListerner.unsubscribe(room);
}
/*说话*/
public void say(final String room,String message){
RedisUtil.publish(room, name+" say:"+message);
}
}
在上面的代码中有一个ChatSubscribe的类,该类为聊天室的动作监听类,在这个类中我们只定义订阅频道、取消订阅频道、接收消息方法:
package redis.publishandsubscribe;
import redis.RedisUtil;
import redis.clients.jedis.JedisPubSub;
public class ChatSubscribe extends JedisPubSub{
/*成员名字*/
private String clientName;
/*房间名*/
private String[] room;
public String getClientName() {
return clientName;
}
public void setClientName(String clientName) {
this.clientName = clientName;
}
public String[] getRoom() {
return room;
}
public void setRoom(String[] room) {
this.room = room;
}
@Override
public void onUnsubscribe(String channel, int subscribedChannels) {
//do nothing
}
@Override
public void onSubscribe(String channel, int subscribedChannels) {
RedisUtil.publish( channel,clientName+ "进入房间");
}
@Override
public void onPUnsubscribe(String pattern, int subscribedChannels) {
}
@Override
public void onPSubscribe(String pattern, int subscribedChannels) {
}
@Override
public void onPMessage(String pattern, String channel, String message) {
}
@Override
public void onMessage(String channel, String message) {
System.out.println("收到来自"+channel+"房间的消息:"+message);
}
@Override
public void unsubscribe(String... channels) {
for(String c : channels)
RedisUtil.publish(c, clientName+"离开房间");
super.unsubscribe(channels);
}
}
接下来redis通用类的编写:
package redis;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisPubSub;
public class RedisUtil {
private static JedisPool jedisPool;
private RedisUtil(){
}
static {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(5);
poolConfig.setMinIdle(1);
poolConfig.setTestOnBorrow(true);
poolConfig.setNumTestsPerEvictionRun(10);
poolConfig.setTimeBetweenEvictionRunsMillis(60000);
poolConfig.setMaxWaitMillis(10000);
jedisPool = new JedisPool(poolConfig,"127.0.0.1",6379);
}
private static void returnResource(Jedis jedis) {
jedisPool.returnResource(jedis);
}
/*发布消息*/
public static void publish(String channel, String message){
Jedis jedis = null ;
try{
jedis = jedisPool.getResource();
jedis.publish(channel, message);
}catch(Exception e){
System.out.println(e);
}finally{
returnResource(jedis);
}
};
/*订阅房间*/
public static void subscribe(String[] room, JedisPubSub pubSub){
Jedis jedis = null ;
try{
jedis = jedisPool.getResource();
jedis.subscribe(pubSub , room);
}catch(Exception e){
System.out.println(e);
}finally{
returnResource(jedis);
}
}
}
最后是主函数启动客户端了:
public static void main(String[] args) throws InterruptedException {
final Client client = new Client();
client.setName("Mark");
final String[] rooms = {"movie::live::room"};
new Thread(new Runnable() {
@Override
public void run() {
// String[] rooms = {"peter::live::room","Bob::live::room"};
client.subscribe(rooms);
}
}).start();
Thread.sleep(3000);
while(true){
System.out.print("say something:");
Scanner scanner = new Scanner(System.in);
String message = scanner.nextLine();
if("quit".equals(message)){
break;
}else{
client.say(rooms[0], message);
System.out.println();
}
}
String[] unSubRoom ={"movie::live::room"};
client.unSubscribe(unSubRoom);
}
到此,一个简单的聊天室编写完成。