不久前接了一个需求,如图:看似只是个上传文件功能,然而可把我给痛疼的
钉钉服务端API发起带有附件的审批流文档链接 : 按照文档一步一步来,不要急https://open.dingtalk.com/document/orgapp/initiate-an-approval-flow-with-attachments
文档就不带着看了,直接上代码吧
1.POM 依赖
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dingtalk</artifactId>
<version>2.0.69</version>
</dependency>
2.DingComplaintCreateDTO 入参
@Data
public class DingComplaintCreateDTO implements Serializable {
/**
* 订单号
*/
@NotBlank(message = "订单号不能为空")
private String complaintOrderNo;
/**
* 投诉人姓名
*/
@NotBlank(message = "投诉人姓名不能为空")
private String complaintUsername;
/**
* 投诉人手机号
*/
@NotBlank(message = "投诉人手机号不能为空")
private String complaintMobile;
/**
* 被投诉人id(对应被投诉人钉钉id)
*/
@NotNull(message = "被投诉人id不能为空")
private Integer byComplaintId;
/**
* 被投诉人类型
*/
@NotBlank(message = "被投诉人类型不能为空")
private String byComplaintType;
/**
* 被投诉人部门id
*/
@NotNull(message = "被投诉人部门id不能为空")
private Integer byComplaintDepartmentId;
/**
* 投诉渠道
*/
@NotBlank(message = "投诉渠道不能为空")
private String complaintFrom;
/**
* 投诉分类
*/
@NotBlank(message = "投诉分类不能为空")
private String complaintType;
/**
* 投诉内容
*/
@NotBlank(message = "投诉内容不能为空")
private String complaintDetail;
private String lineName;
/**
* 上传的文件
*/
private MultipartFile[] files;
/**
* 操作管理员uid(对应投诉发起人钉钉id)
*/
private Long sysUid;
}
3.DingComplaintServiceImpl 实现
public class DingComplaintServiceImpl{
public RestResponse<Boolean> submitDingComplaint(DingComplaintCreateDTO dto) throws Exception {
MultipartFile[] files = dto.getFiles();
log.info("submitDingComplaint dto{}", dto);
com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceHeaders startProcessInstanceHeaders = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceHeaders();
startProcessInstanceHeaders.xAcsDingtalkAccessToken = getAccessToken();
//上传钉盘
List<CommitFileResponse> fileUploadInfos = new ArrayList<>();
if(files.length > 0){
//获取钉盘spaceId
Long attachmentSpaceId = getAttachmentSpace(getAccessToken());
fileUploadInfos = getFileUploadInfo(getAccessToken(), files, String.valueOf(attachmentSpaceId));
}
com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues formComponentValues0 = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues()
.setName("客户姓名")
.setValue(dto.getComplaintUsername())
.setComponentType("TextareaField");
com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues formComponentValues1 = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues()
.setName("联系电话")
.setValue(dto.getComplaintMobile())
.setComponentType("NumberField");
com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues formComponentValues2 = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues()
.setName("被投诉人")
.setValue("[\""+被投诉人钉钉id+"\"]")
.setComponentType("InnerContactField");
com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues formComponentValues3 = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues()
.setName("被投诉人是")
.setValue(dto.getByComplaintType())
.setComponentType("DDSelectField");
com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues formComponentValues4 = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues()
.setName("属于")
.setValue("")
.setComponentType("DDSelectField");
com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues formComponentValues5 = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues()
.setName("被投诉人归属")
.setValue("[\""+被投诉人所在部门id+"\"]")
.setComponentType("DepartmentField");
com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues formComponentValues6 = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues()
.setName("车牌")
.setValue(driverList1.get(0).getCarLicensePlateNum())
.setComponentType("TextField");
com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues formComponentValues7 = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues()
.setName("投诉渠道")
.setValue(dto.getComplaintFrom())
.setComponentType("DDSelectField");
com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues formComponentValues8 = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues()
.setName("投诉分类")
.setValue("[\""+dto.getComplaintType()+"\"]")
.setComponentType("DDMultiSelectField");
com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues formComponentValues9 = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues()
.setName("订单号")
.setValue(dto.getComplaintOrderNo())
.setComponentType("TextField");
com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues formComponentValues10 = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues()
.setName("投诉内容")
.setValue(dto.getComplaintDetail())
.setComponentType("TextareaField");
// List<String> imageUrl = Arrays.asList("https://dycx-obs-uat.obs.cn-south-1.myhuaweicloud.com/TEST/22222222.png","https://dycx-obs-uat.obs.cn-south-1.myhuaweicloud.com/TEST/s0_05325377268906568.png");
// com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues formComponentValues11 = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues()
// .setName("图片证明")
// .setValue(JSON.toJSONString(imageUrl))
// .setComponentType("DDPhotoField");
// 封装附件组件的值
JSONArray attachmentJsonArray = new JSONArray();
if(!CollectionUtils.isEmpty(fileUploadInfos)){
fileUploadInfos.forEach(c->{
CommitFileResponseBody.CommitFileResponseBodyDentry dentry = c.getBody().getDentry();
JSONObject attachmentJson = new JSONObject();
attachmentJson.put("fileId", dentry.getId());
attachmentJson.put("fileName", dentry.getName());
attachmentJson.put("fileType", dentry.getExtension());
attachmentJson.put("spaceId", dentry.getSpaceId());
attachmentJson.put("fileSize", dentry.getSize());
attachmentJsonArray.add(attachmentJson);
});
}
com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues formComponentValues12 = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues()
.setName("其他材料")
.setValue(JSON.toJSONString(attachmentJsonArray))
.setComponentType("DDAttachment");
com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest startProcessInstanceRequest = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest()
.setOriginatorUserId(accountCompany1.get(0).getDingUserId())
.setProcessCode("") //审批流模板code,在老版本跳转模板路径中能拿到
.setDeptId(-1L) //固定-1L
.setFormComponentValues(java.util.Arrays.asList(
formComponentValues0,
formComponentValues1,
formComponentValues2,
formComponentValues3,
formComponentValues4,
formComponentValues5,
formComponentValues6,
formComponentValues7,
formComponentValues8,
formComponentValues9,
formComponentValues10,
// formComponentValues11,
formComponentValues12
));
log.info("startProcessInstanceRequest {}",JSON.toJSONString(startProcessInstanceRequest));
try {
StartProcessInstanceResponse startProcessInstanceResponse = createClientWorkflow().startProcessInstanceWithOptions(startProcessInstanceRequest, startProcessInstanceHeaders, new RuntimeOptions());
log.info("startProcessInstanceResponse {}",startProcessInstanceResponse);
} catch (Exception err) {
err.printStackTrace();
log.error(String.valueOf(err));
return RestResponse.fail(err.getMessage());
}
return RestResponse.success(true).setMsg("投诉成功");
}
//获取accessToken
public String getAccessToken() throws Exception {
GetAccessTokenResponseBody accessTokenBody = new GetAccessTokenResponseBody();
com.aliyun.dingtalkoauth2_1_0.Client client = createClientOauth();
com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest getAccessTokenRequest = new com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest()
.setAppKey(complaintConfig.getDdComplaintAppKey())
.setAppSecret(complaintConfig.getDdComplaintAppSecret());
try {
accessTokenBody = client.getAccessToken(getAccessTokenRequest).getBody();
} catch (Exception err) {
log.error(String.valueOf(err));
}
return accessTokenBody.getAccessToken();
}
//获取钉盘spaceId
public Long getAttachmentSpace(String accessToken) throws Exception {
com.aliyun.dingtalkworkflow_1_0.Client client = createClientWorkflow();
com.aliyun.dingtalkworkflow_1_0.models.GetAttachmentSpaceHeaders getAttachmentSpaceHeaders = new com.aliyun.dingtalkworkflow_1_0.models.GetAttachmentSpaceHeaders();
getAttachmentSpaceHeaders.xAcsDingtalkAccessToken = accessToken;
com.aliyun.dingtalkworkflow_1_0.models.GetAttachmentSpaceRequest getAttachmentSpaceRequest = new com.aliyun.dingtalkworkflow_1_0.models.GetAttachmentSpaceRequest()
.setUserId("钉钉id")
.setAgentId("应用AgentId");
try {
GetAttachmentSpaceResponse attachmentSpaceWithOptions = client.getAttachmentSpaceWithOptions(getAttachmentSpaceRequest, getAttachmentSpaceHeaders, new RuntimeOptions());
System.out.println("钉盘空间信息:" + JSON.toJSONString(attachmentSpaceWithOptions));
return attachmentSpaceWithOptions.getBody().getResult().getSpaceId();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//获取文件上传信息
public List<CommitFileResponse> getFileUploadInfo(String accessToken,MultipartFile[] files,String spaceId) throws Exception {
String unionid = "";
List<CommitFileResponse> commitFileResponses = new ArrayList<>();
try {
String url = "https://oapi.dingtalk.com/topapi/v2/user/get?access_token="+accessToken;
Map<String,String> map = new HashMap<>();
map.put("language","zh_CN");
map.put("userid","钉钉id");
String req = JSON.toJSONString(map);
String res = HttpUtil.post(url, req);
System.out.println(res);
JSONObject jsonObject = JSON.parseObject(res);
if(jsonObject.getInteger("errcode") == 0){
JSONObject result = JSON.parseObject(jsonObject.getString("result"));
unionid = result.getString("unionid");
}
} catch (Exception e) {
e.printStackTrace();
}
com.aliyun.dingtalkstorage_1_0.Client client = talkstorageClient();
GetFileUploadInfoHeaders getFileUploadInfoHeaders = new GetFileUploadInfoHeaders();
getFileUploadInfoHeaders.xAcsDingtalkAccessToken = accessToken;
GetFileUploadInfoRequest getFileUploadInfoRequest = new GetFileUploadInfoRequest()
.setUnionId(unionid)
.setProtocol("HEADER_SIGNATURE")
.setMultipart(false);
try {
//执行上传操作
for (int i = 0; i < files.length; i++) {
GetFileUploadInfoResponse fileUploadInfoWithOptions = client.getFileUploadInfoWithOptions(spaceId, getFileUploadInfoRequest, getFileUploadInfoHeaders, new RuntimeOptions());
System.out.println(JSON.toJSONString(fileUploadInfoWithOptions));
GetFileUploadInfoResponseBody body = fileUploadInfoWithOptions.getBody();
URL url = new URL(body.headerSignatureInfo.getResourceUrls().get(0));
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
Map<String, String> headers = body.headerSignatureInfo.headers;
if (headers != null) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
connection.setRequestProperty(entry.getKey(), entry.getValue());
}
}
connection.setDoOutput(true);
connection.setRequestMethod("PUT");
connection.setUseCaches(false);
connection.setRequestProperty("Accept-Charset", "UTF-8");
connection.setRequestProperty("contentType", "UTF-8");
connection.setRequestProperty("Authorization", body.headerSignatureInfo.headers.get("Authorization"));
connection.setRequestProperty("x-oss-date", body.headerSignatureInfo.headers.get("x-oss-date"));
connection.setReadTimeout(10000);
connection.setConnectTimeout(10000);
connection.connect();
OutputStream out = connection.getOutputStream();
InputStream is = files[i].getInputStream();
byte[] b =new byte[1024];
int temp;
while ((temp=is.read(b))!=-1){
out.write(b,0,temp);
}
out.flush();
out.close();
int responseCode = connection.getResponseCode();
connection.disconnect();
System.out.println("上传文件信息"+connection);
if (responseCode == 200) {
System.out.println("上传成功");
String uploadKey = fileUploadInfoWithOptions.getBody().getUploadKey();
//提交文件
CommitFileResponse commitFileResponse = commitFile(accessToken, unionid, uploadKey, files[i].getOriginalFilename(), spaceId);
commitFileResponses.add(commitFileResponse);
} else {
System.out.println("上传失败");
}
}
} catch (Exception e) {
e.printStackTrace();
}
return commitFileResponses;
}
//提交文件
public CommitFileResponse commitFile(String accessToken,String unionId,String uploadKey,String fileName,String spaceId) throws Exception {
com.aliyun.dingtalkstorage_1_0.Client client = talkstorageClient();
com.aliyun.dingtalkstorage_1_0.models.CommitFileHeaders commitFileHeaders = new com.aliyun.dingtalkstorage_1_0.models.CommitFileHeaders();
commitFileHeaders.xAcsDingtalkAccessToken = accessToken;
com.aliyun.dingtalkstorage_1_0.models.CommitFileRequest commitFileRequest = new com.aliyun.dingtalkstorage_1_0.models.CommitFileRequest()
.setUnionId(unionId)
.setUploadKey(uploadKey)
.setName(fileName)
.setParentId("0");
// .setOption(option);
try {
CommitFileResponse commitFileResponse = client.commitFileWithOptions(spaceId, commitFileRequest, commitFileHeaders, new RuntimeOptions());
System.out.println("文件提交:"+JSON.toJSONString(commitFileResponse));
return commitFileResponse;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//存储client
public static com.aliyun.dingtalkstorage_1_0.Client talkstorageClient() throws Exception {
Config config = new Config();
config.protocol = "https";
config.regionId = "central";
return new com.aliyun.dingtalkstorage_1_0.Client(config);
}
//认证client
public static com.aliyun.dingtalkoauth2_1_0.Client createClientOauth() throws Exception {
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config();
config.protocol = "https";
config.regionId = "central";
return new com.aliyun.dingtalkoauth2_1_0.Client(config);
}
//审批流client
public static com.aliyun.dingtalkworkflow_1_0.Client createClientWorkflow() 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);
}
}
这个是功能已经用在正式环境了,可以直接copy 改一下就能用了,对接文档还是挺坑的。。。。。
附上验证结果
注意:操作审批流用户id,部门id 都是要用钉钉的相关属性,钉钉id,所在部门id