**注意: 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模式发布。
- 简介
- 会员版
- 3.x和4.x的区别
- 新手必读
- 如何高效提问
- 项目地址
- 项目截图
- 架构介绍
- 开发规范
- 租户模式介绍
- lamp-web和lamp-web-plus的区别
- lamp-cloud和lamp-boot区别
- 免费视频&软件下载
- 文档反馈
- lamp-cloud
- 服务介绍
- 环境要求
- 工程导入
- nacos启动(单机版)
- nacos启动(集群版)
- 将配置文件导入Nacos
- seata启动(单机版)
- DATASOURCE模式启动(会员版)
- SCHEMA模式启动
- COLUMN模式
- NONE模式
- lamp-web启动
- lamp-web生产部署
- lamp-web-plus启动(会员版)
- lamp-web-plus生产部署
- lamp-boot
- 环境要求
- 工程导入
- DATASOURCE模式启动(会员版)
- SCHEMA模式启动
- COLUMN模式启动
- NONE模式启动
- lamp-web启动
- lamp-web生产部署
- lamp-web-plus启动(会员版)
- lamp-web-plus生产部署
- 功能介绍
- 租户设置
- 数据源配置(会员版)
- 租户管理
- 超级用户
- 工作台
- 通知公告
- 组织管理
- 机构管理
- 岗位管理
- 用户管理
- 资源中心
- 消息中心
- 短息模版
- 短信中心
- 附件管理
- 流程管理
- 流程部署
- 模型管理
- 系统设置
- 菜单管理
- 角色管理
- 字典管理
- 地区管理
- 参数管理
- 操作日志
- 登录日志
- 在线用户
- 应用管理
- 网关管理
- 限流规则
- 组织访问
- 开发者管理
- 定时任务
- 接口文档
- Nacos
- 服务监控
- 数据库监控
- 缓存监控
- zipkin监控
- SkyWalking监控
- 常用配置
- 如何保证我的代码能更新到最新代码
- 序列化和反序列化
- 修改日志级别
- 文件上传&下载&预览
- 修改租户模式
- 分页
- 导入导出
- 请求放行(忽略token&忽略URI权限&忽略租户编码)
- 异常处理
- 全局返回
- 参数校验(会员版)
- 系统日志
- 自研权限认证(URI、按钮、菜单)
- 数据权限(旧)
- 数据库配置
- Mybatis配置
- 更多数据库/数据源/Mybaits配置
- Redis(缓存)配置
- RabbitMq配置
- 灰度发布
- 上手开发
- 表结构整理
- 项目结构&依赖&调用流程介绍
- 生成一个新服务
- 生成后端代码
- 生成前端lamp-web代码
- 生成前端项目lamp-web-plus代码
- 跨域处理
- Swagger文档调试技巧
- FeignClient接口调用
- 多租户实现原理
- 分布式事务
- Zipkin配置(过时)
- SkyWalking配置
- 代码生成器和自动回显组件使用介绍
- lamp-util原理解析
- 全局注解(lamp-annotation)
- 核心包(lamp-core)
- 自动回显(lamp-echo-starter)
- 权限控制(lamp-security-starter)
- 当前登录用户信息(lamp-jwt-starter)
- 缓存(lamp-cache-starter)
- SpringBoot全局配置(lamp-boot-util)
- SpringCloud全局配置(lamp-cloud-starter)
- 数据源&持久层配置(lamp-databases)
- 对象属性复制(lamp-dozer-starter)
- 操作日志(lamp-log-starter)
- 消息队列(lamp-mq-starter)
- 在线文档(lamp-swagger2-starter)
- 前后端表单统一验证(lamp-validator-starter)
- 防止Xss攻击(lamp-xss-starter)
- 生产部署
- 部署前言
- jar部署