從壹開始前后端分離【 .NET Core2.0 +Vue2.0 】框架之十一 || AOP自定義篩選,Redis入門 11.1

大神留步

先說下一個窩心的問題章姓,求大神幫忙佳遣,如何在Task異步編程中炭序,使用Redis存、取Task<List<T>>泛型苍日,有償幫助惭聂,這里謝謝,文末有詳細(xì)問題說明相恃,可以留言或者私信都可以辜纲。

當(dāng)然我也會一直思考,大家持續(xù)關(guān)注本帖拦耐,如果我想到好辦法耕腾,會及時更新,并通知大家杀糯。

代碼已上傳Github+Gitee扫俺,文末有地址

書說上文《從壹開始前后端分離【 .NET Core2.0 Api + Vue 2.0 + AOP + 分布式】框架之十 || AOP面向切面編程淺解析:簡單日志記錄 + 服務(wù)切面緩存》,昨天咱們說到了AOP面向切面編程固翰,簡單的舉出了兩個栗子狼纬,不知道大家有什么想法呢,不知道是否與傳統(tǒng)的緩存的使用有做對比了么骂际?

傳統(tǒng)的緩存是在Controller中疗琉,將獲取到的數(shù)據(jù)手動處理,然后當(dāng)另一個controller中又使用的時候歉铝,還是Get盈简,Set相關(guān)操作,當(dāng)然如果小項目太示,有兩三個緩存還好柠贤,如果是特別多的接口調(diào)用,面向Service服務(wù)層還是很有必要的类缤,不需要額外寫多余代碼臼勉,只需要正常調(diào)取Service層的接口就行,AOP結(jié)合Autofac注入呀非,會自動的查找坚俗,然后返回數(shù)據(jù),不繼續(xù)往下走Repository倉儲了岸裙。

昨天我發(fā)布文章后猖败,有一個網(wǎng)友提除了一個問題,他想的很好降允,就是如果面向到了Service層恩闻,那BaseService中的CURD等基本方法都被注入了,這樣會造成太多的代理類剧董,不僅沒有必要幢尚,甚至還有問題破停,比如把Update也緩存了,這個就不是很好了尉剩,嗯真慢,我也發(fā)現(xiàn)了這個問題,所以需要給AOP增加驗證特性理茎,只針對Service服務(wù)層中特定的常使用的方法數(shù)據(jù)進(jìn)行緩存等黑界。這樣既能保證切面緩存的高效性,又能手動控制皂林,不知道大家有沒有其他的好辦法朗鸠,如果有的話,歡迎留言础倍,或者加群咱們一起討論烛占,一起解決平時的問題。

零沟启、今天完成的大紅色部分

image

一忆家、給緩存增加驗證篩選特性

1、在解決方案中添加新項目Blog.Core.Common美浦,然后在該Common類庫中添加 特性文件夾 和 特性實體類弦赖,以后特性就在這里

//CachingAttribute

 /// <summary>
    /// 這個Attribute就是使用時候的驗證,把它添加到要緩存數(shù)據(jù)的方法中浦辨,即可完成緩存的操作。注意是對Method驗證有效 /// </summary>
    [AttributeUsage(AttributeTargets.Method, Inherited = true)] public class CachingAttribute : Attribute
    { //緩存絕對過期時間
        public int AbsoluteExpiration { get; set; } = 30;

    }

2沼沈、添加Common程序集引用流酬,然后修改緩存AOP類方法 BlogCacheAOP=》Intercept,簡單對方法的方法進(jìn)行判斷

