【WTM-多租户改造】「建议收藏」

【WTM-多租户改造】「建议收藏」WTM-多租户改造

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

嗨。第一次写文章,给了WTM,先简单介绍下WTM吧。

WTM框架地址 https://wtmdoc.walkingtec.cn

支持4个版本:Layui  React  Vue  Blazor

WtmPlus是建立在WTM开源框架基础上的低代码开发平台,他提供了可视化的模型和页面编辑,更加复杂和智能的代码生成,可使开发效率提升50%以上。

感兴趣可以看一下  地址  WtmPlus

【WTM-多租户改造】「建议收藏」​​ 

第一次写,写的不太好,大家见谅哈。

19年就开始接触WTM框架了,刚开始没有仔细了解。20年开始买亮哥的课程,开始看视频看文档慢慢的对WTM layui版本逐渐熟悉。也不知道说什么好,WTM牛逼,亮哥牛逼。

框架真的很好,希望大家可以一直支持WTM。

简单说下多租户的实现方式

多租户(Multi-Tenant ),即多个租户共用一个实例,租户的数据既有隔离又有共享,说到底是要解决数据存储的问题。

常用的数据存储方式有三种。

方案一:独立数据库

一个Tenant,一个Database的数据存储方式。隔离级别最高、最安全,但成本也高。

优点:

a.为不同租户提供独立数据库,有助于简化数据模型的扩展设计,满足个性化需求;

b.数据恢复简单;

缺点:增大了数据库的安装数量,购置和维护成本高;

方案二:共享数据库,隔离数据架构

多个租户或所有租户共享Database,但一个Tenant,一个Schema的方式。

优点:

a.一定程度的逻辑数据隔离(并非完全),可满足较高程度的安全性保障;

b.每个数据库,可支持更多租户数量;

缺点:

a.恢复数据较困难,因为将牵扯到其他租户数据;

b.跨租户统计数据,实现难度大;

方案三:共享数据库,共享数据架构

一种租户共享同一个Database、同一个Schema,而另行通过TenantID区分租户数据的方式。

优点:

a.每个数据库可支持租户数量多,维护和购置成本低;

缺点:

a. 隔离级别低,安全性低,开发时需做大量安全开发工作;

b. 逐表逐条备份和还原数据,数据备份和恢复困难。

今天主要讲的就是用WTM 改造简易的多租户,我这里用的是Layui版本,其他UI也可以用这种方式实现,我还没有试过,大家有空可以自己试一试。我用的是方案一 独立数据库方式。技术有限,只是希望在这里可以给大家提供一个思路。

开始说下整体步骤

咱们先来创建一个租户表,我这里简单创建几个字段,为了演示,大家根据实际需要自己调整。我这里为了演示方便租户角色直接用系统自带的角色表了,大家自己可以增加一个租户角色表。

public class Tenant : BasePoco
    {
        [Display(Name = "编号")]
        [Required(ErrorMessage = "{0}是必填项")]
        public string Code { get; set; }

        [Display(Name = "域名")]
        [Required(ErrorMessage = "{0}是必填项")]
        public string DomainName { get; set; }

        [Display(Name = "租户角色")]
        [Required(ErrorMessage = "{0}是必填项")]
        public Guid RoleId { get; set; }
        [Display(Name = "租户角色")]
        public FrameworkRole Role { get; set; }

        [Display(Name = "账号")]
        [Required(ErrorMessage = "{0}是必填项")]
        public string Account { get; set; }

        [Display(Name = "名称")]
        [Required(ErrorMessage = "{0}是必填项")]
        public string Name { get; set; }
    }

Jetbrains全家桶1年46,售后保障稳定

【WTM-多租户改造】「建议收藏」​​ 

