【钉钉免登录】(详解)钉钉接口,H5微应用,钉钉免登录及获取当前用户信息

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 【钉钉免登录】(详解)钉钉接口,H5微应用,钉钉免登录及获取当前用户信息

一、背景描述

公司做一个项目要集成到钉钉上,但是呢公司里又没有人做过,所以需要自己研究了。有了需求,就要开始行动。

首先当然是要去钉钉开放平台查看相关资料,钉钉开放平台地址:应用类型介绍 - 钉钉开放平台

二、准备工作

第一、你需要有一个 自己的 企业钉钉,进入企业钉钉管理,如下图所示

第二、看创建H5微应用的教程,链接地址:开发一个钉钉H5微应用 - 钉钉开放平台 ,这个教程上面有很详细的创建微应用的步骤以及注意事项。

三、查看微应用配置信息

以下的AgentId、AppKey、AppSecret会用到,所以找个地方保存一下,如果你是管理员那就更好了,随时都可以登录钉钉组织查看哦。

3.1 基础信息

3.2 开发管理

重点来喽:服务器出口IP,自己刚开始配置的时候不清楚到底是什么意思,也不懂服务器出口IP是干什么用的,虽然官网教程上写的有哈。其实呢,这个服务器出口IP(1、本地测试时:填写你 电脑的IP + 端口 + 映射路径;2、测试环境或者生产环境时:你的测试或者生产 服务器IP + 端口 + 映射路径或者是域名 + 端口号 + 映射路径)就是应用所在的电脑IP,可以这样简单理解哈。

3.3 权限管理

注意:如果想要获取钉钉用户的手机号,需要开通 企业员工手机号信息 这一个权限哦。

一般只需要开启以下几个权限即可,其他权限可根据需要自行开通哦。

3.4 版本管理与发布

只有点击确认发布后,才可以在钉钉工作台看到微应用。

四、核心代码

引入POM依赖:

<!-- 钉钉SDK -->

<dependency>

   <groupId>com.aliyun</groupId>

   <artifactId>alibaba-dingtalk-service-sdk</artifactId>

   <version>1.0.1</version>

</dependency>

接下来就是核心代码实现喽,可能会有点长哈

4.1 Controller层

package com.iot.daily.dingding.web;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiUserGetRequest;
import com.dingtalk.api.request.OapiUserGetuserinfoRequest;
import com.dingtalk.api.response.OapiUserGetResponse;
import com.dingtalk.api.response.OapiUserGetuserinfoResponse;
import com.taobao.api.ApiException;
import com.iot.daily.common.domain.vo.JsonResult;
import com.iot.daily.common.util.CommonUtil;
import com.iot.daily.dingding.config.DingAppConfig;
import com.iot.daily.dingding.config.DingUrlConstant;
import com.iot.daily.dingding.domain.ConfigDTO;
import com.iot.daily.dingding.domain.ServiceResult;
import com.iot.daily.dingding.domain.UserDTO;
import com.iot.daily.dingding.exception.DingtalkEncryptException;
import com.iot.daily.dingding.service.DingAuthService;
import com.iot.daily.dingding.service.TokenService;
import com.iot.daily.dingding.util.JsApiSignature;
import com.iot.daily.module.entity.DailyViewUser;
import com.iot.daily.organization.entity.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Map;
import java.util.Optional;
/**
 * <p>DingLoginController 此类用于:钉钉企业内部应用免登(H5微应用)</p>
 * <p>@author:hujm</p>
 * <p>@date:2021年05月18日 15:06</p>
 * <p>@remark:钉钉企业内部微应用DEMO, 实现了身份验证(免登)功能</p>
 */