//qCachingAttribute 代碼


   //Intercept方法是攔截的關(guān)鍵所在列另,也是IInterceptor接口中的唯一定義
        public void Intercept(IInvocation invocation)
        { var method = invocation.MethodInvocationTarget ?? invocation.Method; //對當(dāng)前方法的特性驗證
            var qCachingAttribute = method.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(CachingAttribute)) as CachingAttribute; //如果需要驗證
            if (qCachingAttribute != null)
            { //獲取自定義緩存鍵
                var cacheKey = CustomCacheKey(invocation); //根據(jù)key獲取相應(yīng)的緩存值
                var cacheValue = _cache.Get(cacheKey); if (cacheValue != null)
                { //將當(dāng)前獲取到的緩存值芽腾,賦值給當(dāng)前執(zhí)行方法
                    invocation.ReturnValue = cacheValue; return;
                } //去執(zhí)行當(dāng)前的方法
 invocation.Proceed(); //存入緩存
                if (!string.IsNullOrWhiteSpace(cacheKey))
                {
                    _cache.Set(cacheKey, invocation.ReturnValue);
                }
            } else {
                invocation.Proceed();//直接執(zhí)行被攔截方法
 }
        }

可見在invocation參數(shù)中,包含了幾乎所有的方法页衙,大家可以深入研究下摊滔,獲取到自己需要的數(shù)據(jù)

3、在制定的Service層中的某些類的某些方法上增加特性(一定是方法店乐,不懂的可以看定義特性的時候AttributeTargets.Method)


     /// <summary>
        /// 獲取博客列表 /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Caching(AbsoluteExpiration = 10)]//增加特性 public async Task<List<BlogArticle>> getBlogs()
        { var bloglist = await dal.Query(a => a.bID > 0, a => a.bID); return bloglist;

        }

4艰躺、運行項目,打斷點眨八,就可以看到腺兴,普通的Query或者CURD等都不繼續(xù)緩存了,只有咱們特定的 getBlogs()方法廉侧,帶有緩存特性的才可以

image

5页响、當(dāng)然篓足,這里還有一個小問題,就是所有的方法還是走的切面闰蚕,只是增加了過濾驗證栈拖,大家也可以直接把那些需要的注入,不需要的干脆不注入容器没陡,我之所以需要都經(jīng)過的目的涩哟,就是想把它和日志結(jié)合,用來記錄Service層的每一個請求诗鸭,包括CURD的調(diào)用情況染簇。

二、什么是Redis强岸,為什么使用它

我個人有一個理解锻弓,關(guān)于Session或Cache等,在普通單服務(wù)器的項目中蝌箍,很簡單青灼,有自己的生命周期等,想獲取Session就獲取妓盲,想拿啥就拿傻杂拨,但是在大型的分布式集群中,有可能這一秒的點擊的頁面和下一秒的都不在一個服務(wù)器上悯衬,對不對弹沽!想想如果普通的辦法,怎么保證session的一致性筋粗,怎么獲取相同的緩存數(shù)據(jù)策橘,怎么有效的進(jìn)行消息隊列傳遞?

這個時候就用到了Redis娜亿,這些內(nèi)容丽已,網(wǎng)上已經(jīng)到處都是,但是還是做下記錄吧

Redis是一個key-value存儲系統(tǒng)买决。和Memcached類似沛婴,它支持存儲的value類型相對更多,包括string(字符串)督赤、list(鏈表)嘁灯、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)够挂。這些數(shù)據(jù)類型都支持push/pop旁仿、add/remove及取交集并集和差集及更豐富的操作,而且這些操作都是原子性的。它內(nèi)置復(fù)制枯冈、Lua腳本毅贮、LRU收回、事務(wù)以及不同級別磁盤持久化功能尘奏,同時通過Redis Sentinel提供高可用滩褥,通過Redis Cluster提供自動分區(qū)。在此基礎(chǔ)上炫加,Redis支持各種不同方式的排序瑰煎。為了保證效率,數(shù)據(jù)都是緩存在內(nèi)存中俗孝。區(qū)別的是redis會周期性的把更新的數(shù)據(jù)寫入磁盤或者把修改操作寫入追加的記錄文件酒甸,并且在此基礎(chǔ)上實現(xiàn)了master-slave(主從)同步。

