Redis 멀 티 채 팅 방 기능 구현

12757 단어 Redis채 팅 방
본 고 는 Redis 가 다 중 채 팅 방 기능 을 지원 하 는 디자인 코드 를 공유 하여 여러분 께 참고 하 시기 바 랍 니 다.구체 적 인 내용 은 다음 과 같 습 니 다.
설계 원리

왼쪽 에 있 는 데이터 필드 는 두 개의 채 팅 방 을 대표 하고 채 팅 방 id 는 각각 827,729 입 니 다.
채 팅 방 827 에 서 는 jason 22,jeff 24 가 각각 채 팅 방 id 5,6 소식 을 읽 었 다.
오른쪽 에 있 는 데이터 필드 는 사용자 가 서로 다른 채 팅 방 에 있 는 것 을 대표 합 니 다.jason 22 는 827 과 729 채 팅 방 에 참 여 했 습 니 다.이 두 채 팅 방 에서 그 는 각각 id 가 5 와 id 가 10 이라는 소식 을 읽 었 습 니 다.
또한 827 채 팅 방 id 가 5 라 는 소식 은 729 채 팅 방 id 가 5 라 는 소식 과 다르다.
동시에 세 개의 도 메 인 이 있다.
msgs:chatid
이것 은 zset 입 니 다.질서 있 는 집합 입 니 다.member 는 메시지 체 이 고 score 는 메시지 id 입 니 다.
어떤 채 팅 방 에서 이미 보 낸 메 시 지 를 대표 합 니 다.
또한 여기에 저 장 된 것 은 유용 한 소식 으로 이미 모두 가 읽 은 소식 은 삭 제 될 것 이다.
ids:chatid
String 형 데이터 입 니 다.최신 메시지 의 번호 가 들 어 있 습 니 다.(메 시 지 를 보 낼 때 이 필드 를 추가 하면 최신 값 을 얻 을 수 있 습 니 다)
ids:chat:
String 형 데이터 입 니 다.최신 채 팅 방 번호 가 들 어 있 습 니 다.(채 팅 방 을 만 들 때 이 필드 를 추가 합 니 다)
코드
OK.코드 보기 시작. 