@Api(value = "dingAuthController", tags = "钉钉企业内部应用免登(H5微应用)")
@Slf4j
@Controller
@RequestMapping(value = "/ding")
public class DingAuthController {
    @Resource
    private TokenService tokenService;
    @Resource
    private DingAppConfig dingAppConfig;
    @Resource
    private DingAuthService dingAuthService;
    /**
     * 欢迎页面,通过 /welcome 访问,判断后端服务是否启动
     *
     * @return 字符串 welcome
     */
    @ApiOperation(value = "日报跳转的首页地址")
    @RequestMapping("/login")
    public String mobileLogin() {
        return "mobile/dinglogin";
    }
    /**
     * 欢迎页面,通过 /welcome 访问,判断后端服务是否启动
     *
     * @return 字符串 welcome
     */
    @ApiOperation(value = "日报跳转的首页地址")
    @RequestMapping("/index")
    public String mobileIndex() {
        return "mobile/index";
    }
    /**
     * 钉钉跳转到页面
     *
     * @param request  请求
     * @param response 响应
     * @return ModelAndView 页面
     */
    @RequestMapping("/toIndex")
    public ModelAndView toDingView(HttpServletRequest request, HttpServletResponse response) {
        String view = request.getParameter("view");
        Map<String, Object> pMap = CommonUtil.getParameterMap(request);
        return new ModelAndView(view, pMap);
    }
    /**
     * 钉钉用户登录,显示当前登录用户的userId和名称
     *
     * @param authCode 免登临时authCode
     * @return 当前用户
     */
    @ApiOperation(value = "钉钉用户登录,显示当前登录用户的userId和名称")
    @PostMapping("/avoidLogin")
    @ResponseBody
    public JsonResult login(@RequestBody String authCode, HttpServletRequest request) {
        String accessToken;
        // 获取accessToken
        ServiceResult<String> accessTokenSr = tokenService.getAccessToken();
        if (!accessTokenSr.isSuccess()) {
            return JsonResult.fail(Integer.parseInt(accessTokenSr.getCode()), accessTokenSr.getMessage());
        }
        accessToken = accessTokenSr.getResult();
        JSONObject jsonObject = JSONObject.parseObject(authCode);
        String getAuthCode = (String) jsonObject.get("authCode");
        // 获取用户userId
        ServiceResult<String> userIdSr = getUserInfo(accessToken, getAuthCode);
        if (!userIdSr.isSuccess()) {
            return JsonResult.fail(Integer.parseInt(userIdSr.getCode()), userIdSr.getMessage());
        }
        // 获取用户详情
        JsonResult userInfo = this.getUser(accessToken, userIdSr.getResult());
        UserDTO userDTO = (UserDTO) userInfo.getResult();
        log.info("根据accessToken和用户userId查询出的用户信息 userDTO = {}", userDTO);
        HttpSession session = request.getSession();
        User user = this.getUserFromUserDTO(userDTO);
        session.setAttribute("date", String.valueOf(System.currentTimeMillis()));
        session.setAttribute("user", user);
        return userInfo;
    }
    /**
     * 封装User对象
     *
     * @param userDTO userDTO对象
     * @return User对象
     */
    private User getUserFromUserDTO(UserDTO userDTO) {
        User user = new User();
        user.setUserName(userDTO.getUserName());
        user.setTrueName(userDTO.getTrueName());
        user.setUserId(userDTO.getUserId());
        user.setAgentSid(userDTO.getAgentSid());
        user.setCreateDate(userDTO.getCreateDate());
        user.setDingUserId(userDTO.getDingUserId());
        user.setDepartment(userDTO.getAgentName());
        user.setFid(userDTO.getFid());
        user.setHandset(userDTO.getHandset());
        user.setHeadPortrait(userDTO.getHeadPortrait());
        user.setIsAdmin(userDTO.getIsAdmin());
        user.setIsAlarm(userDTO.getIsAlarm());
        user.setIsLeader(userDTO.getIsLeader());
        user.setLoginCount(userDTO.getLoginCount());
        user.setLoginLastDate(userDTO.getLoginLastDate());
        user.setLoginLastIp(userDTO.getLoginLastIp());
        user.setOrgEmail(userDTO.getOrgEmail());
        user.setPosition(userDTO.getPosition());
        user.setPassword(userDTO.getPassword());
        user.setPwdLastDate(userDTO.getPwdLastDate());
        user.setRoleId(userDTO.getRoleId());
        user.setUserLevel(userDTO.getUserLevel());
        user.setUserState(userDTO.getUserState());
        return user;
    }
    /**
     * 访问/user/getuserinfo接口获取用户userId
     *
     * @param accessToken access_token
     * @param authCode    临时授权码
     * @return 用户userId或错误信息
     */
    private ServiceResult<String> getUserInfo(String accessToken, String authCode) {
        DingTalkClient client = new DefaultDingTalkClient(DingUrlConstant.URL_GET_USER_INFO);
        OapiUserGetuserinfoRequest request = new OapiUserGetuserinfoRequest();
        request.setCode(authCode);
        request.setHttpMethod("GET");
        OapiUserGetuserinfoResponse response;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            log.error("Failed to {}", DingUrlConstant.URL_GET_USER_INFO, e);
            return ServiceResult.failure(e.getErrCode(), "Failed to getUserInfo: " + e.getErrMsg());
        }
        if (!response.isSuccess()) {
            return ServiceResult.failure(response.getErrorCode(), response.getErrmsg());
        }
        return ServiceResult.success(response.getUserid());
    }
    /**
     * 访问/user/get 获取用户名称
     *
     * @param accessToken access_token
     * @param userId      用户userId
     * @return 用户名称或错误信息
     */
    private JsonResult getUser(String accessToken, String userId) {
        DingTalkClient client = new DefaultDingTalkClient(DingUrlConstant.URL_USER_GET);
        OapiUserGetRequest request = new OapiUserGetRequest();
        request.setUserid(userId);
        request.setHttpMethod("GET");
        OapiUserGetResponse response;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            log.error("Failed to {}", DingUrlConstant.URL_USER_GET, e);
            return JsonResult.fail(Integer.parseInt(e.getErrCode()), "Failed to getUserName: " + e.getErrMsg());
        }
        UserDTO user = this.assembleUserDTO(response, accessToken);
        return JsonResult.ok(user);
    }
    /**
     * 封装返回的用户信息
     *
     * @param response    response
     * @param accessToken accessToken
     * @return 用户信息
     */
    private UserDTO assembleUserDTO(OapiUserGetResponse response, String accessToken) {
        UserDTO user = new UserDTO();
        String userid = response.getUserid();
        String mobile = response.getMobile();
        try {
            DailyViewUser dailyViewUser = Optional.ofNullable(dingAuthService.getUserByUserId(userid))
                    .orElse(dingAuthService.getUserByUsername(mobile));
            BeanUtil.copyProperties(dailyViewUser, user);
            user.setAccessToken(accessToken);
            user.setName(response.getName());
            user.setAvatar(response.getAvatar());
        } catch (Exception e) {
            log.error("E|DingAuthController|assembleUserDTO()|根据用户钉钉userId或者用户钉钉手机号mobile查询用户信息失败!");
        }
        return user;
    }
    @ApiOperation(value = "钉钉配置接口")
    @PostMapping("/config")
    @ResponseBody
    public JsonResult config(HttpServletRequest request) {
        ConfigDTO config = new ConfigDTO();
        String url = request.getRequestURL().toString();
        String queryString = request.getQueryString();
        if (queryString != null) {
            url = url + queryString;
        }
        ServiceResult<String> jsTicketSr = tokenService.getJsTicket();
        if (!jsTicketSr.isSuccess()) {
            return JsonResult.fail(Integer.parseInt(jsTicketSr.getCode()), jsTicketSr.getMessage());
        }
        config.setAgentId(dingAppConfig.getAgentId());
        config.setCorpId(dingAppConfig.getCorpId());
        config.setJsticket(jsTicketSr.getResult());
        config.setNonceStr(JsApiSignature.genNonce());
        config.setTimeStamp(System.currentTimeMillis() / 1000);
        String sign;
        try {
            sign = JsApiSignature.sign(url, config.getNonceStr(), config.getTimeStamp(), config.getJsticket());
        } catch (DingtalkEncryptException e) {
            return JsonResult.fail(e.getCode(), e.getMessage());
        }
        config.setSignature(sign);
        return JsonResult.ok(config);
    }
}

