成人性生交大片免费看视频r_亚洲综合极品香蕉久久网_在线视频免费观看一区_亚洲精品亚洲人成人网在线播放_国产精品毛片av_久久久久国产精品www_亚洲国产一区二区三区在线播_日韩一区二区三区四区区区_亚洲精品国产无套在线观_国产免费www

主頁(yè) > 知識(shí)庫(kù) > 利用redis實(shí)現(xiàn)聊天記錄轉(zhuǎn)存功能的全過(guò)程

利用redis實(shí)現(xiàn)聊天記錄轉(zhuǎn)存功能的全過(guò)程

熱門(mén)標(biāo)簽:智能電銷(xiāo)機(jī)器人銷(xiāo)售話術(shù) 高德地圖標(biāo)注商戶(hù)位置 機(jī)器人外呼系統(tǒng)軟件存在問(wèn)題 沈陽(yáng)營(yíng)銷(xiāo)電銷(xiāo)機(jī)器人招商 徐州ai電銷(xiāo)機(jī)器人原理 企業(yè)智能外呼系統(tǒng)價(jià)格多少 福州電銷(xiāo)機(jī)器人源代碼 南京400電話怎樣辦理 兗州電話外呼營(yíng)銷(xiāo)系統(tǒng)

前言

前一陣子實(shí)現(xiàn)了我開(kāi)源項(xiàng)目的單聊功能,在實(shí)現(xiàn)過(guò)程中遇到了需要將聊天記錄保存至數(shù)據(jù)庫(kù)的問(wèn)題,在收到消息時(shí)肯定不能直接存數(shù)據(jù)庫(kù),因?yàn)檫@樣在高并發(fā)的場(chǎng)景下,數(shù)據(jù)庫(kù)就炸了。

于是,我就想到了redis這個(gè)東西,第一次聽(tīng)說(shuō)它是在2年前,但是一直沒(méi)時(shí)間玩他,現(xiàn)在終于遇到了需要使用它的場(chǎng)景,在用的時(shí)候?qū)W它,本文就跟大家分享下我的實(shí)現(xiàn)思路以及過(guò)程,歡迎各位感興趣的開(kāi)發(fā)者閱讀本文。

環(huán)境搭建

我的項(xiàng)目是基于SpringBoot2.x搭建的,電腦已經(jīng)安裝了redis,用的maven作為jar包管理工具,所以只需要在maven中添加需要的依賴(lài)包即可,如果你用的是其他管理工具,請(qǐng)自行查閱如何添加依賴(lài)。

!-- Redis -->
dependency>
    groupId>org.springframework.boot/groupId>
    artifactId>spring-boot-starter-data-redis/artifactId>
/dependency>
!-- 定時(shí)任務(wù)調(diào)度 -->
dependency>
    groupId>org.springframework.boot/groupId>
    artifactId>spring-boot-starter-quartz/artifactId>
    version>2.3.7.RELEASE/version>
/dependency>

本文需要用到依賴(lài):Redis 、quartz,在pom.xml文件的dependencies標(biāo)簽下添加下述代碼。

spring:
# redis配置
  redis:
    host: 127.0.0.1 # redis地址
    port: 6379 # 端口號(hào)
    password:  # 密碼
    timeout: 3000 # 連接超時(shí)時(shí)間,單位毫秒

實(shí)現(xiàn)思路

在websocket的服務(wù)中,收到客戶(hù)端推送的消息后,我們對(duì)數(shù)據(jù)進(jìn)行解析,構(gòu)造聊天記錄實(shí)體類(lèi),將其保存至redis中,最后我們使用quartz設(shè)置定時(shí)任務(wù)將redis的數(shù)據(jù)定時(shí)寫(xiě)入mysql中。

我們將上述思路進(jìn)行下整理:

  1. 解析客戶(hù)端數(shù)據(jù),構(gòu)造實(shí)體類(lèi)
  2. 將數(shù)據(jù)保存至redis
  3. 使用quartz將redis中的數(shù)據(jù)定時(shí)寫(xiě)入mysql

實(shí)現(xiàn)過(guò)程

實(shí)現(xiàn)思路很簡(jiǎn)單,難在如何將實(shí)體類(lèi)數(shù)據(jù)保存至redis,我們需要把redis這一塊配置好后,才能繼續(xù)實(shí)現(xiàn)我們的業(yè)務(wù)需求。

redis支持的數(shù)據(jù)結(jié)構(gòu)類(lèi)型有:

  • set 集合,string類(lèi)型的無(wú)序集合,元素不允許重復(fù)
  • hash 哈希表,鍵值對(duì)的集合,用于存儲(chǔ)對(duì)象
  • list 列表,鏈表結(jié)構(gòu)
  • zset有序集合
  • string 字符串,最基本的數(shù)據(jù)類(lèi)型,可以包含任何數(shù)據(jù),比如一個(gè)序列化的對(duì)象,它的字符串大小上限是512MB

