最近做项目遇到了一个需求,就是在自己的系统上提交审批,会走钉钉的审批流,并且把上传的文件显示在钉钉的审批流附件中。这里牵扯到的就是文件转存到钉盘的知识了,注意是转存哦,并不是直接上传到钉盘中。这个需求用了半天的时间解决掉了,下面是记录本次解决的步骤,旨在方便后期再遇到此类问题时可以套用,也给遇到此类问题的开发者们提供一个解决的思路。

1、文档链接:保存文件到自定义或审批钉盘空间 - 钉钉开放平台

首先可以根据上面的钉钉开发文档链接,了解钉钉转存文件所需要的参数。也可以通过下面附的截图来粗略的看一下:

2、参数解析:

2.1)所需参数中access_token是钉钉验证权限的token,只需要根据创建的应用中的appkey和appsecret请求一下gettoken接口,就会返回access_token,请求地址如下图:

2.2)agent_id是创建应用中的AgentId,在应用的详情页面也是存在的,直接拿过来即可。

2.3)code 为免登授权码,需要注意的是钉钉返回的code有效期为5分钟,并且使用一次过后立即失效!我们这边实现方式是在选择文件上传时,前端都会去调用免登授权码接口获取code,然后将code传递给后端

2.4) media_id 这个参数需要调用钉钉的单步文件上传接口来获取

单步文件上传 - 钉钉开放平台

fileSize获取比较简单,主要是Post请求体中file的路径这一块儿,我一直不知道该怎么写。后来是通过了比较笨的方式,通过multipartFile转file,然后转存到本地后再把路径附上去,来获取media_id。

2.5) space_id可以通过以下方法获取钉盘id(企业只有一个spaceId,这个值通常是固定的)

public Long getSpaceId() {DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/processinstance/cspace/info");OapiProcessinstanceCspaceInfoRequest req = new OapiProcessinstanceCspaceInfoRequest();
// 用户的钉钉idreq.setUserId("xxxxxxxxx");OapiProcessinstanceCspaceInfoResponse rsp = null;try {rsp = client.execute(req, getAccessToken());} catch (ApiException e) {logger.error("获取钉盘Id失败!原因:{}", e.getErrMsg());}if (Objects.isNull(rsp)) {return null;}return rsp.getResult().getSpaceId();}

2.6)folder_id 我们是审批附件,所以传0。(如果是自定义钉盘,不需要传)

2.7)name的话就是文件名称,比较容易获取,这里也不多赘述

2.8)overwrite 是指遇到同名文件时是否覆盖,布尔类型,默认的话是false,这个参数可以根据具体的业务需求来选择