4.2 Service层以及ServiceImpl

package com.iot.daily.dingding.service;
import com.iot.daily.module.entity.DailyViewUser;
/**
 * <p>DingAuthService 此接口用于:</p>
 * <p>@author:hujm</p>
 * <p>@date:2021年05月20日 15:56</p>
 * <p>@remark:</p>
 */
public interface DingAuthService {
    /**
     * 根据用户手机号查询是否是公司员工
     *
     * @param userId 钉钉用户id
     * @return UIOT员工信息
     */
    DailyViewUser getUserByUserId(String userId);
    /**
     * 根据用户手机号查询是否是公司员工
     *
     * @param mobile 钉钉用户手机号
     * @return UIOT员工信息
     */
    DailyViewUser getUserByUsername(String mobile);
}
package com.iot.daily.dingding.service;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.request.OapiGetJsapiTicketRequest;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.response.OapiGetJsapiTicketResponse;
import com.dingtalk.api.response.OapiGettokenResponse;
import com.taobao.api.ApiException;
import com.iot.daily.common.constant.CommonConstants;
import com.iot.daily.common.util.cache.RedisCache;
import com.iot.daily.dingding.config.DingAppConfig;
import com.iot.daily.dingding.config.DingUrlConstant;
import com.iot.daily.dingding.domain.ServiceResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
/**
 * <p>DingLoginController 此类用于:获取access_token 和 jsTicket方法</p>
 * <p>@author:hujm</p>
 * <p>@date:2021年05月18日 15:06</p>
 * <p>@remark:钉钉企业内部微应用DEMO, 实现了身份验证(免登)功能</p>
 */
