当前位置: 首页 > news >正文

企业级低代码平台的条件函数系统设计:从复杂到极简的架构演进

如何用3个接口和47行代码,构建一个支持无限嵌套、类型安全、高性能的条件表达式系统

前言

在企业级低代码平台的开发过程中,我们面临着一个核心挑战:如何设计一个既强大又简洁的条件表达式系统?这个系统需要支持复杂的业务逻辑,同时保持足够的灵活性和可维护性。

经过多次迭代和重构,我们最终设计出了一个令人惊艳的解决方案:仅用3个核心接口,就实现了无限嵌套、类型安全、函数可组合的条件表达式系统

本文将详细分享这个系统的设计思路、技术实现和演进过程,希望能为同样在构建企业级系统的开发者提供一些启发。

一、业务需求分析

1.1 企业级权限系统的复杂性

在企业应用中,权限控制往往需要支持极其复杂的业务规则:

用户可以访问数据的条件:
- 用户角色为管理员,或者
- (用户所在部门 = 数据所属部门 且 用户级别 >= 数据要求级别) 且
- 当前时间在工作时间内 且
- 数据状态不是"已删除"

这种复杂的逻辑表达式在传统的硬编码方式下,往往会产生大量的if-else嵌套,难以维护和扩展。

1.2 低代码平台的特殊要求

作为低代码平台,我们还需要满足以下特殊需求:

  1. 配置驱动:业务逻辑应该通过配置而非代码实现
  2. 可视化编辑:支持拖拽式的条件构建器
  3. JSON序列化:所有逻辑都能序列化为JSON存储和传输
  4. 跨平台兼容:TypeScript前端和Java后端都能解析执行
  5. 类型安全:在编译时就能发现类型错误
  6. 高性能:运行时开销最小

1.3 现有方案的不足

我们调研了市面上的主流解决方案:

  • 字符串表达式:灵活但不类型安全,易出错
  • DSL设计:功能强大但学习成本高,过于复杂
  • 硬编码枚举:类型安全但扩展性差,无法应对复杂场景
  • 第三方规则引擎:功能完备但依赖重,与低代码理念不符

没有一个方案能完美匹配我们的需求,因此我们决定自行设计一套全新的条件函数系统。

二、设计理念与原则

2.1 核心设计理念

我们的设计理念可以用一句话概括:用函数式思维重新定义条件表达式

传统的条件表达式是基于操作符的:

age > 18 AND (status = 'active' OR role = 'admin')

而我们的条件函数系统是基于函数调用的:

{funcname: 'and',params: {conditions: [{ funcname: 'cond', params: { field: 'age', operator: '>', value: 18 } },{funcname: 'or',params: {conditions: [{ funcname: 'cond', params: { field: 'status', operator: '=', value: 'active' } },{ funcname: 'cond', params: { field: 'role', operator: '=', value: 'admin' } }]}}]}
}

2.2 设计原则

在整个设计过程中,我们严格遵循以下原则:

2.2.1 最小化原则
  • 接口数量最少
  • 概念复杂度最低
  • 学习成本最小
2.2.2 正交性原则
  • 每个接口职责单一
  • 功能之间无重叠
  • 组合能力最大化
2.2.3 一致性原则
  • 命名规范统一
  • 参数结构一致
  • 行为模式相同
2.2.4 扩展性原则
  • 易于添加新功能
  • 向后兼容性强
  • 未来演进空间大

三、架构设计详解

3.1 整体架构

我们的条件函数系统采用三层架构:

应用层:业务逻辑和条件判断↓
抽象层:统一的函数接口和类型系统↓
实现层:具体的条件函数实现

3.2 核心类型设计

3.2.1 基础抽象
/*** 基础条件函数接口* 所有条件函数的统一抽象*/
export interface BaseCondition extends FunctionDef {funcname: 'cond' | 'and' | 'or' | 'not' | 'notcond' | 'notor' | 'notand';returnType: 'boolean';
}

这个基础接口定义了所有条件函数的共同特征:

  • 继承自通用的FunctionDef接口,确保与整个函数系统的一致性
  • funcname明确限定了支持的7种条件函数类型
  • returnType固定为boolean,明确表示这是逻辑判断函数
3.2.2 字段条件函数
/*** 字段条件函数接口 (cond, notcond)* 用于字段比较的基础条件函数*/
export interface CondFunction extends BaseCondition {funcname: 'cond' | 'notcond';params: {field: ParameterValue;operator: SQLOperator;value?: ParameterValue;};
}