redis的客戶(hù)端分為jedis 和 lettuce,在SpringBoot2.x中默認(rèn)客戶(hù)端是使用lettuce實(shí)現(xiàn)的,因此我們不用做過(guò)多配置,在使用的時(shí)候通過(guò)RedisTemplate.xxx來(lái)對(duì)redis進(jìn)行操作即可。

自定義RedisTemplate

在RedisTemplate中,默認(rèn)是使用Java字符串序列化,將字符串存入redis后可讀性很差,因此,我們需要對(duì)他進(jìn)行自定義,使用Jackson 序列化,以 JSON 方式進(jìn)行存儲(chǔ)。

我們?cè)陧?xiàng)目的config包下,創(chuàng)建一個(gè)名為L(zhǎng)ettuceRedisConfig的Java文件,我們?cè)俅宋募信渲闷淠J(rèn)序列化規(guī)則,它的代碼如下:

package com.lk.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;


// 自定義RedisTemplate設(shè)置序列化器, 方便轉(zhuǎn)換redis中的數(shù)據(jù)與實(shí)體類(lèi)互轉(zhuǎn)
@Configuration
public class LettuceRedisConfig {
    /**
     * Redis 序列化配置
     */
    @Bean
    public RedisTemplateString, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplateString, Object> redisTemplate = new RedisTemplate>();
        redisTemplate.setConnectionFactory(connectionFactory);
        // 使用GenericJackson2JsonRedisSerializer替換默認(rèn)序列化
        GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        // 設(shè)置 Key 和 Value 的序列化規(guī)則
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        // 初始化 RedisTemplate 序列化完成
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

封裝redis工具類(lèi)

做完上述操作后,通過(guò)RedisTemplate存儲(chǔ)到redis中的數(shù)據(jù)就是json形式的了,接下來(lái)我們對(duì)其常用的操作封裝成工具類(lèi),方便我們?cè)陧?xiàng)目中使用。

在Utils包中創(chuàng)建一個(gè)名為RedisOperatingUtil,其代碼如下:

package com.lk.utils;

import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
// Redis操作工具類(lèi)
public class RedisOperatingUtil {
    @Resource
    private RedisTemplateObject, Object> redisTemplate;

    /**
     * 指定 key 的過(guò)期時(shí)間
     *
     * @param key  鍵
     * @param time 時(shí)間(秒)
     */
    public void setKeyTime(String key, long time) {
        redisTemplate.expire(key, time, TimeUnit.SECONDS);
    }

