# 升级说明
本文说明如何升级平台版本,以及升级到 1.0 时需要注意的变更。
# 升级步骤
以 Docker 部署 或 生产环境部署 方式运行的平台,按以下步骤升级:
备份数据库和附件(生产环境必做):
docker compose exec -T database pg_dump -U postgres -Fc application > backup_$(date +%F).dump tar czf attachments_$(date +%F).tar.gz runtime/attachments1
2阅读本页后面的变更说明,确认有没有影响现有业务的项。
拉取新配置和新镜像并重启,在
platform目录下执行:git pull && docker compose pull && docker compose up -d1本地改过
docker-compose.yml、runtime/proxy/conf.d/default.conf等文件时,git pull可能冲突。可以先git stash,拉取后git stash pop并检查差异。确认版本和状态:
docker compose images # TAG 列是正在运行的版本 docker compose ps # server 显示 healthy 即启动完成1
2
后端启动时会自动导入平台种子数据和 codes/data/csv 下的应用种子数据,不需要额外操作。
Dokku 部署的升级方法见 在 Dokku 上部署后端应用。
# 升级到 1.0.0-beta18:动态服务的匿名调用
# 变更内容
动态服务(开发定制 > 系统集成 > 动态服务)有一个“允许匿名调用”开关 enableAnonymous,默认为 false。1.0.0-beta18 之前,这个开关实际不生效:未登录的请求也能调用任何动态服务(grails-platform#768)。
从 1.0.0-beta18 起,enableAnonymous 为 false 或未设置的服务会拒绝未登录请求。实测不带令牌调用返回:
POST /api/service/Test%20Echo
HTTP 500
{"msg":"ErrorCode: 11004, ErrorMsg: AnonymousInvocation","errorCode":11004}
2
3
注意
平台为这个错误定义的 HTTP 状态码是 403,但当前版本实际返回的是 500。调用方请按响应体中的 errorCode 11004 判断,不要依赖 HTTP 状态码。
影响范围:凡是一直被匿名调用、但没有打开 enableAnonymous 的服务,升级后都会失败。典型场景是 Webhook 回调、设备上报接口、公开页面调用的接口。
# 升级前排查
在升级前的旧版本数据库中执行以下 SQL,列出曾被匿名调用、升级后会被拒绝的服务:
-- 匿名身份序列化为 "Anonymous"(AnonymousAuthenticationProvider.serializeAuthentication)
select s.name, s.enable_anonymous, count(*) as anonymous_calls, max(r.start_time) as last_call
from dynamic_service_exec_record r
join dynamic_service s on s.id = r.provider_id
where coalesce(s.enable_anonymous, false) = false
and (r.exec_auth is null or r.exec_auth::text like '%Anonymous%')
group by 1, 2 order by 3 desc;
2
3
4
5
6
7
执行方式:
docker compose exec database psql -U postgres -d application
输出示例(有匿名调用记录时):
name | enable_anonymous | anonymous_calls | last_call
-----------+------------------+-----------------+----------------------------
Test Echo | f | 1 | 2026-09-23 13:28:02.959255
2
3
这条 SQL 查不全
平台只为打开了“记录日志”(enable_log)的服务写调用记录。没有打开日志的服务,即使一直被匿名调用,这条 SQL 也查不出来。请再用下面的 SQL 列出所有会拒绝匿名调用的服务,逐个确认调用方是否带登录令牌:
select name, active, enable_log
from dynamic_service
where coalesce(enable_anonymous, false) = false
order by name;
2
3
4
# 处理方式
对确实需要匿名访问的服务,把 enableAnonymous 改为 true:
在界面上:
开发定制 > 系统集成 > 动态服务,编辑对应服务,打开Enable Anonymous(当前版本该字段没有中文翻译);或在种子 CSV 中设置
enableAnonymous列,例如:name(*),active,logic.name,enableAnonymous Device Report,T,Device Report Core Logic,true1
2
其他服务的调用方需要先登录,通过 POST /api/auth/login 获取 access_token,再以 Authorization: Bearer <access_token> 请求头调用。
打开匿名访问的服务,要在服务逻辑里自行校验调用方(例如校验签名或约定的密钥),不要直接暴露增删改操作。
# 1.0 起移除的功能与替代方案
1.0 版本(Grails 7 / Java 25)清理了一批旧功能。从 0.x 版本升级,或按旧文档配置时,请对照下面的列表调整。
- 报表及单据打印(Jasper 报表、
DynamicReport、打印动作) - 向导(Wizard,
DynamicFormWizardStep)- 替代方案:用带参数表单的对象动作收集输入
- 参考文档:对象动作
- 甘特图表单
- 替代方案:暂无内置替代,可开发自定义前端组件
- 参考文档:插件开发
- 动态字段定义 / 实例(
DynamicFieldDefinition、DynamicFieldInstance,CSV 中的(#)列) - 字段钩子(Field Hook:字段默认值、校验、联动、搜索)
- 替代方案:表单 Hook(Form Hook / Data Hook)
- 参考文档:表单客制化
- 显示控件配置(
DomainColumnClientSideTypeConfig)- 替代方案:在表单字段的
displayType中设置控件类型 - 参考文档:高级字段控件
- 替代方案:在表单字段的
RequestMap访问控制- 替代方案:领域模型的增删改查权限、表单/动作/菜单的访问要求,都通过
RoleRequirement配置 - 参考文档:对象权限控制
- 替代方案:领域模型的增删改查权限、表单/动作/菜单的访问要求,都通过
- 对象钩子
Update/delete ability(UPDATE_DELETE)动态权限- 替代方案:钩子类型仍可选择,但不再执行;改用
RoleRequirement的自定义逻辑 - 参考文档:对象权限控制
- 替代方案:钩子类型仍可选择,但不再执行;改用
- 组织(
Organization、Organization.csv、$ROOT_ORG$)- 替代方案:多租户只按租户(
TENANT_ID)区分 - 参考文档:Docker 部署
- 替代方案:多租户只按租户(
- 系统集成
DynamicIntegration:传入集成- 替代方案:Webhook(
开发定制 > 系统集成 > Webhook) - 参考文档:系统集成
- 替代方案:Webhook(
- 系统集成
DynamicIntegration:传出集成- 替代方案:在对象客制化的
After creating等钩子中自行发送 HTTP 请求 - 参考文档:从传出集成迁移
- 替代方案:在对象客制化的
- 动态服务的服务消费者、用户令牌(
UserToken、X-MY-Token请求头)、jvm://服务发现- 替代方案:外部调用用标准登录令牌(
/api/auth/login);平台内互调用动态 RPC - 参考文档:动态服务
- 替代方案:外部调用用标准登录令牌(
LLM_ENGINE逻辑引擎、智能助手、OpenAI / Anthropic 等 AI 配置- 替代方案:无内置替代,可在动态逻辑的 Groovy 代码中直接调用大模型的外部 HTTP API
- 邮件发送(SMTP 配置、邮件模板、邮件发送记录)
- 替代方案:无内置替代,可在动态逻辑的 Groovy 代码中直接调用邮件服务的外部 HTTP API;站内消息用
消息 > 消息中心
- 替代方案:无内置替代,可在动态逻辑的 Groovy 代码中直接调用邮件服务的外部 HTTP API;站内消息用
- 接口返回数据客制化(
Object render钩子)- 替代方案:表单 Data Hook
- 参考文档:表单客制化
- 定时任务的启用逻辑(
enableLogic)- 替代方案:在任务核心逻辑开头自行判断是否执行
- 参考文档:定时任务
- 定时任务的“启动时执行(Run at Startup,
RUN_AT_STARTUP)”类型- 替代方案:需要在系统启动时执行的逻辑,放到插件中实现
MuyanPlatformComponent的类的onLoad()方法里(插件每次重新加载时也会执行,逻辑要能重复执行);升级前请把这类任务改掉,否则升级后这段启动逻辑不会再执行 - 参考文档:定时任务、插件开发 · 生命周期回调
- 替代方案:需要在系统启动时执行的逻辑,放到插件中实现
- 种子数据动作
Reload Seed Data、Import Seed Data Package,gradle 任务packageSeedData- 替代方案:重启后端即可重新导入
codes/data/csv下的应用种子数据,或通过插件导入数据 - 参考文档:数据导入
- 替代方案:重启后端即可重新导入
- Heroku 部署、线上体验环境
- 一体化安装包
muyantech/installer(Docker Swarm + GlusterFS,JDK 11)- 替代方案:用 Docker Compose 部署到服务器
- 参考文档:生产环境部署
旧版前端(0.x)仍随 Docker Compose 一起部署,访问地址是 http://localhost:9080/legacy/,只作过渡使用。