添加完租户信息后,Create方法里需要创建好 这个租户的库、基本信息和提供的域名。我这里租户的库生成规则直接就是默认用主库名+编号生成的。

        [HttpPost]
        [ActionDescription("Sys.Create")]
        public ActionResult Create(TenantVM vm)
        {
            using (var trans = DC.BeginTransaction())
            {
                if (!ModelState.IsValid)
                {
                    return PartialView(vm);
                }
                else
                {
                    vm.DoAdd();
                    if (!ModelState.IsValid)
                    {
                        vm.DoReInit();
                        return PartialView(vm);
                    }
                    else
                    {
                        //我这代码直接写这了 生成租户库和基本信息 随便写了下简单的系统表数据
                        var NDC = new DataContext(Wtm.ConfigInfo.Connections[0].Value.Replace("SAASDEMODB", "SAASDEMODB" + vm.Entity.Code), DBTypeEnum.SqlServer);
                        var Result = NDC.Database.EnsureCreated();

                        if (Result)
                        {
                            var role = DC.Set<FrameworkRole>().Where(x => x.ID == vm.Entity.RoleId).FirstOrDefault();
                            //角色拥有的菜单权限
                            var pr = DC.Set<FunctionPrivilege>().Where(x => x.RoleCode == role.RoleCode).ToList();
                            var user = new FrameworkUser
                            {
                                ITCode = vm.Entity.Account,
                                Password = Utils.GetMD5String("000000"),
                                IsValid = true,
                                Name = vm.Entity.Name
                            };

                            var userrole = new FrameworkUserRole
                            {
                                UserCode = vm.Entity.Account,
                                RoleCode = role.RoleCode
                            };


                            NDC.Set<FrameworkUser>().Add(user);
                            NDC.Set<FrameworkRole>().Add(role);
                            NDC.Set<FrameworkUserRole>().Add(userrole);
                            //这里框架自带角色表  页面权限FunctionPrivilege表没有加父级菜单数据 会导致约束冲突。后期自己添加租户角色表吧
                            NDC.Set<FrameworkMenu>().AddRange(DC.Set<FrameworkMenu>().CheckContain(pr.Select(x => x.MenuItemId).ToList(), x => x.ID).ToList());
                            NDC.Set<FunctionPrivilege>().AddRange(pr);
                            NDC.SaveChanges();

                            //云解析DNS-添加解析记录
                            if (!new CommonHelp().DomainNameResolution(vm.Entity.Code))
                            {
                                trans.Rollback();
                                return FFResult().CloseDialog().RefreshGrid().Alert("域名解析失败!");
                            }
                        }
                        else
                        {
                            trans.Rollback();
                            return FFResult().CloseDialog().RefreshGrid().Alert("租户信息初始化失败!");
                        }
                        trans.Commit();
                        return FFResult().CloseDialog().RefreshGrid();
                    }
                }
            }
        }

主要用到了一个云解析DNS-添加解析记录的方法。调用AddDomainRecord根据传入参数添加解析记录。

云解析 DNS(Domain Name System,简称DNS) 是一种安全、快速、稳定、可靠的权威DNS解析管理服务。 它能够帮助企业和开发者将易于管理识别的域名转换为计算机用于互连通信的数字IP地址,从而将用户的访问路由到相应的网站或应用服务器。

具体看文档 添加解析记录 (aliyun.com)

        #region 云解析DNS-添加解析记录  可以去阿里云地址看文档 https://help.aliyun.com/document_detail/29772.html  但是这种方式服务器要求 80端口只允许部署这一套系统,因为现在这种方式是域名直接指向服务器IP
        public bool DomainNameResolution(string Name)
        {
            IClientProfile profile = DefaultProfile.GetProfile("cn-hangzhou", "", "");//域名 AccessKeyID Secret
            DefaultAcsClient client = new DefaultAcsClient(profile);

            var request = new AddDomainRecordRequest();
            request._Value = "";  //指向服务器IP
            request.Type = "A";
            request.RR = Name;  //随便定义   
            request.DomainName = "xxx.com";  //域名
            try
            {
                var response = client.GetAcsResponse(request);
                return true;
                //Console.WriteLine(System.Text.Encoding.Default.GetString(response.HttpResponse.Content));
            }
            catch (ServerException e)
            {
                return false;
            }
            catch (ClientException e)
            {
                return false;
            }
        }
        #endregion