    /**
     * 根據(jù) key 獲取過(guò)期時(shí)間(-1 即為永不過(guò)期)
     *
     * @param key 鍵
     * @return 過(guò)期時(shí)間
     */
    public Long getKeyTime(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判斷 key 是否存在
     *
     * @param key 鍵
     * @return 如果存在 key 則返回 true,否則返回 false
     */
    public Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 刪除 key
     *
     * @param key 鍵
     */
    public Long delKey(String... key) {
        if (key == null || key.length  1) {
            return 0L;
        }
        return redisTemplate.delete(Arrays.asList(key));
    }

    /**
     * 獲取 Key 的類(lèi)型
     *
     * @param key 鍵
     */
    public String keyType(String key) {
        DataType dataType = redisTemplate.type(key);
        assert dataType != null;
        return dataType.code();
    }

    /**
     * 批量設(shè)置值
     *
     * @param map 要插入的 key value 集合
     */
    public void barchSet(MapString, Object> map) {
        redisTemplate.opsForValue().multiSet(map);
    }

    /**
     * 批量獲取值
     *
     * @param list 查詢(xún)的 Key 列表
     * @return value 列表
     */
    public ListObject> batchGet(ListString> list) {
        return redisTemplate.opsForValue().multiGet(Collections.singleton(list));
    }


    /**
     * 獲取指定對(duì)象類(lèi)型key的值
     *
     * @param key 鍵
     * @return 值
     */
    public Object objectGetKey(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 設(shè)置對(duì)象類(lèi)型的數(shù)據(jù)
     *
     * @param key   鍵
     * @param value 值
     */
    public void objectSetValue(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 向list的頭部插入一條數(shù)據(jù)
     *
     * @param key   鍵
     * @param value 值
     */
    public Long listLeftPush(String key, Object value) {
        return redisTemplate.opsForList().leftPush(key, value);
    }

    /**
     * 向list的末尾插入一條數(shù)據(jù)
     *
     * @param key   鍵
     * @param value 值
     */
    public Long listRightPush(String key, Object value) {
        return redisTemplate.opsForList().rightPush(key, value);
    }

    /**
     * 向list頭部添加list數(shù)據(jù)
     *
     * @param key   鍵
     * @param value 值
     */
    public Long listLeftPushAll(String key, ListObject> value) {
        return redisTemplate.opsForList().leftPushAll(key, value);
    }

    /**
     * 向list末尾添加list數(shù)據(jù)
     *
     * @param key   鍵
     * @param value 值
     */
    public Long listRightPushAll(String key, ListObject> value) {
        return redisTemplate.opsForList().rightPushAll(key, value);
    }

    /**
     * 通過(guò)索引設(shè)置list元素的值
     *
     * @param key   鍵
     * @param index 索引
     * @param value 值
     */
    public void listIndexSet(String key, long index, Object value) {
        redisTemplate.opsForList().set(key, index, value);
    }

    /**
     * 獲取列表指定范圍內(nèi)的list元素,正數(shù)則表示正向查找,負(fù)數(shù)則倒敘查找
     *
     * @param key   鍵
     * @param start 開(kāi)始
     * @param end   結(jié)束
     * @return boolean
     */
    public Object listRange(String key, long start, long end) {
        return redisTemplate.opsForList().range(key, start, end);
    }

    /**
     * 從列表前端開(kāi)始取出數(shù)據(jù)
     *
     * @param key 鍵
     * @return 結(jié)果數(shù)組對(duì)象
     */
    public Object listPopLeftKey(String key) {
        return redisTemplate.opsForList().leftPop(key);
    }

    /**
     * 從列表末尾開(kāi)始遍歷取出數(shù)據(jù)
     *
     * @param key 鍵
     * @return 結(jié)果數(shù)組
     */
    public Object listPopRightKey(String key) {
        return redisTemplate.opsForList().rightPop(key);
    }

    /**
     * 獲取list長(zhǎng)度
     *
     * @param key 鍵
     * @return 列表長(zhǎng)度
     */
    public Long listLen(String key) {
        return redisTemplate.opsForList().size(key);
    }

    /**
     * 通過(guò)索引獲取list中的元素
     *
     * @param key   鍵
     * @param index 索引(index>=0時(shí),0 表頭,1 第二個(gè)元素,依次類(lèi)推;index0時(shí),-1,表尾,-2倒數(shù)第二個(gè)元素,依次類(lèi)推)
     * @return 列表中的元素
     */
    public Object listIndex(String key, long index) {
        return redisTemplate.opsForList().index(key, index);
    }

    /**
     * 移除list元素
     *
     * @param key   鍵
     * @param count 移除數(shù)量("負(fù)數(shù)"則從列表倒敘查找刪除 count 個(gè)對(duì)應(yīng)的值; "整數(shù)"則從列表正序查找刪除 count 個(gè)對(duì)應(yīng)的值;)
     * @param value 值
     * @return 成功移除的個(gè)數(shù)
     */
    public Long listRem(String key, long count, Object value) {
        return redisTemplate.opsForList().remove(key, count, value);
    }

    /**
     * 截取指定范圍內(nèi)的數(shù)據(jù), 移除不是范圍內(nèi)的數(shù)據(jù)
     * @param key 操作的key
     * @param start 截取開(kāi)始位置
     * @param end 截取激素位置
     */
    public void listTrim(String key, long start, long end) {
        redisTemplate.opsForList().trim(key, start, end);
    }
}

進(jìn)行單元測(cè)試

做完上述操作后,最難弄的一關(guān)我們就已經(jīng)搞定了,接下來(lái)我們來(lái)對(duì)一會(huì)需要使用的方法進(jìn)行單元測(cè)試,確保其能夠正常運(yùn)行。

創(chuàng)建一個(gè)名為RedisTest的Java文件,注入需要用到的相關(guān)類(lèi)。

  • redisOperatingUtil為我們的redis工具類(lèi)
  • subMessageMapper為聊天記錄表的dao層
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class RedisTest {
    @Resource
    private RedisOperatingUtil redisOperatingUtil;
    @Resource
    private SubMessageMapper subMessageMapper;
}

接下來(lái),我們看下SubMessage實(shí)體類(lèi)的代碼。

package com.lk.entity;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
// 聊天記錄-消息內(nèi)容
public class SubMessage {
  private Integer id;
  private String msgText; // 消息內(nèi)容
  private String createTime; // 創(chuàng)建時(shí)間
  private String userName; // 用戶(hù)名
  private String userId; // 推送方用戶(hù)id
  private String avatarSrc; // 推送方頭像
  private String msgId; // 接收方用戶(hù)id
  private Boolean status; // 消息狀態(tài)
}

測(cè)試list數(shù)據(jù)的寫(xiě)入與獲取

在單元測(cè)試類(lèi)內(nèi)部加入下述代碼:

    @Test
    public void testSerializableListRedisTemplate() {
        // 構(gòu)造聊天記錄實(shí)體類(lèi)數(shù)據(jù)
        SubMessage subMessage = new SubMessage();
        subMessage.setAvatarSrc("https://www.kaisir.cn/uploads/1ece3749801d4d45933ba8b31403c685touxiang.jpeg");
        subMessage.setUserId("1090192");
        subMessage.setUserName("神奇的程序員");
        subMessage.setMsgText("你好");
        subMessage.setMsgId("2901872");
        subMessage.setCreateTime("2020-12-12 18:54:06");
        subMessage.setStatus(false);
        // 將聊天記錄對(duì)象保存到redis中
        redisOperatingUtil.listRightPush("subMessage", subMessage);
        // 獲取list中的數(shù)據(jù)
        Object resultObj = redisOperatingUtil.listRange("subMessage", 0, redisOperatingUtil.listLen("subMessage"));
        // 將Object安全的轉(zhuǎn)為L(zhǎng)ist
        ListSubMessage> resultList = ObjectToOtherUtil.castList(resultObj, SubMessage.class);
        // 遍歷獲取到的結(jié)果
        if (resultList != null) {
            for (SubMessage message : resultList) {
                System.out.println(message.getUserName());
            }
        }
    }

在上述代碼中,我們從redis中取出的數(shù)據(jù)是Object類(lèi)型的,我們要將它轉(zhuǎn)換為與之對(duì)應(yīng)的實(shí)體類(lèi),一開(kāi)始我是用的類(lèi)型強(qiáng)轉(zhuǎn),但是idea會(huì)報(bào)黃色警告,于是就寫(xiě)了一個(gè)工具類(lèi)用于將Object對(duì)象安全的轉(zhuǎn)換為與之對(duì)應(yīng)的類(lèi)型,代碼如下:

package com.lk.utils;

import java.util.ArrayList;
import java.util.List;

public class ObjectToOtherUtil {
    public static T> ListT> castList(Object obj, ClassT> clazz) {
        ListT> result = new ArrayList>();
        if (obj instanceof List?>) {
            for (Object o : (List?>) obj) {
                result.add(clazz.cast(o));
            }
            return result;
        }
        return null;
    }
}

執(zhí)行后,我們看看redis是否有保存到我們寫(xiě)入的數(shù)據(jù),如下所示,已經(jīng)成功保存。

我們?cè)賮?lái)看看,代碼的執(zhí)行結(jié)果,看看有沒(méi)有成功獲取到數(shù)據(jù),如下圖所示,也成功取到了。

注意:如果你的項(xiàng)目對(duì)websocket進(jìn)行了啟動(dòng)配置,可能會(huì)導(dǎo)致單元測(cè)試失敗,報(bào)錯(cuò)java.lang.IllegalStateException: Failed to load ApplicationContext,解決方案就是注釋掉websocket配置文件中的@Configuration即可。

測(cè)試list數(shù)據(jù)的取出

當(dāng)我們把redis中存儲(chǔ)的數(shù)據(jù)遷移到mysql后,需要?jiǎng)h除redis中的數(shù)據(jù),一開(kāi)始我用的是它的delete方法,但是他的delete方法只能刪除與之匹配的值,不能選擇一個(gè)區(qū)間進(jìn)行刪除,于是就決定用它的pop方法進(jìn)行出棧操作。

