国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Springboot系列】整合redis+jedis(含源碼)

這篇具有很好參考價(jià)值的文章主要介紹了【Springboot系列】整合redis+jedis(含源碼)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

Spring Boot集成Redis和Jedis客戶端使用Redis有以下主要特點(diǎn):

? ??簡(jiǎn)單易用只需要添加相關(guān)依賴和簡(jiǎn)單配置,就可以直接在Spring Boot應(yīng)用中使用Jedis客戶端操作Redis。這大大簡(jiǎn)化了使用Redis的難度。

? ??自動(dòng)配置Spring Boot會(huì)根據(jù)類路徑中的Jedis版本自動(dòng)配置JedisConnectionFactory。我們只需要注入JedisConnectionFactory即可獲取Jedis客戶端實(shí)例。

? ??功能豐富通過Jedis或者Lettuce客戶端,我們可以使用Redis的全部功能,如字符串、列表、集合、排序集合、哈希等數(shù)據(jù)結(jié)構(gòu),以及事務(wù)、管道等功能。

? ??高擴(kuò)展性我們可以很容易切換不同的Redis客戶端,如Jedis、Lettuce。也可以根據(jù)需要自定義RedisTemplate或添加RedisCacheManager等來改變緩存行為。

? ??與Spring Cache集成Spring Boot將Redis Cache Manager與Spring Cache深度集成,我們可以直接使用Spring Cache注解來注解方法和類,實(shí)現(xiàn)緩存功能,而不用直接依賴Redis API。

? ??與Spring Data Redis集成Spring Data Redis在Jedis和Lettuce基礎(chǔ)上提供了更高級(jí)的抽象,我們可以調(diào)用其Repository接口來操作Redis,這提供了類似JPA的編程體驗(yàn)。

? ??多種緩存支持Spring Boot默認(rèn)集成了多種緩存技術(shù),如Redis、Ehcache、Hazelcast等。我們只需要一行配置即可切換緩存技術(shù),不需要更改業(yè)務(wù)邏輯代碼。

? ??健康監(jiān)控Spring Boot Actuator可以監(jiān)控RedisConnectionFactory中的連接池狀態(tài)、等待連接的線程數(shù)等信息,方便我們監(jiān)控Redis的運(yùn)行狀況。

下面我們從以下幾個(gè)步驟來應(yīng)用Jedis:

??依賴

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.0.6</version>
</parent>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>2.0.22</version>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.22</version>
    <optional>true</optional>
</dependency>

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>

??配置文件:

server:
  port: 8080  # 設(shè)置訪問端口

spring:
  redis:
    enable: true
    jedis:
      host: localhost
      port: 6379
      password: 123456
      database: 0
      maxIdle: 100
      minIdle: 0
      maxTotal: 100
      maxWaitMillis: 500
      testOnBorrow: false
      testOnReturn: true

??RedisTestController

@RestController
@RequestMapping("/redis")
public class RedisTestController {

    @Autowired
    RedisComponent redisComponent;

    @ResponseBody
    @GetMapping("/test")
    public String test(){
        String val = "aa";
        String key = "testRedisKey";
        redisComponent.set(key, val);
        String retVal = redisComponent.get(key);
        return retVal;
    }
}

??JedisConfig

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

@Slf4j
@Configuration
public class JedisConfig {

    @Value("${spring.redis.jedis.host}")
    private String redisHost;

    @Value("${spring.redis.jedis.port}")
    private Integer redisPort;

    @Value("${spring.redis.jedis.password}")
    private String redisPassword;

    @Value("${spring.redis.jedis.database}")
    private Integer database;

    @Value("${spring.redis.jedis.maxIdle}")
    private Integer maxIdle;

    @Value("${spring.redis.jedis.minIdle}")
    private Integer minIde;

    @Value("${spring.redis.jedis.maxTotal}")
    private Integer maxTotal;

    @Value("${spring.redis.jedis.maxWaitMillis}")
    private Long maxWaitMillis;

    @Value("${spring.redis.jedis.testOnBorrow}")
    private Boolean testOnBorrow;

    @Value("${spring.redis.jedis.testOnReturn}")
    private Boolean testOnReturn;


