SpringDataRedis 操作redis

一亲澡、SpringDataRedis簡(jiǎn)介
1沥割、Redis
redis是一款開(kāi)源的Key-Value數(shù)據(jù)庫(kù)耗啦,運(yùn)行在內(nèi)存中,由C語(yǔ)言編寫(xiě)机杜。企業(yè)開(kāi)發(fā)通常采用Redis來(lái)實(shí)現(xiàn)緩存帜讲。同類的產(chǎn)品還有memcache 、memcached 等椒拗。

2似将、Jedis
Jedis是Redis官方推出的一款面向Java的客戶端获黔,提供了很多接口供Java語(yǔ)言調(diào)用≡谘椋可以在Redis官網(wǎng)下載玷氏,當(dāng)然還有一些開(kāi)源愛(ài)好者提供的客戶端,如Jredis腋舌、SRP等等预茄,推薦使用Jedis。

3侦厚、Spring Data Redis
Spring-data-redis是spring大家族的一部分耻陕,提供了在srping應(yīng)用中通過(guò)簡(jiǎn)單的配置訪問(wèn)redis服務(wù),對(duì)reids底層開(kāi)發(fā)包(Jedis, JRedis, and RJC)進(jìn)行了高度封裝刨沦,RedisTemplate提供了redis各種操作诗宣、異常處理及序列化,支持發(fā)布訂閱想诅,并對(duì)spring 3.1 cache進(jìn)行了實(shí)現(xiàn)召庞。
spring-data-redis針對(duì)jedis提供了如下功能:

連接池自動(dòng)管理,提供了一個(gè)高度封裝的“RedisTemplate”類
針對(duì)jedis客戶端中大量api進(jìn)行了歸類封裝,將同一類型操作封裝為operation接口
ValueOperations:簡(jiǎn)單K-V操作
SetOperations:set類型數(shù)據(jù)操作
ZSetOperations:zset類型數(shù)據(jù)操作
HashOperations:針對(duì)map類型的數(shù)據(jù)操作
ListOperations:針對(duì)list類型的數(shù)據(jù)操作
提供了對(duì)key的“bound”(綁定)便捷化操作API来破,可以通過(guò)bound封裝指定的key篮灼,然后進(jìn)行一系列的操作而無(wú)須“顯式”的再次指定Key,即BoundKeyOperations:
BoundValueOperations
BoundSetOperations
BoundListOperations
BoundSetOperations
BoundHashOperations
將事務(wù)操作封裝徘禁,有容器控制诅诱。
針對(duì)數(shù)據(jù)的“序列化/反序列化”,提供了多種可選擇策略(RedisSerializer)
JdkSerializationRedisSerializer:POJO對(duì)象的存取場(chǎng)景送朱,使用JDK本身序列化機(jī)制娘荡,將pojo類通過(guò)ObjectInputStream/ObjectOutputStream進(jìn)行序列化操作,最終redis-server中將存儲(chǔ)字節(jié)序列驶沼。是目前最常用的序列化策略炮沐。

StringRedisSerializer:Key或者value為字符串的場(chǎng)景,根據(jù)指定的charset對(duì)數(shù)據(jù)的字節(jié)序列編碼成string回怜,是“new String(bytes, charset)”和“string.getBytes(charset)”的直接封裝大年。是最輕量級(jí)和高效的策略。

JacksonJsonRedisSerializer:jackson-json工具提供了javabean與json之間的轉(zhuǎn)換能力玉雾,可以將pojo實(shí)例序列化成json格式存儲(chǔ)在redis中翔试,也可以將json格式的數(shù)據(jù)轉(zhuǎn)換成pojo實(shí)例。因?yàn)閖ackson工具在序列化和反序列化時(shí)抹凳,需要明確指定Class類型遏餐,因此此策略封裝起來(lái)稍微復(fù)雜伦腐∮祝【需要jackson-mapper-asl工具支持】

二、RedisTemplate中API使用
1、pom.xml依賴

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

2幸冻、配置文件