这种方式不好的一点是 服务器要求 80端口只允许部署这一套系统,因为现在这种方式是域名直接指向服务器IP。我是部署在IIS上,需要注意的一点是应用中不要绑定主机名。(如果大家有更好的办法可以一起沟通沟通【WTM-多租户改造】「建议收藏」​​) 

【WTM-多租户改造】「建议收藏」​​

到这里创建的这个租户的库和基本信息和域名就创建好了。

这个时候所有域名都可以访问到部署的系统了,但是appsettings.json文件中Connections只有一个默认的库,当然不可能添加一个租户就在这加一个连接字符串,不现实。

正好框架支持动态选择连接字符串。框架可以根据页面传递过来的数据,或者session里的信息等动态选择需要连接的数据库,只需编辑Startup文件中的CSSelector方法。

访问系统肯定会先读主库,我这里是根据域名去租户表里查,如果存在就动态添加一个ConnectionStrings,利用Wtm.Session.Set(“TenantKey”, CS.key);,否则就正常访问主库。

        #region 获取当前url
        public string GetAbsoluteUri(HttpRequest request)
        {
            return new StringBuilder()
                .Append(request.Scheme)
                .Append("://")
                .Append(request.Host)
                .Append(request.PathBase)
                .Append(request.Path)
                .Append(request.QueryString)
                .ToString();
        }
        #endregion

        [Public]
        [ActionDescription("Login")]
        public IActionResult Login()
        {
            LoginVM vm = Wtm.CreateVM<LoginVM>();
            string TenantKey = "default";
            string displayUrl = GetAbsoluteUri(HttpContext.Request);
            displayUrl = displayUrl.Replace("http://", "").Replace("https://", "") + "/";
            displayUrl = displayUrl.Substring(0, displayUrl.IndexOf("/"));
            var ZDC = new DataContext(Wtm.ConfigInfo.Connections[0].Value, DBTypeEnum.SqlServer);
            var Tenant = ZDC.Set<Tenant>().Where(x => x.DomainName.Replace("http://", "").Replace("https://", "") == displayUrl).FirstOrDefault();
            if (Tenant != null)
            {
                TenantKey = "SAASDEMODB" + Tenant.Code;
                Wtm.Session.Set("TenantKey", "SAASDEMODB" + Tenant.Code);
            }
            else
            {
                Wtm.Session.Set("TenantKey", TenantKey);
            }
            int i = 0;
            foreach (var item in Wtm.ConfigInfo.Connections)
            {
                if (item.Key == TenantKey)
                {
                    i++;
                    break;
                }
            }
            if (i == 0)
            {
                CS cs = new CS();
                cs.DbContext = "DataContext";
                cs.DbType = DBTypeEnum.SqlServer;
                cs.Key = TenantKey;
                cs.Value = Wtm.ConfigInfo.Connections[0].Value.Replace("SAASDEMODB", cs.Key);
                cs.DcConstructor = Wtm.ConfigInfo.Connections[0].DcConstructor;
                Wtm.ConfigInfo.Connections.Add(cs);
            }
            vm.Redirect = HttpContext.Request.Query["ReturnUrl"];
            if (Wtm.ConfigInfo.IsQuickDebug == true)
            {
                vm.ITCode = "admin";
                vm.Password = "000000";
            }
            return View(vm);
        }

Startup文件中的CSSelector方法

        public string CSSelector(ActionExecutingContext context)
        {
            var wtm = (context.Controller as IBaseController)?.Wtm;
            var TenantKey = wtm.Session.Get<string>("TenantKey");
            return TenantKey;
        }