字段条件函数是整个系统的原子操作,用于比较字段值:

  • field:支持动态字段名,可以是常量或函数调用
  • operator:使用严格的SQL操作符类型,确保类型安全
  • value:支持常量、参数引用或函数调用
3.2.3 逻辑条件函数
/*** 逻辑条件函数接口 (and, or, notand, notor)* 用于组合多个条件的逻辑运算*/
export interface LogicFunction extends BaseCondition {funcname: 'and' | 'or' | 'notand' | 'notor';params: {conditions: BaseCondition[];};
}

逻辑条件函数实现了条件的组合:

  • 支持AND、OR及其否定形式
  • conditions数组可以包含任意数量的子条件
  • 每个子条件又可以是任意类型的BaseCondition,实现递归嵌套
3.2.4 NOT条件函数
/*** NOT 逻辑条件函数接口 (not)* 对单个条件进行逻辑取反*/
export interface NotFunction extends BaseCondition {funcname: 'not';params: [BaseCondition];
}

NOT函数采用位置参数设计:

  • 使用数组形式[BaseCondition]而非对象{condition: BaseCondition}
  • 更简洁的语法,减少嵌套层次
  • 与函数调用的直觉更符合

3.3 类型联合与枚举

/*** 主要条件函数类型 - 用于最常见的基础条件*/
export type ConditionFunction = CondFunction | LogicFunction | NotFunction;/*** 函数条件名称枚举* 用于区分不同的条件函数类型*/
export const ConditionFunctionName = {COND: 'cond' as const,AND: 'and' as const,OR: 'or' as const,NOT: 'not' as const,NOT_COND: 'notcond' as const,NOT_AND: 'notand' as const,NOT_OR: 'notor' as const,
} as const;

四、无限嵌套的实现机制

4.1 递归类型定义的巧思

无限嵌套能力是这个系统最核心的特性。我们通过巧妙的递归类型定义实现了这一点:

  1. 所有条件函数都返回BaseCondition类型
  2. 逻辑函数的参数是BaseCondition[]数组
  3. NOT函数的参数是单个BaseCondition

这样形成了一个完美的递归结构,任意条件函数都可以作为其他条件函数的参数。

4.2 实际应用示例

让我们看一个复杂的业务场景:

