zoukankan      html  css  js  c++  java
  • LayIM.AspNetCore Middleware 开发日记(五)Init接口实现细节

    前言

      “一旦开始了就要坚持下去“。为什么本文的第一句话是这么一句话呢,因为我经常就是开头轰轰烈烈,结果越来越枯燥,就不想做下去了。但是版图就放弃又那么不甘心,继续加油吧。

      吐槽完毕,进入正题。在上一篇中我们的主角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 围观 提意见。

  • 相关阅读:
    Linux搭建测试环境详细步骤
    MongoDB基本查询
    数据库常用sql语句
    Js apply和call
    js中的事件委托
    javascript中的事件处理
    <a>标签的属性
    js中预加载图片
    Yahoo团队:网站性能优化的35条黄金准则
    js中用到的正则表达式
  • 原文地址:https://www.cnblogs.com/panzi/p/9123137.html
Copyright © 2011-2022 走看看