    @Bean
    public JedisPool jedisPool(){
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMinIdle(minIde);
        jedisPoolConfig.setMaxTotal(maxTotal);
        jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
        jedisPoolConfig.setTestOnBorrow(testOnBorrow);
        jedisPoolConfig.setTestOnReturn(testOnReturn);

        log.info("redis properties {}, jedisPoolConfig={}" ,  this.toString(),JSONObject.toJSONString(jedisPoolConfig));
        JedisPool jedisPool = new JedisPool(jedisPoolConfig, redisHost, redisPort,0, redisPassword, database);
        return jedisPool;
    }

    @Override
    public String toString() {
        return "JedisConfig{" +
                "redisHost='" + redisHost + '\'' +
                ", redisPort=" + redisPort +
                ", redisPassword='" + redisPassword + '\'' +
                ", database=" + database +
                '}';
    }
}

??RedisComponent (Redis工具類)

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.Tuple;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * Created   on 2019/8/19.
 */

@Slf4j
// 是否開啟redis
@ConditionalOnProperty(prefix = "spring", name = "redis.enable", havingValue = "true")
@Component
public class RedisComponent {

    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
    private static final Long RELEASE_SUCCESS = 1L;
    private static final Long retryMill = 1000 * 1000 * 1L;

    @Autowired
    private JedisPool jedisPool;

    /**
     * 獲取分布式鎖
     *
     * @param lockKey
     * @param requestId
     * @param expireTime 毫秒
     */
    public Boolean tryDistributedLock(String lockKey, String requestId, int expireTime) {
        log.info("tryGetDistributedLock-->>lockKey = {}, requestId = {}, expireTime = {}", lockKey, requestId, expireTime);
        String result = this.setNxxxExpx(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
        log.info("tryGetDistributedLock-->>lockKey = {}, requestId = {}, result = {}", lockKey, requestId, result);
        return LOCK_SUCCESS.equals(result);
    }

    /**
     * @param lockKey       上鎖的key
     * @param expireTime    鎖的超時(shí)時(shí)間
     * @param retryTimeNano 最多嘗試多久 納秒單位
     * @return
     * @throws InterruptedException
     */
    public String lock(String lockKey, int expireTime, long retryTimeNano) {
        int rt = 0;
        String key = null;
        try {
            while (true) {
                key = String.valueOf(System.nanoTime());
                String result = this.setNxxxExpx(lockKey, key, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
                if (LOCK_SUCCESS.equals(result)) {
                    return key;
                }
                // 獲取鎖失敗

                rt += retryMill;//每隔1 ms執(zhí)行一次
                if (rt <= retryTimeNano) { // 下次可以執(zhí)行
                    Thread.sleep(retryMill);
                } else {
                    return  null;
                }
            }
        } catch (InterruptedException e) {
            return null;
        }

    }


    /**
     * 釋放分布式鎖
     *
     * @param lockKey   鎖
     * @param requestId 請(qǐng)求標(biāo)識(shí)
     * @return 是否釋放成功
     */
    public boolean releaseDistributedLock(String lockKey, String requestId) {
        log.info("releaseDistributedLock-->>, lockKey = {}, requestId = {}", lockKey, requestId);
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = this.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
        log.info("releaseDistributedLock, lockKey = {}, requestId = {}, result = {}", lockKey, requestId, result);
        if (RELEASE_SUCCESS.equals(result)) {
            log.info("releaselock>>>>>>>>>>>>>>>> lockKey = {}, requestId = {}", lockKey, requestId);
            return true;
        }
        log.info("鎖已釋放, lockKey = {}, requestId = {}", lockKey, requestId);
        return false;

    }


    public final <OUT> OUT redisExec(Function<Jedis, OUT> function) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return function.apply(jedis);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("redisExec error, errorMsg = {}", e.getMessage());
            throw e;
        } finally {
            Optional.ofNullable(jedis).ifPresent(j -> j.close());
        }
    }


    public String setNxxxExpx(final String key, final String value, final String nxxx, final String expx,
                              final int time) {
        return redisExec(jedis -> jedis.set(key, value, nxxx, expx, time));
    }

    public Object eval(String script, List<String> keys, List<String> args) {
        return redisExec(jedis -> jedis.eval(script, keys, args));
    }

    public String get(String key) {
        return this.redisExec(redis -> redis.get(key));
    }