# Redis服務(wù)器連接端口
spring.redis.port=6379
# Redis服務(wù)器地址
spring.redis.host=127.0.0.1
# Redis數(shù)據(jù)庫(kù)索引(默認(rèn)為0)
spring.redis.database=0
# Redis服務(wù)器連接密碼(默認(rèn)為空)
spring.redis.password=
# 連接池最大連接數(shù)(使用負(fù)值表示沒(méi)有限制)
spring.redis.jedis.pool.max-active=8
# 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒(méi)有限制)
spring.redis.jedis.pool.max-wait=-1ms
# 連接池中的最大空閑連接
spring.redis.jedis.pool.max-idle=8
# 連接池中的最小空閑連接
spring.redis.jedis.pool.min-idle=0
# 連接超時(shí)時(shí)間(毫秒)
spring.redis.timeout=5000ms

3粹庞、RedisTemplate的直接方法
首先使用@Autowired注入RedisTemplate(后面直接使用,就不特殊說(shuō)明)

@Autowired
private RedisTemplate redisTemplate;

1洽损、刪除單個(gè)key

//    刪除key
public void delete(String key){
    redisTemplate.delete(key);
}

2庞溜、刪除多個(gè)key

//    刪除多個(gè)key
public void deleteKey (String ...keys){
    redisTemplate.delete(keys);
}

3、指定key的失效時(shí)間

//    指定key的失效時(shí)間
public void expire(String key,long time){
    redisTemplate.expire(key,time,TimeUnit.MINUTES);
}

4碑定、根據(jù)key獲取過(guò)期時(shí)間

//    根據(jù)key獲取過(guò)期時(shí)間
public long getExpire(String key){
    Long expire = redisTemplate.getExpire(key);
    return expire;
}

5流码、判斷key是否存在

//    判斷key是否存在

public boolean hasKey(String key){
    return redisTemplate.hasKey(key);
}

4、String類型相關(guān)操作

1)延刘、添加緩存(2/3是1的遞進(jìn)值)
//1漫试、通過(guò)redisTemplate設(shè)置值
redisTemplate.boundValueOps("StringKey").set("StringValue");
redisTemplate.boundValueOps("StringKey").set("StringValue",1, TimeUnit.MINUTES);

//2、通過(guò)BoundValueOperations設(shè)置值
BoundValueOperations stringKey = redisTemplate.boundValueOps("StringKey");
stringKey.set("StringVaule");
stringKey.set("StringValue",1, TimeUnit.MINUTES);

//3碘赖、通過(guò)ValueOperations設(shè)置值
ValueOperations ops = redisTemplate.opsForValue();
ops.set("StringKey", "StringVaule");
ops.set("StringValue","StringVaule",1, TimeUnit.MINUTES);

2)驾荣、設(shè)置過(guò)期時(shí)間(單獨(dú)設(shè)置)

redisTemplate.boundValueOps("StringKey").expire(1,TimeUnit.MINUTES);
redisTemplate.expire("StringKey",1,TimeUnit.MINUTES);

3)、獲取緩存值(2/3是1的遞進(jìn)值)

//1普泡、通過(guò)redisTemplate設(shè)置值
String str1 = (String) redisTemplate.boundValueOps("StringKey").get();

//2播掷、通過(guò)BoundValueOperations獲取值
BoundValueOperations stringKey = redisTemplate.boundValueOps("StringKey");
String str2 = (String) stringKey.get();

//3、通過(guò)ValueOperations獲取值
ValueOperations ops = redisTemplate.opsForValue();
String str3 = (String) ops.get("StringKey");

4)撼班、刪除key

Boolean result = redisTemplate.delete("StringKey");

5)歧匈、順序遞增

redisTemplate.boundValueOps("StringKey").increment(3L);

6)、順序遞減

redisTemplate.boundValueOps("StringKey").increment(-3L);

5砰嘁、Hash類型相關(guān)操作

1)眯亦、添加緩存(2/3是1的遞進(jìn)值)

//1、通過(guò)redisTemplate設(shè)置值
redisTemplate.boundHashOps("HashKey").put("SmallKey", "HashVaue");

//2般码、通過(guò)BoundValueOperations設(shè)置值
BoundHashOperations hashKey = redisTemplate.boundHashOps("HashKey");
hashKey.put("SmallKey", "HashVaue");

//3妻率、通過(guò)ValueOperations設(shè)置值
HashOperations hashOps = redisTemplate.opsForHash();
hashOps.put("HashKey", "SmallKey", "HashVaue");

2)、設(shè)置過(guò)期時(shí)間(單獨(dú)設(shè)置)

