ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

泛微OA e-cology 8 Webservice接口调用指南:DocService与WorkflowService实战

泛微OA e-cology 8 Webservice接口调用指南:DocService与WorkflowService实战 简介面向泛微OA e-cology 8开发者的webservice接口文档主要针对文档管理模块的接口集成需求。文档首先介绍了接口在服务器上的部署流程包括在services.xml中添加DocService服务配置、重启服务并通过浏览器访问wsdl地址来确认部署状态。随后详细说明了login、createDoc、updateDoc、deleteDoc、getDoc、getDocCount、getList等接口方法的参数、返回值与功能覆盖登录验证、文档创建、修改、删除、查询及列表统计等典型操作。同时文档对DocInfo文档对象的核心属性进行了完整说明包括文档ID、类型、标题、编号、版本、状态、主目录、分目录、子目录、部门、语言等字段并解释各字段的含义和取值方便开发者正确构造请求数据。资源以单个docx文件提供大小约330KB内容紧凑便于查阅。已有6765人学习下载对进行泛微OA接口二次开发或系统集成的技术人员具有直接参考价值。1. 泛微OA数据孤岛用 webservice 接口文档拆掉第一堵墙老牌的泛微OA e-cology 8 在国企、制造、地产项目里存量很大多数跑在 Tomcat xfire 这套老容器上。到了要接周边系统的时候问题就来了HR 系统要批量同步新闻公告ERP 要往 OA 里推文档移动端要查文档详情DBA 和集成工程师发现官方给的接口文档往往只有一页方法列表没有可落地的调用示例、没有字段边界说明。这份e-cology 8 的 webservice 接口文档正好补上这块文档服务 DocService 覆盖了登录、创建、修改、删除、查询、分页列表工作流服务 WorkflowService 覆盖了流程检索和提交。适合做第三方系统集成的开发、实施顾问、系统运维参考直接基于 WSDL 生成客户端即可用。下文从部署开始到 Java 调用、参数边界、附件处理逐层给出可直接抄走的方案。2. xfire 容器上部署 DocServiceservices.xml 与 wsdl 自检2.1 部署前先看清 xfire 容器结构泛微 e-cology 8 的 webservice 是基于 XFire 1.2.6 实现的所以服务注册不是 Spring 那套注解扫描而是集中在Ecology/classbean/META-INF/xfire/services.xml这个文件里。要新增一个 webservice 接口本质就是在这个 XML 里注册一个service节点。这里有一个常见路径误区很多实施同事习惯去WEB-INF下找配置文件但 xfire 的服务声明不会出现在 web.xml 里它只负责 servlet 映射。文档服务的配置文件路径是固定的不要改到别处。2.1.1 检查 services.xml 里是否已有 DocService打开services.xml找到service节点列表检查是否存在name为DocService的配置。如果没有直接把原文给的 service 块追加到services标签内部。其关键属性如下name决定最终访问 URL 中的服务名即/services/DocService。serviceClass必须是weaver.docs.webservices.DocService这是接口类。implementationClass必须是weaver.docs.webservices.DocServiceImpl这是实现类。如果写错或漏写部署后调用会直接抛ServiceClassNotFound。serviceFactory固定用org.codehaus.xfire.annotations.AnnotationServiceFactory不要换成 Spring 的否则启动会因找不到 XFire 注解工厂而报错。追加完成后重启 Tomcat 服务。注意 e-cology 8 的 Tomcat 路径一般是Ecology/tomcat重启不只是重载应用需要完整停止再启动因为 XFire 的 services.xml 只在启动时扫描一次。2.2 wsdl 自检与常见部署失败部署完成后在浏览器输入http://OA地址/services/DocService?wsdl能正常返回 XML 形态的 WSDL 文档即表示服务注册成功。这里网页上看到的 WSDL 是 XFire 动态生成的里面会列出login、createDoc、updateDoc、deleteDoc、getDoc、getDocCount、getList这些方法名和参数类型。如果输入地址后报 404优先看以下三点第一Tomcat 是否成功加载了classbean/META-INF/xfire/services.xml。可以在启动日志里搜索DocService有Deploying service字样才是加载成功。第二接口类DocService.class是否在Ecology/WEB-INF/classes或对应的 jar 包里。第三URL 大小写。/services/DocService中 D 和 S 是大写手滑写成小写在跨系统对接时经常查半天。实际集成中更常见的场景是同一个services.xml里既有 DocService 又有 WorkflowService两个名称不能重。曾经遇到过一个项目在追加时把 WorkflowService 的 namespace 误填成http://localhost/services/WorkflowService导致调用时 SoapAction 与 WSDL 不一致客户端报No such operation。这个文件里 namespace 的约定不是统一规则按各 service 原样抄即可。3. DocService 方法拆解登录、文档增删改查与分页3.1 七个方法的调用契约DocService 对外暴露的方法不多但每个方法的参数和返回值的语义需要先对齐否则容易把“返回 1”当成布尔值用。结果如下表方法参数返回值用途loginloginid, password, logintype, ipaddressString Session码登录验证所有后续方法都要带上返回的 sessioncreateDocDocInfo docinfo, String sessioncodeint1成功/0失败创建文档updateDocDocInfo docinfo, String sessioncodeint1成功/0失败修改文档deleteDocint id, String sessioncodeint1成功/0失败按 ID 删除文档getDocint id, String sessioncodeDocInfo按 ID 取文档对象包含内容和附件getDocCountString sessioncodeint获取有权限访问的文档数量getListString sessioncode, int page, int pagesizeDocInfo[]分页获取文档数组不含内容和附件login返回的 Session 是后续所有方法的必传参数这点与泛微其他接口风格一致session 未传或已过期时服务端返回 0 或空数组不抛异常。集成时需要捕获空值做判断不能用返回值为 null 作为异常条件。3.2 login 返回值其实是会话令牌login的第三个参数logintype决定验证方式0 是数据库内建的密码验证1 是动态密码2 是 LDAP 验证。一般第三方系统集成用 0 就够了。第四个参数ipaddress传发起请求的服务 IP。这里有一个需要注意的细节login虽然是返回字符串但这个字符串不是一个简单的随机数而是由服务端生成的 session 标识它的有效期受服务端会话策略限制。e-cology 8 默认的会话超时时间是 30 分钟如果第三方系统是定时任务批量同步建议每次同步前先调用一次login刷新 session不要复用上一次的。3.3 getList 分页实现getList的每次调用需要传入页码、每页条数返回当前页的文档对象数组。与一般的 REST 分页不同这个接口只支持页码翻页不支持基于游标或时间条件的增量查询。做增量同步时常见方案是先调getDocCount拿总数再按固定页大小循环拉取。要注意getDocCount返回的是当前登录用户有权限看到的文档数这个权限是从 OA 的文档目录权限体系里带出来的。也就是说login用的账号是哪个其能看到的文档范围就由该账号在 OA 里的目录权限决定。4. DocInfo 对象创建一条文档需要填哪些字段4.1 从外部系统视角看 DocInfoDocInfo是整个文档服务的核心数据结构字段非常多涉及文档属性、创建人、审批人、附件、自定义字段等。外部系统创建文档时实际上不需要全部字段但有四个字段没有填就直接返回 0docSubject文档标题必填。maincategory、subcategory、seccategory主目录、分目录、子目录的 ID三级目录可以逐级选但至少主目录要传对。docStatus文档状态1 是正常其他状态按业务需要设置。ownerid文档所有者用户 ID决定这条文档归谁管也影响后续谁能看到。比较容易被忽略的是docCreaterType与docCreaterId的关系。在 OA 里创建人可能是人类型 0也可能是外部集成账号类型 1。外部系统用服务号登录时这里建议明确传doccreatertype0因为很多老版本的权限模块对类型 1 的兼容不完整传了之后文档列表里会出现创建人为空。4.2 附件字段的 Base64 传输要求DocAttachment对象中有一个关键字段filecontent它存放的是附件文件内容的 Base64 编码。这是因为 SOAP 协议的文本传输限制二进制必须编码后放在 XML 里传。filerealpath字段是附件在服务器上的绝对路径创建文档时如果传了filerealpath服务端会直接读取该路径的文件作为附件内容如果没传路径就必须确保filecontent非空。这里有一个优先级容易混淆filecontent与filerealpath同时存在时以filecontent为准。实践中的做法是如果附件文件已经上传到 OA 服务器本机的某个共享目录例如d:\\uploads\\xxx.doc直接传路径省流量否则传 Base64 内容。isextfile字段标记该附件是否为 Office 文档内容附件1 表示是扩展附件。iszip表示文件内容是否经过 zip 压缩创建时如果手动压缩过要置 1否则服务端解压时会抛异常。4.3 自定义字段的传递方式DocCustomField数组用来承载文档目录下自定义的字段值。每个元素需要填fieldid、fieldshow、fieldvalue。外部系统第一次对接时最稳妥的方式是在 OA 后台查看文档目录设置里各字段的 ID不要依赖字段名称匹配。调用createDoc时fieldvalue使用字符串类型数字和日期也要转成字符串传。需要注意fieldhtmltype为checkbox或select类型的字段服务端要求传入的是选项的数据库值而不是显示名称。5. Java 客户端调用从登录到创建文档与保存附件5.1 生成客户端代码Java 调用 XFire 服务最省事的方式是用wsdl2java直接从 WSDL 生成客户端桩代码生成后项目里会出现DocServiceLocator、DocServicePortType、DocInfo、DocAttachment等类。如果公司用的是 Axis 1.4也可以用org.apache.axis.wsdl.WSDL2Java生成但生成出来的包名和类型可能有差异。笔者更推荐 XFire 自带的生成工具因为类型与 e-cology 服务端完全一致少一层转换。生成的客户端代码中DocServiceLocator提供getDocServiceHttpPort(URL)方法其中 URL 参数直接传服务的 wsdl 地址。5.2 完整调用链路示例以下代码演示从登录到创建一篇带附件的 HTML 文档再按文号查询并保存附件到本地import java.io.*; import java.net.URL; import org.apache.axis.encoding.Base64; import weaver.docs.webservices.DocAttachment; import weaver.docs.webservices.DocInfo; import localhost.services.DocService.DocServiceLocator; import localhost.services.DocService.DocServicePortType; public class DocWsClient { private static String serviceUrl http://192.168.7.200:8080/services/DocService; private static DocServicePortType service; public static void main(String[] args) throws Exception { service new DocServiceLocator().getDocServiceHttpPort(new URL(serviceUrl)); // 登录logintype0 表示数据库验证 String session service.login(integration01, pass123, 0, 127.0.0.1); System.out.println(session session); // 构造附件对象 DocAttachment da buildAttachment(d:/tmp/需求说明.pdf, 需求说明.pdf); // 构造文档对象 DocInfo doc new DocInfo(); doc.setId(0); doc.setDocType(2); // 2 表示 Office/PDF 文档1 表示 HTML 文档 doc.setDocSubject(第三方系统推送入档-需求说明); doc.setMaincategory(38); // 主目录 ID doc.setSubcategory(53); // 分目录 ID doc.setSeccategory(204); // 子目录 ID doc.setOwnerid(111); // 文档所有者用户 ID doc.setDocStatus(1); // 正常状态 doc.setDocContent(由外部系统生成用于测试 webservice 创建文档.getBytes(UTF-8)); doc.setAccessorycount(1); doc.setAttachments(new DocAttachment[]{da}); int result service.createDoc(doc, session); System.out.println(create result result); // 按 ID 获取文档并解析附件 DocInfo remoteDoc service.getDoc(32194, session); for (DocAttachment remoteDa : remoteDoc.getAttachments()) { byte[] content Base64.decode(remoteDa.getFilecontent()); File outFile new File(d:/output/ remoteDa.getFilename()); try (FileOutputStream fos new FileOutputStream(outFile)) { fos.write(content); } System.out.println(saved: outFile.getAbsolutePath()); } // 分页获取列表 DocInfo[] list service.getList(session, 1, 10); System.out.println(page1 size list.length); } private static DocAttachment buildAttachment(String filePath, String fileName) throws IOException { File f new File(filePath); byte[] fileBytes; try (FileInputStream fis new FileInputStream(f); ByteArrayOutputStream bos new ByteArrayOutputStream()) { byte[] buf new byte[1024]; int len; while ((len fis.read(buf)) ! -1) { bos.write(buf, 0, len); } fileBytes bos.toByteArray(); } DocAttachment da new DocAttachment(); da.setDocid(0); da.setImagefileid(0); da.setFilename(fileName); da.setFilecontent(Base64.encode(fileBytes)); da.setFilerealpath(filePath); da.setIsextfile(1); da.setIszip(0); // 未压缩 da.setDocfiletype(3); // 其他文件类型 return da; } }逻辑说明login返回的 session 不判断空直接作为后续方法参数。若 session 为空串后面调用会静默失败所以生产代码里建议判空并抛出明确异常。DocInfo的doccontent字段是文档正文对 HTML 文档直接放 HTML 源码对 Office 文档放网页正文或不放。上面示例用 UTF-8 字节数组是 e-cology 8 客户端生成的类型要求。buildAttachment方法中filecontent传的是 Base64 后的内容文件较大时注意 JVM 堆内存建议对超过 50MB 的附件改用filerealpath方式。docfiletype的值与 OA 文件类型映射相关3 表示其他类型如果传图片可以设 1Word 文档设 2具体以 OA 客户端枚举为准。getDoc返回的DocInfo中attachments数组可能为 null取值前先判空避免旧版本服务在无附件时返回 null 而不是空数组。5.3 日志与报错定位调用过程中如果createDoc返回 0一般不是服务不可用而是数据校验没过。优先检查maincategory是否有效、ownerid是否存在、附件数组里是否塞了空对象。XFire 服务端的报错日志在Ecology/log下的ecology.log搜DocServiceImpl或抛出的异常栈即可看到具体卡在哪一个字段。还有一种常见情况是sessioncode传了 null服务端会返回 0在日志里能看到空指针但不会影响进程。6. 工作流接口的部署差异与附件压缩判断技巧6.1 WorkflowService 的部署要点与 DocService 相比WorkflowService 在services.xml中的注册方式一致但有一个重要差异serviceClass是weaver.workflow.webservices.WorkflowServiceimplementationClass默认指向WorkflowServiceImpl这个版本没有任何权限验证任何拿到 WSDL 地址的人都能调。因此文档中明确推荐把实现类改成WorkflowServiceImplSec。这个安全版实现类要求客户端先经过weaver.filter.IntefaceSecurityFilter过滤并且系统管理员要在 OA 后台的/workflow/UserList.jsp页面里配置允许调用此接口的 IP 或账号名单。6.2 安全版配置的副作用配置IntefaceSecurityFilter时要把它放在 XFireServlet 映射之前否则过滤器拦截不到/services/*的请求。这个过滤器是全局的也就是说一旦配了所有/services/*路径下的接口都会要求通过 IP 白名单校验。如果项目里还有其他接口需要匿名访问比如给门户页用的公开查询接口就会被一并拦掉。解决方式是单独在 web.xml 里增加一个 servlet 映射将公开接口放到另一个 URL 前缀下或者调整过滤器的url-pattern精确到具体服务路径。6.3 附件是否被 zip 压缩的快速验证技巧在调用 getDoc 拿到附件后经常遇到两类异常一是直接把filecontentBase64 解码后写文件打开乱码二是图片附件正常但 Office 附件打不开。排查思路是先看iszip字段而不是纠结解码方式。如果iszip1filecontent里的字节是 zip 压缩后的内容需要先解压再落盘。文档给的示例代码里有一段被注释掉的 zip 读取逻辑注释原因是 e-cology 的文档附件在不同版本里压缩行为不一致。稳妥的验证方法是先用ZipInputStream解开一层如果能读到 entry就是压缩过的如果解不出来说明文件就是原始内容。把这段逻辑封装成一个byte[] resolveContent(DocAttachment da)方法在读写附件的地方统一调用避免每个集成点各写一套判断。另外集成完成后的验收建议用一个小脚本打印所有返回的附件元数据比较imagefilesize与解码后 content 的长度。两者不一致时大概率是中间加了一层压缩或转码不要直接交付。本文还有配套的精品资源点击获取
返回列表