    public byte[] getBytes(byte[] key) {
        return this.redisExec(redis -> redis.get(key));
    }

    public void set(String key, String val) {
        this.redisExec(redis -> redis.set(key, val));
    }

    public Long incr(String key) {
        return this.redisExec(redis -> redis.incr(key));
    }

    public Long append(String key, String value) {
        return this.redisExec(redis->redis.append(key, value));
    }
    public void set(String key, String val, int expireSecond) {
        this.redisTxExec(tx -> {
            tx.set(key, val);
            tx.expire(key, expireSecond);
        });
    }

    public Long rpush(String key, String val) {
        return this.redisExec(tx-> tx.rpush(key, val));
    }

    public String lpop(String key) {
        return this.redisExec(tx->tx.lpop(key));
    }

    public void setBytes(byte[] key, byte[] val, int expireSecond) {
        this.redisTxExec(tx -> {
            tx.set(key, val);
            tx.expire(key, expireSecond);
        });
    }

    public Long SAdd(String key, final String... field) {
        return this.redisExec((redis -> redis.sadd(key, field)));
    }

    public Long ZAdd(String key, double score, String mem) {
        return this.redisExec((redis -> redis.zadd(key, score, mem)));
    }

    public Long SRem(String key, final String... field) {
        return this.redisExec((redis -> redis.srem(key, field)));
    }


    public Long IncBy(String key, Long val) {
        return this.redisExec((redis -> redis.incrBy(key, val)));
    }

    public Long del(String key) {
        return this.redisExec(redis -> redis.del(key));
    }

    public Long del(byte[] key) {
        return this.redisExec(redis -> redis.del(key));
    }

    public Long delByte(byte[] key) {
        return this.redisExec(redis -> redis.del(key));
    }

    public Long hdel(String key, String fileds) {
        return this.redisExec(redis -> redis.hdel(key, fileds));
    }

    public Boolean exists(String key) {
        return this.redisExec(redis -> redis.exists(key));
    }

    public Long scard(String key) {
        return this.redisExec(redis -> redis.scard(key));
    }

    public String srandmember(String key) {
        return this.redisExec(redis -> redis.srandmember(key));
    }

    public Set<String> smembers(String key) {
        return this.redisExec(redis -> redis.smembers(key));
    }

    public boolean sismember(String key, String value) {
        return this.redisExec(redis -> redis.sismember(key, value));
    }

    public Boolean hexists(String key, String ele) {
        return this.redisExec(redis -> redis.hexists(key, ele));
    }

    public String hget(String key, String filed) {
        return this.redisExec(redis -> redis.hget(key, filed));
    }

    public Map<String, String> hgetall(String key) {
        return redisExec(redis -> redis.hgetAll(key));
    }

    public Set<String> zrange(String key, Long start, Long end) {
        return this.redisExec(redis -> redis.zrange(key, start, end));
    }


    public Long zadd(String key, double score, String member) {
        return this.redisExec(redis->redis.zadd(key, score, member));
    }

    public Long zrem(String key, String... mem) {
        return this.redisExec(r -> r.zrem(key, mem));
    }

    public Set<String> zrevrange(String key, Long start, Long end) {
        return this.redisExec(redis -> redis.zrevrange(key, start, end));
    }

    public Set<Tuple> zrevrangeWithScores(String key, Long start, Long end) {
        return this.redisExec(redis -> redis.zrevrangeWithScores(key, start, end));
    }


    public Set<Tuple> zrangeWithScores(String key, Long start, Long end) {
        return this.redisExec(redis -> redis.zrangeWithScores(key, start, end));
    }

    public Long zrank(String key, String member) {
        return this.redisExec(redis -> redis.zrank(key, member));
    }

    public Set<String> hkeys(String key) {
        return this.redisExec(redis -> redis.hkeys(key));
    }

    public List<String> lrange(String key, Long start, Long end) {
        return this.redisExec(redis -> redis.lrange(key, start, end));
    }

    public Long expire(String key, int expireSecond) {
        return this.redisExec(redis -> redis.expire(key, expireSecond));
    }

    public Long TTL(String key) {
        return this.redisExec(redis -> redis.ttl(key));
    }