我們來(lái)測(cè)試下工具類(lèi)中的listPopLeftKey方法。

    @Test
    public void testListPop() {
        long item = 0;
        // 獲取存儲(chǔ)在redis中聊天記錄的條數(shù)
        long messageListSize = redisOperatingUtil.listLen("subMessage");
        for (int i = 0; i  messageListSize; i++) {
            // 從頭向尾取出鏈表中的元素
            SubMessage messageResult = (SubMessage) redisOperatingUtil.listPopLeftKey("subMessage");
            log.info(messageResult.getMsgText());
            item++;
        }
        log.info(item+"條數(shù)據(jù)已成功取出");
    }

執(zhí)行結(jié)果如下所示,成功取出了redis中存儲(chǔ)的兩條數(shù)據(jù)。

測(cè)試聊天記錄轉(zhuǎn)移至數(shù)據(jù)庫(kù)

接下來(lái)我們?cè)趓edis中放入三條數(shù)據(jù)用于測(cè)試

我們測(cè)試下將redis中的數(shù)據(jù)取出,然后寫(xiě)入數(shù)據(jù)庫(kù),代碼如下:

    // 測(cè)試聊天記錄轉(zhuǎn)移數(shù)據(jù)庫(kù)
    @Test
    public void testRedisToMysqlTask() {
        // 獲取存儲(chǔ)在redis中聊天記錄的條數(shù)
        long messageListSize = redisOperatingUtil.listLen("subMessage");
        // 寫(xiě)入數(shù)據(jù)庫(kù)的數(shù)據(jù)總條數(shù)
        long resultCount = 0;
        for (int i = 0; i  messageListSize; i++) {
            // 從頭到尾取出鏈表中的元素
            SubMessage subMessage= (SubMessage) redisOperatingUtil.listPopLeftKey("subMessage");
            // 向數(shù)據(jù)庫(kù)寫(xiě)入數(shù)據(jù)
            int result = subMessageMapper.addMessageTextInfo(subMessage);
            if (result > 0) {
                // 寫(xiě)入成功
                resultCount++;
            }
        }
        log.info(resultCount+ "條聊天記錄,已寫(xiě)入數(shù)據(jù)庫(kù)");
    }

