简介:《maximo入门培训》文档面向前期接触企业资产管理系统的开发与运维人员,围绕 Maximo 的技术架构与二次开发入门展开,适合需要从概念认知走向实际配置、编码的学习者。内容从 J2EE 架构与 RMI 对象交互讲起,串联程序结构、页面控件与界面开发、工作流模型与组件标记、后台任务配置及数据库连接维护,并延伸到 MboSet、Mbo、FldXX 等代码示例和常用类说明,目录层级较完整,便于按模块查阅与跟练。资源包共 1 个 docx 文件,约 436KB,以图文文档形式集中呈现培训要点,轻量便于通读和检索。目前已有 360 人学习,适合作为团队内训或自学 Maximo 的入门提纲,也能帮助读者快速建立从页面、工作流到后台任务和数据库配置的整体认识,并为后续定制开发打下基础。
1. 资源定位:maximo入门培训适合谁,不适合谁
maximo入门培训这份资料最容易被误读成产品说明书,实际更像一张二次开发地图:从 J2EE、RMI 到页面 XML、工作流、后台任务、数据库配置和 Mbo/MboSet 代码,把散落的入口串成一条能照着走的路径。它不教 Java 语法,也不替代现场数据模型梳理,但能让你知道一个需求该落在页面、工作流、Crontask 还是持久层。
适合已经接触过企业资产管理场景、却被 Maximo 的 jar 包、MAXPRESENTATION 表、工作流节点和 MboSet 继承关系卡住的人。新手可以按章节顺序走一遍,熟手更适合把它当索引:先定位模块,再验证事务、缓存和角色表达式这些容易翻车的边界。不适合指望复制一段代码就上线的人,因为 Maximo 的二开成败往往在配置变更、签名选项和数据库更新顺序上。
2. 程序结构、页面与数据库配置:从 businessobjects.jar 到应用程序设计器
2.1 程序结构:jar、war 与 MAXPRESENTATION 表怎么串起来
先把部署包看明白,再谈改代码。Maximo 的程序结构不是单一 Web 工程,而是由业务类、启动应用、前台应用、集成包、配置文件和资源目录拼起来的运行体。培训目录里列出的 businessobjects.jar、Lib、maximouiweb.war、mboejb.jar、mbojava.jar、mboweb.war、meajmsejb.jar、meaweb.war、META-INF、properties.jar、resources,基本覆盖了二开时最常打交道的落点。我的习惯是先画一张“谁加载谁”的图:mboweb.war 负责启动加载,maximouiweb.war 承接前台页面,businessobjects.jar 放业务对象和持久层逻辑,properties.jar 和 resources 管配置与资源。
| 模块 | 主要职责 | 二开关注点 |
|---|---|---|
| businessobjects.jar | 业务相关类、Mbo/MboSet 等 | 业务逻辑、持久层继承、包路径 |
| Lib | 类库资源 | 依赖冲突、版本对齐 |
| maximouiweb.war | Web 前台应用 | 页面请求、WebClientServlet |
| mboweb.war | 启动加载的 Web 应用 | MAXIMOStartupServlet、启动参数 |
| mboejb.jar / meajmsejb.jar | 集成相关包 | 远程调用、集成边界 |
| mbojava.jar | 自测试相关包 | 本地验证、排查辅助 |
| meaweb.war | 集成相关 Web 应用 | 集成页面与接口 |
| META-INF | 描述文件 | 部署描述符、打包信息 |
| properties.jar | 配置文件 | maximo.properties 等 |
| resources | 相关资源 | 样式、静态资源、资源文件 |
表现层的页面内容除登录验证外,大多由 XML 承载,XML 存储在 MAXPRESENTATION 表中,由 JSP 控制标签组件、components 组件和 JavaScript 共同生成页面,CSS 文件夹定义通用样式。这个结构决定了页面修改不是只改一个 JSP 文件:应用程序设计器里的拖放结果、签名选项、工具栏和选择操作菜单,最终都要落到对应的 XML 和表记录里。排查页面问题时,先确认改的是哪个应用、哪条 MAXPRESENTATION 记录、当前环境有没有缓存,再去怀疑控件本身。
实际动手时,我一般先核对部署目录和 jar 内容,避免在错误的包上改类。下面这组命令只用于本地或测试环境核对结构,不要直接在生产包上做替换。
# 在应用部署目录内核对模块位置,路径按现场部署调整 find . -maxdepth 3 \( -name "businessobjects.jar" -o -name "maximouiweb.war" -o -name "mboweb.war" \) # 查看业务包里是否存在目标包路径,先确认类到底在不在这个 jar unzip -l businessobjects.jar | grep "psdi/mbo" | head -20find的-maxdepth控制搜索深度,避免扫到日志和临时目录;unzip -l只列内容不解压,grep用来确认psdi.mbo这类包路径是否存在。代码块里的路径不是固定值,现场常见做法是把部署目录、补丁目录和自定义包目录分开核对。若类不在 businessobjects.jar 里,先查自定义 jar 是否进了 classpath,而不是急着改继承关系。
2.2 控制层启动链路:MAXIMOStartupServlet、MXServer 与 WebClientServlet
控制层的入口要抓住两个 servlet。mboweb 的部署描述符里,MAXIMOStartupServlet 的load-on-startup为 2,主要功能是读取 maximo.properties,并以 Properties 对象传给 MXServer 的 start 方法。MXServer.start(properties) 建立 MXServer 实例并初始化相关信息,MXServer 是系统服务和应用服务运行期间的上下文。系统服务包括数据连接池建立和管理、缓存实现、调用 MaximoDD 从数据库读取并加载数据字典、实例化系统服务和应用服务对象、远程应用服务定位、注册 RMI、MaxSession 线程管理;应用服务主要是与业务相关的 MBO。程序主要落在psdi.server.*,数据库连接、session、线程、数据对象加载、Mbo/MboSet 访问都在这个范围里。
maximouiweb 的部署描述符里,WebClientServlet 是核心 servlet,/ui/*匹配的 URL 都会映射到它,负责定义页面内容类型并调用 WebClientSession 处理。下面的 XML 片段来自培训材料里的部署描述符结构,用来理解启动链路,不是让你整段照抄到生产。
<!-- 启动 servlet:读取 maximo.properties 并交给 MXServer --> <servlet> <servlet-name>MAXIMOStartupServlet</servlet-name> <servlet-class>psdi.servlet.MAXIMOStartupServlet</servlet-class> <load-on-startup>2</load-on-startup> </servlet> <!-- 前台 servlet:/ui/* 请求进入 WebClientSession --> <servlet> <servlet-name>webclient</servlet-name> <servlet-class>psdi.webclient.servlet.WebClientServlet</servlet-class> <init-param> <param-name>char_encoding</param-name> <param-value>UTF-8</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>webclient</servlet-name> <url-pattern>/ui/*</url-pattern> </servlet-mapping>load-on-startup的数字决定启动顺序,数字越小越早加载;char_encoding设为 UTF-8 是常见做法,避免页面参数乱码;url-pattern的/ui/*决定了前台请求进入哪个 servlet。排查“页面能打开但数据不对”时,先分清楚是启动上下文没读到配置,还是 WebClientSession 处理阶段出了问题。启动阶段看 maximo.properties 和 MXServer 日志,请求阶段看 WebClientServlet 和页面 XML 记录,不要把两类问题混在一起查。
业务层与持久层的包也要分清:psdi.app.*定义业务对象 Mbo、MboSet,描述应用相关业务逻辑;psdi.server.*管理系统级服务;psdi.util.*放克隆 app、删除 app、HttpSession 管理、加密解密、客户化应用生成等工具;psdi.workflow.*放工作流逻辑;psdi.mbo.*放核心持久层操作和 OR 映射。二次开发时,业务规则优先落在psdi.app.*对应的 Mbo/MboSet,系统级扩展才去碰psdi.server.*。这个边界不清,后面很容易把一次简单字段校验写成全局服务改动,维护成本会很高。
2.3 页面开发:应用程序设计器与常用控件的落地步骤
页面开发的第一选择不是写 JSP,而是应用程序设计器。培训材料里明确提到它支持拖放,技术用户和非技术用户都能在不编辑代码的情况下配置应用,常见修改包括移动字段和部分、创建新字段、表和标签页,高级功能有创建或复制应用程序、定义签名选项、编辑工具栏和选择操作菜单。我一般把页面改动拆成四步:先确认目标应用和签名选项,再拖控件,接着绑定字段和查找,最后清缓存做一次回归。签名选项不是摆设,它会影响记录写入时的签名行为,生产环境尤其要先确认。
| 控件/配置 | 常见用途 | 关键参数 |
|---|---|---|
| 文本框 | 编辑短文本字段 | 绑定属性名、是否只读、长度 |
| 下拉列表 | 状态、类型选择 | 值列表、默认值、校验 |
| 表格 | 子表或列表展示 | 关系、列顺序、过滤条件 |
| 标签页 | 分组展示字段 | 页面结构、可见性 |
| 工具栏 | 操作入口 | 按钮签名、选择操作菜单 |
| 签名选项 | 记录变更签名 | 是否启用、签名范围 |
操作步骤可以按这个顺序走:进入应用程序设计器,选择目标应用,复制一份测试用应用或确认当前环境可回退;在画布上移动字段和部分,新增字段时先确认数据库属性已存在;给控件绑定属性名和查找关系;编辑工具栏和选择操作菜单;保存后清理缓存,用不同角色各打开一次页面。常见做法是先做只读展示,再做编辑,最后才加操作按钮。页面 XML 存在 MAXPRESENTATION 表里,改完不生效时不要只盯浏览器缓存,还要看应用缓存和签名选项是否把改动挡住了。
2.4 数据库配置:对象、属性、索引、关系与更新数据库
数据库配置是页面和工作流的地基。培训目录里的顺序是新建对象、创建对象属性、索引和关系,然后打开管理方式,应用配置变更,开始配置数据库。这个顺序不能乱:对象没建就加属性,属性没建就绑页面,关系没建就配工作流条件,后面都会以“看起来配了但运行不对”的形式返工。我通常先把对象和属性列成表,再决定索引和关系,最后统一做配置变更。
| 配置项 | 作用 | 落地注意 |
|---|---|---|
| 对象 | 定义业务实体 | 对象名与 Mbo/MboSet 对应 |
| 对象属性 | 定义字段和类型 | 类型、长度、默认值、是否必填 |
| 索引 | 提升查询与唯一性控制 | 先看现有查询条件,避免重复索引 |
| 关系 | 定义对象间关联 | 关系名要和页面、工作流表达式一致 |
| 管理方式 | 进入配置变更入口 | 测试环境先演练 |
| 更新数据库 | 把配置变更落到数据库 | 变更前备份,变更后验证 |
具体步骤是:打开管理方式,新建或选择对象,创建对象属性并确认类型,按查询场景建索引,按业务关联建关系;进入应用配置变更,确认变更范围后开始配置数据库;完成后再回到页面和工作流做引用验证。这里最容易翻车的是“只保存没应用变更”,页面设计器里能看到字段,数据库里却没有对应结构。另一种情况是关系名改了,页面和工作流表达式还引用旧名,运行时就变成空结果。我的习惯是每次数据库配置变更都留一张对照表:对象名、属性名、关系名、索引名、影响页面、影响工作流,回滚时按表查,比翻日志快。
3. 工作流开发:任务节点、条件分支与子过程的落地拆解
3.1 工作流模型:过程、活动、条件、角色与相关数据
工作流设计器用来为记录创建一系列路径,过程可以理解为一幅图,交互指引记录或用户执行步骤。培训材料把工作流定义拆成过程模型、活动、转换条件、相关数据、角色、需要激活的内部或外部程序。这个拆法很实用:过程模型决定图长什么样,活动是节点上的动作,转换条件决定往哪走,相关数据决定表达式能读到什么,角色决定任务分给谁,内部或外部程序决定节点是否触发扩展逻辑。很多人一上来就拖节点,拖完才发现角色没配、表达式字段不在当前对象上,最后只能返工。
我一般先写一句业务规则,再画图。例如“工单提交后进入审批,金额超过阈值走条件分支,审批拒绝退回原任务”。这句话里已经包含活动、条件、角色和相关数据。然后用工作流设计器建过程,先放开始和停止,再放任务和条件,最后补手动输入、子过程、交互和等待。角色表达式要尽量用当前对象上稳定存在的字段,不要依赖页面临时变量。工作流涉及的应用也要提前列出来,不然测试时找不到收件箱任务或人员组。
3.2 节点类型与标记:开始、停止、任务、条件、手动输入、子过程、交互、等待
培训材料对节点的规则写得很细,照着这些规则配,能少走很多弯路。开始节点表示过程开始,新建过程时画布上会放一个,任何过程只能有一个起点;停止节点标志工作流结束,记录脱离工作流控制,可以放多个;任务节点让用户指引记录路径,必须至少有一个连接引出来,业务规则需要对邮箱任务分配做肯定或否定响应时用它;条件节点根据记录信息自动指向,出来的连接必须有一个正向和一个反向,记录退出条件节点时由节点内 SQL 表达式解析真或假;手动输入节点允许用户从菜单选择下一步;子过程节点表示嵌入在另一个工作流过程中的完整过程,除正向线外还可引反向线,遇到停止节点后沿结束前走过的路线返回主过程,把终止逻辑原因带回主过程;交互节点必须有一个或多个进入操作线,只能有一个退出操作线,通过预定义选项把终端用户引导到特定问题解决路径,通常放在手动输入节点之前;等待节点用来创建对某个操作的特定反应,过程在节点处暂停,直到指定事件发生,再从单一退出点继续。
| 节点 | 关键规则 | 常见误用 |
|---|---|---|
| 开始 | 只能有一个起点 | 建多个开始导致路径混乱 |
| 停止 | 可多个,记录脱离控制 | 忘记放停止,过程无法结束 |
| 任务 | 至少一个输出连接 | 没有角色或表达式导致无人接收 |
| 条件 | 正向和反向连接都要有 | SQL 表达式字段不在当前对象 |
| 手动输入 | 用户菜单选择下一步 | 选项与后续节点不匹配 |
| 子过程 | 可引反向线返回主过程 | 子过程停止条件没设计好 |
| 交互 | 多进入、单退出 | 选项过多,用户不知道走哪条 |
| 等待 | 指定事件触发后单一退出 | 事件没注册,过程一直停着 |
这些规则里,条件节点和任务节点最容易出问题。条件节点的 SQL 表达式要能解析真或假,正向连接和反向连接不能少;任务节点的输出最多两个操作,一个正向对应接受,一个反向对应拒绝,输入可以有多个。任务分配里还有角色表达式,可以限制只有满足表达式时才分配到该角色,同一个任务可以用表达式确定分配对象,这对控制转发很有用。执行接受操作有两个选项:接受任务的所有人都接受才算任务接受,或只要任何一个人接受就算任务接受。这个选项不确认,测试时就会出现“有人点了接受但任务没往下走”的假象。
3.3 一次工单工作流实践:任务分配、表达式与接受操作
培训材料建议利用 demo 库中的工作流实例实践,查看工单工作流过程,修改后在工单中测试。原文示例过程名为 APPWFWO,这里按 demo 工单流程理解。我的做法是先复制一份过程,不改原示例,再按“开始—任务—条件—任务—停止”搭最小闭环。任务节点配置标题、描述、应用程序、时限、任务分配、角色表达式、接受操作和正反向输出。标题显示在图标下,描述说明任务,应用程序指定流程应用的应用,时限规定任务完成时间长度,超过时限任务回分配给升级角色。任务分配给角色,角色下的表达式限制满足条件才分配,接受操作选“所有人都接受”或“任一人接受”,输出操作最多正向和反向各一个。
| 任务节点参数 | 填写建议 | 验证方式 |
|---|---|---|
| 标题 | 用动作短句,别写内部代号 | 收件箱里能否一眼看懂 |
| 描述 | 写清输入和输出 | 测试人员按描述能操作 |
| 应用程序 | 选工单相关应用 | 从任务打开是否到正确页面 |
| 时限 | 按业务时限设置 | 超时后是否回到升级角色 |
| 任务分配 | 绑定角色,不直接绑人 | 换人后任务是否仍能分配 |
| 角色表达式 | 用当前对象稳定字段 | 不满足时是否不分配 |
| 接受操作 | 明确全员或任一人 | 多人接受时流程走向 |
| 正向/反向 | 接受走正向,拒绝走反向 | 拒绝后是否退回 |
测试时不要只用一个账号。至少准备提交人、审批人、升级角色三类人员,分别看收件箱、任务分配和流程历史。常见做法是先测正向,再测反向,最后测超时。正向看任务是否到达角色、接受后是否进入下一节点;反向看拒绝后是否回到预期节点;超时看时限到期后是否转给升级角色。表达式不生效时,先查字段是否在当前对象、值是否为空、角色下人员组是否包含测试人。工作流不是画完就结束,收件箱和任务分配才是验证入口。
3.4 工作流涉及的应用清单与排查入口
培训材料列了一组工作流涉及的应用:Actions 操作、Communication Templates 通信模板、Escalations 上报和自动触发、Inbox/Assignments Setup 收件箱设置、People 人员、Person Groups 人员组、Roles 角色、Workflow Application 工作流应用、Workflow Designer 工作流设计器、Workflow Inbox 工作流收件箱。这些应用不是背景知识,而是排查入口。任务不分配,先看 Roles 和 Person Groups;收件箱看不到,先看 Inbox/Assignments Setup;自动触发不对,看 Escalations;通知没发,看 Communication Templates;动作没执行,看 Actions。
我一般按“人—角色—收件箱—过程—动作”的顺序查。先确认人员是否在人员组,再看角色是否绑了人员组,接着看收件箱设置是否启用,然后看过程里的任务分配和表达式,最后看 Actions 和 Escalations 是否触发。这个顺序能避免一上来就改流程图画法。工作流设计器里能看到图,但图不等于运行态;运行态要靠收件箱、任务分配和日志验证。子过程返回主过程时,反向线带回来的终止原因也要在过程历史里看,别只看主过程是否停止。
4. 后台任务与 MboSet 代码:Crontask、Mbo、FldXX 的写法与边界
4.1 Crontask 的界面配置与 SimpleCronTask 骨架
后台任务开发分界面配置和代码开发。界面侧新建后台任务,配置相关参数;代码侧继承 SimpleCronTask,实现 init 和 cronAction。init 做参数初始化,cronAction 执行相应逻辑。培训材料给出的骨架很短,但现场落地要补三件事:任务类名能被加载、cronAction 不长时间占用线程、异常能进日志。我一般先在测试环境建一个只写日志的任务,确认调度器能跑,再往里加业务逻辑。
package maxdemo.cron; import psdi.server.SimpleCronTask; import psdi.util.MXException; public class CrontaskTest extends SimpleCronTask { @Override public void init() throws MXException { super.init(); // 读取界面配置传入的参数 // 在这里校验批次大小、任务名等参数,避免 cronAction 里才报错 } @Override public void cronAction() { // 执行后台逻辑,建议先写日志再处理数据 // 长时间循环要分段,避免占用调度线程 } }init在任务初始化阶段执行,适合做参数校验和资源准备;cronAction是实际执行入口,界面配置里的任务参数会通过父类上下文进入。类名要和在界面新建后台任务时填写的类一致,包路径要能被 classpath 找到。常见做法是先在 cronAction 里打印任务名和参数,再逐步加入查询和更新。不要把大批量数据一次性塞进一个循环,后台任务翻车多半不是逻辑错,而是执行时间过长把调度线程拖住。
4.2 MboSet 的继承关系与 getMboInstance
MboSet 是 Maximo 持久层的核心类,核心超类是psdi.mbo.MboSet。应用程序对象与 MboSet 类直接关联,创建对象时必须指定与对象关联的 MboSet 类。MboSet 类必须继承psdi.mbo.MboSet,实现psdi.mbo.MboSetRemote接口;必须定义构造方法;实现getMboInstance(MboSet arg0)方法,在该方法中返回 Mbo 类的实例。下面这个骨架来自培训材料里的 CustDemoMboSet 结构,补了注释和返回行对象。
package maxdemo.lesson1; import java.rmi.RemoteException; import psdi.mbo.Mbo; import psdi.mbo.MboServerInterface; import psdi.mbo.MboSet; import psdi.util.MXException; public class CustDemoMboSet extends MboSet implements CustDemoMboSetRemote { private static final long serialVersionUID = 3918526761961603733L; public CustDemoMboSet(MboServerInterface server) throws RemoteException { super(server); // 交给父类建立 MboSet 运行上下文 } @Override protected Mbo getMboInstance(MboSet owner) throws MXException, RemoteException { return new CustDemoMbo(owner); // 每个行对象对应一个 Mbo 实例 } }构造方法的MboServerInterface参数是服务器上下文入口,不能省;serialVersionUID用于远程序列化一致性,改类结构时要留意;getMboInstance的owner是当前 MboSet,返回的 Mbo 要绑定这个 owner。接口CustDemoMboSetRemote按远程约定声明,实际项目里要和部署、RMI 注册方式对齐。常见误用是只写 Mbo 不写 MboSet,或 getMboInstance 返回了错误的 Mbo 类型,运行时就表现为行对象方法找不到、字段访问异常。
4.3 Mbo 与 FldXX 的职责边界
Mbo 是行对象,负责单条记录的字段读写、状态判断和业务动作;FldXX 是字段级监听或校验类,负责某个字段的校验和联动。培训材料列了 Mbo 例子和 FldXX 例子,但现场最容易把两者混着写:在 Mbo 里做所有字段校验,或者在 FldXX 里改整条记录状态。我的边界是:跨字段、跨对象的业务规则放 Mbo 或 MboSet;单字段格式、范围、查找校验放 FldXX。下面是一段 Mbo 设置字段的示例,重点看空值判断、修改标记和清空写法。
public void setDemoValues(Mbo mbo) throws MXException, RemoteException { if (mbo.isNull("DESCRIPTION")) { mbo.setValue("DESCRIPTION", "由培训示例写入"); // 只在为空时写入 } mbo.setValue("STATUS", "WAPPR", 2L); // 标志位按现场访问控制配置取值 if (mbo.isModified("DESCRIPTION")) { mbo.setValueNull("CHANGEBY"); // 清空示例字段,避免残留旧值 } }isNull用来判断字段是否为空,setValue写入字段值,第三个参数是标志位,现场常见做法是按访问控制和校验要求取值,不要随手写 0;isModified判断字段是否被改过,setValueNull把字段置空。FldXX 的校验骨架通常先走父类校验,再读当前 Mbo 和字段值,不满足时抛业务异常。字段级校验不要做跨对象大查询,容易把页面保存拖慢;需要跨对象校验时,放到 Mbo 的 appValidate 或 MboSet 层,配合缓存和事务边界处理。
4.4 Mbo 与 MboSet 常用方法速查
培训材料列了一长串 Mbo 常用类和方法,包括 add、appValidate、canDelete、checkFieldAccess、clear、copy、delete、getXXXX(attributeName)、getInitialBaseLanguageString、getInsertCompanySetId、getThisMboSet、init、initialize、isModified、isModified(attribute)、isNew、isNull(attributeName)、isSelected、modify、rollbackToCheckpoint、setFieldFlag、setFlag、setValue、setValueNull、toBeAdded、toBeUpdated、toBeDeleted、toBeSaved,以及 MboSet 的 save、cleanup、close、commit。不要背签名,按场景记分组更实用。
| 分组 | 方法 | 用途与注意 |
|---|---|---|
| 新增与复制 | add、copy | add 建行对象,copy 复制现有记录,注意字段默认值 |
| 校验 | appValidate、checkFieldAccess | appValidate 做应用级校验,checkFieldAccess 查字段访问权限 |
| 删除 | canDelete、delete | 先判断可删再删,避免关系约束报错 |
| 读取 | getXXXX(attributeName)、getThisMboSet | getXXXX 读字段,getThisMboSet 拿当前 MboSet |
| 状态 | isModified、isModified(attribute)、isNew、isNull、isSelected | 判断修改、新增、空值、选中状态 |
| 写入 | setValue、setValueNull、modify | setValue 写值,setValueNull 置空,modify 标记修改 |
| 标志 | setFieldFlag、setFlag | 控制字段和对象标志,按现场约定取值 |
| 待处理 | toBeAdded、toBeUpdated、toBeDeleted、toBeSaved | 判断待新增、待更新、待删除、待保存 |
| 回滚 | rollbackToCheckpoint | 回到检查点,长事务要配合事务队列 |
| 保存与清理 | save、cleanup、close、commit | save 保存,cleanup 清理,close 关闭,commit 提交 |
事务处理上,Maximo 框架提供自动事务机制,长事务需要把相关方法纳入一个事务队列;缓存机制会在数据变化时自动重新加载;日志使用并扩充 Log4j,可以按所属制定日志方案;异常经过包装,给出友好处理机制。这些机制决定了代码写法:不要自己开数据库连接,不要绕过 MboSet 直接拼 SQL 改业务表,不要在 cronAction 里无限循环。保存后状态不对时,先看 toBeUpdated、toBeDeleted、toBeSaved 这些待处理标记,再看 save、cleanup、commit 的调用顺序。MboSet 的 save 是保存集合,cleanup 做清理,close 释放,commit 提交事务;顺序错了,日志里就会出现“值已经改了但数据库没变”的黑匣子现象。
5. 避坑与常见问题排查:五类翻车现场的现象、原因和解决
5.1 页面改了不生效:缓存、签名选项与 MAXPRESENTATION 记录
现象是应用程序设计器里已经移动字段或新增标签页,保存也提示成功,但打开应用还是旧布局,换浏览器、清浏览器缓存都没用。原因通常不在浏览器,而在应用缓存、页面 XML 记录和签名选项。页面内容由 XML 承载并存储在 MAXPRESENTATION 表中,设计器保存后还要确认当前环境是否刷新应用缓存;如果改的是生产签名应用,签名选项可能让某些修改在特定角色下不可见。另一种情况是改错了应用副本,测试打开的是原应用,不是复制出来的测试应用。
解决顺序是:先确认当前打开的应用名和设计器里编辑的应用名一致;再查 MAXPRESENTATION 表里对应记录是否更新;然后清理应用缓存并重新登录;最后用不同角色验证可见性。我的血泪经验是不要在设计器里连续改十几处再一起保存,改一处验一处,出问题能快速定位是哪次修改。页面 XML 不是普通静态文件,改完不生效时不要只盯 JSP,先把表记录、缓存、签名选项三件事排掉。
5.2 工作流任务不分配:角色表达式与人员组没对上
现象是工单提交后工作流在任务节点停住,收件箱里没有任务,流程历史显示任务已创建但无人接收。原因常见有三类:任务分配的角色下没有人员组,人员组里没有测试人;角色表达式引用了当前对象不存在的字段,表达式解析为假;接受操作选了“所有人都接受”,但只让一个人测试,流程自然不往下走。还有一种情况是时限和升级角色没配,超时后没有回退路径。
解决时先看任务节点的角色和表达式,再查 People、Person Groups、Roles 三个应用。人员要在人员组里,人员组要绑到角色,角色要出现在任务分配里;表达式字段要在当前对象上,值要能解析为真;接受操作要按测试人数选择全员或任一人。测试至少用提交人、审批人、升级角色三类账号各走一遍。工作流不是画完图就完事,收件箱和任务分配才是运行态入口。
5.3 后台任务跑不起来:类名、cronAction 与日志级别
现象是界面新建了后台任务,调度时间也到了,但业务数据没变化,日志里也没有明显报错。原因可能是任务类名填错、包路径不在 classpath、cronAction 里异常被吞掉,或者日志级别没开到能看见任务执行。后台任务继承 SimpleCronTask 后,init 和 cronAction 是入口,类名必须和界面配置一致;如果 cronAction 里只写业务逻辑不写日志,失败时就像黑匣子。
解决时先把 cronAction 简化成写一行日志,确认调度器能调到类;再逐步加查询和更新。检查类名、包路径、任务参数、日志配置,确认异常有没有被包装后丢掉。长任务要分段处理,避免一次跑太久影响调度线程。我的习惯是每个后台任务至少留三类日志:开始、处理条数、结束或异常。没有这三类日志,后台任务出问题只能靠猜。
5.4 数据库配置变更后报错:没应用变更或关系名不一致
现象是页面设计器里能看到新字段,保存记录时报“字段不存在”或“关系无效”;工作流条件里引用了新关系,运行结果为空。原因通常是只保存了对象和属性,没有应用配置变更、没有更新数据库;或者关系名改了,页面和工作流还引用旧名;索引建了但查询条件没变,性能问题被误判为功能问题。
解决时打开管理方式,按“对象—属性—索引—关系—应用配置变更—更新数据库”的顺序复核。变更前备份,变更后在测试环境用页面、工作流、后台任务各引用一次。关系名和属性名一旦被页面或表达式引用,就不要随手改;必须改时先搜引用点。数据库配置不是保存即生效,更新数据库这一步漏了,后面所有验证都是假的。
5.5 MboSet 保存后状态不对:事务、cleanup 与待处理标记
现象是代码里 setValue 后日志显示值已改,页面刷新却还是旧值;或者 save 之后记录状态不对,toBeUpdated、toBeSaved 标记和预期不一致。原因可能是没有走 save 或 commit,cleanup 调用过早,事务边界不对,或者长事务没有放进事务队列。MboSet 的 save、cleanup、close、commit 各有职责,顺序错了就会出现“改了但没落库”的假象。
解决时先看待处理标记,再核对 save、cleanup、commit 的调用顺序;长事务按框架建议纳入事务队列;不要绕过 MboSet 直接改表。日志里记录关键字段修改前后值和 save 结果,能快速判断是没保存还是保存后被回滚。MboSet 代码的边界是持久层操作,不要把页面逻辑、工作流状态判断全塞进来,否则一次保存失败会牵出多条链路。
6. 验证与进阶:用一条工单流程跑通配置、代码和数据库变更
最后一章不再铺功能,换成一条可重复的回归路径。我一般拿一条 demo 工单,从页面加一个展示字段开始,绑到工单应用;再配一个最小工作流,任务节点分给角色,条件节点按状态走正反向;然后建一个只写日志的 Crontask,确认调度器能调到;最后用 MboSet 示例在保存前后打日志。每一步都留验证点,不靠记忆。
| 验证项 | 操作 | 通过标准 |
|---|---|---|
| 页面字段 | 应用程序设计器加字段并保存 | 目标角色打开可见,缓存刷新后生效 |
| 数据库配置 | 建属性、关系并应用变更 | 页面引用不报字段或关系错误 |
| 工作流任务 | 提交工单到任务节点 | 收件箱出现任务,角色能接收 |
| 条件分支 | 构造满足和不满足表达式 | 正反向连接各走一次 |
| 后台任务 | 建 Crontask 并触发 | 日志有开始、处理条数、结束 |
| MboSet 保存 | 设置字段并 save | 页面刷新看到新值,待处理标记正确 |
进阶技巧是给每次变更留一张“影响面表”:页面应用、MAXPRESENTATION 记录、对象属性、关系名、工作流过程、Crontask 类名、MboSet 类名各一列,改完逐项打勾。这个习惯看起来笨,但能挡住大部分“改了页面忘了数据库”“改了关系忘了工作流”的返工。从那以后我每次动 Maximo 配置,都强制走一遍页面、工作流、后台任务、数据库和保存日志的回归,不再靠单个页面点两下就判断成功。希望帮到你。
本文还有配套的精品资源,点击获取