基于订阅/发布模式的简易聊天室实现(java+redis)

对于本篇博文主要从以下两部分介绍简易聊天室的实现:
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);
    }

到此,一个简单的聊天室编写完成。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值