執(zhí)行結(jié)果如下,數(shù)據(jù)已成功寫(xiě)入數(shù)據(jù)庫(kù)且redis中的數(shù)據(jù)也被刪除。

解析客戶(hù)端數(shù)據(jù)保存至redis

完成上述操作后,我們r(jià)edis那一塊的東西就搞定了,接下來(lái)就可以實(shí)現(xiàn)將客戶(hù)端的數(shù)據(jù)存到redis里了。

這里有個(gè)坑,因?yàn)閣ebsocket服務(wù)類(lèi)中用到了@Component,會(huì)導(dǎo)致redis的工具類(lèi)注入失敗,出現(xiàn)null的情況,解決這個(gè)問(wèn)題需要將當(dāng)前類(lèi)名聲明為靜態(tài)變量,然后在init中獲取賦值redis工具類(lèi),代碼如下:

    // 解決redis操作工具類(lèi)注入為null的問(wèn)題
    public static WebSocketServer webSocketServer;
    @PostConstruct
    public void init() {
        webSocketServer = this;
        webSocketServer.redisOperatingUtil = this.redisOperatingUtil;
    }

在websocket服務(wù)的@OnMessage注解中,收到客戶(hù)端發(fā)送的消息,我們將其保存到redis中,代碼如下:

    /**
     * 收到客戶(hù)端消息后調(diào)用的方法
     *
     * @param message 客戶(hù)端發(fā)送過(guò)來(lái)的消息
     *                // @param session 客戶(hù)端會(huì)話
     */
    @OnMessage
    public void onMessage(String message) {
        // 客戶(hù)端發(fā)送的消息
        JSONObject jsReply = new JSONObject(message);
        // 添加在線人數(shù)
        jsReply.put("onlineUsers", getOnlineCount());
        if (jsReply.has("buddyId")) {
            // 獲取推送方id
            String userId = jsReply.getString("userID");
            // 獲取被推送方id
            String buddyId = jsReply.getString("buddyId");
            // 非測(cè)試數(shù)據(jù)則推送消息
            if (!buddyId.equals("121710f399b84322bdecc238199d6888")) {
                // 發(fā)送消息至推送方
                this.sendInfo(jsReply.toString(), userId);
            }
            // 構(gòu)造聊天記錄實(shí)體類(lèi)數(shù)據(jù)
            SubMessage subMessage = new SubMessage();
            subMessage.setAvatarSrc(jsReply.getString("avatarSrc"));
            subMessage.setUserId(jsReply.getString("userID"));
            subMessage.setUserName(jsReply.getString("username"));
            subMessage.setMsgText(jsReply.getString("msg"));
            subMessage.setMsgId(jsReply.getString("msgId"));
            subMessage.setCreateTime(DateUtil.getThisTime());
            subMessage.setStatus(false);
            // 將聊天記錄對(duì)象保存到redis中
            webSocketServer.redisOperatingUtil.listRightPush("subMessage", subMessage);
            // 發(fā)送消息至被推送方
            this.sendInfo(jsReply.toString(), buddyId);
        }
    }

做完上述操作后,收到客戶(hù)端發(fā)送的消息就會(huì)自動(dòng)寫(xiě)入redis。

定時(shí)將redis的數(shù)據(jù)寫(xiě)入mysql

接下來(lái),我們使用quartz定時(shí)向mysql中寫(xiě)入數(shù)據(jù),他執(zhí)行定時(shí)任務(wù)的步驟分為2步:

  1. 創(chuàng)建任務(wù)類(lèi)編寫(xiě)任務(wù)內(nèi)容
  2. 在QuartzConfig文件中設(shè)置定時(shí),執(zhí)行第一步創(chuàng)建的任務(wù)。

首先,創(chuàng)建quartzServer包,在其下創(chuàng)建RedisToMysqlTask.java文件,在此文件內(nèi)實(shí)現(xiàn)redis寫(xiě)入mysql的代碼

package com.lk.quartzServer;

import com.lk.dao.SubMessageMapper;
import com.lk.entity.SubMessage;
import com.lk.utils.RedisOperatingUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