@Slf4j
@Service
public class TokenService {
    @Resource
    private RedisCache redisCache;
    /**
     * 缓存时间:一小时50分钟
     */
    private static final long CACHE_TTL = 60 * 55 * 2;
    @Resource
    private DingAppConfig dingAppConfig;
    /**
     * 在此方法中,为了避免频繁获取access_token,
     * 在距离上一次获取access_token时间在两个小时之内的情况,
     * 将直接从持久化存储中读取access_token
     * <p>
     * 因为access_token和jsapi_ticket的过期时间都是7200秒
     * 所以在获取access_token的同时也去获取了jsapi_ticket
     * 注:jsapi_ticket是在前端页面JSAPI做权限验证配置的时候需要使用的
     * 具体信息请查看开发者文档--权限验证配置
     *
     * @return accessToken 或错误信息
     */
    public ServiceResult<String> getAccessToken() {
        // 从持久化存储中读取
        String accessToken = redisCache.get(CommonConstants.DAILY_DING_ACCESS_TOKEN);
        log.info("从Redis缓存中获取到的accessToken = {}", accessToken);
        if (accessToken != null) {
            return ServiceResult.success(accessToken);
        }
        DefaultDingTalkClient client = new DefaultDingTalkClient(DingUrlConstant.URL_GET_TOKEN);
        OapiGettokenRequest request = new OapiGettokenRequest();
        OapiGettokenResponse response;
        request.setAppkey(dingAppConfig.getAppKey());
        request.setAppsecret(dingAppConfig.getAppSecret());
        request.setHttpMethod("GET");
        try {
            response = client.execute(request);
        } catch (ApiException e) {
            log.error("getAccessToken failed", e);
            return ServiceResult.failure(e.getErrCode(), e.getErrMsg());
        }
        accessToken = response.getAccessToken();
        log.info("向Redis缓存中存取accessToken = {}", accessToken);
        redisCache.set(CommonConstants.DAILY_DING_ACCESS_TOKEN, accessToken, CACHE_TTL, TimeUnit.SECONDS);
        return ServiceResult.success(accessToken);
    }
    /**
     * 获取JSTicket, 用于js的签名计算
     * 正常的情况下,jsapi_ticket的有效期为7200秒,所以开发者需要在某个地方设计一个定时器,定期去更新jsapi_ticket
     *
     * @return jsTicket或错误信息
     */
    public ServiceResult<String> getJsTicket() {
        // 从持久化存储中读取
        String ticket = redisCache.get(CommonConstants.DAILY_DING_JS_TICKET);
        if (ticket != null) {
            return ServiceResult.success(ticket);
        }
        String accessToken;
        ServiceResult<String> tokenSr = getAccessToken();
        if (!tokenSr.isSuccess()) {
            return ServiceResult.failure(tokenSr.getCode(), tokenSr.getMessage());
        }
        accessToken = tokenSr.getResult();
        DefaultDingTalkClient client = new DefaultDingTalkClient(DingUrlConstant.URL_GET_JSTICKET);
        OapiGetJsapiTicketRequest request = new OapiGetJsapiTicketRequest();
        OapiGetJsapiTicketResponse response;
        request.setHttpMethod("GET");
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            log.error("getAccessToken failed", e);
            return ServiceResult.failure(e.getErrCode(), e.getErrMsg());
        }
        if (!response.isSuccess()) {
            return ServiceResult.failure(response.getErrorCode(), response.getErrmsg());
        }
        ticket = response.getTicket();
        redisCache.set(CommonConstants.DAILY_DING_JS_TICKET, ticket, CACHE_TTL, TimeUnit.SECONDS);
        return ServiceResult.success(ticket);
    }
}