也就是說赋铝,緩存服務(wù)器如果意外重啟了插勤,數(shù)據(jù)還都在,嗯革骨!這就是它的強大之處农尖,不僅在內(nèi)存高吞吐,還能持久化良哲。

Redis支持主從同步盛卡。數(shù)據(jù)可以從主服務(wù)器向任意數(shù)量的從服務(wù)器上同步,從服務(wù)器可以是關(guān)聯(lián)其他從服務(wù)器的主服務(wù)器筑凫。這使得Redis可執(zhí)行單層樹復(fù)制滑沧。存盤可以有意無意的對數(shù)據(jù)進(jìn)行寫操作。由于完全實現(xiàn)了發(fā)布/訂閱機制巍实,使得從數(shù)據(jù)庫在任何地方同步樹時嚎货,可訂閱一個頻道并接收主服務(wù)器完整的消息發(fā)布記錄。同步對讀取操作的可擴展性和數(shù)據(jù)冗余很有幫助蔫浆。

Redis也是可以做為消息隊列的,與之相同功能比較優(yōu)秀的就是Kafka

Redis還是有自身的缺點:

Redis只能存儲key/value類型姐叁,雖然value的類型可以有多種瓦盛,但是對于關(guān)聯(lián)性的記錄查詢,沒有Sqlserver外潜、Oracle原环、Mysql等關(guān)系數(shù)據(jù)庫方便。
Redis內(nèi)存數(shù)據(jù)寫入硬盤有一定的時間間隔处窥,在這個間隔內(nèi)數(shù)據(jù)可能會丟失嘱吗,雖然后續(xù)會介紹各種模式來保證數(shù)據(jù)丟失的可能性,但是依然會有可能,所以對數(shù)據(jù)有嚴(yán)格要求的不建議使用Redis做為數(shù)據(jù)庫谒麦。

三俄讹、Redis的安裝和調(diào)試使用

**1.下載最新版redis,選擇.msi安裝版本绕德,或者.zip免安裝 **(我這里是.msi安裝)

下載地址:https://github.com/MicrosoftArchive/redis/releases

image

2.雙擊執(zhí)行.msi文件患膛,一路next,中間有一個需要注冊服務(wù)耻蛇,因為如果不注冊的話踪蹬,把啟動的Dos窗口關(guān)閉的話,Redis就中斷連接了臣咖。

image

3.如果你是免安裝的跃捣,需要執(zhí)行以下語句

啟動命令:redis-server.exe redis.windows.conf

注冊服務(wù)命令:redis-server.exe --service-install redis.windows.conf

去服務(wù)列表查詢服務(wù),可以看到redis服務(wù)默認(rèn)沒有開啟夺蛇,開啟redis服務(wù)(可以設(shè)置為開機自動啟動)

image

四疚漆、創(chuàng)建appsettings.json數(shù)據(jù)獲取類

如果你對.net 獲取app.config或者web.config得心應(yīng)手的話,在.net core中就稍顯吃力蚊惯,因為不支持直接對Configuration的操作

前幾篇文章中有一個網(wǎng)友說了這樣的方法愿卸,在Starup.cs中的ConfigureServices方法中,添加

Blog.Core.Repository.BaseDBConfig.ConnectionString = Configuration.GetSection("AppSettings:SqlServerConnection").Value;

當(dāng)然這是可行的截型,只不過趴荸,如果配置的數(shù)據(jù)很多,比如這樣的宦焦,那就不好寫了发钝。

{ "Logging": { "IncludeScopes": false, "Debug": { "LogLevel": { "Default": "Warning" }
    }, "Console": { "LogLevel": { "Default": "Warning" }
    }
  }, //用戶配置信息
  "AppSettings": { //Redis緩存
    "RedisCaching": { "Enabled": true, "ConnectionString": "127.0.0.1:6379" }, //數(shù)據(jù)庫配置
    "SqlServer": { "SqlServerConnection": "Server=.;Database=WMBlogDB;User ID=sa;Password=123;", "ProviderName": "System.Data.SqlClient" }, "Date": "2018-08-28", "Author": "Blog.Core" }
}

