ABAP 集成钉钉开放平台

news2024/9/20 5:42:22

SAP->钉钉审批集成流程图

在这里插入图片描述

钉钉开放平台下载证书

进入钉钉开放平台,找到钉钉被调用api的域名
钉钉获取应用token官方文档
请求方法处可以找到域名,直接通过域名访问api地址下载证书
域名:api.dingtalk.com
在这里插入图片描述
访问域名获取证书信息
在这里插入图片描述
在这里插入图片描述
有三层证书,每一层都需要单独下载导出到本地
在这里插入图片描述
在这里插入图片描述

SAP STRUST导入证书

进入sap系统输入事务码STRUST
按如下步骤以此导入之前下载的三个证书
在这里插入图片描述

SAP SM59新建sap与外部系统的http连接

事务码sm59
选中到外部服务器的http连接,再选中创建
在这里插入图片描述
参考如下信息创建
在这里插入图片描述
登录&安全性处,需要将安全协议选择【活动】,ssl证书选择刚刚钉钉证书导入的【标准】

如果证书无误,此时点击上方连接测试,即可收到2xx响应成功的反馈
此处如果提示ssl证书错误,重复前两部重新导入证书
在这里插入图片描述

SE37 封装通用请求函数

使用该函数避免相同调用接口代码重复使用,故封装成统一请求函数
通过SM59创建HTTP实例的目的也是为了将域名和请求地址解耦

FUNCTION ZDD_SEND_TO_DING .
*"----------------------------------------------------------------------
*"*"本地接口:
*"  IMPORTING
*"     REFERENCE(IV_PATH) TYPE  STRING OPTIONAL		接口后缀
*"     REFERENCE(IV_KEY) TYPE  STRING OPTIONAL
*"     REFERENCE(IV_BODY) TYPE  STRING OPTIONAL
*"     REFERENCE(IV_METHOD) TYPE  STRING OPTIONAL
*"  EXPORTING
*"     REFERENCE(EV_DATA)
*"     REFERENCE(EV_STATUS)
*"  TABLES
*"      IT_HEADER STRUCTURE  ZDDS001 OPTIONAL
*"      IT_PARAM STRUCTURE  ZDDS001 OPTIONAL
*"----------------------------------------------------------------------


*&---Global data declarations

  DATA: lr_http_client TYPE REF TO if_http_client,
        lv_url         TYPE string,
        lv_xstr        TYPE xstring,
        lv_len         TYPE i,
        lv_result      TYPE string.

  DATA: lv_key               TYPE string,
        lv_value             TYPE string,
        lv_entcode           TYPE string,
        lv_json              TYPE string,
        lr_json_serializer   TYPE REF TO cl_trex_json_serializer,
        lr_json_deserializer TYPE REF TO cl_trex_json_deserializer,
        lv_sign              TYPE string,
        lv_msg               TYPE string,
        lv_name              TYPE string,
        lv_path              TYPE string.

*&--- 根据SM59 创建 HTTP 对象实例
  cl_http_client=>create_by_destination(
    EXPORTING
      destination = 'DINGTALK'
    IMPORTING
      client =  lr_http_client
    EXCEPTIONS
      argument_not_found =  1
      destination_no_authority = 2
      destination_not_found = 3
      internal_error = 4
      plugin_not_active = 5
      OTHERS = 6
      ).

*&---- 设置PARAM
  lv_path = iv_path.
  LOOP AT it_param INTO DATA(ls_param).
    AT FIRST.
      lv_path = iv_path && '?'.
    ENDAT.

    lv_path = lv_path && ls_param-key && '=' && ls_param-value && '&'.
  ENDLOOP.
  lv_path = shift_right( val = iv_path sub = |&| ). " 去除末尾多余&

*&--- 补充后缀
  cl_http_utility=>set_request_uri(
   EXPORTING
     request = lr_http_client->request
     uri     = lv_path
     ).

*&---- 设置调用方法
  CALL METHOD lr_http_client->request->set_header_field
    EXPORTING
      name  = '~request_method'
      value = iv_method.

*&---- 设置调用方法
  CALL METHOD lr_http_client->request->set_header_field
    EXPORTING
      name  = 'Content-Type' ##NO_TEXT
      value = 'application/json'.