上面TokenService类中的两个常量分别是:

/**

* 日报系统钉钉JSTICKET命名空间和ACCESSTOKEN命名空间

*/

public static final String DAILY_DING_JS_TICKET = "dailyApplication:login:ticket:";

public static final String DAILY_DING_ACCESS_TOKEN = "dailyApplication:login:accessToken:";

package com.iot.daily.dingding.service.impl;
import com.iot.daily.dingding.service.DingAuthService;
import com.iot.daily.module.dao.DailyViewUserMapper;
import com.iot.daily.module.entity.DailyViewUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
 * <p>DingAuthServiceImpl 此类用于:</p>
 * <p>@author:hujm</p>
 * <p>@date:2021年05月20日 15:56</p>
 * <p>@remark:</p>
 */
@Slf4j
@Service
public class DingAuthServiceImpl implements DingAuthService {
    @Resource
    private DailyViewUserMapper dailyViewUserMapper;
    @Override
    public DailyViewUser getUserByUserId(String userId) {
        if (userId == null) {
            log.error("E|DingAuthServiceImpl|getUserByUserId()|根据用户手机号查询UIOT用户时,当前钉钉用户id为空!");
            return new DailyViewUser();
        }
        DailyViewUser dailyViewUser = dailyViewUserMapper.getDailyViewUserByUserId(userId);
        log.info("E|DingAuthServiceImpl|getUserByUserId()|根据用户手机号查询UIOT用户,userId = {}", userId);
        return dailyViewUser;
    }
    @Override
    public DailyViewUser getUserByUsername(String mobile) {
        if (mobile == null) {
            log.error("E|DingAuthServiceImpl|getUserByUsername()|根据用户手机号查询UIOT用户时,当前钉钉用户id为空!");
            return new DailyViewUser();
        }
        DailyViewUser dailyViewUser = dailyViewUserMapper.getDailyViewUserByUsername(mobile);
        log.info("E|DingAuthServiceImpl|getUserByUsername()|根据用户手机号查询UIOT用户,userId = {}", mobile);
        return dailyViewUser;
    }
}

4.3 相关配置类

package com.iot.daily.dingding.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
 * <p>DingAppConfig 此类用于:应用凭证配置</p>
 * <p>@author:hujm</p>
 * <p>@date:2021年05月18日 17:25</p>
 * <p>@remark:</p>
 */
@Data
@Configuration
public class DingAppConfig {
    @Value("${dingtalk.app_key}")
    private String appKey;
    @Value("${dingtalk.app_secret}")
    private String appSecret;
    @Value("${dingtalk.agent_id}")
    private String agentId;
    @Value("${dingtalk.corp_id}")
    private String corpId;
}
package com.iot.daily.dingding.config;
/**
 * 钉钉开放接口网关常量
 *
 * @author Administrator
 */
public class DingUrlConstant {
    private static final String HOST = "https://oapi.dingtalk.com";
    /**
     * 获取access_token url
     */
    public static final String URL_GET_TOKEN = HOST + "/gettoken";
    /**
     * 获取jsapi_ticket url
     */
    public static final String URL_GET_JSTICKET = HOST + "/get_jsapi_ticket";
    /**
     * 通过免登授权码获取用户信息 url
     */
    public static final String URL_GET_USER_INFO = HOST + "/user/getuserinfo";
    /**
     * 根据用户id获取用户详情 url
     */
    public static final String URL_USER_GET = HOST + "/user/get";
    /**
     * 获取部门列表 url
     */
    public static final String URL_DEPARTMENT_LIST = HOST + "/department/list";
    /**
     * 获取部门用户 url
     */
    public static final String URL_USER_SIMPLELIST = HOST + "/user/simplelist";
}
package com.iot.daily.dingding.domain;
import java.io.Serializable;
/**
 * <p>DingLoginController 此类用于:service层返回对象列表封装</p>
 * <p>@author:hujm</p>
 * <p>@date:2021年05月18日 15:06</p>
 * <p>@remark:service层返回对象列表封装</p>
 */