redisTemplate.boundValueOps("HashKey").expire(1,TimeUnit.MINUTES);
redisTemplate.expire("HashKey",1,TimeUnit.MINUTES);

3)板祝、添加一個(gè)Map集合

HashMap<String, String> hashMap = new HashMap<>();
redisTemplate.boundHashOps("HashKey").putAll(hashMap );

4)宫静、設(shè)置過(guò)期時(shí)間(單獨(dú)設(shè)置)

redisTemplate.boundValueOps("HashKey").expire(1,TimeUnit.MINUTES);
redisTemplate.expire("HashKey",1,TimeUnit.MINUTES);

5)、提取所有的小key

//1券时、通過(guò)redisTemplate獲取值
Set keys1 = redisTemplate.boundHashOps("HashKey").keys();

//2孤里、通過(guò)BoundValueOperations獲取值
BoundHashOperations hashKey = redisTemplate.boundHashOps("HashKey");
Set keys2 = hashKey.keys();

//3、通過(guò)ValueOperations獲取值
HashOperations hashOps = redisTemplate.opsForHash();
Set keys3 = hashOps.keys("HashKey");

6)橘洞、提取所有的value值

//1捌袜、通過(guò)redisTemplate獲取值
List values1 = redisTemplate.boundHashOps("HashKey").values();

//2、通過(guò)BoundValueOperations獲取值
BoundHashOperations hashKey = redisTemplate.boundHashOps("HashKey");
List values2 = hashKey.values();

//3炸枣、通過(guò)ValueOperations獲取值
HashOperations hashOps = redisTemplate.opsForHash();
List values3 = hashOps.values("HashKey");

7)虏等、根據(jù)key提取value值

//1弄唧、通過(guò)redisTemplate獲取
String value1 = (String) redisTemplate.boundHashOps("HashKey").get("SmallKey");

//2、通過(guò)BoundValueOperations獲取值
BoundHashOperations hashKey = redisTemplate.boundHashOps("HashKey");
String value2 = (String) hashKey.get("SmallKey");

//3霍衫、通過(guò)ValueOperations獲取值
HashOperations hashOps = redisTemplate.opsForHash();
String value3 = (String) hashOps.get("HashKey", "SmallKey");

8)候引、獲取所有的鍵值對(duì)集合

//1、通過(guò)redisTemplate獲取
Map entries = redisTemplate.boundHashOps("HashKey").entries();

//2敦跌、通過(guò)BoundValueOperations獲取值
BoundHashOperations hashKey = redisTemplate.boundHashOps("HashKey");
Map entries1 = hashKey.entries();

//3澄干、通過(guò)ValueOperations獲取值
HashOperations hashOps = redisTemplate.opsForHash();
Map entries2 = hashOps.entries("HashKey");

9)、刪除

//刪除小key
redisTemplate.boundHashOps("HashKey").delete("SmallKey");
//刪除大key
redisTemplate.delete("HashKey");

10)柠傍、判斷Hash中是否含有該值

Boolean isEmpty = redisTemplate.boundHashOps("HashKey").hasKey("SmallKey");

6麸俘、Set類型相關(guān)操作
1)、添加Set緩存(值可以是一個(gè)惧笛,也可是多個(gè))(2/3是1的遞進(jìn)值)

//1疾掰、通過(guò)redisTemplate設(shè)置值
redisTemplate.boundSetOps("setKey").add("setValue1", "setValue2", "setValue3");

//2、通過(guò)BoundValueOperations設(shè)置值
BoundSetOperations setKey = redisTemplate.boundSetOps("setKey");
setKey.add("setValue1", "setValue2", "setValue3");

//3徐紧、通過(guò)ValueOperations設(shè)置值
SetOperations setOps = redisTemplate.opsForSet();
setOps.add("setKey", "SetValue1", "setValue2", "setValue3");

2)静檬、設(shè)置過(guò)期時(shí)間(單獨(dú)設(shè)置)

redisTemplate.boundValueOps("setKey").expire(1,TimeUnit.MINUTES);
redisTemplate.expire("setKey",1,TimeUnit.MINUTES);

3)、根據(jù)key獲取Set中的所有值

//1并级、通過(guò)redisTemplate獲取值
Set set1 = redisTemplate.boundSetOps("setKey").members();

//2拂檩、通過(guò)BoundValueOperations獲取值
BoundSetOperations setKey = redisTemplate.boundSetOps("setKey");
Set set2 = setKey.members();