*&---- 设置HEADER
  LOOP AT it_header INTO DATA(ls_header).
    lv_key   = ls_header-key.
    lv_value = ls_header-value.
    CALL METHOD lr_http_client->request->set_header_field
      EXPORTING
        name  = lv_key ##NO_TEXT
        value = lv_value.
  ENDLOOP.

  lv_json = iv_body.
  CONDENSE lv_json.
  CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
    EXPORTING
      text     = lv_json
      encoding = '4110'
    IMPORTING
      buffer   = lv_xstr
    EXCEPTIONS
      failed   = 1
      OTHERS   = 2.

  lr_http_client->request->set_data( data = lv_xstr ).

*&--- 数据发送
  CALL METHOD lr_http_client->send
    EXCEPTIONS
      http_communication_failure = 1
      http_invalid_state         = 2
      http_processing_failed     = 3
      http_invalid_timeout       = 4.

  IF sy-subrc <> 0.
    lr_http_client->get_last_error( IMPORTING message = ev_data ).
    ev_status = 'E'.
    RETURN.
  ENDIF.

*&--- 返回结果判断
  CALL METHOD lr_http_client->receive
    EXCEPTIONS
      http_communication_failure = 1
      http_invalid_state         = 2
      http_processing_failed     = 3.

  IF sy-subrc <> 0 .	" 连接异常
    lr_http_client->get_last_error( IMPORTING message = ev_data ).
    ev_status = 'E'.
    RETURN.
  ELSE.
    ev_data = lr_http_client->response->get_cdata( ).
    CALL METHOD lr_http_client->close.
    ev_status = 'S'.

  ENDIF.

ENDFUNCTION.

SE37 封装获取钉钉 token函数

获取token的前提是需要有相关权限,参考官方文档配置权限
钉钉获取应用token官方文档
获取token函数几乎在每个接口前均需调用,因为钉钉的鉴权机制要求调用其他接口前需传入token
新建一个钉钉应用接口的配置表,用于存储不同应用的token,因为频繁调用获取token接口将会被拦截,使用中间表可以降低访问频次同时也节省接口调用次数
在这里插入图片描述

FUNCTION zdd_get_token.
*"----------------------------------------------------------------------
*"*"本地接口:
*"  IMPORTING
*"     REFERENCE(IV_APPNAME) TYPE  ZEL_APPNAME
*"  EXPORTING
*"     REFERENCE(EV_TOKEN) TYPE  ZEL_TOKEN
*"----------------------------------------------------------------------

*----------------------------------------------------------------------*
* 结构声明类型/Structure type declaration
*----------------------------------------------------------------------*
  TYPES: BEGIN OF ty_request,
           appkey    TYPE string,
           appsecret TYPE string,
         END OF ty_request.

  TYPES: BEGIN OF ty_result,
           expirein    TYPE i,
           accesstoken TYPE string,
         END OF ty_result.

*----------------------------------------------------------------------*
* 变量定义/Global variable definition
*----------------------------------------------------------------------*
  DATA: ls_request TYPE ty_request,
        ls_result  TYPE ty_result,
        ls_zddt001 TYPE zddt001,
        lv_body    TYPE string,
        lv_path    TYPE string,
        lv_method  TYPE string,
        lv_result  TYPE string,
        lv_status  TYPE c.

  lv_path   = '/v1.0/oauth2/accessToken'. " 获取token
  lv_method = 'POST'.


  " 根据应用获取token信息
  SELECT SINGLE
    appname     , " 应用名称
    appkey      , " appKey
    appsecret   , " appSecret
    token       , " token
    overdate    , " token过期日
    overtime      " token过期时间
  FROM zddt001
  WHERE
    appname = @iv_appname
  INTO CORRESPONDING FIELDS OF @ls_zddt001.

  " 校验过期日
  " 钉钉有限额,且频繁访问token会被拦截
  IF sy-datum <= ls_zddt001-overdate AND sy-uzeit < ls_zddt001-overtime.
    " 使用已保存的token
    ev_token = ls_zddt001-token.
  ELSE.
    " token已过期则重新获取
    " 结构转换json
    MOVE-CORRESPONDING ls_zddt001 TO ls_request.
    lv_body = /ui2/cl_json=>serialize(
      data = ls_request
      compress = abap_true
      pretty_name = /ui2/cl_json=>pretty_mode-camel_case ).

    " 替换请求字符
    REPLACE ALL OCCURRENCES OF 'appkey' IN lv_body WITH 'appKey'.
    REPLACE ALL OCCURRENCES OF 'appsecret' IN lv_body WITH 'appSecret'.

    CALL FUNCTION 'ZDD_SEND_TO_DING'
      EXPORTING
        iv_path   = lv_path
        iv_body   = lv_body
        iv_method = lv_method
      IMPORTING
        ev_data   = lv_result
        ev_status = lv_status.
    IF lv_status = 'E'.
      " 异常处理
    ELSE.
      " 返回成功
      " 解析json
      /ui2/cl_json=>deserialize(
        EXPORTING
          json = lv_result
          CHANGING data = ls_result ).

      IF ls_result IS INITIAL.
        " 异常处理
      ELSE.
        " 更新过期日
        IF sy-uzeit > '220000'. " 跨日
          ls_zddt001-overtime = '000000'.
          ls_zddt001-overdate = sy-datum + 1.
        ELSE.
          ls_zddt001-overtime = sy-uzeit + ( 60 * 90 ). " 设置逾期时间90分钟后(官网是2小时,稍微提前一点)
          ls_zddt001-overdate = sy-datum.
        ENDIF.
        ls_zddt001-token = ls_result-accesstoken.
        MODIFY zddt001 FROM ls_zddt001.
      ENDIF.
    ENDIF.

    ev_token = ls_result-accesstoken.
  ENDIF.