OK,咱们来测试一下下。

我这里就用默认超级管理员角色创建租户了,为了添加一个租户让大家看下效果。

【WTM-多租户改造】「建议收藏」

添加成功,访问一下租户的地址

【WTM-多租户改造】「建议收藏」

添加一条新的角色数据,跟主库作下比较,发下数据已经隔离了。

【WTM-多租户改造】「建议收藏」

如果你跟着测试到这一步,说明已经通了,可以自己多试试。有问题或者有好的想法,可以在群里一起沟通学习学习。

有些可能需要用到数据共享,框架本身支持在控制器中设置[FixConnection(DBOperationEnum.Default, CsName = “”)]设置Cs指定连接字符串。

项目我已经上传到Gitee上了,大家可以下载看一下。

地址:wtm-layui版本多租户: wtm框架 layui版本都租户改造

下载完项目,如果想直接运行调试的话,记得去Common文件下的CommonHelp类中把DomainNameResolution方法中的参数补充全,就可以直接运行看效果了。

目前这种方式有正式的项目,目前也比较稳定。第一次写文章,希望大家多支持哈。

有什么问题想法,大家在WTM群里沟通哈。谢谢,最后也感谢亮哥、感谢WTM哈,感谢有这么好的框架。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/234896.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 面试题:MySQL的union all和union有什么区别、MySQL有哪几种join方式(阿里面试题)[通俗易懂]

    面试题:MySQL的union all和union有什么区别、MySQL有哪几种join方式(阿里面试题)[通俗易懂]面试题:MySQL的union all和union有什么区别、MySQL有哪几种join方式(阿里面试题)————————————————————————————————————————————————-…

  • java 简单分页原理

    java 简单分页原理java 简单分页原理

  • matlab填充图形_不同图案填充条形图

    matlab填充图形_不同图案填充条形图1、下载填充函数:applyhatch.  2、有四种选择:applyhatch,applyhatchplus, applyhatch_plusC , 和 HatchfillpatternsplusColor&Invert,个人感觉后两种更好一些。3、下载以后,放在自己存放m文件的地方,就可以在其他m文件中调用applyhatch***函数了。文件注释里都有

    2022年10月18日
  • 三、设计模式介绍—她是谁,我们要去哪里? #和设计模式一起旅行#

    模式模式(Pattern),指事物的标准样式,百度百科上面说的,其实说白了模式就是我们现在说的套路!模式 == 套路模式是一种思想,说大了特别的复杂和深奥,不管怎么样模式的使用可以解决特定场景下特定的问题!准确表达:模式是在特定环境下人们解决某类重复出现问题的一套成功或有效的解决方案。软件模式那么在软件中使用模式,就是软件模式(Software Pattern),用…

  • 理查德费曼学习法「建议收藏」

    理查德费曼学习法「建议收藏」其实大部分人的智力水平相差不大,但是学习力却大相径庭,造成这样差异的更多地是我们的学习方法、学习习惯等可控因素。那么,什么是费曼学习法呢?费曼学习法可以简化为四个单词:Concept(概念)、Teach(教给别人)、Review(回顾)、Simplify(简化)。什么是费曼学习法怎么用费曼学习法1)费曼学习法是什么意思简单来说就是用更少的时间学习更多的知识。费曼以能够快速吸收信息,并且在更短时间内掌握知识闻名,在高中最后一年就拿了纽约大学数学锦标赛冠军,而且后来在普林斯顿大学的数学

  • SQL datetime和smalldatetime区别

    SQL datetime和smalldatetime区别datetime存储大小8个字节,精确到分后的3为小数,日期范围从1753年1月1日到9999年12月31日;而smalldatetime存储大小为4个字节,精确到分,日期范围从1900年1月1日到2079年6月6日。参考http://msdn.microsoft.com/zh-cn/library/ms187819%28v=…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号