public String createChat(Jedis conn, String sender, Set<String> recipients, String message) { 
//     redis    ids:chat:     
//      1 
    String chatId = String.valueOf(conn.incr("ids:chat:")); 
    return createChat(conn, sender, recipients, message, chatId); 
  } 
 
 
  /** 
  * 
  * @param conn 
  * @param sender        
  * @param recipients        
  * @param message        
  * @param chatId        
  * @return 
  */ 
  public String createChat( Jedis conn, String sender,  
    Set<String> recipients, String message, String chatId){ 
  //               
    recipients.add(sender); 
 
 
    Transaction trans = conn.multi(); 
    for (String recipient : recipients){ 
  //                 0    
      trans.zadd("chat:" + chatId, 0, recipient); 
  //            
      trans.zadd("seen:" + recipient, 0, chatId); 
    } 
    trans.exec(); 
 
 
    return sendMessage(conn, chatId, sender, message); 
  } 
 
 
  public String sendMessage(Jedis conn, String chatId, String sender, String message) { 
   
  //        ?         
  //  acquireLock     
    String identifier = acquireLock(conn, "chat:" + chatId); 
    if (identifier == null){ 
      throw new RuntimeException("Couldn't get the lock"); 
    } 
    try { 
    //                          1 
      long messageId = conn.incr("ids:" + chatId); 
      HashMap<String,Object> values = new HashMap<String,Object>(); 
      values.put("id", messageId); 
      values.put("ts", System.currentTimeMillis()); 
      values.put("sender", sender); 
      values.put("message", message); 
      String packed = new Gson().toJson(values); 
       
      //           
      //     ----  json  
      //   zset   score         
      conn.zadd("msgs:" + chatId, messageId, packed); 
    }finally{ 
      releaseLock(conn, "chat:" + chatId, identifier); 
    } 
    return chatId; 
  } 
 메 시 지 를 보 내 면 이제 OK 입 니 다.나머지 는 사용자 가 읽 지 않 은 메 시 지 를 가 져 오 는 것 입 니 다.이것 은 비교적 번거롭다,응,상당히 번거롭다 

 @SuppressWarnings("unchecked") 
  public List<ChatMessages> fetchPendingMessages(Jedis conn, String recipient) { 
   
  //                     id 
  //       seenSet size    
    Set<Tuple> seenSet = conn.zrangeWithScores("seen:" + recipient, 0, -1); 
    List<Tuple> seenList = new ArrayList<Tuple>(seenSet); 
 
 
    Transaction trans = conn.multi(); 
    for (Tuple tuple : seenList){ 
      String chatId = tuple.getElement(); 
      int seenId = (int)tuple.getScore(); 
      //                 
      //min   max     -inf   +inf 
      trans.zrangeByScore("msgs:" + chatId, String.valueOf(seenId + 1), "inf"); 
    } 
    //          results       
    List<Object> results = trans.exec(); 
 
 
    //com.google.gson.Gson jar       
    Gson gson = new Gson(); 
    Iterator<Tuple> seenIterator = seenList.iterator(); 
    Iterator<Object> resultsIterator = results.iterator(); 
 
 
    //                 chatMessages 
    List<ChatMessages> chatMessages = new ArrayList<ChatMessages>(); 
    List<Object[]> seenUpdates = new ArrayList<Object[]>(); 
    List<Object[]> msgRemoves = new ArrayList<Object[]>(); 
     
     
    //    while                    
    while (seenIterator.hasNext()){ 
      Tuple seen = seenIterator.next(); 
      Set<String> messageStrings = (Set<String>)resultsIterator.next(); 
      if (messageStrings.size() == 0){ 
      //        
        continue; 
      } 
 
 
      //        
      //                   
      //seedid               0 
      int seenId = 0; 
      //            
      String chatId = seen.getElement(); 
       
      List<Map<String,Object>> messages = new ArrayList<Map<String,Object>>(); 
       
      //             
      for (String messageJson : messageStrings){ 
        Map<String,Object> message = (Map<String,Object>)gson.fromJson( 
          messageJson, new TypeToken<Map<String,Object>>(){}.getType()); 
        int messageId = ((Double)message.get("id")).intValue(); 
 
 
        if (messageId > seenId){ 
          seenId = messageId; 
        } 
        message.put("id", messageId); 
        //            
        messages.add(message); 
      } 
      //                 
      conn.zadd("chat:" + chatId, seenId, recipient); 
       
      //                 
      seenUpdates.add(new Object[]{"seen:" + recipient, seenId, chatId}); 
 
 
      //   0 member-score 
      Set<Tuple> minIdSet = conn.zrangeWithScores("chat:" + chatId, 0, 0); 
      //     ?         zset                          
      if (minIdSet.size() > 0){ 
      Tuple tuple=minIdSet.iterator().next(); 
      System.out.println("     tuple:"+tuple.getElement()+"--"+tuple.getScore()); 
        msgRemoves.add(new Object[]{"msgs:" + chatId, tuple.getScore()}); 
      } 
      chatMessages.add(new ChatMessages(chatId, messages)); 
    } 
 
 
    trans = conn.multi(); 
    for (Object[] seenUpdate : seenUpdates){ 
      trans.zadd( 
        (String)seenUpdate[0], 
        (Integer)seenUpdate[1], 
        (String)seenUpdate[2]); 
    } 
    for (Object[] msgRemove : msgRemoves){ 
      trans.zremrangeByScore( 
        (String)msgRemove[0], 0, ((Double)msgRemove[1]).intValue()); 
    } 
    trans.exec(); 
 
 
    //                   
    return chatMessages; 
  } 
OK,테스트 코드 를 봅 시다.