ENDFUNCTION.

创建钉钉待办任务示例

到上一步为止基本的框架就搭建好了,后面的步骤就是封装其他功能接口做对接,以创建钉钉待办为例子
创建钉钉待办任务

FUNCTION zdd_create_task.
*"----------------------------------------------------------------------
*"*"本地接口:
*"  EXPORTING
*"     REFERENCE(EV_ID) TYPE  STRING
*"----------------------------------------------------------------------

*----------------------------------------------------------------------*
* 结构声明类型/Structure type declaration
*----------------------------------------------------------------------*
  " 请求body
  TYPES: BEGIN OF ty_request,
           subject     TYPE string,  " 主题
           description TYPE string,  " 描述
           duetime     TYPE p,       " 逾期时间
         END OF ty_request.

  " 响应
  TYPES: BEGIN OF ty_result,
           id TYPE string,        " 待办id
         END OF ty_result.

*----------------------------------------------------------------------*
* 变量定义/Global variable definition
*----------------------------------------------------------------------*
  DATA: lt_header  TYPE TABLE OF zdds001,
        ls_header  TYPE zdds001,
        ls_request TYPE ty_request,
        ls_result  TYPE ty_result,
        lv_token   TYPE zel_token,
        lv_body    TYPE string,
        lv_path    TYPE string,
        lv_method  TYPE string,
        lv_result  TYPE string,
        lv_status  TYPE c.

  " 调用的路径可以再设计自建表存储,暂时没想好用哪些字段
  lv_path   = '/v1.0/todo/users/PUoiinWIpa2yH2ymhiiGiP6g/tasks?operatorId=PUoiinWIpxxx'.
  lv_method = 'POST'.

  " 请求body
  ls_request-subject      = '待办事项测试'.
  ls_request-description  = '你有一个待办事项'.
  ls_request-duetime      = 1684287389233.

  " 请求token
  CALL FUNCTION 'ZDD_GET_TOKEN'
    EXPORTING
      iv_appname = 'DEMO'
    IMPORTING
      ev_token   = lv_token.

  " token填入header
  ls_header-key   = 'x-acs-dingtalk-access-token'.
  ls_header-value = lv_token.
  APPEND ls_header TO lt_header.

  " 请求body转json
  lv_body = /ui2/cl_json=>serialize(
    data = ls_request
    compress = abap_true
    pretty_name = /ui2/cl_json=>pretty_mode-camel_case ).
  REPLACE ALL OCCURRENCES OF 'duetime' IN lv_body WITH 'dueTime'.

  " 发送钉钉请求待办
  CALL FUNCTION 'ZDD_SEND_TO_DING'
    EXPORTING
      iv_path   = lv_path
      iv_body   = lv_body
      iv_method = lv_method
    IMPORTING
      ev_data   = lv_result
      ev_status = lv_status
    TABLES
      it_header = lt_header.
  IF lv_status = 'E'.
    " SM59连接异常
  ELSE.
    " 返回成功
    " 解析json
    /ui2/cl_json=>deserialize(
      EXPORTING
        json = lv_result
        CHANGING data = ls_result ).
    IF ls_result IS INITIAL.
      " 未正常解析,异常
    ELSE.
      ev_id = ls_result-id.
    ENDIF.

  ENDIF.


