**注意: 4.x 目前尚无开源和个人版** 可以把3.x和4.x看成2个不同的项目,下面列出详细变化: ## 一. 项目拆分 > 项目名带 pro 或 plus 的表示企业商用版或个人学习版,不带 pro 或 plus 的表示对应的开源版 3.x 一个lamp-cloud项目,通过配置即可任意切换租户模式,3.x 的全部项目包括: - lamp-util(lamp-util-plus):工具类 - lamp-cloud(lamp-cloud-plus): spring cloud 版 后台 - lamp-boot(lamp-boot-plus):spring boot 版 后台 - lamp-web: vue2 + element-ui 版 前台 - lamp-web-plus: vue3 + ant design vue 版 前台 (仅企业版拥有) - lamp-job(lamp-job-plus): 定时任务 - lamp-generator(lamp-generator-plus): 代码生成 4.x 之后,除了 lamp-util-pro、lamp-generator-pro、lamp-job-pro 等工具类项目会共用, 其他的租户模式,业务流程可能会不一致,会视情况会独立多个项目,大家根据情况进行选择: #### 4.x 的公共项目 - lamp-util-pro (lamp-util)(已完成) - lamp-generator-pro(lamp-generator)(已完成) - lamp-job-pro(lamp-job)(已完成) ##### 4.x 的 大租户小门店模式(DATASOURCE_COLUMN) (仅企业版拥有) - lamp-cloud-pro-datasource-column (已完成) - lamp-web-pro-datasource-column(已完成) - lamp-boot-pro-datasource-column (已完成) ##### 4.x 的 字段模式(COLUMN) (已完成) - lamp-cloud-pro-column (lamp-cloud-column) - lamp-web-pro-column(lamp-web-column) - lamp-boot-pro-column(lamp-boot-column) ##### 4.x 的 普通模式(NONE) (即将发布) - lamp-cloud-pro-none (lamp-cloud-none) - lamp-web-pro-none (lamp-web-none) - lamp-boot-pro-none(lamp-boot-none) ## 二. 服务合并 为了方便新手入门、降低系统部署成本、降低系统复杂度,隧对服务做了合并。 | 3.x 拥有服务 | 4.x 拥有服务 | | --------------------- | ------------------- | | lamp-authority-server | lamp-base-server | | lamp-file-server | lamp-base-server | | lamp-msg-server | lamp-base-server | | lamp-oauth-server | lamp-oauth-server | | lamp-tenant-server | lamp-system-server | | lamp-gateway-server | lamp-gateway-server | - lamp-system-server: 对应开发运营系统的功能接口 - lamp-base-server: 对应基础平台的功能接口 - lamp-oauth-server:对应登录、菜单获取、权限获取、个人信息获取等 - lamp-gateway-server:路由、token鉴权、URI鉴权等 > 合并原因? file 和 msg 服务的业务比较单一,而且也是比较基础的功能 ------ ## 三. 数据库变化 为了方便新手入门、降低系统部署成本、降低系统复杂度,隧对租户数据库做了合并。 | 3.x 拥有数据库 | 4.x 拥有数据库 | 备注 | | ---------------------- | ----------------------- | ------------------------------ | | lamp_defaults | lamp_ds_c_defaults | 所有租户都相同的数据放在默认库 | | lamp_base_{租户编码} | lamp_ds_c_base_{租户ID} | 租户自己的数据,放在base库 | | lamp_extend_{租户编码} | lamp_ds_c_base_{租户ID} | | - datasource_column 模式库名为:lamp_ds_c_defaults、lamp_ds_c_base_{租户ID} - datasource 模式库名为:lamp_defaults、lamp_base_{租户ID} - column 模式库名为:lamp_column - none 模式库名为:lamp_none > 合并后,并不是指 不支持1个租户配置多个租户库! 通过修改配置文件可以轻松实现调整数据库。 ## 四. 租户数据的使用发生变化 3.x 除了租户的创建相关的表和数据是全局库(lamp_defaults库),所有的租户数据都在租户库(lamp_base_xxx或lamp_extend_xxx) 。 这样做的好处是方便租户拥有自己个性数据,但弊端也很明显,对于一些全局数据,每个租户都需要自己维护一份,后期发生改变,需要每个租户都一起修改全局数据。 比如: 菜单、字典等数据。 > 对于菜单的配置,应该是全局仅有一份,而且只有让系统开发方进行增删改操作。租户应该只有菜单的授权操作,即给不同的角色分配不同的菜单。 > 对于字典数据,应该是全局有一份系统内置的字典,租户拥有一些自定义字典项(字典是字典的分类,字典项是字典的明细),租户可以新增、修改或删除字典项,但不会对全局字典造成影响。租户读取字典数据时,应先查询自己是否有自己的字典,若自己没有配置个性的字典,在读取系统全局的字典。 上述的功能在3.x是不支持的,但在4.x得到了很好的解决。 ------ ## 五. 功能变化 - 菜单管理:更名为:资源维护 3.x 的菜单管理,需要每个租户都维护1份`菜单`(c_menu) 和 `资源`(c_resource),即c_menu和c_resource存放在租户库(lamp_base_xxx),**当菜单变动时,需要调整所有租户的菜单数据**。 4.x 的资源维护 将菜单、视图(可以理解为隐藏菜单)、按钮、字段、接口 统称为资源,其中前4种资源存放在 `def_resource` 表通过type字段区分,URI存放在 def_resource_api 表,且存放在全局的lamp_defaults库。 > 后面提到的`资源`都是这几种类型的一个统称,根据上下文可以是任意一种类型的资源, 甚至应用都可以理解为一种资源,因为应用是需要分配权限的,只是应用是给企业授权,资源是给企业下的员工授权。 ``` * 菜单:页面上可以点击的菜单,可以是1级、2级、n级 (有些系统会区分为目录和菜单,本系统都统称为菜单) * 视图:隐藏的菜单,在页面上看不见,但需要注册到router中。常用于详情页,复杂的编辑页等。 * 按钮:页面上的新增、删除、修改、导入、下载等按钮。 * 字段:控制页面上不同人,能看到不一样的字段。 可以控制显示、隐藏、脱敏、是否可以编辑等。(功能尚未完善) * 接口:菜单或视图调用的所有接口,员工拥有菜单或视图后,就应该拥有此菜单或视图下的所有接口权限。 ``` 好处: 资源本应该是全局的,后期新增、修改或删除 `菜单`、`uri`、`字段`、`按钮`时,只需要调整全局的资源数据,即可影响所有租户。 而资源数据是不允许租户自己配置的,所以调整到了defaults库。 - 角色管理:角色权限维护 4.x和3.x功能上没有太大的调整,但在3.x基础上增强了角色管理的逻辑: - **3.x版本每次新增一个资源,都需要给每个租户的超管绑定这个新增的资源**, 4.x 的每个租户都内置一个`租户管理员`,租户管理员默认拥有管理租户的所有权限,且他的权限是无需分配和删除的,后期系统新增资源,也无需分配权限给这个租户管理员角色。 - 给角色绑定资源时做了限制:①勾选了子资源,必定要勾选所有的父; ②取消了父资源,必定取消所有的子;③增加资源全选按钮; - 给角色绑定员工,为了优化员工过多的问题,调整为实时绑定、实时取消绑定。 - 字典管理:字典维护 + 个性字典 3.x 的字典管理,需要每个租户都维护1份字典数据, 即c_dictionary存放在租户库(lamp_base_xxx),所有租户都需要维护整个系统所需要的全部字典, **当字典变动时,需要调整所有租户的字典数据。** 4.x 分为`字典维护`和`个性字典`,字典维护 维护的是全局的字典,个性字典维护每个租户自己的字典项,租户可以新增、修改或删除字典项,但不会对全局字典造成影响。租户读取字典数据时,应先查询自己是否有自己的字典,若自己没有配置个性的字典,在读取系统全局的字典。 - 参数管理:参数维护 + 个性参数 同 字典维护 + 个性字典 - 地区管理:地区维护 增加了导出地区json文件的功能,地址数据调整后,重新生成json文件,供前端使用。前端选择级联地区数据时,直接读取json文件内容,加快响应速度。 - 应用管理:客户端维护 维护你们系统的客户端,比如:小程序端、安卓端、IOS端、WEB端等,然后将client_id和client_secret分配给对应的客户端,接口请求时后台接口时,携带client_id和client_secret, 方便日后做统计或其他限制。 - 登录日志:登录日志 + 登录日志 在基础平台的登录日志是租户自己的登录日志,在开发运营系统查看的登录日志是**所有租户**的登录日志。 ------ ## 六. 新增功能 - 租户体系 在3.x的基础上,4.x 优化了以下功能: 1. 租户在线创建 2. 在线初始化各个微服务数据源 3. 在线初始化各个租户的数据库建表脚本和初始数据 4. 每个租户的数据源失败重连 5. 数据源链接情况查看 6. 租户拥有的应用授权、续期、查看 7. 租户拥有的租户管理员绑定、解绑、查看 - 应用体系 ​ 平台级的SAAS系统,往往拥有多个`自建应用`或`第三方应用`,在`应用管理` ->`应用维护` 中创建好`自建应用`,配置好应用的资源,然后给企业授予相应的应用权限后, 用户即可切换到对应的应用,并使用应用下的功能。 对于`第三方应用` 经过简单的单点登录对接,即可实现单点登录。 ​ 同时,给企业授权应用时,还支持给不同的企业授权不同的资源,即对于同一个应用,不同的租户可以拥有不同的功能(菜单)。 - 用户体系 ​ 3.x 系统中,一个用户,若同时属于多个租户,必须创建多个账号。 ​ 4.x 用户体系,使用身份证(或其他唯一标识)作为用户的唯一标识,当你属于多个租户时,用户在登录系统后,可以切换自己的身份,即可操作不同租户的数据。而每个租户通过员工表和全局用户表做好映射。 - 员工体系 - 每个员工可以有多个部门,并设置主部门 - 可以给部门分配一个部门的角色,部门下的员工拥有部门角色的权限 - 可以给员工分配角色 - 也可以在角色界面绑定员工 ## 七. 分层 3.x 应用分层采用 Controller -> Service -> Mapper ,领域模型采用DTO、Entity。 > 3.x 的分层是最简单,最易于理解的分层,但随着不断的出现复杂的业务,所有逻辑都放在Service层已经不在合适,故而对其改造。但3.x和4.x的分层,并没有绝对的谁好谁坏,对于业务极其简单,只为快速交付的项目,3.x的分层更加便捷;而4.x的分层更适合于长期迭代、业务复杂、对接第三方的系统。 4.x 应用分层采用 Controller -> Biz -> Service -> Manager -> Mapper ,领域模式采用VO、DTO、Query、Entity等。 1. 应用分层 (借鉴阿里规范,调整成适合本项目的分层模型) 图中默认上层依赖于下层,箭头关系表示可直接依赖,如:开放接口层可以依赖于 Controller 层,也可以直接依赖于 Biz、Service 层,依此类推。 ![](https://img.kancloud.cn/c1/f6/c1f661a6fbb42014d4ba805ef1205efa_381x531.png) - 开放接口层:开放给其他第三方调用的接口,可直接封装Service方法暴露成PRC接口;通过Web封装成HTTP接口等 - 终端显示层:各个端的默认渲染层。如:模板引擎渲染、移动端展示、Vue展示等 - 请求处理层(Controller):主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等 。 - 分布式事务业务逻辑层(Biz)**(可选)**:具于分布式事务、跨库操作(查询和写入)的业务逻辑服务层。若业务无分布式事务或跨库操作Controller可以直接调用Service层,Biz层一定不能加`Transactional`注解,否则动态数据源跨库操作将会时效。 - 业务逻辑层(Service):相对具体的业务逻辑服务层,只保证单个数据源本地事务。对多个Manager的组合复用。 - 通用处理层(Manager):通用业务处理层, 它有如下特征: 1) 对 Service 层通用能力的下沉,如缓存方案、中间件通用处理。 2) 与 DAO 层交互,对多个 DAO 的组合复用。 3) 继承Mybatis-plus的ServiceImpl接口,封装了单表的业务操作。 - 数据持久层(Mapper/Dao):数据访问层,与底层 MySQL、Oracle、Hbase、OB 等进行数据交互。 - 缓存或第三方接口:包括其它部门 RPC 开放接口,基础平台,其它公司的 HTTP 接口。 > 1. biz的方法都是跨数据源或跨服务的且需要保证事务的;service的save方法更加贴切实际业务,可操作多个表,并组合逻辑;manager 的save方法只负责单个表的保存操作(可以对字段进行一些默认值设置), mapper 的insert 方法只负责原封不动的插入数据库。 > 2. 调用只能从上往下,不能反着调用,最好也不要平层调用,严禁平层交叉调用。 2. 领域模型 - Entity: 跟数据库表一一对应 - DTO:数据传输对象,Service或Manager 使用的对象 - Query:数据查询对象,各层接收上层的查询请求。建议超过3个参数的查询进行封装。 - VO:显示层对象,Controller层接收和返回参数。 ## 八、请求头 3.x 版本,系统每次请求携带的请求头为: - Authorization: Basic {Base64加密的客户端id和密码} - tenant: {Base64加密的租户编码} - token: Bearer {JWT 生成的token} 4.x 版本,系统每次请求携带的请求头为: - Authorization: {Base64加密的客户端id和密码} - TenantId: {雪花算法生成的租户ID} - Token: {JWT 生成的token} - ApplicationId: {雪花算法生成的应用ID} 区别: 1. Authorization的值去除了Basic前缀。 2. tenant(加密租户编码)变更为TenantId(雪花租户ID)。 3. token变更为Token,并将值除去了Bearer前缀。 4. 新增了ApplicationId(雪花应用ID),用于记录请求来自那个应用。 调整理由: 方便新手入门成本、降低出错率、降低系统复杂度。Base64加密无加密意义,还徒增项目的复杂度。 > 有朋友可能觉得不加密不安全,可以自行思考如何进行安全的加密传输。 > > 1. 可以使用 https 协议 > 2. 请求头明文参数不安全,普通的参数明文传输就安全了吗?请求头要加密,普通参数也要想办法加密。 > 3. 3.x版本使用Base64加密请求头基本无意义,因为直接Base64解密即可。 ## 九、权限配置、分配和鉴权 名词解释: 1. 配置:通过系统的数据库或UI,为需要**鉴权**的配置全局唯一的**资源编码[^1]**。 2. 分配:先给角色绑定**资源[^2]**,在将角色分配给用户[^3](或给用户绑定角色) 3. 鉴权:鉴定用户是否拥有访问某些**资源**的权限 [^1]: 资源编码:确定资源的唯一编码,全系统不能重复 [^2]: 资源:3.x 的菜单表(c_menu) + 资源表(c_resource) = 4.x的资源表(def_resource) + 资源接口表(def_resource_api),4.x的资源包括:菜单、视图(隐藏的菜单)、按钮、URI(API)、字段等,你要你想通过权限来控制不同的人看到或访问不同的东西,它都可以称作资源。(注意区分通过业务状态控制显示/隐藏和通过权限控制显示/隐藏的区别!) [^3]: 用户:3.x没有用户和员工的概念;4.x一个用户可以属于多企业,在不同的企业拥有不同的员工身份。 | 异同点 | 3.x | 4.x | | ------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | | 在那配置资源? | 系统管理 -> 菜单管理 | 开发运营系统 -> 应用管理 -> 资源维护 | | 在那分配权限? | 系统管理 -> 角色管理 | 1. 基础平台 -> 系统功能 -> 角色权限维护<br/>2. 用户中心 -> 员工维护 | | URI权限在那鉴权? | 后端服务AOP拦截鉴权 | 网关统一拦截URI请求鉴权 | | 按钮权限在那鉴权? | 自定义指令 | 自定义指令 或 filter方式 | | 菜单权限在那鉴权? | 后端控制菜单数据! | 后端控制菜单数据! | | 字段权限在那鉴权? | 不支持 | 自定义指令 或 filter方式 | | 表结构 | c_menu + c_resource | def_resource + def_resource_api | | 表所在数据库 | 租户库 (lamp_base_{租户编码}) | 默认库(lamp_defaults) | | 缺点 | 1. 每个租户都需要维护一份相同的资源数据,且不能让租户自己修改。<br/> 2. 每次调整资源数据,需要更新所有的租户库。 | 需要跨库查询。 | | 优点 | 查询方便 | 资源表全局唯一,仅由开发者维护,不易出错。 | ## 十、分布式事务 3.x 没有主动在业务上使用分布式事务,二次开发时可以根据你们自身需求来决定是否使用seata。 4.x 的业务发生了巨大的变化,为了使得流程更加贴合实际,所以DATASOURCE、DATASOURCE_COLUMN模式必须使用seata!介意使用分布式事务的可以根据情况等待COLUMN模式发布。