# 升级说明

本文说明如何升级平台版本,以及升级到 1.0 时需要注意的变更。

# 升级步骤

以 Docker 部署 或 生产环境部署 方式运行的平台,按以下步骤升级:

  1. 备份数据库和附件(生产环境必做):

    docker compose exec -T database pg_dump -U postgres -Fc application > backup_$(date +%F).dump
    tar czf attachments_$(date +%F).tar.gz runtime/attachments
    
    1
    2
  2. 阅读本页后面的变更说明,确认有没有影响现有业务的项。

  3. 拉取新配置和新镜像并重启,在 platform 目录下执行:

    git pull && docker compose pull && docker compose up -d
    
    1

    本地改过 docker-compose.yml、runtime/proxy/conf.d/default.conf 等文件时,git pull 可能冲突。可以先 git stash,拉取后 git stash pop 并检查差异。

  4. 确认版本和状态:

    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}
1
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;
1
2
3
4
5
6
7

执行方式:

docker compose exec database psql -U postgres -d application
1

输出示例(有匿名调用记录时):

   name    | enable_anonymous | anonymous_calls |         last_call
-----------+------------------+-----------------+----------------------------
 Test Echo | f                |               1 | 2026-09-23 13:28:02.959255
1
2
3

这条 SQL 查不全

平台只为打开了“记录日志”(enable_log)的服务写调用记录。没有打开日志的服务,即使一直被匿名调用,这条 SQL 也查不出来。请再用下面的 SQL 列出所有会拒绝匿名调用的服务,逐个确认调用方是否带登录令牌:

select name, active, enable_log
from dynamic_service
where coalesce(enable_anonymous, false) = false
order by name;
1
2
3
4

# 处理方式

对确实需要匿名访问的服务,把 enableAnonymous 改为 true:

  • 在界面上:开发定制 > 系统集成 > 动态服务,编辑对应服务,打开 Enable Anonymous(当前版本该字段没有中文翻译);

  • 或在种子 CSV 中设置 enableAnonymous 列,例如:

    name(*),active,logic.name,enableAnonymous
    Device Report,T,Device Report Core Logic,true
    
    1
    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 中的 (#) 列)
    • 替代方案:给对象加字段用动态领域模型的模型字段;动作参数用 ACTION 类型表单的字段
    • 参考文档:动态领域模型、对象动作
  • 字段钩子(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)
    • 参考文档:系统集成
  • 系统集成 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;站内消息用 消息 > 消息中心
  • 接口返回数据客制化(Object render 钩子)
  • 定时任务的启用逻辑(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)

旧版前端(0.x)仍随 Docker Compose 一起部署,访问地址是 http://localhost:9080/legacy/,只作过渡使用。

Last Updated: 2026/9/24 14:27:35