1. 框架定位与生产准入评估
1.1 什么是 Magic API
Magic API 是一个基于 Java 的接口快速开发框架,通过 Web UI 编写脚本(magic-script),自动映射为 HTTP 接口。保存即生效,无需重启、无需编译、无需定义 Controller/Service/Mapper。
1.2 生产环境适用场景 ✅
| 场景 | 说明 |
|---|---|
| 运营后台 / 管理端接口 | 迭代频繁、逻辑相对简单、对性能要求不极端 |
| 报表查询 / 数据看板 | 复杂 SQL 直接在脚本中编写,避免大量 Mapper XML |
| 第三方对接 / 网关转发 | 快速适配外部接口格式变更 |
| 原型验证 / MVP | 天级别交付验证 |
| 动态配置 / 规则引擎 | 业务规则频繁调整,不想每次发版 |
1.3 不建议使用的场景 ❌
- 核心交易链路(支付、下单等对稳定性和性能要求极高的场景)
- 复杂领域模型驱动的业务(DDD 架构)
- 需要严格单元测试覆盖率的项目(动态脚本难以做传统单测)
- 团队对动态脚本完全陌生且无专人维护
2. 生产级环境搭建
2.1 Maven 依赖
xml
1<!-- Magic API 核心 -->
2<dependency>
3 <groupId>org.ssssssss</groupId>
4 <artifactId>magic-api-spring-boot-starter</artifactId>
5 <version>2.1.0</version> <!-- 务必使用最新稳定版 -->
6</dependency>
7
8<!-- 数据库驱动(按需) -->
9<dependency>
10 <groupId>com.mysql</groupId>
11 <artifactId>mysql-connector-j</artifactId>
12 <scope>runtime</scope>
13</dependency>
14
15<!-- Redis(生产环境强烈建议引入,用于缓存和分布式锁) -->
16<dependency>
17 <groupId>org.springframework.boot</groupId>
18 <artifactId>spring-boot-starter-data-redis</artifactId>
19</dependency>
2.2 生产环境配置 (application-prod.yml)
yaml
编辑
1magic-api:
2 web: /magic/web # ⚠️ 生产环境务必加鉴权或改路径
3 resource:
4 type: database # ⚠️ 生产必须用DB存储,不要用file
5 table-name: magic_api_resource # 脚本存储表
6 backup:
7 enable: true # 开启备份
8 max-history: 30 # 保留30天历史版本
9 response: # 统一响应格式
10 success-code: 200
11 exception-message-key: message
12 page: # 分页参数名统一
13 page: pageNum
14 size: pageSize
15 security: # ⚠️ 安全配置(关键!)
16 username: ${MAGIC_API_ADMIN} # 从环境变量读取,不要硬编码
17 password: ${MAGIC_API_PWD}
18 token: ${MAGIC_API_TOKEN} # Token验证
19 ip-white-list: 10.0.0.0/8,172.16.0.0/12 # 仅内网IP可访问UI
2.3 初始化数据库表
当 resource.type=database 时,Magic API 会自动建表。如需手动创建:
sql
1CREATE TABLE `magic_api_resource` (
2 `id` varchar(32) NOT NULL,
3 `create_time` bigint NOT NULL,
4 `update_time` bigint NOT NULL,
5 `path` varchar(512) DEFAULT NULL,
6 `method` varchar(16) DEFAULT NULL,
7 `script` text,
8 `name` varchar(256) DEFAULT NULL,
9 `group_id` varchar(32) DEFAULT NULL,
10 PRIMARY KEY (`id`)
11) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3. 核心语法速查与实战示例
3.1 基础 CRUD
GET 分页查询
javascript
1// 路径: GET /api/user/list
2var status = request.getParameter('status', 1)
3var keyword = request.getParameter('keyword')
4
5return db.page('''
6 select id, username, phone, age, create_time
7 from t_user
8 where status = ?
9 <if test="keyword != null and keyword != ''">
10 and (username like concat('%', #{keyword}, '%')
11 or phone like concat('%', #{keyword}, '%'))
12 </if>
13 order by create_time desc
14''', status, keyword)
POST 新增 + 参数校验
javascript
1// 路径: POST /api/user/add
2var body = request.getBody()
3
4// ✅ 生产级校验:失败自动返回错误信息
5assert.isNotNull(body.username, '用户名不能为空')
6assert.isTrue(body.username.length() >= 2 && body.username.length() <= 32, '用户名长度2-32位')
7assert.matches(body.phone, '^1[3-9]\\d{9}$', '手机号格式不正确')
8
9// 检查唯一性
10var exists = db.selectInt('select count(*) from t_user where username = ?', body.username)
11assert.isTrue(exists == 0, '用户名已存在')
12
13var rows = db.insert('''
14 insert into t_user(username, phone, age, status, create_time)
15 values(?, ?, ?, 1, now())
16''', body.username, body.phone, body.age)
17
18return { id: db.lastInsertId(), affectedRows: rows }
3.2 事务处理
javascript
1// 路径: POST /api/order/create
2var body = request.getBody()
3
4return db.transaction(() => {
5 // 扣减库存(乐观锁)
6 var stockRows = db.update('''
7 update t_product set stock = stock - ?
8 where id = ? and stock >= ?
9 ''', body.quantity, body.productId, body.quantity)
10 assert.isTrue(stockRows > 0, '库存不足或商品不存在')
11
12 // 创建订单
13 db.insert('''
14 insert into t_order(order_no, product_id, quantity, user_id, create_time)
15 values(?, ?, ?, ?, now())
16 ''', UUID.randomUUID().toString(), body.productId, body.quantity, body.userId)
17
18 return { orderId: db.lastInsertId() }
19})
20// ⚠️ lambda 内任何异常自动回滚,无需手动 rollback
3.3 Redis 缓存模式
javascript
1// 路径: GET /api/config/{key}
2var cacheKey = 'sys:config:' + pathVariable.key
3
4// Cache-Aside 模式
5var cached = redis.get(cacheKey)
6if (cached != null) {
7 return JSON.parse(cached)
8}
9
10var config = db.selectOne('select * from sys_config where config_key = ?', pathVariable.key)
11if (config != null) {
12 redis.set(cacheKey, JSON.stringify(config), 3600) // TTL 1小时
13}
14return config
3.4 模块化复用
在 UI 左侧 "模块" 中新建 user-utils:
javascript
1// 模块: user-utils
2function checkUserExists(userId) {
3 var count = db.selectInt('select count(*) from t_user where id = ?', userId)
4 assert.isTrue(count > 0, '用户不存在')
5}
6
7function formatUserVO(user) {
8 user.phoneMask = user.phone.replaceAll('(\\d{3})\\d{4}(\\d{4})', '$1****$2')
9 delete user.password
10 return user
11}
在接口中引用:
javascript
1import user_utils as userUtil
2
3userUtil.checkUserExists(body.userId)
4var user = db.selectOne('select * from t_user where id = ?', body.userId)
5return userUtil.formatUserVO(user)
4. ⚠️ 生产安全规范(必读)
4.1 访问控制
表格
| 措施 | 实现方式 |
|---|---|
| IP 白名单 | security.ip-white-list 限制仅内网访问 |
| Token 验证 | 配置 security.token,请求头携带 Magic-Token |
| Nginx 层拦截 | 生产 Nginx 禁止 对外暴露 /magic/web 路径 |
| 操作审计 | 实现 MagicAPIRequestInterceptor 记录所有修改操作 |
4.2 SQL 注入防护
- ✅ 始终使用
?占位符,Magic API 底层使用 PreparedStatement - ❌ 严禁字符串拼接 SQL :
'select * from user where name = "' + name + '"' - ✅ 动态条件使用
<if>标签,而非字符串拼接
4.3 敏感数据处理
- 数据库密码、Redis 密码等通过环境变量注入,不写入脚本
- 日志中脱敏:
logger.info('用户{}登录', phoneMask) - 响应中删除敏感字段:
delete user.password
5. 运维与监控
5.1 版本管理与发布
- 开发环境:
type=file+ Git 管理脚本文件 - 生产环境:
type=database,通过 UI 的 "导出/导入" 功能同步 - 推荐流程:开发 → Git Review → 导出 JSON → 生产导入 → 验证
5.2 监控指标
Magic API 内置 Actuator 端点,接入 Prometheus/Grafana:
yaml
1management:
2 endpoints:
3 web:
4 exposure:
5 include: magic-api
关注指标:接口调用次数、平均耗时、错误率、慢脚本告警。
5.3 日志规范
javascript
1// ✅ 使用占位符,避免字符串拼接
2logger.info('查询用户列表, pageNum={}, size={}, keyword={}', pageNum, size, keyword)
3
4// ✅ 异常日志带上下文
5try {
6 // 业务逻辑
7} catch(e) {
8 logger.error('创建订单失败, userId={}, productId={}', body.userId, body.productId, e)
9 throw e // 重新抛出,让全局异常处理器返回统一错误格式
10}
6. 常见问题排查清单
表格
| 现象 | 排查方向 |
|---|---|
| 保存后接口未生效 | 检查是否点击保存;确认 DB 连接正常;查看启动日志有无报错 |
| SQL 执行报错 | 检查 ? 数量与参数是否匹配;在 UI 中使用"调试"功能预览实际 SQL |
| 性能突然下降 | 检查是否缺少索引;是否循环查库(应改为批量查询);Redis 是否穿透 |
| 内存溢出 | 检查是否在脚本中缓存了大量数据;避免在循环中创建大对象 |
| 并发问题 | 脚本变量是请求级隔离的,但共享模块中的全局变量需注意线程安全 |
7. 学习资源
- 官方文档:https://www.ssssssss.org/magic-api/
- 在线体验:https://www.ssssssss.org/magic-api/demo/
- GitHub:https://github.com/ssssssss-team/magic-api
- 社区交流群:官方文档首页有 QQ/微信群号
最后提醒: Magic API 是利器但不是银弹。建议先在非核心业务试点,团队熟悉后再逐步推广。建立代码审查机制,定期 Review 线上脚本质量,避免"方便"变成"灾难"。