import javax.annotation.Resource;

// 將redis數(shù)據(jù)放進(jìn)mysql中
@Slf4j
public class RedisToMysqlTask extends QuartzJobBean {
    @Resource
    private RedisOperatingUtil redisOperatingUtil;
    @Resource
    private SubMessageMapper subMessageMapper;

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 獲取存儲(chǔ)在redis中聊天記錄的條數(shù)
        long messageListSize = redisOperatingUtil.listLen("subMessage");
        // 寫(xiě)入數(shù)據(jù)庫(kù)的數(shù)據(jù)總條數(shù)
        long resultCount = 0;
        for (int i = 0; i  messageListSize; i++) {
            // 從頭到尾取出鏈表中的元素
            SubMessage subMessage= (SubMessage) redisOperatingUtil.listPopLeftKey("subMessage");
            // 向數(shù)據(jù)庫(kù)寫(xiě)入數(shù)據(jù)
            int result = subMessageMapper.addMessageTextInfo(subMessage);
            if (result > 0) {
                // 寫(xiě)入成功
                resultCount++;
            }
        }
        log.info(resultCount+ "條聊天記錄,已寫(xiě)入數(shù)據(jù)庫(kù)");
    }
}

在config包下創(chuàng)建QuartzConfig.java文件,創(chuàng)建定時(shí)任務(wù)

package com.lk.config;

import com.lk.quartzServer.RedisToMysqlTask;
import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Quartz定時(shí)任務(wù)配置
 */
@Configuration
public class QuartzConfig {
    @Bean
    public JobDetail RedisToMysqlQuartz() {
        // 執(zhí)行定時(shí)任務(wù)
        return JobBuilder.newJob(RedisToMysqlTask.class).withIdentity("CallPayQuartzTask").storeDurably().build();
    }

    @Bean
    public Trigger CallPayQuartzTaskTrigger() {
        //cron方式,從每月1號(hào)開(kāi)始,每隔三天就執(zhí)行一次
        return TriggerBuilder.newTrigger().forJob(RedisToMysqlQuartz())
                .withIdentity("CallPayQuartzTask")
                .withSchedule(CronScheduleBuilder.cronSchedule("* * 4 1/3 * ?"))
                .build();
    }
}

這里我設(shè)置的定時(shí)任務(wù)是從每月1號(hào)開(kāi)始,每隔三天就執(zhí)行一次,Quartz定時(shí)任務(wù)采用的是cron表達(dá)式,自己算這個(gè)比較麻煩,這里推薦一個(gè)在線網(wǎng)站,可以很容易的生成表達(dá)式:Cron表達(dá)式生成器

實(shí)現(xiàn)效果

最后,配合Vue實(shí)現(xiàn)的瀏覽器端,跟大家展示下實(shí)現(xiàn)效果:

效果視頻:使用Vue實(shí)現(xiàn)單聊

項(xiàng)目瀏覽器端代碼地址:github/chat-system

項(xiàng)目在線體驗(yàn)地址:chat-system

總結(jié)

到此這篇關(guān)于利用redis實(shí)現(xiàn)聊天記錄轉(zhuǎn)存功能的文章就介紹到這了,更多相關(guān)redis聊天記錄轉(zhuǎn)存內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

