尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

泛微E9统一待办中心WebService接口集成实践指南

泛微E9统一待办中心WebService接口集成实践指南 简介面向需要对接泛微E9统一待办中心的开发人员这份PDF文档完整阐述了基于WebService的待办集成方案。内容涵盖services.xml接口配置、receiveTodoRequestByMap方法定义、Map结构参数说明如syscode、flowid、receivets等并给出SOAP请求XML及返回值示例可帮助异构系统快速接入统一待办中心实现各业务系统待办任务的集中展示。资源为1个PDF文件大小1.6MB便于随时查阅。已有4130人学习下载适合OA集成开发、系统对接及流程整合场景参考。1. 泛微E9统一待办中心的集成价值与适用场景企业上完泛微E9之后待办事项往往还散落在SAP、HR、ERP和自研系统里门户端的统一待办中心如果只展示OA内部流程价值就砍掉了一大半。泛微E9给出的方案是一组WebService接口让异构系统把待办数据主动推送进来由E9统一聚合、统一跳转、统一办结。这里的关键认知是统一待办中心的本质不是页面而是接口页面只是接口数据的消费者。这套接口文档的核心是OfsTodoDataWebService服务提供了 Map、JSON 两种格式的接收入口以及待办、已办、办结三态处理能力。真正值得深入研究的不是SOAP XML长什么样而是syscode隔离、receivets防覆盖、operType状态机这三件事。适合人群负责E9二次开发的集成工程师、企业门户拉通待办的项目实施人员以及需要把SAP工单、HR审批接入统一待办的研发。2. xfire 服务注册与五个核心接口的分工逻辑2.1 services.xml 注册三个不可改错的元素泛微E9的WebService基于XFire框架服务注册文件固定存放在/ecology/classbean/META-INF/xfire/services.xml。不要把这个文件理解成普通的Spring Bean配置XFire启动时会扫描这个XML动态生成WSDL并绑定HTTP路由。以文档给出的配置为例service nameOfsTodoDataWebService/name namespacewebservices.ofs.weaver.com.cn/namespace serviceClassweaver.ofs.webservices.OfsTodoDataWebService/serviceClass implementationClassweaver.ofs.webservices.OfsTodoDataWebServiceImpl/implementationClass /servicename决定了WSDL访问路径配置完成后通过http://E9服务器IP:端口/services/OfsTodoDataWebService?wsdl即可看到服务定义namespace必须与SOAP请求体里的xmlns保持一致否则XFire会直接抛出命名空间不匹配异常serviceClass是接口全限定名implementationClass是业务实现类。提示如果修改了services.xml需要重启Tomcat或对应的E9应用服务。XFire的配置加载发生在容器启动阶段热更新在这个文件上不生效生产环境改完务必确认服务注册日志。2.2 五方法矩阵按数据格式与业务动作划分接口文档给出了五个核心方法按传递格式分成 Map 和 JSON 两组按业务动作分成接收、转已办、转办结、接收异构系统流程四类。把它们放到同一张表里看分工逻辑会清晰很多方法名数据格式业务动作典型使用场景receiveTodoRequestByMapMap接收待办流程标准格式异构系统推送新待办processDoneRequestByMapMap处理待办流程变为已办异构系统同步审批完成动作processOverRequestByMapMap处理办结流程变为办结异构系统同步流程终结动作receiveRequestInfoByMapMap接收异构系统流程异构系统全量推送含已办/办结/已读状态receiveTodoRequestByJsonJSON接收待办流程JSON格式轻量客户端、ajax后台拼接场景这里需要区分processDoneRequestByMap和processOverRequestByMap前者是把待办变成已办流程还能继续流转后者是流程彻底结束。如果异构系统的业务对象没有办结概念只做挂起处理就不要调用办结接口否则在统一待办中心里流程会直接消失用户点不到详情。2.3 为什么XFire时代选择了Map而非实体对象XFire是JAX-RPC时期的产物对复杂对象序列化的支持远不如JAX-WS成熟。用MapString, String传递参数有三个现实原因第一所有异构语言生成的客户端都能把Map序列化成entry列表不需要各自维护一套DTO类型定义第二新增参数不影响已有客户端只要服务端 Map 里多取一个 key 即可这给接口迭代留下了空间第三E9的服务端实现里对所有key做循环读取代码可以写得非常统一。当然Map也有明显代价参数名拼写错误无法在编译期暴露且所有值都被当成字符串处理时间字段的格式要由双方约定。文档里的createdatetime、receivedatetime统一采用yyyy-MM-dd HH:mm:ss如果某个系统传了带时区的ISO格式E9侧解析会直接落库为空。3. 手工构造SOAP请求从curl验证到返回码语义3.1 用curl直接触发接口先绕过客户端代码不少人拿到接口文档后第一件事是写Java客户端但最稳妥的做法是先用手工SOAP请求验证服务连通性。以下是对应receiveTodoRequestByMap的最小请求体注意SOAPAction在XFire中通常可以留空服务端按请求体里的方法名路由curl -s -X POST http://192.168.1.100/services/OfsTodoDataWebService \ -H Content-Type: text/xml; charsetutf-8 \ -d receiveTodo.xmlreceiveTodo.xml的内容如下in0是XFire对MapString, String参数的固定包装名请求里的中文统一使用XML实体转义文档中#x67E5;#x770B;#x8282;#x70B9;即“查看节点”的Unicode编码?xml version1.0 encodingUTF-8? soapenv:Envelope xmlns:soapenvhttp://schemas.xmlsoap.org/soap/envelope/ xmlns:xsdhttp://www.w3.org/2001/XMLSchema xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance soapenv:Body receiveTodoRequestByMap xmlnswebservices.ofs.weaver.com.cn in0 entry key xsi:typexsd:stringsyscode/key value xsi:typexsd:string0001/value /entry entry key xsi:typexsd:stringflowid/key value xsi:typexsd:stringA00000000007/value /entry entry key xsi:typexsd:stringrequestname/key value xsi:typexsd:string员工请假流程_0001_-1_A00000000007_luffy/value /entry entry key xsi:typexsd:stringworkflowname/key value xsi:typexsd:string员工请假流程/value /entry entry key xsi:typexsd:stringnodename/key value xsi:typexsd:string查看节点/value /entry entry key xsi:typexsd:stringpcurl/key value xsi:typexsd:string/showtask.aspx?idA00000000007/value /entry entry key xsi:typexsd:stringappurl/key value xsi:typexsd:string/showtask.aspx?idA00000000007/value /entry entry key xsi:typexsd:stringcreator/key value xsi:typexsd:stringwld/value /entry entry key xsi:typexsd:stringcreatedatetime/key value xsi:typexsd:string2016-03-09 10:10:10/value /entry entry key xsi:typexsd:stringreceiver/key value xsi:typexsd:stringluffy/value /entry entry key xsi:typexsd:stringreceivedatetime/key value xsi:typexsd:string2016-03-10 10:10:10/value /entry /in0 /receiveTodoRequestByMap /soapenv:Body /soapenv:Envelopepcurl和appurl需要特别注意文档示例里给的是相对路径/showtask.aspx?idA00000000007但生产环境的统一待办中心在跳转时会根据E9的系统参数拼装完整域名。如果异构系统有自己的详情页这里应该传完整URL例如https://oa.example.com/thirdparty/todo/detail?idxxx。还有receiver字段必须传E9里的登录名原值不是显示名也不能传工号否则待办归属不到具体用户。3.2 operType 与 operResult一次调用的完整语义响应解析不能只看成功失败要把dataType、operType、operResult三个字段组合起来理解。文档给出的响应示例里operTypeAutoNew表示服务端推断这是一条新数据并自动创建operResult0却表示执行失败原因是message中提示“流程数据已存在”。字段取值含义dataTypeIsUse / OtherSys / WfType / WfData / SetParam数据归属类型WfData表示流程数据operTypeAutoNew / New / AutoEdit / Edit / Del / Check / Set服务端判定的操作类型Auto开头是自动推断operResult1 / 01成功0失败message文本具体错误或成功信息AutoNew和AutoEdit的区别值得展开当一条 flowid 首次推入时服务端自动走新建逻辑返回 AutoNew当相同的 flowid 再次推入服务端对比已有数据后走更新逻辑返回 AutoEdit。这也是文档示例里第二次调用返回AutoEdit且operResult1的原因。在实际排错中如果连续调用同一个 flowid 却一直返回 AutoNew说明请求里的requestname或receiver发生了变化导致唯一性匹配失败数据被重复创建。3.3 JSON 格式与泛微E9的ajax调用场景receiveTodoRequestByJson是receiveTodoRequestByMap的JSON版本适合前后端分离架构里由服务端拼装JSON直接推送也适合在泛微E9的自定义接口里通过ajax方式调用后端逻辑。泛微ecology9的ajax调用后端接口通常走ajax.do网关或自建Action外层系统可以把待办数据先写入中间表再触发E9的Action调用这个JSON接口{ syscode: 0001, flowid: A00000000008, requestname: 采购审批_0001_-1_A00000000008_wangwu, workflowname: 采购审批流程, nodename: 部门经理审批, pcurl: /showtask.aspx?idA00000000008, appurl: /showtask.aspx?idA00000000008, creator: zhaoliu, createdatetime: 2024-06-01 09:00:00, receiver: wangwu, receivedatetime: 2024-06-01 09:30:00 }JSON格式不涉及XML转义中文可以直接传输但接口的Content-Type必须是application/json或text/json。这里埋着一个常见的坑XFire对JSON格式的适配不是原生的多数E9版本是通过额外的JSON插件或服务端代码里手动JSONObject.parseObject完成的所以JSON的key顺序、字符串首尾空格都会影响解析结果。建议在调用方先做trim并把flowid、requestname、receiver三个字段设为无法为空的强校验任何异常都直接返回失败而不是静默丢弃。3.4 receiveRequestInfoByMap 与 isremark 状态位receiveRequestInfoByMap和前几个方法最大区别是多了isremark和viewtype两个状态位。isremark取值0、2、4分别代表待办、已办、办结viewtype取值0、1代表未读、已读。这个接口适合异构系统做全量同步比如SAP侧扫码后把单据状态推过来用一次调用替代三次状态流转。实际使用中有个容易混淆的点isremark为4的办结状态和processOverRequestByMap的办结是重叠的如果业务流程里已经用了processOverRequestByMap再次通过receiveRequestInfoByMap推送isremark4就会触发重复办结校验。文档中的响应示例operTypeCheck就是这种检测场景的返回值说明服务端在判定数据是否允许转换需要结合message看具体拦截原因。4. receivets 时间戳机制并发推送下的乱序覆盖防线4.1 问题来源两个线程先后调用同一流程异构系统推送待办往往不是单线程行为。一个流程在SAP里审批通过的同时E9的定时任务可能刚把旧的待办数据拉取进来或者异构系统两个节点几乎同时向统一待办中心推送同一 flowid 的不同步骤数据。如果没有时间戳控制后发请求的数据可能被先发的旧请求覆盖用户在门户里看到的步骤永远是旧节点。receivets字段就是用来解决这个问题的。文档说明里写得很明确客户端使用线程调用接口时根据此字段判断是否需要更新数据防止后发的请求数据被之前的覆盖。不传时服务端根据当前系统时间自动生成。要注意的是服务端不会无条件信任客户端传值最终写入时会上抛给最终数据比较所以这个字段必须保证在同一业务对象上是递增的。4.2 服务端比对逻辑与时间戳判定的边界服务端收到请求后会拿请求里的receivets与库中已有数据的receivets做比较新的时间戳大于旧的才允许更新否则直接丢弃请求内容并返回操作失败或返回旧的 AutoEdit 成功。这个机制有三个边界条件需要理解到位。同一条流程记录的判定维度是syscode flowid receiver requestname四个字段完全一致才认为是同一条数据其中requestname参与唯一性计算是很容易被忽略的。文档示例里 requestname 的拼接规则是流程标题_syscode_(-1)_flowid_接收人例如员工请假流程_0001_-1_A00000000007_luffy如果异构系统修改了拼接格式哪怕 flowid 相同也会被当成新数据生成两条重复待办。时间比较不是而是严格的大于相同时间戳的请求会被视作已处理避免重复消费。这要求调用方在同一个流程实例上生成严格递增的时间戳Python、Java 这类语言直接取毫秒即可毫秒相同的情况加一个自增序列后缀更稳妥。4.3 并发场景下的完整Java调用示例以下代码展示如何在一个线程池里对同一个 flowid 发起三次请求分别使用递增值模拟乱序场景。代码使用 JDK 原生的HttpURLConnection不依赖CXF或Axis的stub适合快速接入import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TodoPushClient { private static final String ENDPOINT http://192.168.1.100/services/OfsTodoDataWebService; static String buildSoap(String flowid, String receiver, long receivets) { String requestName 员工请假流程_0001_-1_ flowid _ receiver; return ?xml version\1.0\ encoding\UTF-8\? soapenv:Envelope xmlns:soapenv\http://schemas.xmlsoap.org/soap/envelope/\ xmlns:xsd\http://www.w3.org/2001/XMLSchema\ xmlns:xsi\http://www.w3.org/2001/XMLSchema-instance\ soapenv:Body receiveTodoRequestByMap xmlns\webservices.ofs.weaver.com.cn\ in0 entrykeysyscode/keyvalue0001/value/entry entrykeyflowid/keyvalue flowid /value/entry entrykeyrequestname/keyvalue requestName /value/entry entrykeyworkflowname/keyvalue员工请假流程/value/entry entrykeynodename/keyvalue查看节点/value/entry entrykeypcurl/keyvalue/showtask.aspx?id flowid /value/entry entrykeyappurl/keyvalue/showtask.aspx?id flowid /value/entry entrykeycreator/keyvaluewld/value/entry entrykeycreatedatetime/keyvalue2024-06-01 10:00:00/value/entry entrykeyreceiver/keyvalue receiver /value/entry entrykeyreceivedatetime/keyvalue2024-06-01 10:30:00/value/entry entrykeyreceivets/keyvalue receivets /value/entry /in0/receiveTodoRequestByMap/soapenv:Body/soapenv:Envelope; } static void post(String body) throws Exception { URL url new URL(ENDPOINT); HttpURLConnection conn (HttpURLConnection) url.openConnection(); conn.setRequestMethod(POST); conn.setRequestProperty(Content-Type, text/xml; charsetutf-8); conn.setDoOutput(true); try (OutputStream os conn.getOutputStream()) { os.write(body.getBytes(StandardCharsets.UTF_8)); } System.out.println(HTTP conn.getResponseCode()); conn.disconnect(); } public static void main(String[] args) throws Exception { String flowid A00000000007; String receiver luffy; ExecutorService pool Executors.newFixedThreadPool(3); // 乱序推送receivets 小的时间反而最后执行 pool.execute(() - { try { Thread.sleep(200); post(buildSoap(flowid, receiver, 300L)); } catch (Exception e) { e.printStackTrace(); } }); pool.execute(() - { try { Thread.sleep(50); post(buildSoap(flowid, receiver, 100L)); } catch (Exception e) { e.printStackTrace(); } }); pool.execute(() - { try { Thread.sleep(0); post(buildSoap(flowid, receiver, 200L)); } catch (Exception e) { e.printStackTrace(); } }); pool.shutdown(); } }这段代码里receivets被显式传入三个线程分别使用300、100、200的递增值并故意乱序执行。最终落库的节点信息取决于服务端对比后的最大值也就是先执行完的请求不一定生效receivets 为200的请求最后到达时会覆盖掉中间执行的100请求但无法覆盖最早的300请求。这演示了为什么要由调用方统一生成单调递增的时间戳而不是用System.currentTimeMillis()直接并发生成因为乱序执行时本地时间的先后不能代表业务数据的先后。提示如果业务上无法保证receivets单调递增建议调用方增加一个同步锁或使用数据库序列生成时间戳否则会出现“报文显示推送成功但门户里仍是旧节点”的诡异故障。4.4 requestname 拼接规则是重复数据的根源文档示例中 requestname 的完整值员工请假流程_0001_-1_A00000000007_luffy已经揭示了它的构造逻辑flowName _ syscode _ (-1) _ flowid _ receiver。这个拼接不是写死的而是由集成方在推送前生成。拼接规则的稳定性直接决定了服务端能否正确识别同一条流程。如果异构系统的流程标题会变化比如“员工请假流程-张三”在审批中被修改为“员工请假流程-李四”requestname 就会跟着变服务端会把同一 flowid 识别成两条数据。解决方法是让 requestname 始终使用业务单据号例如PUR-2024-0001_0001_-1_A00000000007_receiver从源头保证拼接前缀不随标题改变。5. 生产落地泛微E9待办集成的坑位清单5.1 常见报错与处理动作集成过程中遇到最多的三类问题如下报错或现象可能原因处理动作提示代码 -16 或 OA系统访问失败未走E9的授权认证或IP不在白名单确认服务地址是否带 ecology 前缀确认防火墙放行8080端口返回 operResult0message 提示数据已存在requestname 或 receiver 与库中不一致对比库中已有记录的requestname检查拼接规则返回 AutoNew 但门户看不到待办receiver 不是E9登录名或流程类型未启用用E9管理员账号在用户管理里查登录名原值接口返回正常但页面跳转404pcurl 和 appurl 传的是相对路径且未配置域名检查E9的系统参数中是否存在域名配置否则改用绝对URL-16这类错误码在E9里经常出现在外部系统集成场景本质是请求没有拿到合法的身份标识。E9的WebService默认不做登录态校验但如果中间有nginx反代或安全网关拦截就会出现访问失败。排查顺序是先绕过网关用IP直连确认服务存活再加Host头部测试最后才查业务参数。5.2 泛微e10迁移时的差异提醒泛微E10在接口风格上做了明显演进部分新项目使用RESTful API不再依赖XFire的services.xml配置。如果你正在用E9的接口文档去对接E10环境需要先确认对方提供的服务地址是services/OfsTodoDataWebService还是新版的/api/前缀。E10的待办集成更多走消息队列或OpenAPIMap格式的SOAP推送在新版本里不一定保留。老集成迁移时最稳妥的做法是保留E9环境作为待办汇聚层E10侧通过OpenAPI把数据推到E9而不是直接改报文格式。5.3 最小验证清单与最终建议完成联调后建议按以下清单做一轮收尾验证推送一条新流程确认响应operTypeAutoNew且operResult1修改节点名称后同flowid再推一次确认返回AutoEdit且门户展示新节点用不同receiver推同flowid确认生成两条独立待办连续推送相同请求确认不会产生重复数据调用processDoneRequestByMap后待办从待办列表消失且出现在已办列表对比调用方日志和E9日志确认receivets最大值最终落库日常维护中建议把 E9服务端OfsTodoDataWebServiceImpl的入参日志打开XFire默认会记录SOAP报文但实现类里新增字段时记得同步打印完整Map方便核对异构系统实际推送的key名称。泛微E9统一待办中心的集成核心不是把XML拼对而是把receivets的单调性、requestname的稳定性和receiver的原值传递这三件事管住待办数据就会稳定流转。本文还有配套的精品资源点击获取
返回列表