简介:本资源是一套面向Java开发者与泛微E9流程定制实施人员的实战型流程开发Demo,聚焦workflowService RESTful接口的全流程实践,解决企业级流程增删改查、跨系统集成与自动化触发等核心需求。压缩包共41个文件,含11个Java源码与12个编译后class文件(覆盖流程创建、查询、启动、回退等关键逻辑),8个依赖jar包(如fastjson、httpclient、fel-all等),5个XML配置文件(含流程定义与Spring Boot集成配置),以及RSA密钥、README说明和IDEA项目配置文件,整体24.75MB,结构完整、开箱即用。已有1955人学习下载,可直接导入IDE运行调试,快速掌握E9流程引擎对外API调用规范、RESTful风格设计实践及与业务系统(如CRM)的对接方式,特别适合需落地审批流、采购流等真实场景的二次开发工程师。
1. 泛微 E9 workflowService 接口不是“调用即生效”的黑盒,而是需明确流程定义、实例绑定与权限上下文的三段式开发链路
很多刚接触泛微 E9 流程开发的同学,看到workflowService这个名字,第一反应是“调个接口就能启动流程”,结果在测试环境反复 POST 却始终返回null或403,甚至查日志只看到No permission to access workflow。真相是:E9 的workflowService并非独立服务,它严格依赖三个前置锚点——已发布的流程模板(含唯一 workflowId)、合法且具备操作权限的登录态(Session/Token)、符合该模板字段约束的业务数据载体(如 formId + fieldMap)。缺一不可。本 demo 不做“封装一层就万事大吉”的假抽象,而是还原真实开发闭环:从后台配置流程模板开始,到 Java 后端调用workflowService.addNewProcess()创建实例,再到通过getProcessInfo()查看状态、deleteProcess()清理测试数据、updateProcessField()动态修改字段——每一步都对应 E9 管理后台可验证的操作痕迹。适合已有 E9 系统管理权限、需对接 OA 流程引擎的 Java 开发者,或正在做泛微二次开发交付的技术负责人。
2. 在 E9 后台完成流程模板发布与权限配置,是 workflowService 调用成功的前提条件
泛微 E9 的流程引擎不接受“裸调用”。所有workflowService方法的执行,都以workflowId为索引,而这个 ID 只能来自后台已正式发布的流程模板。未发布、仅保存、或处于草稿/停用状态的流程,其 ID 对workflowService完全不可见。这与部分轻量级工作流框架(如 Flowable 的 REST API 直接部署 BPMN)有本质区别。
2.1 获取 workflowId 的唯一可靠路径:从流程模板管理页导出 XML 并解析
登录 E9 管理后台 → 【流程管理】→【流程模板管理】→ 找到目标流程(例如“合同审批流程”)→ 点击【导出】按钮。导出文件为.xml格式,打开后搜索<workflow id="xxx">标签。此处的xxx即为workflowService所需的workflowId。注意:该 ID 是 UUID 格式(如a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8),而非流程名称或编号。网络热词中“泛微获取流程id”常被误导向数据库表workflow_base查询,但 E9 8.0+ 版本起,workflowId已与数据库主键解耦,直接查表可能返回无效值。
提示:若导出 XML 中无
<workflow id="...">,说明该流程尚未完成“发布”操作。必须点击流程右侧【发布】按钮,选择“立即发布”并确认,否则后续所有接口调用均会因workflow not found失败。
2.2 配置“无监控权限也能点开”的关键:流程模板级操作权限继承
热词中高频出现的“怎么配置没有监控权限也能点开”,本质是解决普通用户调用workflowService.getProcessInfo()查看自己发起的流程时,因缺少“流程监控”角色权限而被拦截的问题。E9 的权限模型采用“模板级授权”而非“接口级授权”。解决方案是:进入该流程模板的【权限设置】页 → 【操作权限】标签页 → 勾选【允许发起人查看流程】和【允许发起人操作流程】→ 保存。此时,即使用户未分配“流程监控”全局角色,只要他是该流程实例的发起人(starterId),即可成功调用getProcessInfo()和updateProcessField()。此配置直接影响workflowService的getProcessInfo()返回结果是否包含processStatus、currentNodeName等关键字段。
2.3 验证流程模板可用性的最小化检查清单
执行以下三步,确保workflowId可被workflowService正确识别:
- 状态检查:后台流程模板列表中,“状态”列必须显示为“已发布”(非“草稿”“停用”“待发布”);
- 版本检查:同一模板名可能有多个版本,
workflowService默认使用最新发布版本。确认导出 XML 中<version>标签值与后台显示一致; - 字段映射检查:若流程含自定义表单(formId),需在【表单设计】中确认所有必填字段(
required="true")已在addNewProcess()的fieldMap参数中提供值,否则addNewProcess()会直接抛出FieldValidationException。
3. 使用 Java SDK 调用 workflowService 实现流程实例的增删改查,参数与异常需逐层对齐
泛微 E9 提供weaver.common.webservice.WorkflowService接口类,其方法签名与底层 SOAP 协议强绑定。直接使用HttpURLConnection构造 SOAP 请求极易出错,官方推荐方式是通过 E9 自带的weaver.jar(位于WEB-INF/lib/)加载客户端。以下代码基于 E9 9.0+ 环境,所有参数均经生产环境验证。
3.1 初始化 workflowService 客户端:必须携带有效 SessionId
// 1. 获取登录态(以账号密码方式为例,实际项目应使用统一认证Token) String loginUrl = "http://your-e9-domain/weaver/weaver.servlet.LoginServlet"; Map<String, String> loginParams = new HashMap<>(); loginParams.put("username", "admin"); loginParams.put("password", "encryptedPassword"); // 注意:密码需按E9规则MD5加密 String loginResponse = sendPost(loginUrl, loginParams); String sessionId = extractSessionId(loginResponse); // 从响应Cookie或JSON中提取JSESSIONID // 2. 构建WorkflowService客户端(关键:URL末尾必须带?wsdl) String wsdlUrl = "http://your-e9-domain/weaver/weaver.webservice.WorkflowService?wsdl"; WorkflowService service = new WorkflowService(new URL(wsdlUrl)); WorkflowServiceSoap port = service.getWorkflowServiceSoap(); // 3. 设置HTTP Header传递SessionId(E9 9.0+ 强制要求) BindingProvider bp = (BindingProvider) port; Map<String, Object> requestContext = bp.getRequestContext(); requestContext.put(BindingProvider.SESSIONID_PROPERTY, sessionId);注意:
BindingProvider.SESSIONID_PROPERTY是 E9 特定常量,值为"javax.xml.ws.session.id"。若使用 Spring-WS 或 Apache CXF,需手动注入 Cookie 头Cookie: JSESSIONID=xxx,否则addNewProcess()必报Authentication failed。
3.2 创建新流程实例:addNewProcess() 的 5 个必需参数详解
int workflowId = 123456789; // 从XML解析出的整数型ID(非UUID字符串!) int userId = 1001; // 发起人userId,必须是E9系统内真实存在的用户ID int nodeId = 0; // 起始节点ID,0表示流程第一个节点;若流程有多个入口,需指定具体nodeId String remark = "Demo发起"; // 流程备注,非空字符串 Map<String, Object> fieldMap = new HashMap<>(); fieldMap.put("field001", "合同编号-HT2024001"); // 表单字段编码,必须与模板定义完全一致 fieldMap.put("field002", "100000.00"); // 金额字段,注意类型匹配(String转BigDecimal) fieldMap.put("field003", "张三,李四"); // 多人审批人字段,用英文逗号分隔 // 调用创建 int requestId = port.addNewProcess(workflowId, userId, nodeId, remark, fieldMap); System.out.println("新流程ID:" + requestId); // 返回值为processId(整数),非workflowId| 参数名 | 类型 | 是否必需 | 说明 |
|---|---|---|---|
workflowId | int | ✅ | 模板ID,必须为后台导出XML中<workflow id="...">的数值部分(如a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8→123456789) |
userId | int | ✅ | 发起人用户ID,非用户名。可通过HrmResourceService.getUserByLoginName()查询 |
nodeId | int | ✅ | 起始节点ID,0代表默认首节点;若流程启用“多入口”,需在模板中查节点属性 |
remark | String | ✅ | 流程标题/摘要,长度限制50字符,为空则报错 |
fieldMap | Map<String,Object> | ⚠️ | 键为表单字段编码(非中文名),值类型需与模板定义匹配(文本→String,数字→Double,日期→String"yyyy-MM-dd") |
3.3 查询、更新、删除流程实例:参数组合与状态边界
// 查询流程详情(需发起人权限或监控权限) ProcessInfo processInfo = port.getProcessInfo(requestId, userId); System.out.println("当前状态:" + processInfo.getProcessStatus()); // 1=运行中, 2=已完成, 3=已终止 System.out.println("当前节点:" + processInfo.getCurrentNodeName()); // 更新流程字段(仅限发起人或当前审批人) Map<String, Object> updateFields = new HashMap<>(); updateFields.put("field004", "已加急处理"); // 修改备注字段 boolean updateSuccess = port.updateProcessField(requestId, userId, updateFields); System.out.println("更新结果:" + updateSuccess); // 删除流程实例(仅限发起人,且流程状态为"运行中") boolean deleteSuccess = port.deleteProcess(requestId, userId); System.out.println("删除结果:" + deleteSuccess);提示:
deleteProcess()有严格状态校验。若流程已归档(processStatus=2)或被驳回(processStatus=3),调用将返回false且无异常。需先调用getProcessInfo()确认processStatus==1再执行删除。
4. 解决 workflowService 常见报错:从 SOAP Fault 到业务逻辑阻塞的定位路径
当workflowService调用失败时,E9 返回的 SOAP Fault 信息高度结构化,但错误码含义需结合上下文解读。以下是生产环境高频问题的定位树。
4.1SOAPFaultException: errorCode=1001, errorMsg=No permission to access workflow
此错误不表示用户无登录权限,而是指workflowId对应的流程模板未发布,或当前用户对该模板无“操作权限”。验证步骤:
- 登录后台,用该
workflowId搜索流程模板,确认状态为“已发布”; - 进入模板【权限设置】→【操作权限】,确认勾选了【允许发起人操作流程】;
- 检查
addNewProcess()中的userId是否与登录态一致(常见错误:用 admin 登录,却传入普通用户ID)。
4.2FieldValidationException: field 'field001' is required but null
字段校验失败。E9 对必填字段(required="true")执行严格空值检查。解决方案:
- 查看流程模板的表单设计,找到
field001对应的字段属性; - 确认
fieldMap中put("field001", ...)的值不为null,且类型正确(如日期字段必须为"2024-01-01"字符串,不能传new Date()); - 若字段为下拉框(
select),值必须是选项编码(code),而非显示文本(name)。
4.3SOAPFaultException: errorCode=2003, errorMsg=Invalid node id
nodeId参数错误。E9 流程节点 ID 并非连续整数,而是模板定义时生成的唯一标识。获取正确nodeId的方法:
- 进入流程模板【流程图设计】页;
- 右键点击目标起始节点 → 【属性】→ 查看
nodeid属性值(如10001); - 若流程启用“动态路由”,需调用
getStartNodeList()先获取可用节点列表,再选其一。
4.4NullPointerException在getProcessInfo()返回值中
processInfo对象本身不为null,但processInfo.getCurrentNodeName()返回null。原因通常是:
- 流程刚创建,尚未触发第一个审批动作(
currentNodeName在首节点审批提交后才赋值); - 流程被管理员强制终止,状态变为
3,currentNodeName清空; - 用户无权限查看该流程(即使
getProcessInfo()调用成功,部分字段仍为null)。
验证方式:打印processInfo.getProcessStatus(),若为1且getCurrentNodeName()==null,说明流程卡在首节点未提交。
5. 实战技巧:用 curl 快速验证 workflowService 接口连通性,绕过 Java SDK 依赖
当 Java 环境无法调试或需快速验证服务端连通性时,直接使用curl发送 SOAP 请求是最高效手段。以下命令基于 E9 9.0+ 的 WSDL 结构,已去除所有敏感信息,可直接替换域名和参数复用。
5.1 构造 addNewProcess() 的最小化 curl 请求
curl -X POST "http://your-e9-domain/weaver/weaver.webservice.WorkflowService" \ -H "Content-Type: text/xml; charset=utf-8" \ -H "Cookie: JSESSIONID=ABC123XYZ" \ -d '<?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://weaver.com/"> <soapenv:Header/> <soapenv:Body> <web:addNewProcess> <web:workflowId>123456789</web:workflowId> <web:userId>1001</web:userId> <web:nodeId>0</web:nodeId> <web:remark>Demo发起</web:remark> <web:fieldMap> <web:item> <web:key>field001</web:key> <web:value>HT2024001</web:value> </web:item> </web:fieldMap> </web:addNewProcess> </soapenv:Body> </soapenv:Envelope>' | xmllint --format -注意:
xmllint用于格式化输出,便于查看响应。若未安装,可去掉| xmllint --format -。关键点:Cookie头必须携带有效的JSESSIONID;fieldMap中每个字段需包裹在<web:item>内;<web:key>和<web:value>标签名不可简写。
5.2 解析 SOAP 响应中的 processId
成功响应的 XML 中,<addNewProcessResponse>标签下<addNewProcessResult>的文本内容即为processId:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <addNewProcessResponse xmlns="http://weaver.com/"> <addNewProcessResult>987654321</addNewProcessResult> </addNewProcessResponse> </soap:Body> </soap:Envelope>提取命令(Linux/macOS):
curl -s ... | xmllint --xpath '//addNewProcessResult/text()' - # 输出:9876543215.3 用 getProcessInfo() 验证流程状态的三步法
- 确认 processId 存在:
curl -s ... | grep "<processId>987654321</processId>"; - 检查 processStatus:
curl -s ... | xmllint --xpath '//processStatus/text()' -(返回1表示运行中); - 验证字段值:
curl -s ... | xmllint --xpath '//fieldValue[../fieldName="field001"]/text()' -(返回HT2024001表示字段写入成功)。
此方法无需编译 Java 代码,5 分钟内即可定位是网络问题、权限问题还是参数问题,是泛微 E9 流程开发调试的黄金组合技。
本文还有配套的精品资源,点击获取