標(biāo)簽:邯鄲 本溪 吉安 鶴崗 景德鎮(zhèn) 大理 丹東 昭通

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《利用redis實(shí)現(xiàn)聊天記錄轉(zhuǎn)存功能的全過(guò)程》,本文關(guān)鍵詞  利用,redis,實(shí)現(xiàn),聊天記錄,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《利用redis實(shí)現(xiàn)聊天記錄轉(zhuǎn)存功能的全過(guò)程》相關(guān)的同類(lèi)信息!
  • 本頁(yè)收集關(guān)于利用redis實(shí)現(xiàn)聊天記錄轉(zhuǎn)存功能的全過(guò)程的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    日韩中文字幕国产| 不卡av中文字幕| 欧美另类极品videosbest视| 91国内在线视频| 日本熟女毛茸茸| 成人偷拍自拍| 精品一区二区三区中文字幕视频| 亚洲精品合集| 天天av天天翘天天综合网色鬼国产| 欧美久久久网站| 免费福利视频一区二区三区| 女人天堂网站| 天堂v在线视频| 一区二区三区观看| 国产99久久久精品| 福利小视频在线观看| 一区二区三区美女xx视频| 蜜桃视频在线观看网站| 日韩中文在线中文网三级| 女同另类激情重口| 欧美一区视频在线| 欧美天天综合| 国产sm调教视频| 国产精品成人**免费视频| 国产精品专区一| 色窝窝无码一区二区三区成人网站| 亚洲盗摄视频| 蜜臀av.com| www.五月天色| 香蕉视频一区二区三区| 欧美精品日韩一区| 午夜精品免费看| 亚洲精品第1页| 日韩欧美福利视频| 一区二区三区电影大全| 亚洲国语精品自产拍在线观看| 亚洲成色999久久网站| 亚洲一区二区天堂| 成人三级视频在线观看| 午夜婷婷国产麻豆精品| 亚洲人www| 精品人妻一区二区乱码| 日韩久久在线| 国产精品日韩一区二区| 国产精品一区二区三区在线免费观看| 麻豆精品国产自产在线| 欧美有码在线观看| 国产日韩欧美在线播放不卡| 午夜精品婷婷| 欧美色综合影院| 国产精品666| 天堂久久久久va久久久久| 欧美色图综合网| 日韩影院精彩在线| 很黄的网站在线观看| 欧美一区二不卡视频| 久久国内精品| 范冰冰一级做a爰片久久毛片| 中国女人特级毛片| 日韩女优在线视频| 你懂的免费在线观看| 久久国内精品自在自线400部| 久久中文字幕二区| 91麻豆精品国产91久久久资源速度| 97热精品视频官网| 欧美日韩免费一区二区三区视频| 激情综合视频| 国产97在线视频| 欧美高清一区二区| 欧美国产精品专区| eeuss鲁丝片eeuss影院| 免费看污黄网站| 天天鲁一鲁摸一摸爽一爽| 特级黄国产片一级视频播放| 婷婷久久综合九色综合99蜜桃| 91在线视频成人| 高清不卡一区二区| 在线一区二区三区精品| 艳妇乳肉亭妇荡乳av| 98色花堂精品视频在线观看| 视频在线观看91| 欧美亚洲综合视频| 一级特黄大欧美久久久| 亚洲色图另类图片| 欧美在线小视频| 99久久这里有精品| 欧美日韩在线另类| 69久久久久久| 丁香久久五月| 欧美高清影院| 国产日产欧美一区二区视频| 国产精品久久久久久久久免费高清| 91中文字幕精品永久在线| 裸模一区二区三区免费| 在线观看中文字幕码| 精品无码久久久久久久动漫| 国产精品亚洲精品| 朝桐光一区二区| 亚洲影视第一页| youjizz在线播放| 亚洲自拍电影| 国产成人亚洲精品乱码在线观看| 国产日韩欧美在线| 久久精品资源| www在线播放| 国产成人精品一区二区免费视频| 高清精品一区二区三区一区| 亚洲第九十七页| 奇米四色7777| 亚洲av成人无码久久精品| 国产精品自在线| 天堂tv亚洲tv日本tv欧美人tv| 中文字幕亚洲综合久久筱田步美| 无码国产69精品久久久久网站| 国产成人精品日本亚洲专区61| 视频一区二区免费| 羞羞视频在线观看| 尤物视频免费在线观看| 黄色免费直接看| 风间由美一区二区三区在线观看| 成人黄色激情网| 中文字幕永久在线视频| 午夜精品久久久久久99热| 海角社区69精品视频| 无码人妻精品一区二区三区温州| 国产一区二区在线| 自拍偷拍99| 国产盗摄一区二区三区在线| 天堂男人av| 久久超碰97人人做人人爱| xxxxxx国产| 日韩尤物视频| 偷拍精品一区二区三区| 91麻豆制片厂| 欧美高清视频一区二区| 国偷自产av一区二区三区麻豆| 国产第一页浮力| 在线观看欧美日韩| 国产亚洲女人久久久久毛片| 国语自产精品视频在线看8查询8| 亚洲精品视频专区| 在线播放欧美女士性生活| 影音先锋国产在线资源| 亚洲第一综合色| 妓院一钑片免看黄大片| 又大又硬又爽免费视频| 精品一区二区三区在线观看国产| 日韩和欧美的一区二区| 色视频在线看| 51精品秘密在线观看| 欧美性猛交xxxx乱大交极品| 日本福利片免费看| 欧美日韩激情一区二区三区| 国产乱国产乱300精品| 无码免费一区二区三区免费播放| 97碰碰碰免费公开在线视频| 亚洲色婷婷久久精品av蜜桃| 波多野结衣av无码| 老司机一区二区三区| 国产精品亚洲专一区二区三区| 亚洲熟妇av乱码在线观看| 91网在线免费观看| 91l九色lporny| 色香蕉在线观看| 国产精品欧美经典| 国产成人av电影在线观看| 中文字幕2019第三页| 国产强伦人妻毛片| 国产精品麻豆成人av电影艾秋| 中国成人在线视频| 欧美fxxxxxx另类| 色婷婷粉嫩av| 在线观看精品自拍视频| 午夜成年女人毛片免费观看| 九九热精品在线播放| 国产日韩欧美在线观看视频| 日本一区二区三区视频在线观看| 先锋av影院| 999成人精品视频线3| 国产乱在线观看视频| 最新电影电视剧在线观看免费观看| 亚洲国产欧美自拍| 欧美日韩三级电影在线| 伊人色综合影院| 精品国产av一区二区三区| 特一级黄色录像| 中文字幕视频网站| 亚洲v在线观看| 57pao成人永久免费| 精品国产一二三区| 俄罗斯av网站| 欧洲色大大久久| 亚洲国产精品女人| 粉嫩一区二区三区国产精品| 日韩精品视频免费在线观看| 久久精品视频99| 久久久久久国产精品免费无遮挡| 中文字幕在线影院| 色视频www在线播放国产成人| 亚洲免费av一区二区三区| 中文字幕在线中文字幕在线中三区| 免费在线精品视频| 国精产品乱码一区一区三区四区| 91丨porny丨探花| 麻豆精品国产91久久久久久| 成人无码精品1区2区3区免费看| 欧美第一精品| 国产美女一区二区三区| 免费在线观看91| 欧美一区二区在线观看| 久久美女性网| 国产精品十八以下禁看| 人妻体体内射精一区二区| 精品97人妻无码中文永久在线| 亚洲视频在线一区二区| 中文字幕在线观看高清| 欧美欧美黄在线二区| 欧美精品一卡两卡| 性一交一乱一乱一视频| 欧美videos另类| 日韩中文字幕在线视频| 69国产成人精品视频软件| 22288色视频在线观看| 好看的中文字幕在线播放| 国产一区二区三区不卡av| 麻豆传媒视频在线观看免费| 最近中文字幕mv免费高清在线| 网友自拍区视频精品| 国模吧无码一区二区三区| 国产日韩欧美高清在线| 日本黄在线观看| wwwwxxxx在线观看| 日本一二三四高清不卡| 性金发美女69hd大尺寸| av资源一区二区| 亚洲女同另类| 国产男女免费视频| 国产免费大片| 久久免费精品视频| 精品一区二区三区久久久| 天堂网.www在线资源| 三级中文字幕在线观看| 亚洲精品中文字幕在线观看| 7777精品| 欧美性猛交xxxxxxxx| 久久免费电影| 手机在线成人免费视频| 99reav在线| 精品久久久久久久久久中文字幕| 精品国产1区二区| 99tv成人| 欧美三级一区| 碰碰在线视频| 91精品国产91久久综合桃花| 38少妇精品导航| 狠狠爱免费视频| 九九热这里只有| 国产精品jvid在线观看| 色男人天堂综合再现| 亚洲欧美日本精品| 伊人久久免费视频| 美女精品视频| 国产成人精品白浆久久69| 色婷婷一区二区三区在线观看| 伊人久久久久久久久| 成人免费福利在线| 国产日韩在线不卡| 日韩一卡二卡在线观看| 欧美黑人xxxx猛牲大交| 黄色片视频在线免费观看| 国产91|九色| 精品一区二区三区人妻| japanese色系久久精品| 韩国一区二区电影| 国产精品一区免费在线| 午夜男人的天堂| 亚洲网站啪啪| 91制片厂毛片| 91麻豆免费观看| 日韩三级精品电影久久久| 激情小说网站亚洲综合网| 国产成人午夜片在线观看高清观看| 欧美另类videosbestsex日本| 国产精品入口麻豆免费观看| 精品人人人人| 蜜桃视频成人| 成人影院在线免费观看| 亚洲人精品午夜在线观看| 国产 欧美 在线| 国产一区二区三区视频免费观看| 久久亚洲AV无码专区成人国产| 亚洲影院色无极综合| 99国产一区| 一个人免费观看视频www在线播放| 日本欧洲国产一区二区| 成人性生生活性生交12| 影音先锋在线一区| 国产欧美日韩视频在线观看| 亚洲精品成人图区| 老司机福利在线观看| 久操av在线| 日本高清无吗v一区| 欧美在线色视频| 999精品视频| 欧美日韩性生活片| 娇小11一12╳yⅹ╳毛片| 亚洲 欧美 激情 另类| 国产韩日影视精品| 国产区视频在线观看| 91丨九色丨蝌蚪丨老板| 99久久99久久精品免费看蜜桃| 成人污网站在线观看| 久久久久久久久亚洲精品| 黄色网络在线观看| 色资源网在线观看| 日韩av电影手机在线观看| 欧美一级播放| 色大18成网站www在线观看| 欧美一级片免费在线观看| 日产亚洲一区二区三区| 久久国产免费视频| 黄视频网站在线看| 国产精品自产拍在线网站| 日本中文字幕免费在线观看| 日韩成人精品一区| 欧美久久精品午夜青青大伊人| 国产美女精彩久久| 日韩欧美一区二区三区视频|