Orange Form 后端架构解析:Mybatis-Flex 与 Mybatis-Plus
本文深入解析Orange Form的后端架构设计,重点对比Mybatis-Flex和Mybatis-Plus两大ORM框架的特性与适用场景。文章将从模块化设计、核心服务实现、数据权限控制到多数据源配置等维度展开,揭示如何通过技术选型与架构设计实现高内聚、低耦合的企业级应用。
后端模块化设计与核心服务
Orange Form 的后端架构采用了模块化设计,通过将功能拆分为独立的模块,实现了高内聚、低耦合的系统架构。这种设计不仅提升了代码的可维护性,还便于团队协作和功能扩展。以下将详细介绍后端模块化设计的核心思想及其实现。
模块化设计概述
后端模块化设计基于 Spring Boot 和 Maven 的多模块架构,每个模块负责特定的功能领域。例如:
- common-core:提供基础工具类和通用功能。
- common-ext:扩展功能模块,如业务组件和自定义工具。
- common-minio:集成 MinIO 存储服务。
- common-datafilter:实现数据过滤和权限控制。
- common-flow-online:在线流程引擎的核心逻辑。
核心服务解析
1. 数据过滤与权限控制
通过 DataFilterInterceptor 和 MybatisDataFilterInterceptor 实现动态数据过滤,支持多租户和数据权限控制。例如:
public class MybatisDataFilterInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) {
// 动态注入数据过滤条件
}
}
2. 文件存储服务
MinioTemplate 封装了 MinIO 的常用操作,支持文件上传、下载和管理:
public class MinioTemplate {
public void putObject(String bucketName, String objectName, InputStream stream) {
// 文件上传逻辑
}
}
3. 流程引擎服务
FlowOnlineOperationService 提供了流程的启动、任务处理等功能:
public class FlowOnlineOperationServiceImpl implements FlowOnlineOperationService {
@Transactional
public void saveNewAndStartProcess(String processDefinitionId, FlowTaskComment comment, JSONObject data) {
// 流程启动逻辑
}
}
模块依赖关系
| 模块名称 | 主要功能 | 依赖模块 |
|---|---|---|
| common-core | 基础工具和通用功能 | 无 |
| common-ext | 扩展业务组件 | common-core |
| common-minio | 文件存储服务 | common-core |
| common-datafilter | 数据过滤和权限控制 | common-core |
| common-flow-online | 在线流程引擎 | common-core, common-ext |
总结
通过模块化设计和核心服务的拆分,Orange Form 的后端架构实现了功能解耦和高效协作。每个模块专注于特定领域,通过清晰的依赖关系确保系统的可扩展性和可维护性。
Mybatis-Flex 与 Mybatis-Plus 对比与选择
在 Orange Form 的后端架构中,Mybatis-Flex 和 Mybatis-Plus 是两个核心的 ORM 框架选择。它们各自有不同的设计理念和适用场景,本节将从功能、性能、灵活性等方面进行对比,帮助开发者根据实际需求做出合理选择。
功能对比
| 特性 | Mybatis-Flex | Mybatis-Plus |
|---|---|---|
| 动态 SQL | 支持动态 SQL 生成,语法简洁 | 提供丰富的动态 SQL 功能 |
| 多数据源 | 内置多数据源支持,配置简单 | 需额外配置多数据源插件 |
| 分页插件 | 内置高性能分页插件 | 提供分页插件,但性能稍逊 |
| 代码生成器 | 支持代码生成,但功能较基础 | 提供强大的代码生成器 |
| 注解支持 | 注解丰富,支持复杂映射 | 注解功能全面,但部分场景需 XML 辅助 |
性能对比
Mybatis-Flex 在性能优化方面表现突出,尤其是在复杂查询和大数据量场景下。以下是一个简单的性能测试对比:
// Mybatis-Flex 查询示例
List<User> users = userMapper.selectListByQuery(
Query.create().where(User::getAge).gt(18)
);
// Mybatis-Plus 查询示例
List<User> users = userMapper.selectList(
Wrappers.<User>lambdaQuery().gt(User::getAge, 18)
);
从代码示例可以看出,Mybatis-Flex 的查询语法更加简洁,且在高并发场景下性能更优。
灵活性对比
Mybatis-Flex 的设计更注重灵活性,支持动态表名、动态字段等高级功能。例如:
// 动态表名示例
String dynamicTableName = "user_" + tenantId;
List<User> users = userMapper.selectListByQuery(
Query.create().from(dynamicTableName)
);
而 Mybatis-Plus 则更注重易用性,适合快速开发。
选择建议
-
选择 Mybatis-Flex 的场景:
- 需要高性能的复杂查询。
- 项目涉及多数据源或动态表名。
- 对代码简洁性有较高要求。
-
选择 Mybatis-Plus 的场景:
- 快速开发,需要丰富的代码生成工具。
- 项目规模较小,对性能要求不高。
- 团队熟悉 Mybatis-Plus 生态。
示例流程图
以下是一个选择框架的决策流程图:
通过以上对比,开发者可以根据项目需求和团队技术栈,选择最适合的 ORM 框架。
数据权限与用户权限实现
在 Orange Form 的后端架构中,数据权限与用户权限的实现是确保系统安全性和数据隔离的核心功能。通过 Mybatis-Flex 和 Mybatis-Plus 提供的灵活扩展能力,项目实现了多层次的数据过滤和权限控制机制。以下将详细介绍其实现细节。
数据权限的实现
数据权限的核心是通过动态 SQL 拦截器对查询语句进行拦截和改写,从而实现数据的动态过滤。Orange Form 中通过 MybatisDataFilterInterceptor 类实现这一功能。
关键类解析
-
MybatisDataFilterInterceptor
- 该类是 Mybatis 的拦截器,负责在 SQL 执行前动态注入数据权限条件。
- 主要方法:
intercept:拦截 SQL 执行,注入数据权限条件。loadInfoWithDataFilter:加载数据权限配置信息。
public class MybatisDataFilterInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { // 动态注入数据权限条件 return invocation.proceed(); } } -
DataFilterProperties
- 用于配置数据权限的全局属性,如是否启用数据权限、默认过滤字段等。
public class DataFilterProperties { private boolean enabled = true; private String defaultFilterField = "tenant_id"; } -
DataFilterWebMvcConfigurer
- 通过 Spring MVC 的拦截器机制,确保数据权限在请求处理前后生效。
public class DataFilterWebMvcConfigurer implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new DataFilterInterceptor()); } }
数据权限流程图
用户权限的实现
用户权限的实现依赖于 Spring Security 和自定义注解,确保只有具备特定权限的用户才能访问某些资源。
关键类解析
-
DisableDataFilterAspect
- 通过 AOP 切面,实现对特定方法或类禁用数据权限的功能。
@Aspect @Component public class DisableDataFilterAspect { @Around("disableDataFilterPointCut()") public Object around(ProceedingJoinPoint point) throws Throwable { // 禁用数据权限逻辑 return point.proceed(); } } -
LoadDataFilterInfoListener
- 在应用启动时加载数据权限配置信息。
public class LoadDataFilterInfoListener implements ApplicationListener<ApplicationReadyEvent> { @Override public void onApplicationEvent(ApplicationReadyEvent event) { // 加载数据权限配置 } }
用户权限流程图
数据权限与用户权限的结合
通过将数据权限和用户权限结合,Orange Form 实现了细粒度的权限控制。例如,管理员可以查看所有租户的数据,而普通用户只能查看自己租户的数据。
示例代码
@RestController
@RequestMapping("/api/data")
public class DataController {
@GetMapping
@DisableDataFilter
public List<Data> getAllData() {
// 禁用数据权限,返回所有数据
return dataService.getAllData();
}
@GetMapping("/filtered")
public List<Data> getFilteredData() {
// 启用数据权限,返回过滤后的数据
return dataService.getFilteredData();
}
}
权限控制表
| 角色 | 数据权限范围 | 用户权限范围 |
|---|---|---|
| 超级管理员 | 所有租户数据 | 所有功能 |
| 租户管理员 | 当前租户数据 | 租户内功能 |
| 普通用户 | 当前用户创建的数据 | 部分功能 |
通过以上机制,Orange Form 实现了灵活、高效的数据权限与用户权限控制,为多租户场景下的数据安全提供了保障。
多数据源配置与动态切换
在现代企业级应用中,多数据源的需求日益普遍,尤其是在微服务架构中,不同业务模块可能需要访问不同的数据库。Orange Form 后端架构通过 Mybatis-Flex 和 Mybatis-Plus 提供了灵活的多数据源配置与动态切换能力。本节将深入探讨其实现机制,并通过代码示例和流程图展示其核心逻辑。
多数据源配置
Orange Form 通过 DataSourceUtil 类统一管理数据源的创建、销毁和连接获取。以下是关键配置步骤:
-
数据源定义
在application.yml或application.properties中定义多个数据源的连接信息,例如:spring: datasource: primary: url: jdbc:mysql://localhost:3306/primary_db username: root password: root secondary: url: jdbc:mysql://localhost:3306/secondary_db username: root password: root -
数据源提供者
通过DataSourceProvider接口实现不同数据库类型的数据源配置。例如,MySqlProvider负责 MySQL 数据源的配置:public class MySqlProvider implements DataSourceProvider { @Override public JdbcConfig getJdbcConfig(String configuration) { // 解析配置并返回 JdbcConfig } } -
数据源初始化
使用DataSourceUtil动态创建数据源并缓存:public DataSource getDataSource(Long dblinkId) { // 根据 dblinkId 获取数据源配置并初始化 }
动态切换数据源
动态切换数据源的核心在于通过 AOP 和线程上下文实现。以下是关键实现点:
-
注解驱动
使用@MyDataSource注解标记需要切换数据源的方法或类:@MyDataSource(ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE) public class FlowOnlineOperationServiceImpl { // 业务逻辑 } -
上下文管理
通过DataSourceContextHolder保存当前线程的数据源类型:public class DataSourceContextHolder { private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); public static void setDataSourceType(String dataSourceType) { contextHolder.set(dataSourceType); } } -
AOP 拦截
在切面中根据注解动态切换数据源:@Aspect @Component public class DataSourceAspect { @Before("@annotation(myDataSource)") public void before(MyDataSource myDataSource) { DataSourceContextHolder.setDataSourceType(myDataSource.value()); } }
流程图展示
以下是一个动态切换数据源的流程图:
代码示例
以下是一个完整的动态切换数据源示例:
@Service
public class BusinessService {
@MyDataSource("secondary")
public List<User> getUsers() {
// 使用 secondary 数据源查询
return userMapper.selectList(null);
}
}
表格总结
| 组件 | 功能描述 |
|---|---|
DataSourceUtil | 管理数据源的生命周期,提供动态创建和销毁能力。 |
DataSourceProvider | 定义不同数据库类型的配置解析逻辑。 |
@MyDataSource | 注解标记需要切换数据源的方法或类。 |
DataSourceAspect | 通过 AOP 拦截注解并动态切换数据源。 |
DataSourceContextHolder | 线程上下文管理当前数据源类型。 |
总结
Orange Form的后端架构通过模块化设计和清晰的依赖关系,实现了功能解耦与高效协作。Mybatis-Flex在性能与灵活性上的优势,配合Mybatis-Plus的快速开发特性,为不同场景提供了最优解决方案。数据权限与多数据源动态切换的精细化设计,则确保了系统安全性与扩展性。该架构为复杂业务系统提供了可复用的技术实践。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



