工作小结-钉钉OA审批
|字数总计:2.5k|阅读时长:10分钟|阅读量:
概述
因为业务需求原因,业务单据的审批功能需要接入到钉钉OA审批上。
因为未接触过钉钉OA审批这方面的东西,所以第一步肯定是打开钉钉开放平台。

进了开放平台,肯定就得找文档,不过我看到了搜索框,既然明确自己需要查询OA审批,那就直接搜索了。

根据搜索结果,有两百多条,可见找对地方了。看推荐提示,钉钉的OA审批有多种(官方、自有...),点进“官方OA审批”。

结果跑进“常见问题”来了,切换目录到“概述”,先了解下整个OA审批。

文档内容“一目了然”(接口参数文档和错误码解释给我整麻了),也确定了OA审批分为了“官方OA审批”和“自有OA审批”两种。
把目录菜单都大致点完一遍,总结如下:
- 官方OA审批是走的钉钉审批流;自有OA审批只是做了层跳转和展示,可用于多系统的统一审批入口。
- OA审批的元素有:审批表单、审批实例、审批任务。
- 审批单据里面的附件是必须要上传到钉钉的钉盘,才能展示到审批详情里面的。
- 审批回调需要单独配置,属于钉钉事件订阅中的一种,事件推送方式有HTTP推送、Stream推送两种(个人推荐首选Stream方式),配置完推送方式后还需要配置需要订阅的事件。
- HTTP推送就是将公网地址接口提供给钉钉,让钉钉回调;Stream推送是业务系统与钉钉开放平台通过Websocket连接。Stream模式介绍:服务端Stream模式
- 与钉钉开放平台的API交互,全程都要有token,因此在应用开发中需要配置钉钉应用,获取对应的AppKey、AppSecret,通过AK和AS调用接口获取token。
- 使用钉钉开放平台的OA审批功能,是需要钉钉用户具有开发者权限的(偷懒方式是直接使用拥有主管理员权限的账号),也需要开启应用的接口权限,在应用开发-权限管理下申请如下权限:
- 成员信息读权限
- 工作流实例写权限
- OA审批和存储的所有权限 (工作流模板写权限、工作流模板读权限)
- 根据手机号姓名获取成员信息的接口访问权限
官方OA审批示例
了解文档大致后,与需求方确定使用“官方OA审批”,因此后续示例中都默认表示官方OA审批的demo。
接下来,将通过发起一个OA审批单来展示调用API的全过程。
添加maven依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <dependency> <groupId>com.aliyun</groupId> <artifactId>dingtalk</artifactId> <version>2.0.30</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>alibaba-dingtalk-service-sdk</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>com.dingtalk.open</groupId> <artifactId>app-stream-client</artifactId> <version>1.0.5</version> </dependency>
|
获取token
在概述里也说明了,钉钉开放平台的所有接口基本都是需要使用token的,一是确保数据安全,二是根据token识别钉钉企业。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class GetTokenSample { public static void main(String[] args) { try { DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken"); OapiGettokenRequest req = new OapiGettokenRequest(); req.setAppkey("AppKey"); req.setAppsecret("AppSecret"); req.setHttpMethod("GET"); OapiGettokenResponse rsp = client.execute(req); System.out.println(rsp.getBody()); } catch (ApiException e) { e.printStackTrace(); } } }
|
打印响应数据如下:
1 2 3 4 5 6
| { "errcode":0, "access_token":"7011eb7b5a5e37c694b18c6c79406111", "errmsg":"ok", "expires_in":7200 }
|
创建审批表单模板
示例代码展示创建一个“最简单”的审批表单模板,详情的参数说明、示例代码可以参考钉钉开放平台文档-创建或更新审批表单模板。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public class CreateFormTemplateSample {
public static com.aliyun.dingtalkworkflow_1_0.Client createClient() throws Exception { Config config = new Config(); config.protocol = "https"; config.regionId = "central"; return new com.aliyun.dingtalkworkflow_1_0.Client(config); }
public static void main(String[] args_) throws Exception { com.aliyun.dingtalkworkflow_1_0.Client client = CreateFormTemplateSample.createClient(); FormCreateHeaders formCreateHeaders = new FormCreateHeaders(); formCreateHeaders.xAcsDingtalkAccessToken = "7011eb7b5a5e37c694b18c6c79406111"; FormComponentProps formComponentProps1 = new FormComponentProps() .setLabel("名称"); FormComponent formComponent1 = new FormComponent() .setComponentType("TextField") .setProps(formComponentProps1);
FormCreateRequest formCreateRequest = new FormCreateRequest() .setName("表单示例") .setFormComponents(java.util.Arrays.asList( formComponent1 )); try { FormCreateResponse response = client.formCreateWithOptions(formCreateRequest, formCreateHeaders, new RuntimeOptions()); System.out.println(JSON.toJSONString(response)); } catch (Exception _err) { _err.printStackTrace(); } } }
|
打印响应数据如下:
1
| {"processCode":"PROC-0FAB48EA-FB39-4981-AD80-E67D552B3355"}
|
发起审批实例
示例代码展示发起一个“最简单”的审批实例,详情的参数说明、示例代码可以参考钉钉开放平台文档-发起审批实例。
💡提示:钉钉开放平台在创建审批实例的文档中,有个“巨大”的坑。在body参数的介绍中,未提及到deptId(用户所属部门id)字段,在API Explorer中才有介绍,根据提示说明,在approvers(审批人对象)未传值时,deptId为必填字段,根部门传-1。
如果没有传approvers,同时也没有传deptId,接口回调就会返回异常信息,异常信息就提示个“审批实例参数错误”,根本无从分析具体是哪里错误,这种情况充斥在钉钉OA审批相关的各个API中。
如果你“恰好”碰到了这种类似的“参数错误”,不要着急,仔细浏览钉钉开放平台的文档、示例代码、API Explorer,再不济可以调成功的接口进行分析。例如这里如果创建审批实例错误,可以用钉钉直接人为发起一个审批,接着调用“获取审批实例ID列表”接口得到审批实例id,再调用“获取单个审批实例详情”接口得到审批实例详情数据,进而与自己的代码进行比较分析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class StartInstanceSample {
public static com.aliyun.dingtalkworkflow_1_0.Client createClient() throws Exception { Config config = new Config(); config.protocol = "https"; config.regionId = "central"; return new com.aliyun.dingtalkworkflow_1_0.Client(config); }
public static void main(String[] args_) throws Exception { com.aliyun.dingtalkworkflow_1_0.Client client = StartInstanceSample.createClient(); StartProcessInstanceHeaders startProcessInstanceHeaders = new StartProcessInstanceHeaders(); startProcessInstanceHeaders.xAcsDingtalkAccessToken = "7011eb7b5a5e37c694b18c6c79406111"; StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues formComponentValues0 = new StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues() .setName("名称") .setValue("wray"); StartProcessInstanceRequest startProcessInstanceRequest = new StartProcessInstanceRequest() .setOriginatorUserId("306354436429120376") .setProcessCode("PROC-0FAB48EA-FB39-4981-AD80-E67D552B3355") .setDeptId(-1L) .setFormComponentValues(Collections.singletonList(formComponentValues0)); try { StartProcessInstanceResponse response = client.startProcessInstanceWithOptions(startProcessInstanceRequest, startProcessInstanceHeaders, new RuntimeOptions()); System.out.println(JSON.toJSONString(response)); } catch (Exception _err) { _err.printStackTrace(); } } }
|
打印数据如下:
1
| {"instanceId":"KW2ZY679TRyy3Nupz5MN8A10181692956791"}
|
查询审批实例详情
审批实例详情大致包含了一个审批实例的实例基础信息(审批状态、发起人信息等)、操作记录、任务列表、组件详情列表。
示例代码展示查询上述发起的审批实例详情,详情的参数说明、示例代码可以参考钉钉开放平台文档-获取单个审批实例详情。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class GetInstanceDetailSample {
public static com.aliyun.dingtalkworkflow_1_0.Client createClient() throws Exception { com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config(); config.protocol = "https"; config.regionId = "central"; return new com.aliyun.dingtalkworkflow_1_0.Client(config); }
public static void main(String[] args_) throws Exception { com.aliyun.dingtalkworkflow_1_0.Client client = GetInstanceDetailSample.createClient(); com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceHeaders getProcessInstanceHeaders = new com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceHeaders(); getProcessInstanceHeaders.xAcsDingtalkAccessToken = "d62086b9f7943eedb06ee0c096d9e111"; com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceRequest getProcessInstanceRequest = new com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceRequest() .setProcessInstanceId("KW2ZY679TRyy3Nupz5MN8A10181692956791"); try { GetProcessInstanceResponse response = client.getProcessInstanceWithOptions(getProcessInstanceRequest, getProcessInstanceHeaders, new RuntimeOptions()); System.out.println(JSON.toJSONString(response)); } catch (Exception _err) { _err.printStackTrace(); } } }
|
打印数据如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| { "attachedProcessInstanceIds":[
], "bizAction":"NONE", "businessId":"202308251746000319111", "createTime":"2023-08-25T17:46Z", "finishTime":"2023-08-25T17:46Z", "formComponentValues":[ { "componentType":"TextField", "id":"TextField_HWna4IkQPgtWz", "name":"名称", "value":"wray" } ], "operationRecords":[ { "date":"2023-08-25T17:46Z", "result":"NONE", "type":"START_PROCESS_INSTANCE", "userId":"306354436429120111" } ], "originatorDeptId":"-1", "originatorDeptName":"开发部", "originatorUserId":"306354436429120111", "result":"agree", "status":"COMPLETED", "tasks":[
], "title":"Wray提交的表单示例" }
|
OA审批事件回调
OA审批事件是钉钉事件消息的一种,在「概述-总结」中也提到过,这里主要就展示Stream推送的代码示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class StreamCallbackSample {
public static void main(String[] args) throws Exception { OpenDingTalkStreamClientBuilder .custom() .credential(new AuthClientCredential("AppKey", "AppSecret")) .registerAllEventListener(new GenericEventListener() { public EventAckStatus onEvent(GenericOpenDingTalkEvent event) { try { String eventType = event.getEventType(); JSONObject bizData = event.getData(); System.out.println(JSON.toJSONString(bizData)); return EventAckStatus.SUCCESS; } catch (Exception e) { return EventAckStatus.LATER; } } }) .build().start(); } }
|
启动代码后,在钉钉后台验证Stream模式通道。

推送数据分为两个部分,一个部分为事件的基础信息,另一个部分为事件业务数据信息。
格式如下:
1 2 3 4 5 6 7 8 9 10
| { "eventBornTime":1684132707000, "eventCorpId":"ding9f50b15b*****41", "eventId":"c69632e6e3794bfbb07d33fad9fa82d2", "eventType":"suite_ticket", "eventUnifiedAppId":"unifiedAppId1", "data":{ "suiteTicket":"1234455" } }
|
接入成功之后,对钉钉实例进行操作,例如现在对OA审批任务进行评论,推送的业务信息如下:
1 2 3 4 5 6 7 8 9 10 11
| { "processInstanceId":"FiFx7mFVTX6R9Iw8TOeheQ10181693105111", "createTime":1693108281607, "processCode":"PROC-4650E083-0D7F-42BD-BC1A-30043D5BC111", "businessId":"202308271058000577111", "title":"wray提交的表单示例", "type":"comment", "businessType":"", "content":"3", "staffId":"306354436429120376" }
|
相关文章
项目搭建钉钉OA审批底层框架的历程:工作小结-钉钉OA审批(2)