當(dāng)然,我受到他的啟發(fā)波闹,簡單做了下處理酝豪,大家看看是否可行

0、將上面代碼添加到appsettings.json文件中

1精堕、在Blog.Core.Common類庫中孵淘,新建Helper文件夾,新建Appsettings.cs操作類歹篓,然后引用 Microsoft.Extensions.Configuration.Json 的Nuget包

   /// <summary>
    /// appsettings.json操作類 /// </summary>
    public class Appsettings
    { static IConfiguration Configuration { get; set; } static Appsettings()
        { //ReloadOnChange = true 當(dāng)appsettings.json被修改時重新加載
            Configuration = new ConfigurationBuilder()
            .Add(new JsonConfigurationSource { Path = "appsettings.json", ReloadOnChange = true })
            .Build();
        } /// <summary>
        /// 封裝要操作的字符 /// </summary>
        /// <param name="sections"></param>
        /// <returns></returns>
        public static string app(params string[] sections)
        { try { var val = string.Empty; for (int i = 0; i < sections.Length; i++)
                {
                    val += sections[i] + ":";
                } return Configuration[val.TrimEnd(':')];
            } catch (Exception)
            { return "";
            }

        }
    }

2瘫证、如何使用呢,直接引用類庫庄撮,傳遞想要的參數(shù)就行(這里對參數(shù)是有順序要求的背捌,這個順序就是json文件中的層級)

        /// <summary>
        /// 獲取博客列表 /// </summary>
        /// <returns></returns>
 [HttpGet]
        [Route("GetBlogs")] public async Task<List<BlogArticle>> GetBlogs()
        { var connect=Appsettings.app(new string[] { "AppSettings", "RedisCaching" , "ConnectionString" });//按照層級的順序,依次寫出來

            return await blogArticleServices.getBlogs();
        } 

3洞斯、注意:U鼻臁!把appsettings.json文件添加到bin生成文件中!么抗!

如果直接運行毅否,會報錯,提示沒有權(quán)限乖坠,

操作:右鍵appsettings.json =》 屬性 =》 Advanced =》 復(fù)制到輸出文件夾 =》 永遠(yuǎn)復(fù)制 =》應(yīng)用搀突,保存

image

4、這個時候運行項目熊泵,就可以看到結(jié)果了

image

五仰迁、創(chuàng)建Redis緩存接口以及類,并在Controller中測試

1顽分、在Blog.Core.Common的Helper文件夾中徐许,添加SerializeHelper.cs 對象序列化操作,以后再擴展

    public class SerializeHelper
    { /// <summary>
        /// 序列化 /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public static byte[] Serialize(object item)
        { var jsonString = JsonConvert.SerializeObject(item); return Encoding.UTF8.GetBytes(jsonString);
        } /// <summary>
        /// 反序列化 /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        public static TEntity Deserialize<TEntity>(byte[] value)
        { if (value == null)
            { return default(TEntity);
            } var jsonString = Encoding.UTF8.GetString(value); return JsonConvert.DeserializeObject<TEntity>(jsonString);
        }
    }

2卒蘸、在Blog.Core.Common類庫中雌隅,新建Redis文件夾,并新建IRedisCacheManager接口和RedisCacheManager類缸沃,并引用Nuget包StackExchange.Redis

   public interface IRedisCacheManager
    { /// <summary>
       /// 獲取 /// </summary>
       /// <typeparam name="TEntity"></typeparam>
       /// <param name="key"></param>
       /// <returns></returns>
        TEntity Get<TEntity>(string key); //設(shè)置
        void Set(string key, object value, TimeSpan cacheTime); //判斷是否存在
        bool Get(string key); //移除
        void Remove(string key); //清除
        void Clear();
    }