ENDFUNCTION.

调用结果

PS:钉钉待办事项有新版和旧版,下图为旧版待办事项,如果为新版待办事项可能显示不出来,在其他栏位藏着
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/535775.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++显式,默认拷贝构造函数的特征以及使用

文章目录 前言一、拷贝构造函数特征二、默认拷贝构造函数&#xff08;编译器生成&#xff09; 前言 C规定&#xff1a; 1.内置类型传参直接拷贝。 2.自定义类型传参要进行拷贝构造完成拷贝 拷贝构造函数&#xff1a;只有单个形参&#xff0c;该形参是对本类类型对象的引用(一般…

ofo小黄车创始人赴美创业,他还欠你押金不?

ofo创始人近期又去美丽国创业去了&#xff0c;开始搞冰镇珍珠咖啡的生意去了&#xff0c;做为普通大众吃瓜的我&#xff0c;不禁想到&#xff0c;不是还欠了那么多钱呢&#xff0c;又开始创业了&#xff1f;钱从哪里来的&#xff1f;创业真的是想创就创&#xff1f;咋我还是苦哈…

ChatGPT实现旅行安排

工作之余&#xff0c;出门旅行一趟放松放松身心&#xff0c;是对自己辛勤工作最好的犒劳方式之一。旅行可以近郊游、可以远游&#xff0c;可以穷游&#xff0c;可以自驾游&#xff0c;可以一言不合打飞的喂鸽子&#xff0c;方式多种多样。但是多数情况&#xff0c;我们是到一个…

[Golang] 管理日志信息就用Zap包

&#x1f61a;一个不甘平凡的普通人&#xff0c;致力于为Golang社区和算法学习做出贡献&#xff0c;期待您的关注和认可&#xff0c;陪您一起学习打卡&#xff01;&#xff01;&#xff01;&#x1f618;&#x1f618;&#x1f618; &#x1f917;专栏&#xff1a;算法学习 &am…

数字图像处理【9】频域应用—快速傅里叶和二维变换

第一篇我们系统的介绍了傅里叶级数、傅里叶变换、离散傅里叶变换。本篇介绍快速傅里叶变换&#xff0c;并说说傅里叶变换在二维图像上是如何应用的。 首先我们快速的回顾一下第一篇内容&#xff0c;伟大的法国数学家、物理学家——让巴普蒂斯约瑟夫傅里叶&#xff0c;发现了周…

【Spark编程基础】第7章 Structured Streaming

系列文章目录 文章目录 系列文章目录前言第7章 Structured Streaming7.1 概述7.1.1 基本概念7.1.2 两种处理模型7.1.3 Structured Streaming 和 Spark SQL、Spark Streaming 关系 7.2 编写Structured Streaming程序的基本步骤7.3 输入源7.3.1 File源7.3.2 Kafka源7.3.3 Socket源…

开发框架Furion之WebApi+SqlSugar (一)

目录 1.开发环境 2.项目创建 2.1创建WebApi主项目 2.2 创建Start类库 2.3创建Model实体类库 2.4创建Application仓储业务类库 2.5创建Unility通用方法类库 3.基础功能配置 3.1 Model实体对象与数据表映射 3.2 基类仓储及动态Api接口配置 3.3 数据库IOC注册 3.4 Star…

Java字符串知多少:String、StringBuffer、StringBuilder

一、String 1、简介 String 是 Java 中使用得最频繁的一个类了&#xff0c;不管是作为开发者的业务使用&#xff0c;还是一些系统级别的字符使用&#xff0c; String 都发挥着重要的作用。String 是不可变的、final的&#xff0c;不能被继承&#xff0c;且 Java 在运行时也保…

【C++】哈希表-开散列闭散列

文章目录 哈希概念例子: 哈希冲突哈希函数哈希冲突解决方法1:闭散列 哈希表的闭散列实现闭散列结构设计**哈希表的插入过程:****哈希表的查找过程:**哈希表的删除过程:只能存储key为整形的元素 那其他类型怎么解决 CloseHash.h哈希表的开散列实现开散列概念开散列的最坏情况及解…