public class ServiceResult<T> implements Serializable {
    private boolean success = false;
    private String code;
    private String message;
    private T result;
    private ServiceResult() {
    }
    public static <T> ServiceResult<T> success(T result) {
        ServiceResult<T> item = new ServiceResult<T>();
        item.success = true;
        item.result = result;
        item.code = "0";
        item.message = "success";
        return item;
    }
    public static <T> ServiceResult<T> failure(String errorCode, String errorMessage) {
        ServiceResult<T> item = new ServiceResult<T>();
        item.success = false;
        item.code = errorCode;
        item.message = errorMessage;
        return item;
    }
    public static <T> ServiceResult<T> failure(String errorCode) {
        ServiceResult<T> item = new ServiceResult<T>();
        item.success = false;
        item.code = errorCode;
        item.message = "failure";
        return item;
    }
    public boolean hasResult() {
        return result != null;
    }
    public boolean isSuccess() {
        return success;
    }
    public T getResult() {
        return result;
    }
    public String getCode() {
        return code;
    }
    public String getMessage() {
        return message;
    }
}

以上代码为核心代码,如果想要查看全部代码请移步至码云上哦,地址:daily: 公司每天需要员工填写的日报内容 。或者找博主索取哦!

五、免登录注意事项

钉钉免登录应用注意事项:

  1. 创建应用;
  2. 配置出口IP与访问首页;
  3. 开放权限(手机号码信息、通讯录部门信息读权限、成员信息读权限、通讯录部门成员读权限);

完结!


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
7月前
|
JSON API 数据格式
您可以在钉钉开放平台的API文档中找到对应的API接口来创建审批实例
您可以在钉钉开放平台的API文档中找到对应的API接口来创建审批实例【1月更文挑战第20天】【1月更文挑战第96篇】
134 2
|
7月前
|
JSON API 数据格式
在钉钉开放平台中,创建或更新OA审批表单模板需要通过API接口进行操作
在钉钉开放平台中,创建或更新OA审批表单模板需要通过API接口进行操作【1月更文挑战第20天】【1月更文挑战第97篇】
188 1
|
7月前
|
安全 前端开发 iOS开发
钉钉里微应用ios 底部安全区域的颜色怎么修改?
钉钉里微应用ios 底部安全区域的颜色怎么修改?
220 5
|
7月前
|
运维 监控 安全
调用钉钉机器人API接口将堡垒机安全运维告警单发给运维人员
调用钉钉机器人API接口将堡垒机安全运维告警单发给运维人员
209 0
|
6月前
|
jenkins 机器人 测试技术
jenkins接入钉钉api接口自动化测试报告自动发送
该教程介绍了如何在Jenkins上实现接口自动化测试的持续集成,并将可视化报告发送至钉钉工作群。首先,确保准备好了自动化脚本。接着配置Jenkins:安装Git插件,设置源代码管理(如Git)和触发器(定时或推送)。使用Post build task插件处理构建后的报告,读取Allure的prometheusData.txt文件以获取测试结果。最后,安装Ding Talk插件,配置钉钉机器人,通过 Dingtalkchatbot 库发送测试报告信息到钉钉群。整个流程包括Jenkins的定时构建、Git仓库的监听以及自动化报告发送到钉钉的通知。
|
6月前
|
JSON 分布式计算 DataWorks
DataWorks产品使用合集之能否支持从结果表取出示警信息并且打通钉钉进行告警
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
7月前
|
移动开发
在使用钉钉H5微应用时,通过消息通知链接跳转到特定页面可能会出现一些问题
【2月更文挑战第12天】在使用钉钉H5微应用时,通过消息通知链接跳转到特定页面可能会出现一些问题
118 3
|
7月前
|
移动开发
在使用钉钉H5微应用时,通过消息通知链接跳转到特定页面可能会出现一些问题
在使用钉钉H5微应用时,通过消息通知链接跳转到特定页面可能会出现一些问题
296 2
|
7月前
|
API 开发工具
POSTMAN在测试调用钉钉待办事项接口时权限问题
POSTMAN在测试调用钉钉待办事项接口时权限问题
|
7月前
|
运维 监控 安全
【优化篇】调用钉钉机器人API接口将堡垒机安全运维告警单发给运维人员
【优化篇】调用钉钉机器人API接口将堡垒机安全运维告警单发给运维人员
137 0