因為在開發(fā)的過程中恰起,通過ConnectionMultiplexer頻繁的連接關(guān)閉服務(wù),是很占內(nèi)存資源的趾牧,所以我們使用單例模式來實現(xiàn)

   public class RedisCacheManager : IRedisCacheManager
    { private readonly string redisConnenctionString; public volatile ConnectionMultiplexer redisConnection; private readonly object redisConnectionLock = new object(); public RedisCacheManager()
        { string redisConfiguration = Appsettings.app(new string[] { "AppSettings", "RedisCaching", "ConnectionString" });//獲取連接字符串

            if (string.IsNullOrWhiteSpace(redisConfiguration))
            { throw new ArgumentException("redis config is empty", nameof(redisConfiguration));
            } this.redisConnenctionString = redisConfiguration; this.redisConnection = GetRedisConnection();
        } /// <summary>
        /// 核心代碼限嫌,獲取連接實例 /// 通過雙if 夾lock的方式须床,實現(xiàn)單例模式 /// </summary>
        /// <returns></returns>
        private ConnectionMultiplexer GetRedisConnection()
        { //如果已經(jīng)連接實例性置,直接返回
            if (this.redisConnection != null && this.redisConnection.IsConnected)
            { return this.redisConnection;
            } //加鎖伪冰,防止異步編程中,出現(xiàn)單例無效的問題
            lock (redisConnectionLock)
            { if (this.redisConnection != null)
                { //釋放redis連接
                    this.redisConnection.Dispose();
                } this.redisConnection = ConnectionMultiplexer.Connect(redisConnenctionString);
            } return this.redisConnection;
        } /// <summary>
        /// 清除 /// </summary>
        public void Clear()
        { foreach (var endPoint in this.GetRedisConnection().GetEndPoints())
            { var server = this.GetRedisConnection().GetServer(endPoint); foreach (var key in server.Keys())
                {
                    redisConnection.GetDatabase().KeyDelete(key);
                }
            }
        } /// <summary>
        /// 判斷是否存在 /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool Get(string key)
        { return redisConnection.GetDatabase().KeyExists(key);
        } /// <summary>
        /// 獲取 /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public TEntity Get<TEntity>(string key)
        { var value = redisConnection.GetDatabase().StringGet(key); if (value.HasValue)
            { //需要用的反序列化哄芜,將Redis存儲的Byte[]貌亭,進(jìn)行反序列化
                return SerializeHelper.Deserialize<TEntity>(value);
            } else { return default(TEntity);
            }
        } /// <summary>
        /// 移除 /// </summary>
        /// <param name="key"></param>
        public void Remove(string key)
        {
            redisConnection.GetDatabase().KeyDelete(key);
        } /// <summary>
        /// 設(shè)置 /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="cacheTime"></param>
        public void Set(string key, object value, TimeSpan cacheTime)
        { if (value != null)
            { //序列化,將object值生成RedisValue
 redisConnection.GetDatabase().StringSet(key, SerializeHelper.Serialize(value), cacheTime);
            }
        }

    }

代碼還是很簡單的认臊,網(wǎng)上都有很多資源圃庭,就是普通的添加,獲取

3失晴、將redis接口和類 在ConfigureServices中 進(jìn)行注入冤议,(注意是構(gòu)造函數(shù)注入)然后在controller中添加代碼測試

services.AddScoped<IRedisCacheManager, RedisCacheManager>();

 IAdvertisementServices advertisementServices;
        IBlogArticleServices blogArticleServices;
        IRedisCacheManager redisCacheManager;//Reids緩存 /// <summary>
        /// 構(gòu)造函數(shù) /// </summary>
        /// <param name="advertisementServices"></param>
        /// <param name="blogArticleServices"></param>
        /// <param name="redisCacheManager"></param>
        public BlogController(IAdvertisementServices advertisementServices, IBlogArticleServices blogArticleServices, IRedisCacheManager redisCacheManager)
        { this.advertisementServices = advertisementServices; this.blogArticleServices = blogArticleServices; this.redisCacheManager = redisCacheManager;
        }</pre>