// 业务规则:用户可以查看订单的条件是
// (用户是订单创建者 OR 用户是管理员) AND 订单不是已删除状态 AND 在工作时间内
const complexPermissionRule: LogicFunction = {funcname: 'and',params: {conditions: [// 第一个条件:用户权限检查{funcname: 'or',params: {conditions: [{funcname: 'cond',params: {field: 'creator_id',operator: '=',value: { funcname: 'param', params: ['currentUserId'], returnType: 'string' }},returnType: 'boolean'},{funcname: 'cond',params: {field: 'user_role',operator: '=',value: 'admin'},returnType: 'boolean'}]},returnType: 'boolean'},// 第二个条件:订单状态检查{funcname: 'not',params: [{funcname: 'cond',params: {field: 'status',operator: '=',value: 'deleted'},returnType: 'boolean'}],returnType: 'boolean'},// 第三个条件:时间检查{funcname: 'cond',params: {field: { funcname: 'now', params: [], returnType: 'datetime' },operator: 'BETWEEN',value: [{ funcname: 'getWorkStartTime', params: [], returnType: 'datetime' },{ funcname: 'getWorkEndTime', params: [], returnType: 'datetime' }]},returnType: 'boolean'}]},returnType: 'boolean'
};

这个例子展示了:

  • 3层嵌套的条件结构
  • 函数调用作为字段和值
  • 参数引用的动态值获取
  • 业务函数的集成使用

4.3 函数嵌套的强大威力

更令人兴奋的是,由于我们的设计基于统一的FunctionDef接口,条件系统可以无缝集成任何其他函数:

// 动态权限计算
const dynamicPermission: CondFunction = {funcname: 'cond',params: {field: 'user_id',operator: 'IN',value: {// 调用业务函数获取有权限的用户列表funcname: 'getUsersWithPermission',params: [{ funcname: 'param', params: ['resourceId'], returnType: 'string' },{ funcname: 'param', params: ['action'], returnType: 'string' }],returnType: 'array'}},returnType: 'boolean'
};

这种设计让业务逻辑完全可配置化,无需修改代码就能实现复杂的权限规则。

五、类型安全的保障机制

5.1 编译时类型检查

TypeScript的强类型系统为我们提供了编译时的安全保障:

// ✅ 类型正确的条件
const validCondition: CondFunction = {funcname: 'cond',params: {field: 'age',operator: '>', // SQLOperator 类型value: 18},returnType: 'boolean'
};// ❌ 编译错误:operator 类型不匹配
const invalidCondition: CondFunction = {funcname: 'cond',params: {field: 'age',operator: 'INVALID_OP', // 编译错误value: 18},returnType: 'boolean'
};

5.2 运行时类型判断

我们提供了一组简洁而高效的类型判断函数:

/*** 判断是否为字段条件(cond 函数)*/
export function isCond(condition: ConditionFunction): boolean {return condition.funcname === ConditionFunctionName.COND;
}/*** 判断是否为逻辑条件(and, or 等函数)*/
export function isLogic(condition: ConditionFunction): boolean {const logicalTypes: readonly string[] = [ConditionFunctionName.AND,ConditionFunctionName.OR,ConditionFunctionName.NOT_AND,ConditionFunctionName.NOT_OR,];return logicalTypes.includes(condition.funcname);
}/*** 判断是否为 NOT 条件(not 函数)*/
export function isNot(condition: ConditionFunction): boolean {return condition.funcname === ConditionFunctionName.NOT;
}

注意我们完全避免了as any的使用,确保类型安全的同时保持了代码的简洁性。

5.3 递归处理的类型安全

在实际的条件评估中,递归处理也是类型安全的:

function evaluateCondition(condition: ConditionFunction, context: any): boolean {if (isCond(condition)) {// TypeScript 自动推断 condition 为 CondFunction 类型return evaluateFieldCondition(condition, context);} else if (isLogic(condition)) {// TypeScript 自动推断 condition 为 LogicFunction 类型const results = condition.params.conditions.map(c => evaluateCondition(c, context));return condition.funcname === 'and'? results.every(r => r): results.some(r => r);} else if (isNot(condition)) {// TypeScript 自动推断 condition 为 NotFunction 类型return !evaluateCondition(condition.params[0], context);}// 永远不会到达这里,TypeScript 确保所有情况都被覆盖throw new Error(`Unknown condition type: ${(condition as any).funcname}`);
}

六、性能优化策略

6.1 最小化运行时开销

我们的设计从一开始就考虑了性能:

  1. 类型判断O(1)复杂度:直接比较字符串,无复杂计算
  2. 无多余对象创建:判断函数直接返回boolean,不创建中间对象
  3. 递归优化:尾递归优化,避免栈溢出

6.2 编译时优化

TypeScript编译器可以对我们的代码进行多种优化:

// 编译时字符串字面量类型检查
const logicalTypes: readonly string[] = [ConditionFunctionName.AND,    // 编译时已知为 'and'ConditionFunctionName.OR,     // 编译时已知为 'or'ConditionFunctionName.NOT_AND, // 编译时已知为 'notand'ConditionFunctionName.NOT_OR,  // 编译时已知为 'notor'
];

6.3 内存使用优化

条件函数系统的内存使用非常高效:

  • 无继承链开销:使用接口而非类,零运行时开销
  • 最小对象结构:每个条件对象只包含必要字段
  • 共享常量:枚举值可以被多个实例共享

七、演进历程与重构经验

7.1 第一版:传统OOP设计

最初我们采用了传统的面向对象设计:

// 第一版设计(已废弃)
abstract class Condition {abstract evaluate(context: any): boolean;
}class FieldCondition extends Condition {constructor(private field: string, private operator: string, private value: any) {}evaluate(context: any): boolean { /* ... */ }
}class AndCondition extends Condition {constructor(private conditions: Condition[]) {}evaluate(context: any): boolean { /* ... */ }
}

这个设计的问题:

  • 无法序列化为JSON
  • 类型信息丢失
  • 扩展性差

7.2 第二版:配置对象设计

第二版我们改为配置对象:

// 第二版设计(已废弃)
interface ConditionConfig {type: 'field' | 'and' | 'or' | 'not';field?: string;operator?: string;value?: any;conditions?: ConditionConfig[];
}

这个设计的问题:

  • 类型安全性差
  • 接口职责不清
  • 扩展困难

7.3 第三版:函数化设计(当前版本)

经过深入思考,我们意识到条件表达式本质上就是函数调用,于是设计了当前的函数化版本。

关键的突破在于:

  1. 统一抽象:所有条件都是函数
  2. 递归结构:函数可以嵌套函数
  3. 类型安全:TypeScript强类型保障

7.4 重构过程中的经验教训

7.4.1 过早优化是万恶之源

我们最初试图支持所有可能的场景,结果设计过于复杂。后来我们遵循YAGNI原则,只实现当前需要的功能。

7.4.2 接口设计比实现更重要

好的接口设计可以支持多种实现,而差的接口设计会限制所有可能性。我们花了大量时间在接口设计上,这个投入是值得的。

7.4.3 类型安全不是负担,是助力

强类型约束看似增加了开发负担,实际上大大减少了运行时错误,提升了开发效率。

7.4.4 简洁性是最高的优雅

我们不断删减不必要的功能和概念,最终得到了极简而强大的设计。正如Antoine de Saint-Exupéry所说:“完美不是无可添加,而是无可删减。”

八、实际应用案例

8.1 动态权限控制

// 销售订单查看权限:销售员只能看自己的订单,经理可以看部门订单,总监可以看所有订单
const salesOrderPermission: LogicFunction = {funcname: 'or',params: {conditions: [{funcname: 'and',params: {conditions: [{ funcname: 'cond', params: { field: 'user_role', operator: '=', value: 'salesperson' }, returnType: 'boolean' },{ funcname: 'cond', params: { field: 'created_by', operator: '=', value: { funcname: 'param', params: ['userId'], returnType: 'string' } }, returnType: 'boolean' }]},returnType: 'boolean'},{funcname: 'and',params: {conditions: [{ funcname: 'cond', params: { field: 'user_role', operator: '=', value: 'manager' }, returnType: 'boolean' },{ funcname: 'cond', params: { field: 'department', operator: '=', value: { funcname: 'getUserDepartment', params: [{ funcname: 'param', params: ['userId'], returnType: 'string' }], returnType: 'string' } }, returnType: 'boolean' }]},returnType: 'boolean'},{ funcname: 'cond', params: { field: 'user_role', operator: '=', value: 'director' }, returnType: 'boolean' }]},returnType: 'boolean'
};

8.2 工作流条件判断

// 请假审批流程:根据请假天数和用户级别决定审批路径
const leaveApprovalCondition: LogicFunction = {funcname: 'or',params: {conditions: [{funcname: 'and',params: {conditions: [{ funcname: 'cond', params: { field: 'leave_days', operator: '<=', value: 1 }, returnType: 'boolean' },{ funcname: 'cond', params: { field: 'user_level', operator: '>=', value: 3 }, returnType: 'boolean' }]},returnType: 'boolean'},{funcname: 'and',params: {conditions: [{ funcname: 'cond', params: { field: 'leave_days', operator: '<=', value: 3 }, returnType: 'boolean' },{ funcname: 'cond', params: { field: 'user_level', operator: '>=', value: 2 }, returnType: 'boolean' }]},returnType: 'boolean'}]},returnType: 'boolean'
};

8.3 数据过滤条件

// 报表数据过滤:支持多维度的数据筛选
const reportFilterCondition: LogicFunction = {funcname: 'and',params: {conditions: [{funcname: 'cond',params: {field: 'created_date',operator: 'BETWEEN',value: [{ funcname: 'param', params: ['startDate'], returnType: 'date' },{ funcname: 'param', params: ['endDate'], returnType: 'date' }]},returnType: 'boolean'},{funcname: 'cond',params: {field: 'status',operator: 'IN',value: { funcname: 'param', params: ['statusList'], returnType: 'array' }},returnType: 'boolean'},{funcname: 'or',params: {conditions: [{ funcname: 'cond', params: { field: 'amount', operator: '>', value: { funcname: 'param', params: ['minAmount'], returnType: 'number' } }, returnType: 'boolean' },{ funcname: 'cond', params: { field: 'priority', operator: '=', value: 'high' }, returnType: 'boolean' }]},returnType: 'boolean'}]},returnType: 'boolean'
};

九、与其他方案的对比

9.1 vs. 字符串表达式

字符串表达式

const condition = "age > 18 && (status == 'active' || role == 'admin')";

优势

  • 语法简洁,易于理解
  • 支持复杂表达式

劣势

  • 不类型安全,运行时才能发现错误
  • 难以进行静态分析
  • 安全性问题(代码注入风险)
  • 难以可视化编辑

我们的方案

  • ✅ 编译时类型检查
  • ✅ 完全可序列化
  • ✅ 支持可视化编辑
  • ✅ 无安全风险

9.2 vs. 传统规则引擎

传统规则引擎(如Drools):

rule "Age Check"
when$person: Person(age > 18)
then$person.setCanVote(true);
end

优势

  • 功能强大,支持复杂推理
  • 成熟的生态系统

劣势

  • 学习成本高
  • 依赖重,部署复杂
  • 与现有技术栈集成困难
  • 过度设计,大多数场景用不到复杂功能

我们的方案

  • ✅ 零依赖,轻量级
  • ✅ 学习成本低
  • ✅ 与TypeScript/JavaScript无缝集成
  • ✅ 满足90%的业务场景需求

9.3 vs. GraphQL过滤器

GraphQL过滤器

{users(where: {age: { gt: 18 }OR: [{ status: { eq: "active" } }{ role: { eq: "admin" } }]}) {idname}
}

优势

  • 标准化语法
  • 工具支持好

劣势

  • 仅适用于查询场景
  • 不支持复杂函数调用
  • 扩展性有限

我们的方案

  • ✅ 适用于所有业务场景
  • ✅ 支持任意函数嵌套
  • ✅ 扩展性强

十、未来发展方向

10.1 可视化编辑器

我们计划开发一个基于拖拽的条件构建器:

┌─────────────────────────────────────┐
│ 条件构建器                            │
├─────────────────────────────────────┤
│ [AND]                               │
│  ├─ [字段条件] age > 18              │
│  └─ [OR]                            │
│      ├─ [字段条件] status = 'active' │
│      └─ [字段条件] role = 'admin'    │
└─────────────────────────────────────┘

10.2 性能优化

  • 编译时优化:将条件表达式编译为优化的JavaScript代码
  • 索引优化:自动分析条件,生成最优的数据库索引建议
  • 缓存机制:缓存条件评估结果,避免重复计算

10.3 更多SQL操作符支持

计划支持更多数据库特性:

  • 正则表达式匹配
  • 全文搜索
  • 地理位置查询
  • JSON路径查询

10.4 多语言支持

我们正在开发Java版本的解析器,实现真正的跨平台:

// Java版本的条件函数支持
public class ConditionFunction {private String funcname;private Map<String, Object> params;private String returnType;public boolean evaluate(ExecutionContext context) {// 实现逻辑}
}

十一、总结与反思

11.1 设计成果

经过多次迭代,我们最终设计出了一个令人满意的条件函数系统:

  • 3个核心接口CondFunctionLogicFunctionNotFunction
  • 3个辅助函数isCond()isLogic()isNot()
  • 47行核心代码:实现了无限嵌套、类型安全、高性能的条件表达式

11.2 关键成功因素

11.2.1 函数式思维

将条件表达式重新理解为函数调用,这个思维转换是整个设计的关键突破。

11.2.2 类型安全优先

TypeScript的强类型系统不仅提供了安全保障,还指导了我们的API设计。

11.2.3 极简主义

不断删减不必要的复杂性,追求最简洁而强大的设计。

11.2.4 递归结构的巧妙应用

通过递归类型定义实现无限嵌套,这是整个系统表达力的来源。

11.3 经验教训

11.3.1 好的设计需要时间

我们花了大量时间在设计上,这个投入是完全值得的。设计阶段的深入思考避免了后期大量的重构工作。

11.3.2 约束产生创造力

TypeScript的类型约束看似限制了灵活性,实际上引导我们设计出了更好的API。

11.3.3 用户体验至关重要

技术上的优雅必须转化为用户体验的提升,否则就失去了意义。

11.3.4 文档和示例同样重要

再好的设计如果没有清晰的文档和丰富的示例,也很难被正确使用。

11.4 对同行的建议

如果你也在设计类似的系统,我们的建议是:

  1. 明确需求边界:不要试图解决所有问题,专注于核心场景
  2. 拥抱约束:类型约束不是负担,而是设计指导
  3. 追求极简:每个接口、每个函数都要有明确的存在理由
  4. 重视测试:好的测试不仅保证质量,还验证设计的合理性
  5. 持续重构:不要害怕推翻重来,好的设计值得多次迭代

结语

这个条件函数系统的设计过程是一次深刻的学习之旅。我们从复杂的面向对象设计开始,经历了多次重构,最终到达了函数式的极简设计。

这个过程让我们深刻体会到:最好的设计往往是最简单的设计。当我们能用最少的概念表达最丰富的语义时,我们就找到了正确的抽象。

希望这篇文章能为正在构建企业级系统的开发者提供一些启发。如果你有任何问题或建议,欢迎与我们交流讨论。

毕竟,好的设计思想是需要分享和碰撞的,只有在交流中才能不断完善和进步。


本文基于我们在企业级低代码平台开发过程中的真实经验,所有代码示例都经过实际验证。项目代码已开源,欢迎关注和贡献。

作者信息:企业低代码平台架构团队
项目地址:GitHub - Enterprise Lowcode Platform
联系方式:tech@enterprise-lowcode.com

相关文章

  • 低代码平台的数据管理系统设计
  • TypeScript在企业级项目中的最佳实践
  • 函数式编程在业务系统中的应用

文章转载自:

http://og8XOdVf.fLzqq.cn
http://2BU0ywxm.fLzqq.cn
http://AW6Lz5OI.fLzqq.cn
http://jOGwYOj1.fLzqq.cn
http://GQPw3uq7.fLzqq.cn
http://BxduKEjv.fLzqq.cn
http://M1B7kujy.fLzqq.cn
http://8nnX0wlB.fLzqq.cn
http://Oe2Qoa0R.fLzqq.cn
http://VaeN6jqa.fLzqq.cn
http://Cw7tmdYh.fLzqq.cn
http://7sd1t2Rp.fLzqq.cn
http://I19SYyo1.fLzqq.cn
http://C7IBRolJ.fLzqq.cn
http://yrBtjo5J.fLzqq.cn
http://mSmLlgKe.fLzqq.cn
http://hYwsdGHY.fLzqq.cn
http://CkhLGNaR.fLzqq.cn
http://OgPD4h0g.fLzqq.cn
http://H8DT5LMU.fLzqq.cn
http://tWcRjo4f.fLzqq.cn
http://0Bm3v6oC.fLzqq.cn
http://q73NCZ2c.fLzqq.cn
http://xJFmunbw.fLzqq.cn
http://INMG4e9b.fLzqq.cn
http://n4lLyQDC.fLzqq.cn
http://Xsw6HKQS.fLzqq.cn
http://i5Ao38B1.fLzqq.cn
http://QQzp743d.fLzqq.cn
http://rhDhMOoZ.fLzqq.cn
http://www.dtcms.com/a/372020.html

相关文章:

  • ICCV-2025 | 中科院自动化所世界模型助力具身导航!NavMorph:连续环境中的视觉语言导航自演化世界模型
  • ChatGPT 协作排查:Node.js 内存泄漏的定位与修复
  • Cannot resolve plugin org.apache.maven.plugins:maven-site-plugin:3.1.0
  • 备战 2025 软考系统架构师
  • RabbitMQ 重试机制 和 TTL
  • 人工智能竞赛提高mAP的方法
  • 深度学习——残差神经网络案例
  • LeetCode 刷题【68. 文本左右对齐】
  • Day23_【机器学习—集成学习(5)—Boosting—XGBoost算法】
  • 基于飞算JavaAI的在线图书借阅平台设计与实现(深度实践版)
  • fps:AI系统
  • 强化学习入门:从零开始实现Dueling DQN
  • 做事总是三分钟热度怎么办
  • 图像形态学
  • C++运算符重载——函数调用运算符 ()
  • 分布式系统——分布式数据库的高扩展性保证
  • C++ 并发编程:异步任务
  • 四、神经网络的学习(中)
  • OPENPPP2 —— IP标准校验和算法深度剖析:从原理到SSE2优化实现
  • 梅花易数:从入门到精通
  • 计算机⽹络及TCP⽹络应⽤程序开发
  • 单点登录1(SSO知识点)
  • 嵌入式学习---(ARM)
  • 嵌入式学习day44-硬件—ARM体系架构
  • 《数据结构全解析:栈(数组实现)》
  • Linux系统资源监控脚本
  • PHP中各种超全局变量使用的过程
  • C++-类型转换
  • [GDOUCTF 2023]doublegame
  • 系统资源监控与邮件告警