    public void redisTxExec(Consumer<Transaction> consumer) {
        List<Object> result = this.redisExec(jedis -> {
            Transaction tx = jedis.multi();
            consumer.accept(tx);
            return tx.exec();
        });
    }

    public void redisWatchTxExec(Consumer<Transaction> consumer, String... args) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.watch(args);
            Transaction tx = jedis.multi();
            consumer.accept(tx);
            List<Object> execResult = tx.exec();
            log.info("jedis tx result = {}", execResult);
            if (CollectionUtils.isEmpty(execResult)) {
               return;
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info("redisExec error, errorMsg = {}", e.getMessage());
            throw e;
        } finally {
            Optional.ofNullable(jedis).ifPresent(j -> j.close());
        }
    }
}

簡(jiǎn)而言之,Spring Boot與Redis和Jedis的深度集成,讓Redis變得異常易用和高效。憑借Spring Boot的“自動(dòng)配置、起步依賴、產(chǎn)生型API”等特性,我們可以快速上手Redis,開發(fā)基于Redis的應(yīng)用,從而享受Redis強(qiáng)大的功能。這大大提高了開發(fā)效率和項(xiàng)目的重用性。

掌握Spring Boot與Redis的集成技術(shù),對(duì)我們成為一名專業(yè)的后端開發(fā)者來說是非常有必要的。這是一項(xiàng)值得長(zhǎng)期研究與實(shí)踐的技能。文章來源地址http://www.zghlxwxcb.cn/news/detail-520564.html

??如果需要完整源碼請(qǐng)關(guān)注公眾號(hào)"架構(gòu)殿堂" ,回復(fù) "redis+jedis"即可獲得

??寫在最后

如果大家對(duì)相關(guān)文章感興趣,可以關(guān)注公眾號(hào)"架構(gòu)殿堂",會(huì)持續(xù)更新AIGC,java基礎(chǔ)面試題, netty, spring boot,spring cloud等系列文章,一系列干貨隨時(shí)送達(dá)!

