简介Axelor Open Platform是一套面向现代商业应用开发的开源Java框架适合希望在Java EE技术栈上快速构建模块化、可扩展业务系统的开发者。它基于JPA、JSF等标准同时借助JavaScript库实现前后端交互能够帮助团队在同一平台内完成数据模型、服务逻辑与用户界面的协同开发。资源以zip压缩包形式提供大小约6.53MB内含框架主分支源码master文件总数与类型明细暂未披露用户可基于该版本进行定制或拉取具体版本。目前已有505人学习下载对于正在选型或希望深入Axelor的开发者可从中获得开源框架源码、快速入门指南以及API参考、最佳实践等配套资料便于快速理解安装配置、模型设计、服务编写和界面构建流程降低上手成本。该资源适合具备一定Java基础的中高级开发者用于企业级业务系统原型验证或内部工具开发。1. Axelor Open Platform用 XML 描述业务让 Java 框架代替你写增删改查Axelor Open Platform 是一个用于业务应用程序开发的开源 Java 框架它的核心卖点不是给你一堆代码生成器而是用“元数据驱动”的方式重新定义了业务系统的搭建过程。简单说你不再需要为每个实体手写 Controller、Service、Repository 和一堆表单页面而是用 XML 描述数据结构、界面布局和菜单导航框架在运行时把这些声明翻译成可操作的真实业务系统。这个思路对做 CRM、订单管理、审批流这类“表格密集、流程清晰”的企业应用特别合适——Java 团队想缩短交付周期又不想被商业低代码平台绑架时它是很值得评估的一条路。我见过不少团队从零搭建后台管理系统半年后代码量过万行、大部分是 CRUD 样板而用这套框架同样的业务模型只需要几十行 XML。更关键的是它低代码但不黑匣子关键时刻你随时可以写 Java Action 接管逻辑。2. 架构拆解元数据引擎如何把 XML 变成一张表和一个界面2.1 元数据引擎到底做了什么要理解 Axelor Open Platform 的运行方式核心是抓住它和传统 Spring MVC 项目的分工差异。传统项目里你写一个实体类再写一个 Controller 暴露 REST 接口再写前端页面去调用接口。这套流程里实体、接口、页面之间是手工对齐的改一个字段要动三层代码。而 Axelor 的做法是你在 XML 里定义一次模型引擎同时完成三件事——生成 Java 领域类、映射数据库表结构、生成表单和列表界面。定义本身变成了唯一的事实来源。引擎内部的处理大致分三条链路模型链路XML 里的entity被解析成 JPA 实体类Hibernate 根据它同步数据库表。字段名、类型、是否必填、是否唯一都在 XML 里声明。视图链路XML 里的form和grid描述界面长什么样引擎在运行时把它们渲染成 Web 界面绑定到对应模型。你甚至不需要写一行前端代码。行为链路界面上的按钮、字段变更、保存动作可以绑定 Java Action 类或内置的 Action 类型业务逻辑在这里插入。这三条链路由同一份模型定义连接起来。所以你在模型 XML 里加一个字段只要重新构建模块列表页、表单页、数据库列都会自动跟上——这是它和“代码生成后手工改”最大的区别。后者生成的代码是静态的改模型要重新跑生成器而 Axelor 的元数据是运行时解析的界面结构始终跟随模型声明。传统开发模式下一个订单模块大概需要实体类、Mapper、Service、Controller、Vue 页面、接口文档六个部分在 Axelor 下你只需要一个模型 XML、一个视图 XML、一个菜单 XML。这个对比不是要否定传统开发而是说明 Axelor 把 CRUD 的重复成本压到了极低。2.2 开源技术底座为什么是这套组合Axelor Open Platform 虽然是低代码风格但底层没有另起炉灶。它的技术栈是 Java 企业开发里最主流的那一套Spring Boot 做应用组装和依赖管理JPA/Hibernate 做对象关系映射Gradle 做构建和模块管理内置 Web 服务器数据库层兼容 PostgreSQL、MySQL、Oracle、H2 等常见选择。安全方面自带了基于角色的权限体系工作流引擎也内置在平台里。这个选型对 Java 团队的最大价值是学习成本曲线不陡峭。只要你会 Spring Boot 和 JPA 的基本用法理解 Axelor 只是把“注解”换成了“XML 声明”把“手动装配”换成了“模块化约定”。比起很多自研低代码平台动辄发明一套 DSL 和私有脚本语言Axelor 的规则更接近你已有的知识体系。权限模型值得一提。Axelor 的角色权限是配置在 XML 里的可以精细到“某个组对某个模型的某个视图是否有访问权”。这个能力在企业应用中几乎必用但如果自己写通常是拦截器加数据库表来回折腾。Axelor 直接把它作为平台能力提供菜单、按钮、字段级权限都能配。加上它开源你完全可以在「开源协议允许的范围」内把权限逻辑改成自己的实现——这不是商业产品那种只能点配置项的封闭玩法。2.3 哪些业务适合用、哪些场景别硬上明确边界才能选对工具。适合 Axelor Open Platform 的项目有共同特征实体数量多但字段结构规整、界面以表单和表格为主、业务流程依赖状态流转和审批、输出以报表和导出为主。典型如进销存、客户管理、项目管理系统、内部运营后台。这类系统的开发成本大头本来就花在 CRUD 界面上用元数据驱动能省掉一大半。不适合的场景也很清楚。第一是超高并发交易系统Axelor 的抽象层会带来额外开销你能直接写 JDBC 压榨性能为什么要绕一圈第二是需要大量自定义前端交互的产品——比如复杂图表联动、画布拖拽、实时协作编辑元数据生成的界面不足以支撑你最终还是要嵌自定义页面。第三是团队里没人懂 JPA 和 Spring Boot纯业务人员想靠拖拽搭系统Axelor 的 XML 配置对他们还是太硬核。我的建议是如果团队是 Java 背景项目是管理类系统Axelor 可以把交付周期压缩到传统方式的五到六成如果是产品型项目、交互要求高那就把 Axelor 当后台管理端的快速生成器核心业务另起炉灶。选型这事先看清楚边界比什么都重要。3. 在本地跑通最小业务系统模块创建、数据模型、视图菜单与权限3.1 创建模块从发行版压缩包到第一个业务模块Axelor Open Platform 的部署单位是 Gradle 项目业务功能以模块Module的形式挂载到平台上。常见做法是下载官方发行版后在modules目录下新建自己的业务模块然后在配置文件里登记模块名启动时平台就会加载它。先看模块目录的标准结构axelor-demo/ pom.xml或 build.gradle取决于发行版版本 modules/ demo-base/ src/main/ java/com/demo/base/ resources/ views/ # 界面 XML ># 登记业务模块 # 多个模块用逗号分隔模块名与 module.properties 中一致 axelor.modulesaxelor-core,axelor-human-resource,demo-base参数说明axelor.modules是模块加载清单顺序很重要——依赖其他业务模块时被依赖的要写在前面。这里把demo-base放在最后是因为它不依赖其他业务模块。module.properties里要声明模块名、版本、标题以及它依赖了哪些平台模块。第一次建模块时最容易踩的坑是忘了登记启动界面里永远看不到你的菜单。3.2 数据模型 XML把销售订单表定义出来现在定义一个最简单的业务对象“销售订单”。在resources/data-model/下新建DemoOrder.xmlmodel:model xmlns:modelhttp://www.axelor.com/ns/xml-models nameDemoOrder entityNamecom.demo.base.db.DemoOrder title销售订单 !-- 订单号业务主键必填且唯一 -- model:field nameorderNo title订单号 typeSTRING requiredtrue uniquetrue/ !-- 客户名称必填 -- model:field namecustomerName title客户名称 typeSTRING requiredtrue/ !-- 订单金额小数点后两位 -- model:field nameamount title订单金额 typeDECIMAL scale2/ !-- 状态下拉选择取值来自 selection -- model:field namestatus title状态 typeSELECT selectiondemo.order.status/ !-- 下单日期 -- model:field nameorderDate title下单日期 typeDATE/ /model:model字段参数说明name字段在 Java 实体中的属性名一般用驼峰命名会直接映射成数据库列名。type字段类型。STRING对应 varcharDECIMAL对应 BigDecimalSELECT是枚举型下拉框DATE是 java.time.LocalDate。required是否必填。设为 true 后界面保存校验和数据库约束会同时生效。unique是否唯一。订单号这类业务编号一定加上。scale对 DECIMAL 有效表示保留几位小数。selection对应一个枚举值集合集合需要在模型或配置里预定义。这个 XML 定义会被引擎解析成一个 JPA 实体类DemoOrderHibernate 会在启动时尝试创建或更新表。注意一点Axelor 不只是把 XML 当配置它会在构建阶段生成对应的 Java 类到 target 目录。所以你在 IDE 里写 Java Action 时引用的com.demo.base.db.DemoOrder是真实存在的类不是字符串。这里体现的是 Axelor 的“定义即实现”订单号唯一、金额精度、状态枚举全在一个文件里解决。相比传统开发里数据库脚本、实体校验、前端表单校验各写一遍的方式维护成本低得多。3.3 界面与菜单表单、表格、导航一起配好模型定义完下一步是告诉平台“用户怎么看到它”。在resources/views/下新建表单视图和列表视图!-- 表单视图新增和编辑订单时看到的样子 -- form title销售订单 modelcom.demo.base.db.DemoOrder actionGroupdemo.order.form.group onNewdemo.order.form.new !-- 订单号在编辑后不允许改所以设为 readonly -- field nameorderNo readonlytrue/ field namecustomerName width300/ !-- 金额用 decimal 组件展示支持千分位 -- field nameamount widgetdecimal/ !-- 状态字段渲染为下拉框 -- field namestatus widgetselect/ field nameorderDate widgetdate/ /form!-- 列表视图订单管理首页的表格 -- grid title销售订单列表 modelcom.demo.base.db.DemoOrder orderByorderDate desc field nameorderNo/ field namecustomerName/ field nameamount aggregatesum/ field namestatus/ field nameorderDate/ /grid视图配置的要点model必须是模型 XML 里entityName的全限定名大小写敏感。widget决定字段的交互控件。decimal让金额显示精确、支持汇总select让枚举字段渲染成下拉date是日期选择器。readonly常用于主键或业务编号防手滑改掉主数据。列表里的aggregatesum可以让表格底部自动显示金额合计这对业务人员非常实用。orderBy指定列表默认排序避免每次打开都要手动点排序。菜单也要单独定义否则功能藏在后台里没人能找到。在resources/menus/下创建菜单 XML把“销售订单”挂到一个业务菜单下menus xmlnshttp://www.axelor.com/ns/xml-menus !-- 一级菜单业务管理 -- menuitem namedemo-business-root title业务管理/ !-- 二级菜单点击后打开订单列表 -- menuitem namedemo-order-menu title销售订单 parentdemo-business-root actiondemo.order.list iconicon-list/ /menus菜单里的action指向一个视图 Action它定义了打开哪个视图、以什么模式打开。demo.order.list是框架根据列表视图自动注册的 Action 名称也可以在当前模块的views/Actions.xml里显式声明——建议显式写出来因为后期要加过滤条件或默认查询时你都得改 Action。最后是权限。默认情况下新建模块的所有视图只对admin组可见其他角色什么都看不到。需要在resources/security/下的权限配置文件里加一段security xmlnshttp://www.axelor.com/ns/xml-security !-- 对运营组开放订单的列表和表单访问权 -- object-view groupoperations modelcom.demo.base.db.DemoOrder namedemo.order.list valuetrue/ object-view groupoperations modelcom.demo.base.db.DemoOrder namedemo.order.form valuetrue/ /security这里的group是用户组名称name是视图 Action 名称valuetrue表示允许访问。不配置的话后台能进但菜单和界面都打不开这也是新手最常见的“我明明配了菜单为什么看不到”的原因。3.4 跑起来本地编译、启动与后台开箱模型、视图、菜单、权限都配齐后从命令行启动本地开发环境# 跳过单元测试编译并安装模块 ./gradlew build -x test # 启动内置 Web 服务器 ./gradlew run参数说明-x test跳过测试是为了本地快速迭代CI 环境不要省。run任务会启动内置服务器默认端口是 8080浏览器访问http://localhost:8080就能看到登录页。默认管理员账号在发行版文档里有说明首次登录后建议立刻改密码——很多团队把默认密码留在生产环境直到被扫到才处理。数据库默认使用本地 H2 文件库适合先跑通逻辑。要切到 PostgreSQL只需在主配置里改数据源参数spring.datasource.urljdbc:postgresql://localhost:5432/axelor_demo spring.datasource.usernameaxelor spring.datasource.passwordaxelor123 spring.datasource.driver-class-nameorg.postgresql.Driver提示切换数据库时要注意字符集。PostgreSQL 侧建议建库时使用 UTF8 编码连接串里显式加characterEncodingUTF-8不然中文乱码问题会浪费你一个下午。跑起来后在“销售订单”菜单里新增一条数据保存、再编辑、再列表汇总整套 CRUD 不需要写一行 Java 代码。到了这一步你已经完成了一次完整的元数据驱动开发循环——剩下的工作是往这个骨架里填真正的业务逻辑。4. 在视图背后加逻辑Action、附加点与审批流程4.1 在保存、字段变更时插入自己的 Java 代码CRUD 页面能跑只是开始真实业务总有“保存前校验客户信用”“金额超过阈值自动转审批”之类的规则。Axelor 的做法是写一个 Java Action 类然后在视图 XML 里绑定到保存或字段变更事件上。先看一个最典型的 Action 写法——保存前校验订单金额并自动设置状态package com.demo.base.web; import java.math.BigDecimal; import com.axelor.rpc.ActionRequest; import com.axelor.rpc.ActionResponse; import com.axelor.rpc.ActionHandler; /** * 销售订单相关业务逻辑 */ public class DemoOrderAction implements ActionHandler { Override public Object act(ActionRequest request, ActionResponse response) throws Exception { // 从请求中取出前端传入的字段值 BigDecimal amount (BigDecimal) request.getData().get(amount); String status (String) request.getData().get(status); // 校验订单金额必须大于 0 if (amount null || amount.compareTo(BigDecimal.ZERO) 0) { response.setError(订单金额必须大于 0); return response; } // 金额超过 10 万时自动把状态置为待审批 if (amount.compareTo(new BigDecimal(100000)) 0 draft.equals(status)) { response.setValue(status, pending); response.setInfo(订单金额超过 10 万已自动转入待审批); } return response; } }这个 Action 的逻辑很直白request.getData()拿到前端提交的字段映射校验不通过就调response.setError()中断保存校验通过但需要调整字段时用response.setValue()把新值回写到表单。setInfo会弹一条提示消息给操作员不会中断流程。绑定方式是在视图 XML 的字段或表单级事件上挂这个 Action!-- 金额变化时触发校验和状态联动 -- field nameamount onChangecom.demo.base.web.DemoOrderAction/!-- 保存前执行 -- form ... onSavecom.demo.base.web.DemoOrderAction/事件说明onChange在字段值变化并失焦时触发适合做实时联动onSave在点击保存按钮后、实际写入数据库前触发适合做校验。两者的执行顺序要心里有数onChange先于onSave如果字段级逻辑已经改过状态保存时的 Action 里读到的status已经是改过的值了——写逻辑时别假设前端字段的初始状态。4.2 把审批流程接进业务对象从草稿到完成Axelor 内置工作流引擎业务流程不需要拿状态字段硬编码。常见做法是给模型启用工作流定义“草稿 → 待审批 → 已通过 / 已驳回”的流程然后在 Action 里触发流程节点流转。流程配置一般分三步在模型 XML 或模型配置界面里启用“工作流支持”让业务对象具备流程状态属性。在线工作流设计器里画流程设置每个节点的名称、允许的操作提交、审批、驳回和流转目标节点。在界面按钮或 Action 中调用“启动流程”“提交”“审批通过”等操作。工作流最核心的价值是状态机从业务代码里剥离了。很多团队用“状态字段 if/else 判断”硬堆业务逻辑刚开始只有两三个状态还能撑等状态到七八个时改一个流转分支就要捋一遍所有 Service 方法。Axelor 的工作流把流转规则变成了可视化配置代码里只关心“我现在要执行哪个操作”。如果流程需要联动业务逻辑——比如审批通过后锁定订单、驳回后清空校验状态做法是在流程节点上挂 Java Action跟普通 Action 写法一样只是触发时机从“界面事件”变成“流程节点事件”。这也是我刚才强调 Action 模型统一的优势你不需要学两套写法。4.3 把业务结果输出报表、PDF 与 Excel 导出管理类系统的最后一步往往是把数据变成文件。Axelor 的处理方式不是内置一个报表设计器让你拖拽而是提供数据接口和模板的配合链路Java Action 里查询数据套用打印模板生成 PDF 或 Excel。导出逻辑同样走 Action// 伪代码示意查询符合条件的订单写入 Excel 响应 response.setValue(exported, true); // 注意实际导出通常通过平台提供的 report 服务完成 // Action 里负责组装查询条件和数据集。在视图上只需要给表单或列表加一个“导出”按钮绑定导出 Action员工点一下就能下载文件。要注意的是导出 Action 在数据量大时容易超时常见做法是先异步生成文件再通知下载而不是用户点了等同步响应。这在传统开发里也是老问题Axelor 下同样要提前规划。5. 避坑专题元数据驱动的 4 个高发问题与排查路径5.1 模型加了字段数据库和界面都没反应现象在模型 XML 里新增了字段重新编译启动后数据库表里没有新列表单界面也看不到这个字段。原因Axelor 对模型变更不是“启动时自动同步数据库结构”的傻瓜模式。模型解析成功后还需要执行模块更新升级脚本才会把表结构变更落到数据库。很多人只重启了应用没跑更新步骤。解决执行模块更新任务。命令行方式是./gradlew update -PupdateModuledemo-base或者在系统管理界面里找到模块管理对demo-base点“更新”。更新成功后数据库列就出来了。界面看不到字段则要检查视图 XML 里有没有把新字段加到form或grid——模型字段和视图字段是两回事加了模型不加快视图界面上就是空。提示执行更新前先备份数据库。虽然这个操作在多数场景是安全的但涉及已有数据的表加非空列时更新脚本可能因默认值缺失失败备份是自救的唯一办法。5.2 视图字段拼错一个名整个页面打不开现象点击菜单进入某个业务对象时页面空白或直接 500后台日志里报类似 “Field not found: xxx” 的信息。原因视图 XML 里某个field name...的名称与模型里的实际属性名不一致大小写或拼写差一个字母都算错。框架在解析视图时会严格校验字段归属遇到不存在的字段名直接抛异常不做容错跳过。解决先看日志里报错的具体字段名回到视图 XML 里搜索它对照模型 XML 改回正确的属性名。我习惯在写完视图后立刻做一次编译校验不要拖到运行期再试很多 IDE 的 XML 校验插件能提前发现这类错误。排查时还要注意如果视图里引用的字段属于关联对象格式必须是关联对象属性名.字段名少写一层也会报错。5.3 工作流配好了提交后状态却不流转现象业务对象启用了工作流界面也能打开流程设计器但点“提交”按钮后状态没变也没有任何报错提示。原因通常是流程触发器和界面操作没有对应起来。Axelor 的工作流不会自动接管你页面上的每个按钮必须在视图的按钮或 Action 里显式调用“提交”“通过”“驳回”等操作操作名要与流程设计器里定义的按钮标识完全一致。对不上时点击就变成了普通保存或直接没有响应。解决回到流程设计器确认每个节点的操作名称再打开视图 XML 检查按钮绑定的 Action 操作名是否一致。另外一个高发原因是流程状态字段没有被正确写入——在流程节点上挂的 Action 里如果手动setValue(status, ...)覆盖了流程引擎的状态值就会出现“数据变了但流程线没走”的诡异现象。流程流转应该交给工作流引擎去管理业务 Action 不要手动改状态字段。5.4 部署到服务器后中文乱码、连接超时一起来现象本地开发一切正常部署到某台 Linux 服务器后登录页就出现了中文乱码操作一会儿还会遇到数据库连接超时。原因两个独立问题叠在一起。乱码通常是数据库连接串没有指定字符集导致应用按 ISO-8859-1 读写 UTF-8 数据连接超时则是连接池配置过小加上服务器网络环境比本地复杂空闲连接被数据库端回收后连接池没有及时重建。解决连接串里显式加字符集参数比如 PostgreSQL 的?characterEncodingUTF-8如果数据库本身编码不对还要先重建库表为 UTF8。连接池方面在数据源配置里适当调大最大连接数并设置空闲连接检测# 数据源连接池调优示例 spring.datasource.hikari.maximum-pool-size20 spring.datasource.hikari.minimum-idle5 spring.datasource.hikari.idle-timeout300000 spring.datasource.hikari.connection-timeout30000参数说明maximum-pool-size是连接池上限建议根据应用并发数估算不是越大越好过大会占用数据库资源idle-timeout控制空闲连接多久被回收要和数据库端的wait_timeout配合设置否则会出现“连接被数据库杀了连接池还不知道”的情况。这类问题在本地很难复现全靠部署后的日志定位所以上线前把连接池参数调好比上线后排查省事得多。6. 进阶验证从“能跑”到“能扛”的三个动作6.1 交付前给核心接口做一轮冒烟压测元数据驱动的界面 CRUD 看起来很流畅但高并发下引擎的解析开销会暴露出来。我习惯在交付前用接口压测工具对订单列表、保存接口做一轮冒烟测试重点看两个指标并发 50 时的响应时间 P95以及数据库连接池是否被打满。如果 P95 超过 2 秒先看数据库慢查询日志再看视图有没有不必要的关联字段加载。很多时候问题不在框架而在视图 XML 里关联字段太多列表页一条数据带出了一堆关联查询。6.2 缓存配置字典表可以缓存业务表别乱开框架底层使用 JPA 缓存机制开启查询缓存对频繁读取且变更少的字典类数据有明显效果——比如状态枚举、客户等级这类数据。但业务表尤其是订单这种写入频繁的表不要为了“提升性能”盲目开二级缓存。写多读少的表启用缓存后缓存一致性维护成本很高经常出现“数据改了界面不变”的玄学问题。我给团队定的规矩是只有明确读多写少的参考数据才配置缓存业务数据一律走数据库实时查询。6.3 上线前固定一条自检命令我后来习惯把“模型变更后的标准动作”固化成一条命令链编译 → 更新模块 → 导出权限配置 → 重启。每次改完模型 XML先跑一次更新模块确认数据库结构同步再检查权限配置里有没有遗漏新视图的访问权。这个习惯在一次项目上线前救过我——当时夜里十点改了一个模型字段差点遗忘更新步骤直接重启如果那样第二天早上业务人员打开页面就会发现保存报错。元数据驱动的开发方式省了很多重复劳动但代价是“流程步骤不能被跳过”这件事没有代码生成器那么显眼。把它固化成肌肉记忆才真正吃到了这套框架的红利。希望帮到你。本文还有配套的精品资源点击获取