//3、通過(guò)ValueOperations獲取值
SetOperations setOps = redisTemplate.opsForSet();
Set set3 = setOps.members("setKey");

4)嘲碧、根據(jù)value從一個(gè)set中查詢,是否存在

Boolean isEmpty = redisTemplate.boundSetOps("setKey").isMember("setValue2");

5)稻励、獲取Set緩存的長(zhǎng)度

Long size = redisTemplate.boundSetOps("setKey").size();

6)、移除指定的元素

Long result1 = redisTemplate.boundSetOps("setKey").remove("setValue1");

7)愈涩、移除指定的key

Boolean result2 = redisTemplate.delete("setKey");

7望抽、 LIST類型相關(guān)操作
1)、添加緩存(2/3是1的遞進(jìn)值)

//1履婉、通過(guò)redisTemplate設(shè)置值
redisTemplate.boundListOps("listKey").leftPush("listLeftValue1");
redisTemplate.boundListOps("listKey").rightPush("listRightValue2");

//2煤篙、通過(guò)BoundValueOperations設(shè)置值
BoundListOperations listKey = redisTemplate.boundListOps("listKey");
listKey.leftPush("listLeftValue3");
listKey.rightPush("listRightValue4");

//3、通過(guò)ValueOperations設(shè)置值
ListOperations opsList = redisTemplate.opsForList();
opsList.leftPush("listKey", "listLeftValue5");
opsList.rightPush("listKey", "listRightValue6");

2)毁腿、將List放入緩存

ArrayList<String> list = new ArrayList<>();
redisTemplate.boundListOps("listKey").rightPushAll(list);
redisTemplate.boundListOps("listKey").leftPushAll(list);

3)辑奈、設(shè)置過(guò)期時(shí)間(單獨(dú)設(shè)置)

redisTemplate.boundValueOps("listKey").expire(1,TimeUnit.MINUTES);
redisTemplate.expire("listKey",1,TimeUnit.MINUTES);

4)、獲取List緩存全部?jī)?nèi)容(起始索引已烤,結(jié)束索引)

List listKey1 = redisTemplate.boundListOps("listKey").range(0, 10); 

5)鸠窗、從左或從右彈出一個(gè)元素

String listKey2 = (String) redisTemplate.boundListOps("listKey").leftPop();  //從左側(cè)彈出一個(gè)元素
String listKey3 = (String) redisTemplate.boundListOps("listKey").rightPop(); //從右側(cè)彈出一個(gè)元素

6)、根據(jù)索引查詢?cè)?/p>

String listKey4 = (String) redisTemplate.boundListOps("listKey").index(1);

7)胯究、獲取List緩存的長(zhǎng)度

Long size = redisTemplate.boundListOps("listKey").size();

8)稍计、根據(jù)索引修改List中的某條數(shù)據(jù)(key,索引裕循,值)

redisTemplate.boundListOps("listKey").set(3L,"listLeftValue3");

9)臣嚣、移除N個(gè)值為value(key,移除個(gè)數(shù)净刮,值)

redisTemplate.boundListOps("listKey").remove(3L,"value");

8、Zset類型的相關(guān)操作
1)茧球、向集合中插入元素庭瑰,并設(shè)置分?jǐn)?shù)

//1星持、通過(guò)redisTemplate設(shè)置值
redisTemplate.boundZSetOps("zSetKey").add("zSetVaule", 100D);

//2抢埋、通過(guò)BoundValueOperations設(shè)置值
BoundZSetOperations zSetKey = redisTemplate.boundZSetOps("zSetKey");
zSetKey.add("zSetVaule", 100D);

//3、通過(guò)ValueOperations設(shè)置值
ZSetOperations zSetOps = redisTemplate.opsForZSet();
zSetOps.add("zSetKey", "zSetVaule", 100D);

2)督暂、向集合中插入多個(gè)元素,并設(shè)置分?jǐn)?shù)

DefaultTypedTuple<String> p1 = new DefaultTypedTuple<>("zSetVaule1", 2.1D);
DefaultTypedTuple<String> p2 = new DefaultTypedTuple<>("zSetVaule2", 3.3D);
redisTemplate.boundZSetOps("zSetKey").add(new HashSet<>(Arrays.asList(p1,p2)));