<pre style="color: rgb(0, 0, 0); font-family: &quot;Courier New&quot;; font-size: 12px; margin: 5px 8px; padding: 5px;">     /// <summary>
        /// 獲取博客列表 /// </summary>
        /// <returns></returns>
 [HttpGet]
        [Route("GetBlogs")] public async Task<List<BlogArticle>> GetBlogs()
        { var connect=Appsettings.app(new string[] { "AppSettings", "RedisCaching" , "ConnectionString" });//按照層級的順序,依次寫出來
 List<BlogArticle> blogArticleList = new List<BlogArticle>(); if (redisCacheManager.Get<object>("Redis.Blog") != null)
            {
                blogArticleList = redisCacheManager.Get<List<BlogArticle>>("Redis.Blog");
            } else {
                blogArticleList = await blogArticleServices..Query(d => d.bID > 5);
                redisCacheManager.Set("Redis.Blog", blogArticleList, TimeSpan.FromHours(2));
            } return blogArticleList;
        }
image

4师坎、運行,執(zhí)行Redis緩存堪滨,看到結(jié)果

image

六胯陋、心結(jié)

今天的講解就到里了,是不是有一種草草收場的感覺,是的遏乔!本來后來應(yīng)該最后一節(jié)义矛。細(xì)心的你應(yīng)該發(fā)現(xiàn)了,我們是在controller進(jìn)行測試盟萨,Redis緩存的是List泛型凉翻,但是呢,AOP切面緩存還是基于內(nèi)存緩存捻激,昨天我本想合并下制轰,奈何AOP切面是通過異步編程,獲取到的Task的List泛型胞谭,在Redis中需要序列化垃杖,鄙人表示不是很懂,希望看到的大神幫忙解決下丈屹,

如何把異步返回的Task<List<T>>結(jié)果调俘,緩存到Redis,并能通過泛型取出來旺垒,有償服務(wù)彩库。感謝!

七先蒋、CODE

https://github.com/anjoy8/Blog.Core

https://gitee.com/laozhangIsPhi/Blog.Core

QQ群:
867095512 (blod.core)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末骇钦,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鞭达,更是在濱河造成了極大的恐慌司忱,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件畴蹭,死亡現(xiàn)場離奇詭異坦仍,居然都是意外死亡,警方通過查閱死者的電腦和手機叨襟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進(jìn)店門繁扎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人糊闽,你說我怎么就攤上這事梳玫。” “怎么了右犹?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵提澎,是天一觀的道長。 經(jīng)常有香客問我念链,道長盼忌,這世上最難降的妖魔是什么积糯? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮谦纱,結(jié)果婚禮上看成,老公的妹妹穿的比我還像新娘。我一直安慰自己跨嘉,他們只是感情好川慌,可當(dāng)我...
    茶點故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著祠乃,像睡著了一般梦重。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上跳纳,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天忍饰,我揣著相機與錄音,去河邊找鬼寺庄。 笑死艾蓝,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的斗塘。 我是一名探鬼主播赢织,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼馍盟!你這毒婦竟也來了于置?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤贞岭,失蹤者是張志新(化名)和其女友劉穎八毯,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瞄桨,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡话速,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了芯侥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泊交。...
    茶點故事閱讀 40,561評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖柱查,靈堂內(nèi)的尸體忽然破棺而出廓俭,到底是詐尸還是另有隱情,我是刑警寧澤唉工,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布研乒,位于F島的核電站,受9級特大地震影響淋硝,放射性物質(zhì)發(fā)生泄漏告嘲。R本人自食惡果不足惜错维,卻給世界環(huán)境...
    茶點故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望橄唬。 院中可真熱鬧,春花似錦参歹、人聲如沸仰楚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽僧界。三九已至,卻和暖如春臭挽,著一層夾襖步出監(jiān)牢的瞬間捂襟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工欢峰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留葬荷,地道東北人。 一個月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓纽帖,卻偏偏與公主長得像宠漩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子懊直,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,573評論 2 359

推薦閱讀更多精彩內(nèi)容