1. 程式人生 > >LayIM.AspNetCore Middleware 開發日記(五)Init接口實現細節

LayIM.AspNetCore Middleware 開發日記(五)Init接口實現細節

nco 記得 結果 主界面 群組 ont 轉發器 取出 ima

前言

  “一旦開始了就要堅持下去“。為什麽本文的第一句話是這麽一句話呢,因為我經常就是開頭轟轟烈烈,結果越來越枯燥,就不想做下去了。但是版圖就放棄又那麽不甘心,繼續加油吧。

  吐槽完畢,進入正題。在上一篇中我們的主角LayIM已經登場了。而且界面已經實現,那麽有些小夥伴就有疑惑了,詳細流程是什麽樣的,今天我就介紹一個東西,那就是 /layim/init 接口的實現細節

  另外,項目已經升級至 .NET CORE 2.1 ,最新代碼在 dev-netcore2.1 分支上

需求

  需求是什麽?需求是將LayIM的主界面顯示出來。如下:

  技術分享圖片 技術分享圖片

  嗯,就是這麽個東西。在上一篇中我已經介紹到,init接口就是為了實現主界面的,那麽主界面的數據是什麽樣的呢?(其實在兩年前的博客中已經講過,這裏在稍微提一下)我們看一下DEMO中的getList.json.

  技術分享圖片

  如上圖,我們只要定義一個接口然後輸出上圖格式中的json數據即可。由於我在框架中用SQLServer給了一個默認實現,關系型數據庫那肯定是各種關系啦。首先定義最基本的表。

  用戶表,用戶好友分組表,用戶好友關系表,群組表,群組群員關系表。目前這五個表足夠了。

  下面逐個分析擊破:

  mine:當前用戶信息,從用戶表取出即可

  friend:首先從用戶好友分組表取出當前用戶所有的分組,在從用戶好友關系表取出好友。然後程序中去匹配該好友對應的分組即可。及分組和好友是一對多的關系

  group:從群組群員關系表中取出當前用戶所在的群,然後在從群組表取出相應的群信息,組合數據即可

具體代碼實現

  下面的代碼如果有不理解的地方,可以先從前面幾篇中補補課。

  首先,毋庸置疑,先將路由配置上:

  routes.AddQuery("/init", async context => await GetInitData(context));

  GetInitData 做了什麽事呢?它就是獲取註冊的 ILayIMStorage 實例,然後調用接口方法獲取數據。

   public interface ILayIMStorage
    {
        /// <summary>
        /// 初始化數據
        /// </summary>
/// <param name="userId"></param> /// <returns></returns> Task<LayIMInitModel> GetInitData(string userId); /// <summary> /// 保存聊天記錄 /// </summary> /// <param name="message"></param> /// <returns></returns> Task<int> SaveMessage(LayIMMessageModel message); }

接口實現類

  在項目 LayIM.AspNetCore.Storage.SqlServer中實現ILayIMStorage接口.Repository具體代碼就不在粘貼了,就是一系列Sql的查詢然後數據組合。

        /// <summary>
        /// 獲取初始化數據
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<LayIMInitModel> GetInitData(string userId)
        {
            var mineTsk = userRepository.GetUserById(userId);
            var friendGroupsTask = friendGroupRepository.GetUserGroups(userId);
            var friendRelationsTask = friendRelationRepository.GetFriendRelations(userId);
            var groupIdsTask = groupMemberRepository.GetUserBigGroups(userId);

            LayIMInitModel initModel = new LayIMInitModel
            {
                //用戶自己
                mine = await mineTsk
            };
            //好友列表
            List<FriendGroupModel> friend = new List<FriendGroupModel>();

            IEnumerable<FriendGroupModel> friendGroups = await friendGroupsTask;
            IEnumerable<FriendRelationShip> friendRelations = await friendRelationsTask;
            IEnumerable<long> friendIds = friendRelations.Select(x => x.FriendId);

            IEnumerable<UserModel> friends = await userRepository.GetUsersByIds(friendIds);

            if (friendIds?.Count() > 0)
            {
                foreach (var group in friendGroups)
                {
                    var friendIdsInGroup = friendRelations.Where(r => r.GroupId == group.id).Select(r => r.FriendId);

                    group.list = friends.Where(x => friendIdsInGroup.Any(f => f == x.id));
                }
            }

            friend.AddRange(friendGroups);

            initModel.friend = friend;

            //群組列表
            IEnumerable<long> groupIds = await groupIdsTask;
            var bigGroupsTask = bigGroupRepository.GetBigGroups(groupIds);
            initModel.group = await bigGroupsTask;

            return initModel;
        }

  寫完方法之後,記得要註冊服務。

        /// <summary>
        /// 使用SqlServer
        /// </summary>
        /// <param name="services"></param>
        /// <param name="setConfig"></param>
        public static IServiceCollection AddSqlServer(this IServiceCollection services,string connectionString)
        {
            var dbConfig = new DBConnectionConfig(DBType.SqlServer)
            {
                ConnectionString = connectionString
            };
            services.AddSingleton(dbConfig);
            services.AddSingleton<ILayIMStorage, LayIMDapperStorage>();
            return services;
        }

  然後在Demo中的使用方法如下:

 services.AddLayIM().AddRongCloud(config =>
                    {
                        config.AppKey = "appkey";
                        config.AppSecret = "appsecret";
                    })
                .AddSqlServer("connectionString");

  重啟項目,測試一下 layim/init 接口。數據返回正常

  技術分享圖片

  當然,一個好友的用戶數據一般變化不大,所以對於接口要增加緩存設計。不過這裏我暫時沒有實現,只是先臨時用了 IMemoryCache

請求回放

  首先,由於請求的 Path /layim 開頭的,所以中間件判定為LayIM請求,然後在經過路由轉發器,找到對應的處理器。

 var dispatcher = LayIMRoutes.Routes.FindDispatcher(path);

  之前已經介紹過,Dispatcher 是實現了Dispatch 方法的。

 internal interface ILayIMDispatcher
    {
        Task Dispatch(HttpContext context);
    }

  所以,最終的請求其實都會落到路由註冊的方法中,也就是上文中的 routes.AddQuery("/init", async context => await GetInitData(context)); 那麽其他的返回ContentType,轉JSON就是框架實現了,業務沒必要關心它了。

  說到這裏可能大家還是比較迷糊,下面是一個Dispatcher之間的關系圖.

  技術分享圖片

  MethodFilterDispatcher 抽象類 負責請求方法的校驗。GET POST PUT DELETE 等

  CommandDispatcher<TResult> 抽象類 負責主業務邏輯處理,模板方法,處理細節交給實現類

  ExecuteCommandDispatcher<TResult> 實現類,POST請求

  QueryCommandDispatcher<TResult> 實現類,GET 請求

  其他待擴展

總結

  本文通過一個 /layim/init 接口的詳細介紹,通過這個接口請求流程,大家能夠對框架的處理部分設計有所理解。另外,本文內容都是在後端,至於前臺怎麽綁定數據處理等,咱們下回分解。

  博客預告:LayIM.AspNetCore Middleware 開發日記(六)嵌入資源的使用,layim.config的封裝

  項目地址:https://github.com/fanpan26/LayIM.AspNetCore 歡迎小夥伴們star 圍觀 提意見。

LayIM.AspNetCore Middleware 開發日記(五)Init接口實現細節