到了這里,關(guān)于【Springboot系列】整合redis+jedis(含源碼)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【萬字長(zhǎng)文】SpringBoot整合SpringSecurity+JWT+Redis完整教程(提供Gitee源碼)

    前言:最近在學(xué)習(xí)SpringSecurity的過程中,參考了很多網(wǎng)上的教程,同時(shí)也參考了一些目前主流的開源框架,于是結(jié)合自己的思路寫了一個(gè)SpringBoot整合SpringSecurity+JWT+Redis完整的項(xiàng)目,從0到1寫完感覺還是收獲到不少的,于是我把我完整的筆記寫成博客分享給大家,算是比較全的

    2024年02月15日
    瀏覽(50)
  • springboot+redis+mysql+quartz-通過Java操作jedis使用pipeline獲取緩存數(shù)據(jù)定時(shí)更新數(shù)據(jù)庫(kù)

    springboot+redis+mysql+quartz-通過Java操作jedis使用pipeline獲取緩存數(shù)據(jù)定時(shí)更新數(shù)據(jù)庫(kù)

    代碼講解:6-點(diǎn)贊功能-定時(shí)持久化到數(shù)據(jù)庫(kù)-pipeline+lua-優(yōu)化pipeline_嗶哩嗶哩_bilibili https://www.bilibili.com/video/BV1yP411C7dr 代碼: blogLike_schedule/like06 · xin麒/XinQiUtilsOrDemo - 碼云 - 開源中國(guó) (gitee.com) https://gitee.com/flowers-bloom-is-the-sea/XinQiUtilsOrDemo/tree/master/blogLike_schedule/like06 數(shù)據(jù)庫(kù)表的

    2024年02月16日
    瀏覽(28)
  • springboot+redis+mysql+quartz-通過Java操作jedis定時(shí)使用lua腳本獲取緩存數(shù)據(jù)并更新數(shù)據(jù)庫(kù)

    springboot+redis+mysql+quartz-通過Java操作jedis定時(shí)使用lua腳本獲取緩存數(shù)據(jù)并更新數(shù)據(jù)庫(kù) 代碼講解:7.1點(diǎn)贊功能-定時(shí)持久化到數(shù)據(jù)庫(kù)-Java整合lua_嗶哩嗶哩_bilibili https://www.bilibili.com/video/BV1ZX4y1H7JT/ 代碼: blogLike_schedule/like07 · xin麒/XinQiUtilsOrDemo - 碼云 - 開源中國(guó) (gitee.com) https://gitee

    2024年02月13日
    瀏覽(17)
  • 【SpringBoot整合系列】SpringBoot整合FastDFS(一)

    【SpringBoot整合系列】SpringBoot整合FastDFS(一)

    FastDFS(Fast Distributed File System)是一款開源的分布式文件系統(tǒng),它提供了高性能、高可靠性、高擴(kuò)展性和高容錯(cuò)性的分布式文件存儲(chǔ)解決方案。 FastDFS采用了類似于Google File System(GFS)的架構(gòu),它的設(shè)計(jì)目標(biāo)是解決大規(guī)模數(shù)據(jù)存儲(chǔ)和高訪問速度的問題。 分布式架構(gòu): FastDFS采用

    2024年04月27日
    瀏覽(17)
  • 【Redis】SpringBoot整合Redis

    SpringData是Spring里專門用來操作數(shù)據(jù)的模塊,其中對(duì)redis集成的模塊 它提供了對(duì)不同的redis客戶端的整合比如Lettuce和Jedis,提供了RedisTemplate統(tǒng)一的API來操作redis,而且它支持Redis的發(fā)布訂閱模式、哨兵和Redis集群,以及Lettuce的響應(yīng)式編程,支持序列化于反序列化,支持Redis的JD

    2023年04月23日
    瀏覽(20)
  • 【Springboot系列】SpringBoot整合Jpa

    【Springboot系列】SpringBoot整合Jpa

    前言: Spring Boot是一種快速開發(fā)框架,它簡(jiǎn)化了Java應(yīng)用程序的開發(fā)過程。而Jpa(Java Persistence API)是Java持久化規(guī)范的一種實(shí)現(xiàn),它提供了一種方便的方式來訪問和操作數(shù)據(jù)庫(kù)。將Spring Boot與Jpa整合可以更加方便地進(jìn)行數(shù)據(jù)庫(kù)操作,提高開發(fā)效率。本文將介紹如何使用Spring Bo

    2024年02月05日
    瀏覽(23)
  • [SpringBoot系列]SpringBoot如何整合SSMP

    [SpringBoot系列]SpringBoot如何整合SSMP

    SpringBoot之所以好用,就是它能方便快捷的整合其他技術(shù),這里我們先介紹四種技術(shù)的整合: 整合JUnit 整合MyBatis 整合MyBatis-Plus 整合Druid ? SpringBoot技術(shù)的定位用于簡(jiǎn)化開發(fā),再具體點(diǎn)是簡(jiǎn)化Spring程序的開發(fā)。所以在整合任意技術(shù)的時(shí)候,如果你想直觀感觸到簡(jiǎn)化的效果,你必

    2023年04月23日
    瀏覽(15)
  • SpringBoot 整合 Redis 緩存

    Spring Boot提供了對(duì)Spring Cache抽象的支持,可以很容易地與Redis集成。 在pom.xml文件中添加Spring Boot Starter Redis依賴: 在application.properties或application.yml中配置Redis連接信息: 在Spring Boot應(yīng)用的主類(通常是帶有@SpringBootApplication注解的類)上添加@EnableCaching注解,啟用緩存支持: 在

    2024年01月16日
    瀏覽(35)
  • Springboot 整合 Redis配置

    RedisService接口 RedisServiceImpl 實(shí)現(xiàn)類 Redis 配置類

    2024年02月10日
    瀏覽(15)
  • SpringBoot——整合Redis

    SpringBoot——整合Redis

    redis是一款key-velue存儲(chǔ)結(jié)構(gòu)的內(nèi)存級(jí)NoSQL數(shù)據(jù)庫(kù) - 支持多種數(shù)存儲(chǔ)格式 - 支持持久化 - 支持集群 簡(jiǎn)單理解成一個(gè)大Map,反正我就是這么理解的。當(dāng)然他的內(nèi)部有很多復(fù)雜的數(shù)據(jù)類型和操作,咱們?cè)谶@里就不過多贅述了。 首先你要操作Redis你得先有Redis的服務(wù),那么第一步就是安

    2024年02月03日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包