3、具体实现方式(伪代码):

    @Resourceprivate IDingDingService dingDingService;/*** * @param multipartFile 上传的文件* @param code 前端调用钉钉免登授权接口获取的code* @return*/@PostMapping("/upload")public AjaxResult uploadFile(@RequestParam("file") MultipartFile multipartFile, @RequestParam(value = "code") String code) {String originalFilename = multipartFile.getOriginalFilename();Map<String, Object> resultMap = Maps.newHashMap();// 获取钉盘id的方法在参数介绍中已经写明了,可以向上找找看/* 上面说过,钉盘id一个企业只有一个,那么这里为什么不写死呢? 因为2点:1、写死试过,没成功2、钉钉推荐每次转存文件前,都先获取一次spaceId所以没办法,只能跟着文档走喽~~*/Long spaceId = dingDingService.getSpaceId();if (Objects.isNull(spaceId)) {return AjaxResult.error("获取钉盘ID失败!");}// 获取钉钉返回的mediaIdString mediaId = dingDingService.getMediaId(multipartFile);if (StringUtils.isBlank(mediaId)) {return AjaxResult.error("获取文件钉盘mediaId出错!");}/* 文件转存钉盘后返回的spaceId,fileName,fileId,fileType,fileSize等信息,
这些信息在文件设置到钉钉审批流附件中需要用到*/String dentry = dingDingService.saveFileToDingSpace(code, mediaId, originalFilename);if (Objects.isNull(dentry)) {return AjaxResult.error("转存审批钉盘失败!");}
// 将返回的json字符串转换,并封装到map后返回JSONObject jsonObject = JSON.parseObject(dentry);resultMap.put("file_id", jsonObject.get("id"));resultMap.put("file_Name", jsonObject.get("name"));resultMap.put("file_size", jsonObject.get("size"));resultMap.put("file_type", jsonObject.get("type"));resultMap.put("space_id", spaceId);} 
/*** 获取钉盘mediaId** @param multipartFile 上传的文件* @return*/public String getMediaId(MultipartFile multipartFile) {// 将multipartFile转为fileFile file = transferToFile(multipartFile);// 这里我把获取accessToken的方法封装了一下String accessToken = getAccessToken();OapiFileUploadSingleRequest request = new OapiFileUploadSingleRequest();// 获取文件大小request.setFileSize(multipartFile.getSize());// 应用的AgentIdrequest.setAgentId(SpringUtils.getBean(AppConfig.class).getAgentId());DingTalkClient client = null;try {client = new DefaultDingTalkClient("https://oapi.dingtalk.com/file/upload/single?" + WebUtils.buildQuery(request.getTextParams(), "utf-8"));} catch (IOException e) {logger.error("创建钉钉单步文件上传路径失败!");}// 必须重新new一个请求request = new OapiFileUploadSingleRequest();// 这里文件的路径使用的是转成file之后文件存储的路径request.setFile(new FileItem(file.getPath()));OapiFileUploadSingleResponse response = null;try {response = client.execute(request, accessToken);} catch (ApiException e) {logger.error("调用钉钉单步文件上传接口,获取mediaId失败!");return null;}if (Objects.isNull(response)) {return null;}return response.getMediaId();}
// multipartFile 转 file的方法
public static File transferToFile(MultipartFile multipartFile) {
//        选择用缓冲区来实现这个转换即使用java 创建的临时文件 使用 MultipartFile.transferto()方法 。File file = null;try {String originalFilename = multipartFile.getOriginalFilename();String[] filename = originalFilename.split("\\.");/* ReviewConfig.getUploadPath()是我写在配置文件中的路径,这里要注意路径必须是存在的,因为项目发布在linux中,所以这里我写的是 /home/uploadPath/upload,可以根据自己的需求进行替换,生成的文件会保存在指定的路径下 */file=File.createTempFile(filename[0] + System.currentTimeMillis(), "." + filename[1], new File(ReviewConfig.getUploadPath())); multipartFile.transferTo(file);file.deleteOnExit();} catch (IOException e) {e.printStackTrace();}return file;}
/* 封装的获取access_token的方法,
如果不想频繁的获取token,可以考虑放到redis中做缓存 */
public String getAccessToken() {DefaultDingTalkClient client = new DefaultDingTalkClient(UrlConstant.URL_GET_TOKEN);OapiGettokenRequest request = new OapiGettokenRequest();OapiGettokenResponse response;/* 应用中的appkey和appsercet 这里我写在了配置文件中,大家也可以写死,毕竟一个H5微应用的appkey和appsercet是固定的*/request.setAppkey(appconfig.getAppKey());request.setAppsecret(appconfig.getAppSecret());// 请求方式是getrequest.setHttpMethod("GET");try {response = client.execute(request);} catch (ApiException e) {logger.debug(e.getErrCode(), e.getErrMsg());return null;}return accessToken.toString();}
/*** 转存文件到审批钉盘** @param code 钉钉免登授权码* @param mediaId 获取到钉钉返回的media_id* @return*/@Overridepublic String saveFileToDingSpace(String code, String mediaId, String fileName) {DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/cspace/add");OapiCspaceAddRequest req = new OapiCspaceAddRequest();// AgentId同上,写在配置文件中的req.setAgentId(SpringUtils.getBean(AppConfig.class).getAgentId());req.setCode(code);req.setMediaId(mediaId);// 前面获取到的spaceIdreq.setSpaceId("40xxxxxx");req.setName(fileName);// 遇到同名文件是否覆盖,我这里根据业务需求,选择了falsereq.setOverwrite(false);req.setHttpMethod("GET");OapiCspaceAddResponse rsp = null;try {rsp = client.execute(req, getAccessToken());} catch (ApiException e) {logger.error("文件转存钉盘失败!原因:{}", e.getErrMsg());return null;}if (Objects.isNull(rsp)) {return null;}// 将返回信息中的json串取出并返回return rsp.getDentry();}

那么至此,文件转存到钉盘的功能就完结啦。我们这边的需求实际上是在上传图片的时候,先把文件转存到钉盘一份, 获取到spaceId、fileSize、fileName,fileId,fileType这几个参数(因为文件设置到钉钉审批流附件时需要这5个参数),获取完成后,再上传到自己的minio服务器上,这样在钉钉审批流查看附件时,看到的是钉盘中的附件,而在我们的系统中查看附件时,是minio上的附件。

写的比较简单粗暴啊,建议大家先熟悉钉钉开放文档后再结合本文查看,效果更优。有不清楚的可以评论或者私信问我,如果对你有帮助,帮忙点个赞,谢啦~~

将文件转存到钉钉的钉盘中相关推荐

  1. 专有钉钉 浙政钉 前端 对接流程(小程序)

    主要开发流程 本公司专有钉钉开发平台账号(公司钉钉超管注册 给开发人员权限) 超管按照文档给予开发人员权限 创建项目 下载开发工具 配置专有钉钉开发环境 免登录(用户不用输入账号密码直接登录) 根据业 ...

  2. 关于浙政钉、专有钉钉的数据埋点小心得总结(稳定性监控、流量分析)

    关于浙政钉.专有钉钉的数据埋点小心得总结(稳定性监控.流量分析) 先说一下关于专有钉钉得开放文档专有钉钉门户这上面会有一些入门介绍,以及api文档,可以方便开发者迅速上手.本文得重点是说明如何进行数据 ...

  3. 用java模仿钉钉_java接入钉钉机器人(附源码)

    前言 有研究pinpoint的网友提出,想实现pinpoint告警接入钉钉群和微信群聊, 正所谓,路要一步步走,饭要一口口吃.我们将这个任务拆解一下,以便以后的开发中能够复用这些能力. 1.接入微信群 ...

  4. 互联网快讯:华虹虹芯基金正式发起成立;极米高性能投影产品获用户青睐;中国电信联手钉钉研发“天翼钉”

    国内要闻 新华三与中国工业互联网研究院达成战略合作,为工业互联网发展按下加速键: 中国海洋石油:中国证监会受理公司A股发行股份申请材料: 3.华润创业与冯氏投资签订合作备忘录,3亿美元共拓新消费领域创 ...

  5. 对接钉钉审批_钉钉审批对接是什么-和钉钉审批对接相关的问题-阿里云开发者社区...

    关于 钉钉审批对接的搜索结果 问题 企业系统对接钉钉生成审批单,企业系统处理审批后,如何撤销钉钉审批单 公司erp系统与钉钉对接,erp发起审批后同步到钉钉生成审批实例,在erp中用户处理了审批,如何 ...

  6. 浙政钉(专有钉钉)门户免登(超详细)

    钉钉家族 介绍浙政钉门户免登之前,首先搞清楚几个软件的关系,软件分别是:钉钉,专有钉钉,浙政钉 钉钉 是阿里巴巴集团专为中小企业打造的沟通和协同的多端平台. 专有钉钉 原名 政务钉钉,有更开放的设计能 ...

  7. python3 钉钉 加签名 钉钉群机器人巡检告警 脚本

    本文接上文 python3 钉钉 加签名 钉钉群机器人告警 脚本 https://blog.csdn.net/frdevolcqzyxynjds/article/details/128455191 c ...

  8. 从浙政钉-企业微信-钉钉同步数据步骤

    概述 在于浙政钉-企业微信-钉钉进行组织结构同步的代码步骤. 首先需要理解ccbpm的部门.人员.以及部门于人员对应关系的表结构. 理解OrgNo的组织编号概念. 理解集团模式,SAAS模式的概念. ...

  9. python3 钉钉 加签名 钉钉群机器人告警 脚本

    钉钉群聊 关于为何设置加签名? 这里主要是想着使用起来更方便,因为签名这块更加灵活 全网普遍用 自定义关键词多,不予置评 添加群机器人 智能群助手 添加机器人 自定义 机器人 设置加签 复制一下签名 ...

最新文章

  1. 为什么说C语言和linux是分不开的?
  2. UVA10537 The Toll! Revisited (思维、最短路、输出字典序最小路径)
  3. 简单剖析C语言中的位扩展问题
  4. Ajax,再生还是幻灭---好文推荐
  5. hdu 2069 Coin Change(改)-dp
  6. [蓝桥杯2018初赛]星期一-日期计算
  7. java putifabsent_java8中Map的一些骚操作总结
  8. 阅读器java_纯Java文档阅读器
  9. 在互联网行业呆了这么多年
  10. POJ 2942Knights of the Round Table(二分图判定+双连通分量)
  11. 简单易用的网络调试工具——NetAssist
  12. 这些神奇的 QQ 你还记得几个?
  13. 希腊字母在Vim 中的输入方法
  14. HDU5285.wyh2000 and pupil
  15. 用java设计一个矩形类_6-1 设计一个矩形类Rectangle (10分)
  16. 【个人提升】如何克服惰性
  17. linux系统英语词汇大全,Linux系统管理中基本命令和英语词汇
  18. 开发人员面试62到经典题
  19. 银河麒麟中的录屏软件
  20. Unity开发元宇宙多人交互XR应用

热门文章

  1. 【Python机器学习】Sklearn库中Kmeans类、超参数K值确定、特征归一化的讲解(图文解释)
  2. 蓝桥杯 ALGO-1004 无聊的逗 01背包+回溯 python
  3. 输入两个正整数,求其最大公约数和最小公倍数。
  4. 少用的却实用的计算机知识
  5. 高通骁龙800系列处理器规格型号及代表机型大全
  6. 心电图实验(使用vivado进行编程,VHDL语言)
  7. PHY驱动调试之 --- PHY控制器驱动(二)
  8. 华为鸿蒙系统应用开发工具介绍 DevEco Studio
  9. linux搞笑图片,2017高考表情包(最新最全表情包合集)-高考表情包恶搞搞笑图片下载-西西软件下载...
  10. 看雪2w3w安卓高级研修Frida原理学习