【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,转载请注明出处:http://www.javaforall.cn/234896.html原文链接:http://www.javaforall.cn

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

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

(0)
blank

相关推荐

  • AD域介绍

    AD域介绍域的背景介绍为什么要使用域?假设你是公司的系统管理员,你们公司有一千台电脑。如果你要为每台电脑设置登录帐户,设置权限(比如是否允许登录帐户安装软件),那你要分别坐在这一千台电脑前工作。如果你要做一些改变,你也要分别在这一千台电脑上修改。相信没有哪个管理员想要用这种不吃不喝不睡觉的方式来工作,所以就应运而生了域的概念。域(Domain):概念域模型就是针对大型网络的管理需求而设计的,域就是共享用户账号,计算机账号和安全策略的计算机集合。域的管理优点因为所有的用户信息都被集中存储,所以,域提供了集

  • sql语法:inner join on, left join on, right join on具体用法

    sql语法:inner join on, left join on, right join on具体用法

    2021年12月15日
  • vue环境安装与配置(Linux安装常用开发工具)

    vue安装环境搭建提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录vue安装环境搭建前言一、node.js安装和配置1.下载安装node.js2.配置默认安装目录和缓存日志目录3.node.js环境配置4.配置淘宝镜像源二、使用步骤1.引入库2.读入数据总结前言vue前端框架的环境搭建一、node.js安装和配置1.下载安装node.js官网下载最新版本:https://nodejs.org/en/download/可以下载安装包(安装教程见:http

  • sqlserver截断字符和二进制数据_SQL异常字符串截断

    sqlserver截断字符和二进制数据_SQL异常字符串截断错误信息提示:  Java代码  Error! [8152]System.Data.SqlClient.SqlException: 将截断字符串或二进制数据。语句已终止。   原因:增加的数据类型与数据库中字段所定义的不符。 解决方法:1、修改数据库字段大小;2、加强数据强壮性,严格的输入判断。 防止添加的信息类型或者长度与数据库表中字段所对应的类型不符合。…

  • latex的参考文献写法标准_endnote怎么修改参考文献编号格式

    latex的参考文献写法标准_endnote怎么修改参考文献编号格式LaTeX参考文献的排版与引用​ 在论文写作的过程中,为了体现论文的科学性、严谨性和规范性,我们常常需要引用大量的参考文献来引证自己的观点。参考文献(Reference)往往都是放在论文的最后,记录了所引用论文的标题、作者、期刊或会议、出版时间等信息,文中还需要明确有顺序的进行引用标注。​ 本篇将介绍LaTeX常用的参考文献排版与引用方式,所用到的宏包都要写在\documentclass命令之后和\begin{docuemnt}之前,在本文中,我们会用的宏包文件有:\usepackag

  • wireshark过滤规则及使用方法

    wireshark过滤规则及使用方法Wireshark基本语法,基本使用方法,及包过滤规则:1.过滤IP,如来源IP或者目标IP等于某个IP例子:ip.src eq 192.168.1.107 or ip.dst eq 192.168.1.107或者ip.addr eq 192.168.1.107 // 都能显示来源IP和目标IPLinux上运行的wireshark图形窗口截图示例,

发表回复

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

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