将文件转存到钉钉的钉盘中 您所在的位置:网站首页 转存文件数升至3000 将文件转存到钉钉的钉盘中

将文件转存到钉钉的钉盘中

2023-08-09 14:19| 来源: 网络整理| 查看: 265

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

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(); // 用户的钉钉id req.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、具体实现方式(伪代码):

@Resource private 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 resultMap = Maps.newHashMap(); // 获取钉盘id的方法在参数介绍中已经写明了,可以向上找找看 /* 上面说过,钉盘id一个企业只有一个,那么这里为什么不写死呢? 因为2点: 1、写死试过,没成功 2、钉钉推荐每次转存文件前,都先获取一次spaceId 所以没办法,只能跟着文档走喽~~ */ Long spaceId = dingDingService.getSpaceId(); if (Objects.isNull(spaceId)) { return AjaxResult.error("获取钉盘ID失败!"); } // 获取钉钉返回的mediaId String 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转为file File file = transferToFile(multipartFile); // 这里我把获取accessToken的方法封装了一下 String accessToken = getAccessToken(); OapiFileUploadSingleRequest request = new OapiFileUploadSingleRequest(); // 获取文件大小 request.setFileSize(multipartFile.getSize()); // 应用的AgentId request.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()); // 请求方式是get request.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 */ @Override public 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); // 前面获取到的spaceId req.setSpaceId("40xxxxxx"); req.setName(fileName); // 遇到同名文件是否覆盖,我这里根据业务需求,选择了false req.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上的附件。

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



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有