车机CarLauncher的Activity多屏模式WindowingMode为WINDOWING_MODE_MULTI_WINDOW疑问解析

hi&#xff0c;粉丝朋友们&#xff01; IntDef(prefix { "WINDOWING_MODE_" }, value {WINDOWING_MODE_UNDEFINED,WINDOWING_MODE_FULLSCREEN,WINDOWING_MODE_MULTI_WINDOW,WINDOWING_MODE_PINNED,WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,WINDOWING_MODE_SPLIT_SCREE…

nacos注册中心源码分析一之服务注册、服务心跳

源码分析 nacos客户端注册分析 依赖包 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>Nacos的客户端是基于SpringBoot的自动装配实现的 看下依…

算法性能分析

一、时间复杂度分析 1.什么是时间复杂度 时间复杂度是一个函数&#xff0c;它定性描述该算法的运行时间。我们在软件开发中&#xff0c;时间复杂度就是用来方便开发者估算出程序运行的答题时间。 那么该如何估计程序运行时间呢&#xff0c;通常会估算算法的操作单元数量来代表…

10个顶级AI艺术生成器

人工智能 (AI) 不仅影响商业和医疗保健等行业。 通过开创人工智能生成艺术的新时代&#xff0c;它还在创意产业中发挥着越来越重要的作用。 人工智能技术和工具通常可供任何人广泛使用&#xff0c;这有助于创造全新一代的艺术家。 我们经常听说人工智能将自动化或接管所有人类…

Java中的正则表达式详解

文章和代码已经归档至【Github仓库&#xff1a;https://github.com/timerring/java-tutorial 】或者【AIShareLab】回复 java 也可获取。 文章目录 正则表达式为什么要学习正则表达式再提出几个问题解决之道-正则表达式正则表达式基本介绍介绍 正则表达式底层实现实例分析 正则…

Word控件Aspose.Words教程:设置图表数据标签的默认选项

Aspose.Words是一种高级Word文档处理API&#xff0c;用于执行各种文档管理和操作任务。API支持生成&#xff0c;修改&#xff0c;转换&#xff0c;呈现和打印文档&#xff0c;而无需在跨平台应用程序中直接使用Microsoft Word。 Aspose API支持流行文件格式处理&#xff0c;并…

新星计划2023【网络应用领域基础】————————Day4

常见的网络基础介绍 前言 我们学习了一些基础的网络协议&#xff0c;以及子网掩码和vlan&#xff0c;同时也做了个简单的单臂路由实验 这篇文章我将仔细的讲解单臂路由的应用和交换机二层接口类型&#xff0c;以及wireshark的教程。 一&#xff0c;交换机二层接口 交换机的二…

Everypixel: AI图片搜索引擎

【产品介绍】 Everypixel是一个基于人工智能的图片搜索引擎。可以搜索超过 50 个图片来源的优质的授权图库版权素材图片&#xff0c;还可以使用免费图案功能&#xff0c;找到适合自己需求的可定制无缝图案。 Everypixel利用深度学习和计算机视觉技术&#xff0c;为客户提供先进…

Taro小程序配置网络请求

目录 1. 创建目录结构2. 全局通用的config的变量配置3. 配置http网络请求4. 使用 1. 创建目录结构 在 src 目录下新建 service 目录&#xff0c;目录下创建 api 和 http 子目录在 src 目录下新建 config 配置文件 2. 全局通用的config的变量配置 在 config 文件中添加一下代…

日本进口Hioki IM3536 LCR测试仪

Hioki IM3536 LCR测试仪 测量频率DC&#xff0c;4Hz~8MHz 测量时间&#xff1a;最快1ms 基本精度&#xff1a;0.05% rdg 1mΩ以上的精度保证范围&#xff0c;也可安心进行低阻测量 可内部发生DC偏压测量 从研发到生产线活跃在各种领域中 测量频率4Hz~8MHz&#xff0c;精度…

【pyq文案】可可爱爱、脑回路清奇の朋友圈文案

1.人每一个身体器官都是无价之宝&#xff0c;全部加起来1个月3000 2.别人出门&#xff1a;辣妹风、复古风、学院风&#xff1b;我出门&#xff1a;打工的勤劳小蜜蜂 3.看见自己就烦&#xff0c;50出&#xff1b;和今天星期四没关系 4.上学时拿钱混日子&#xff0c;上班后拿日…