package redisinaction; 
 
 
import java.util.Arrays; 
import java.util.HashSet; 
import java.util.Iterator; 
import java.util.List; 
import java.util.Map; 
import java.util.Set; 
 
 
import org.junit.BeforeClass; 
import org.junit.Test; 
 
 
import jedis.redis_in_action.Chapter06; 
import jedis.redis_in_action.Chapter06.ChatMessages; 
import redis.clients.jedis.Jedis; 
import redis.clients.jedis.Tuple; 
 
 
/**  
 * This class is used for ...  
 * @author dlf([email protected]) 
 * @version 1.0, 2016 10 17    10:15:58  
 */ 
public class Chapter06Test { 
  static Jedis conn = null; 
  static Chapter06 c=null; 
   
  @BeforeClass 
  public static void initConn(){ 
    System.out.println("test before"); 
    conn = new Jedis("10.150.0.80"); 
    conn.auth("dlf123123"); 
     
    c=new Chapter06(); 
  } 
   
 
 
   
  @Test 
   public void testMultiRecipientMessaging() { 
      System.out.println("
----- testMultiRecipientMessaging -----"); conn.del("ids:chat:", "msgs:1", "ids:1", "seen:joe", "seen:jeff", "seen:jenny"); System.out.println("Let's create a new chat session with some recipients..."); Set<String> recipients = new HashSet<String>(); recipients.add("jeff"); recipients.add("jenny"); String chatId = c.createChat(conn, "joe", recipients, "message 1"); System.out.println("Now let's send a few messages..."); for (int i = 2; i < 5; i++){ c.sendMessage(conn, chatId, "joe", "message " + i); } System.out.println(); System.out.println(" "); // Set<Tuple> messageFromBase=conn.zrangeWithScores("msgs:"+chatId, 0, -1); Iterator<Tuple> iterator=messageFromBase.iterator(); while(iterator.hasNext()){ Tuple tuple=iterator.next(); System.out.println(tuple.getElement()+" --  "+tuple.getScore()); } System.out.println("And let's get the messages that are waiting for jeff and jenny..."); List<ChatMessages> r1 = c.fetchPendingMessages(conn, "jeff"); List<ChatMessages> r2 = c.fetchPendingMessages(conn, "jenny"); // joe msgs:1 // ? ? List<ChatMessages> r3 = c.fetchPendingMessages(conn, "joe"); System.out.println("They are the same? " + r1.equals(r2)); System.out.println("Those messages are:"); for(ChatMessages chat : r1){ System.out.println(" chatId: " + chat.chatId); System.out.println(" messages:"); for(Map<String,Object> message : chat.messages){ System.out.println(" " + message); } } System.out.println(" "); messageFromBase=conn.zrangeWithScores("msgs:"+chatId, 0, -1); iterator=messageFromBase.iterator(); while(iterator.hasNext()){ Tuple tuple=iterator.next(); System.out.println(tuple.getElement()+" --  "+tuple.getScore()); } conn.del("ids:chat:", "msgs:1", "ids:1", "seen:joe", "seen:jeff", "seen:jenny"); } }
다 됐 으 니 코드 를 복사 해서 직접 보 세 요.
다음은 테스트 결과 입 니 다.
test before
----- testMultiRecipientMessaging -----
Let's create a new chat session with some recipients...
Now let's send a few messages...
메시지 라 이브 러 리 보기
{"sender":"joe","id":1,"message":"message 1","ts":1477276890018} --  1.0
{"sender":"joe","id":2,"message":"message 2","ts":1477276890113} --  2.0
{"sender":"joe","id":3,"message":"message 3","ts":1477276890115} --  3.0
{"sender":"joe","id":4,"message":"message 4","ts":1477276890116} --  4.0
And let's get the messages that are waiting for jeff and jenny...
삭제 할 tuple:제니-0
삭제 할 tuple:joe-0
삭제 할 tuple:jeff--4.0
They are the same? true
Those messages are:
  chatId: 1
    messages:
      {sender=joe, id=1, message=message 1, ts=1.477276890018E12}
      {sender=joe, id=2, message=message 2, ts=1.477276890113E12}
      {sender=joe, id=3, message=message 3, ts=1.477276890115E12}
      {sender=joe, id=4, message=message 4, ts=1.477276890116E12}
아직 있 나 봐.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기