3)揪垄、按照排名先后(從小到大)打印指定區(qū)間內(nèi)的元素, -1為打印全部

Set<String> range = redisTemplate.boundZSetOps("zSetKey").range(0, -1);

4)、獲得指定元素的分?jǐn)?shù)

Double score = redisTemplate.boundZSetOps("zSetKey").score("zSetVaule");

5)逻翁、返回集合內(nèi)的成員個(gè)數(shù)

Long size = redisTemplate.boundZSetOps("zSetKey").size();

6)饥努、返回集合內(nèi)指定分?jǐn)?shù)范圍的成員個(gè)數(shù)(Double類型)

Long COUNT = redisTemplate.boundZSetOps("zSetKey").count(0D, 2.2D);

7)、返回集合內(nèi)元素在指定分?jǐn)?shù)范圍內(nèi)的排名(從小到大)

Set byScore = redisTemplate.boundZSetOps("zSetKey").rangeByScore(0D, 2.2D);

8)八回、帶偏移量和個(gè)數(shù)酷愧,(key,起始分?jǐn)?shù)缠诅,最大分?jǐn)?shù)溶浴,偏移量,個(gè)數(shù))

Set<String> ranking2 = redisTemplate.opsForZSet().rangeByScore("zSetKey", 0D, 2.2D 1, 3);

9)管引、返回集合內(nèi)元素的排名士败,以及分?jǐn)?shù)(從小到大)

Set<TypedTuple<String>> tuples = redisTemplate.boundZSetOps("zSetKey").rangeWithScores(0L, 3L);
  for (TypedTuple<String> tuple : tuples) {
      System.out.println(tuple.getValue() + " : " + tuple.getScore());
  }ss

10)、返回指定成員的排名

//從小到大
Long startRank = redisTemplate.boundZSetOps("zSetKey").rank("zSetVaule");
//從大到小
Long endRank = redisTemplate.boundZSetOps("zSetKey").reverseRank("zSetVaule");

11)褥伴、從集合中刪除指定元素

redisTemplate.boundZSetOps("zSetKey").remove("zSetVaule");

12)谅将、刪除指定索引范圍的元素(Long類型)

redisTemplate.boundZSetOps("zSetKey").removeRange(0L,3L);

13)、刪除指定分?jǐn)?shù)范圍內(nèi)的元素(Double類型)

redisTemplate.boundZSetOps("zSetKey").removeRangeByScorssse(0D,2.2D);

14)重慢、為指定元素加分(Double類型)

Double score = redisTemplate.boundZSetOps("zSetKey").incrementScore("zSetVaule",1.1D);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末饥臂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子似踱,更是在濱河造成了極大的恐慌擅笔,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件屯援,死亡現(xiàn)場(chǎng)離奇詭異猛们,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)狞洋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)弯淘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人吉懊,你說(shuō)我怎么就攤上這事庐橙〖傥穑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵态鳖,是天一觀的道長(zhǎng)转培。 經(jīng)常有香客問(wèn)我,道長(zhǎng)浆竭,這世上最難降的妖魔是什么浸须? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮邦泄,結(jié)果婚禮上删窒,老公的妹妹穿的比我還像新娘篓叶。我一直安慰自己限番,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布蛀蜜。 她就那樣靜靜地躺著特碳,像睡著了一般诚亚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上午乓,一...
    開(kāi)封第一講書(shū)人閱讀 52,328評(píng)論 1 310
  • 那天站宗,我揣著相機(jī)與錄音,去河邊找鬼硅瞧。 笑死份乒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的腕唧。 我是一名探鬼主播或辖,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼枣接!你這毒婦竟也來(lái)了颂暇?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤但惶,失蹤者是張志新(化名)和其女友劉穎耳鸯,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體膀曾,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡县爬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了添谊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片财喳。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出耳高,到底是詐尸還是另有隱情扎瓶,我是刑警寧澤,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布泌枪,位于F島的核電站概荷,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏碌燕。R本人自食惡果不足惜误证,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望陆蟆。 院中可真熱鬧雷厂,春花似錦惋增、人聲如沸叠殷。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)林束。三九已至,卻和暖如春稽亏,著一層夾襖步出監(jiān)牢的瞬間壶冒,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工截歉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胖腾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓瘪松,卻偏偏與公主長(zhǎng)得像咸作,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子宵睦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359