Java系统对接企业微信审批项目流程
若依做的一个系统需求需要对接企业微信的人员去审核订单 回款之类,以下是详细步骤.
1.首先登入企业微信管理后台:
企业微信
2.找到应用管理
3.自建一个应用
4.这些数据都可以拿到
5.配置可信Ip
6.进入有两种方法让你去配置 ,第一种用公司的域名,然后下面有个文件需要导入,必须导入,不然不会成功的。导入之后配置自己电脑的IP公网地址。
7.配置回调的url接口
踩雷:::框架用的若依,这个接口必须开放,返回的也是字符串格式不能是json格式。
这里需要写两个接口 一个是get 一个是post。
8.创建自己的模板
9.模板显示范围和自建的应用必须关联
10.开发前必读 - 文档 - 企业微信开发者中心进入这个里面查看具体的教程
11.附所有的代码
wechat:# 企业IDcorpId: wwd# 审批应用IDagentId: 100# 审批应用SecretcorpSecret: 5vE# 回调校验的TokensToken: 2a# 回调校验的KeyencodingAesKey: 5JH4nvyvb1# tokenURLtokenUrl: https://qyapi.weixin.qq.com/cgi-bin/gettoken# 审核申请URLapprovalUrl: https://qyapi.weixin.qq.com/cgi-bin/oa/applyevent# 获取模板详情URLtemplateUrl: https://qyapi.weixin.qq.com/cgi-bin/oa/gettemplatedetail# 上传文件到企业微信URLuploadFileUrl: https://qyapi.weixin.qq.com/cgi-bin/media/upload# 获取用户信息urlgetUserUrl: https://qyapi.weixin.qq.com/cgi-bin/user/get# 添加实验区审批流模版IDareaTemplateId: 3WMV
package com.ruoyi.bingo.config.wechat;import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;/*** @author yj*/
@Data
@Component
public class WeChatConfig {@Value("${wechat.corpId}")private String corpId;@Value("${wechat.agentId}")private String agentId;@Value("${wechat.corpSecret}")private String corpSecret;@Value("${wechat.sToken}")private String sToken;@Value("${wechat.encodingAesKey}")private String encodingAesKey;@Value("${wechat.tokenUrl}")private String tokenUrl;@Value("${wechat.templateUrl}")private String templateUrl;@Value("${wechat.approvalUrl}")private String approvalUrl;@Value("${wechat.uploadFileUrl}")private String uploadFileUrl;@Value("${wechat.getUserUrl}")private String getUserUrl;@Value("${wechat.areaTemplateId}")private String areaTemplateId;@Value("${wechat.schoolTemplateId}")private String schoolTemplateId;@Value("${wechat.clientTemplateId}")private String clientTemplateId;@Value("${wechat.createOrderTemplateId}")private String createOrderTemplateId;@Value("${wechat.costTemplateId}")private String costTemplateId;@Value("${wechat.returnedTemplateId}")private String returnedTemplateId;@Value("${wechat.contractTemplateId}")private String contractTemplateId;@Value("${wechat.finishOrderTemplateId}")private String finishOrderTemplateId;// 提供公开的 Getter 方法public String getCorpId() {return corpId;}public String getAgentId() {return agentId;}public String getCorpSecret() {return corpSecret;}public String getSToken() {return sToken;}public String getEncodingAesKey() {return encodingAesKey;}public String getTokenUrl() {return tokenUrl;}public String getTemplateUrl() {return templateUrl;}public String getApprovalUrl() {return approvalUrl;}public String getUploadFileUrl() {return uploadFileUrl;}public String getGetUserUrl() {return getUserUrl;}public String getAreaTemplateId() {return areaTemplateId;}public String getSchoolTemplateId() {return schoolTemplateId;}public String getClientTemplateId() {return clientTemplateId;}public String getCreateOrderTemplateId() {return createOrderTemplateId;}public String getCostTemplateId() {return costTemplateId;}public String getReturnedTemplateId() {return returnedTemplateId;}public String getContractTemplateId() {return contractTemplateId;}public String getFinishOrderTemplateId() {return finishOrderTemplateId;}
}
12.加密解密XML工具栏
package com.ruoyi.bingo.config.wechat.xml;import com.ruoyi.common.utils.bean.BeanUtils;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.util.ArrayList;
import java.util.List;/*** Description :** @author YJ* date 2024-12-15* time 20:28*/
@Component
public class XmlUtils {/*** 解析xmL** @param xmlData*/public ApprovalBack analysis(String xmlData) {try {// 调用 fromXml 方法解析 XML 数据ApprovalCallback callback = ApprovalCallback.fromXml(xmlData);// 输出解析结果System.out.println("ToUserName: " + callback.toUserName);System.out.println("FromUserName: " + callback.fromUserName);System.out.println("CreateTime: " + callback.createTime);System.out.println("MsgType: " + callback.msgType);System.out.println("Event: " + callback.event);System.out.println("AgentID: " + callback.agentID);System.out.println("SpNo: " + callback.spNo);System.out.println("SpName: " + callback.spName);System.out.println("SpStatus: " + callback.spStatus);System.out.println("TemplateId: " + callback.templateId);System.out.println("ApplyTime: " + callback.applyTime);//System.out.println("Applyer UserId: " + callback.applyer.userId);//System.out.println("Applyer Party: " + callback.applyer.party);//System.out.println("SpRecord SpStatus: " + callback.spRecord.spStatus);//System.out.println("StatuChangeEvent: " + callback.statuChangeEvent);//输出 ProcessList 中的 SubNodeList 信息//if (callback.processList != null && callback.processList.nodeList != null) {// for (ApprovalCallback.UserInfo userInfo : callback.processList.nodeList.subNodeList) {// System.out.println("SubNode UserId: " + userInfo.userId);// }//}System.out.println("解密内容call: " + callback);ApprovalBack approvalBack = new ApprovalBack();approvalBack.setSpNo(callback.spNo);approvalBack.setSpStatus(callback.spStatus);return approvalBack;} catch (Exception e) {e.printStackTrace();}return null;}
}class ApprovalCallback {String toUserName;String fromUserName;String createTime;String msgType;String event;String agentID;String spNo;String spName;String spStatus;String templateId;String applyTime;Applyer applyer;SpRecord spRecord;String statuChangeEvent;ProcessList processList;public static ApprovalCallback fromXml(String xmlContent) throws Exception {DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = factory.newDocumentBuilder();InputSource inputSource = new InputSource(new java.io.StringReader(xmlContent));Document doc = builder.parse(inputSource);ApprovalCallback callback = new ApprovalCallback();callback.toUserName = doc.getElementsByTagName("ToUserName").item(0).getTextContent();callback.fromUserName = doc.getElementsByTagName("FromUserName").item(0).getTextContent();callback.createTime = doc.getElementsByTagName("CreateTime").item(0).getTextContent();callback.msgType = doc.getElementsByTagName("MsgType").item(0).getTextContent();callback.event = doc.getElementsByTagName("Event").item(0).getTextContent();callback.agentID = doc.getElementsByTagName("AgentID").item(0).getTextContent();// 解析 ApprovalInfoorg.w3c.dom.NodeList approvalInfo = doc.getElementsByTagName("ApprovalInfo");if (approvalInfo.getLength() > 0) {Element approvalInfoElement = (Element) approvalInfo.item(0);callback.spNo = approvalInfoElement.getElementsByTagName("SpNo").item(0).getTextContent();callback.spName = approvalInfoElement.getElementsByTagName("SpName").item(0).getTextContent();callback.spStatus = approvalInfoElement.getElementsByTagName("SpStatus").item(0).getTextContent();callback.templateId = approvalInfoElement.getElementsByTagName("TemplateId").item(0).getTextContent();callback.applyTime = approvalInfoElement.getElementsByTagName("ApplyTime").item(0).getTextContent();// Applyer infoElement applyerElement = (Element) approvalInfoElement.getElementsByTagName("Applyer").item(0);callback.applyer = new Applyer();callback.applyer.userId = applyerElement.getElementsByTagName("UserId").item(0).getTextContent();callback.applyer.party = applyerElement.getElementsByTagName("Party").item(0).getTextContent();// SpRecord infoorg.w3c.dom.NodeList spRecordList = approvalInfoElement.getElementsByTagName("SpRecord");if (spRecordList.getLength() > 0) {Element spRecordElement = (Element) spRecordList.item(0);callback.spRecord = new SpRecord();callback.spRecord.spStatus = spRecordElement.getElementsByTagName("SpStatus").item(0).getTextContent();callback.spRecord.approverAttr = spRecordElement.getElementsByTagName("ApproverAttr").item(0).getTextContent();// Details infoorg.w3c.dom.NodeList detailsList = spRecordElement.getElementsByTagName("Details");if (detailsList.getLength() > 0) {Element detailsElement = (Element) detailsList.item(0);callback.spRecord.details = new Details();callback.spRecord.details.userId = detailsElement.getElementsByTagName("UserId").item(0).getTextContent();callback.spRecord.details.speech = detailsElement.getElementsByTagName("Speech").item(0).getTextContent();callback.spRecord.details.spStatus = detailsElement.getElementsByTagName("SpStatus").item(0).getTextContent();}}callback.statuChangeEvent = approvalInfoElement.getElementsByTagName("StatuChangeEvent").item(0).getTextContent();// ProcessList infoorg.w3c.dom.NodeList processList = approvalInfoElement.getElementsByTagName("ProcessList");if (processList.getLength() > 0) {Element processListElement = (Element) processList.item(0);callback.processList = new ProcessList();org.w3c.dom.NodeList nodeList = processListElement.getElementsByTagName("NodeList");if (nodeList.getLength() > 0) {Element nodeListElement = (Element) nodeList.item(0);org.w3c.dom.NodeList subNodeList = nodeListElement.getElementsByTagName("SubNodeList");callback.processList.nodeList = new ApprovalCallback.NodeList();callback.processList.nodeList.subNodeList = new ArrayList<>();for (int i = 0; i < subNodeList.getLength(); i++) {Element subNodeElement = (Element) subNodeList.item(i);UserInfo userInfo = new UserInfo();userInfo.userId = subNodeElement.getElementsByTagName("UserId").item(0).getTextContent();callback.processList.nodeList.subNodeList.add(userInfo);}}}}return callback;}public static class Applyer {private String userId;private String party;}public static class SpRecord {private String spStatus;private String approverAttr;private ApprovalCallback.Details details;}public static class Details {private String userId;private String speech;private String spStatus;}public static class ProcessList {private NodeList nodeList;}public static class NodeList {private List<UserInfo> subNodeList;}public static class UserInfo {private String userId;}
}
package com.ruoyi.bingo.config.wechat.xml;import lombok.Data;/*** Description :** @author YJ* date 2024-12-15* time 20:40*/
@Data
public class ApprovalBack {private String toUserName;private String createTime;private String msgType;private String event;private String agentID;//审批编号private String spNo;private String spName;private String spStatus;private String templateId;private String applyTime;private ApprovalCallback.Applyer applyer;private ApprovalCallback.SpRecord spRecord;private String statuChangeEvent;private ApprovalCallback.ProcessList processList;
}
13.controller层
@Anonymous
@Api(description = "对接企业微信")
@RestController
@RequestMapping("/enterprise/wechat")
public class EnterpriseWeChatController extends BaseController {@Autowiredprivate EnterpriseWeChatService weChatService;/*** 获取Access Token** @return*/@ApiOperation("获取Access Token")@PreAuthorize("@ss.hasPermi('bingo:wechat:accessToken')")@PostMapping("/accessToken")public String getAccessToken() {return weChatService.getAccessToken();}/*** 验证回调 URL 的有效性** @return*/@ApiOperation("验证回调 URL 的有效性")@GetMapping("/approval/back")public String approvalBack(@RequestParam("msg_signature") String msgSignature,@RequestParam("timestamp") String timestamp,@RequestParam("nonce") String nonce,@RequestParam("echostr") String ech,HttpServletResponse response) {return weChatService.approvalBack(msgSignature, timestamp, nonce, ech, response);}/*** 处理审批回调事件*/@PostMapping("/approval/back")public void handleApprovalCallback(@RequestParam("msg_signature") String msgSignature,@RequestParam("timestamp") String timestamp,@RequestParam("nonce") String nonce,HttpServletRequest request,HttpServletResponse response) {weChatService.handleApprovalCallback(msgSignature, timestamp, nonce, request, response);}/*** 获取企业微信用户信息** @return*/@ApiOperation("获取企业微信用户信息")@PreAuthorize("@ss.hasPermi('bingo:wechat:getUser')")@PostMapping("/getUser")public AjaxResult getUser(@RequestBody WechatUserDTO wechatUserDTO) {return success(weChatService.getUser(wechatUserDTO));}/*** 上传文件到企业微信** @return*/@ApiOperation("上传文件到企业微信")@PreAuthorize("@ss.hasPermi('bingo:wechat:upload')")@PostMapping("/upload")public AjaxResult upload(MultipartFile file) {return success(weChatService.uploadWeChat(file));}
}
14.server层
/*** 验证回调 URL 的有效性** @param msgSignature* @param timestamp* @param nonce* @param echostr* @param response* @return*/@Overridepublic String approvalBack(String msgSignature, String timestamp, String nonce, Stringechostr, HttpServletResponse response) {try {log.info("验证回调 URL 的有效性");return wxBizMsgCrypt.VerifyURL(msgSignature, timestamp, nonce, echostr);} catch (Exception e) {e.printStackTrace();log.error("验证回调 URL 的有效性");}return null;}
/*** 处理审批回调事件** @param msgSignature* @param timestamp* @param nonce* @param request* @param response*/@Overridepublic void handleApprovalCallback(String msgSignature, String timestamp, String nonce, HttpServletRequestrequest, HttpServletResponse response) {log.info("处理审批回调事件----------");try {// 读取回调数据StringBuilder sb = new StringBuilder();BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));String line;while ((line = reader.readLine()) != null) {sb.append(line);}String callbackXml = sb.toString();String decryptedMessage = wxBizMsgCrypt.DecryptMsg(msgSignature, timestamp, nonce, callbackXml);ApprovalBack analysis = xmlUtils.analysis(decryptedMessage);System.out.println("解密内容analysis: " + analysis);auditInfoMapper.updateAuditStatus(analysis);AuditInfo audit = auditInfoMapper.selectApprovalInfo(analysis.getSpNo());//实验区if (audit.getAuditType().equals(FileTypeConstants.FILE_AREA_TYPE)) {ExperimentArea experimentArea = new ExperimentArea();experimentArea.setId(audit.getId());experimentArea.setApprovalStatus(Integer.valueOf(analysis.getSpStatus()));areaMapper.updateById(experimentArea);}//实验校if (audit.getAuditType().equals(FileTypeConstants.FILE_SCHOOL_TYPE)) {ExperimentSchool experimentSchool = new ExperimentSchool();experimentSchool.setId(audit.getId());experimentSchool.setApprovalStatus(Integer.valueOf(analysis.getSpStatus()));schoolMapper.updateById(experimentSchool);}//客户if (audit.getAuditType().equals(FileTypeConstants.FILE_CLIENT_TYPE)) {Client client = new Client();client.setId(audit.getId());client.setApprovalStatus(Integer.valueOf(analysis.getSpStatus()));clientMapper.updateById(client);}//创建订单if (audit.getAuditType().equals(FileTypeConstants.FILE_CREATE_ORDER_TYPE)) {Orders orders = new Orders();orders.setId(audit.getId());orders.setApprovalCreateStatus(Integer.valueOf(analysis.getSpStatus()));ordersMapper.updateById(orders);}//费用if (audit.getAuditType().equals(FileTypeConstants.FILE_COST_TYPE)) {Cost cost = new Cost();cost.setId(audit.getId());cost.setApprovalStatus(Integer.valueOf(analysis.getSpStatus()));costMapper.updateById(cost);}//合同if (audit.getAuditType().equals(FileTypeConstants.FILE_CONTRACT_TYPE)) {Contract contract = new Contract();contract.setId(audit.getId());contract.setApprovalStatus(Integer.valueOf(analysis.getSpStatus()));contractMapper.updateById(contract);}//完成订单if (audit.getAuditType().equals(FileTypeConstants.FILE_FINISH_ORDER_TYPE)) {Orders orders = new Orders();orders.setId(audit.getId());orders.setApprovalFinishStatus(Integer.valueOf(analysis.getSpStatus()));ordersMapper.updateById(orders);}//回款if (audit.getAuditType().equals(FileTypeConstants.FILE_RETURNED_TYPE)) {Returned returned = new Returned();returned.setId(audit.getId());returned.setApprovalStatus(Integer.valueOf(analysis.getSpStatus()));returnedMapper.updateById(returned);}// 返回成功响应} catch (Exception e) {// 处理异常,例如返回错误信息throw new ServiceException(e.getMessage());}
callbackXml就是回调的xml,然后进行解密解析。 analysis 属于明文
ApprovalCallback callback = ApprovalCallback.fromXml(xmlData);
这个属于解密后所有的明文数据
15.提交审批的代码
/*** 创建订单申请** @param approvalOrderDTO* @return*/@Overridepublic String approvalOrder(ApprovalOrderDTO approvalOrderDTO) {ApprovalTemplateDTO approvalTemplateDTO = new ApprovalTemplateDTO();approvalTemplateDTO.setTemplate_id(weChatConfig.getCreateOrderTemplateId());try {String url = weChatConfig.getTemplateUrl() + "?access_token=" + getAccessToken();// 获取模板信息String jsonBody = new ObjectMapper().writeValueAsString(approvalTemplateDTO);String response = HttpUtils.sendPost(url, jsonBody);System.out.println("获取创建订单模板:" + response);JSONObject jsonResponse = new JSONObject(response);if (jsonResponse.getInt("errcode") != 0) {return null;}// 获取模板控件内容JSONObject templateContent = jsonResponse.getJSONObject("template_content");JSONArray controls = templateContent.getJSONArray("controls");// 构造字段内容JSONArray formArray = new JSONArray();//构造内容setArrayOrder(approvalOrderDTO, controls, formArray);String businessName = ordersMapper.selectOrderBusinessName(approvalOrderDTO.getBusinessType());approvalOrderDTO.setBusinessName(businessName);JSONObject applyData = new JSONObject();for (int i = 0; i < controls.length(); i++) {JSONObject control = controls.getJSONObject(i).getJSONObject("property");String controlType = control.getString("control");String controlId = control.getString("id");String title = control.getJSONArray("title").getJSONObject(0).getString("text");JSONObject field = new JSONObject();field.put("id", controlId);field.put("control", controlType);JSONObject fieldValue = new JSONObject();if ("Text".equals(controlType)) {switch (title) {case "客户名称":fieldValue.put("text", approvalOrderDTO.getClientName());break;case "业务类型":fieldValue.put("text", approvalOrderDTO.getBusinessName());break;case "合同总额":fieldValue.put("text", approvalOrderDTO.getOrderMoney());break;default:fieldValue.put("text", "无");break;}} else if ("File".equals(controlType)) {if (approvalOrderDTO.getMediaIdList() != null) {JSONArray filesArray = new JSONArray();for (String mediaId : approvalAreaDTO.getMediaIdList()) {JSONObject fileObject = new JSONObject();fileObject.put("file_id", mediaId);filesArray.put(fileObject);}fieldValue.put("files", filesArray);}} else if ("Textarea".equals(controlType)) {if (!StringUtils.isNull(approvalOrderDTO.getRemark())) {fieldValue.put("text", approvalOrderDTO.getRemark());}}field.put("value", fieldValue);formArray.put(field);}//处理子控件for (int i = 0; i < controls.length(); i++) {JSONObject control = controls.getJSONObject(i).getJSONObject("property");String controlType = control.getString("control");String controlId = control.getString("id");JSONObject resultObject = new JSONObject();resultObject.put("id", controlId);resultObject.put("control", controlType);if ("Table".equals(controlType)) {// 获取表格控件的配置信息JSONObject config = controls.getJSONObject(i).getJSONObject("config");JSONArray children = config.getJSONObject("table").getJSONArray("children");// 获取订单项目列表List<OrdersProjectListDTO> orderDetails = approvalOrderDTO.getOrdersProjectList();JSONArray jsonArray = new JSONArray(); // 用于存放所有表格行数据if (orderDetails != null && !orderDetails.isEmpty()) {for (OrdersProjectListDTO detail : orderDetails) {// 用于存放当前行的所有列数据JSONArray rowArray = new JSONArray();// 遍历表格模板的 children 数组,按模板字段顺序填充数据for (int n = 0; n < children.length(); n++) {JSONObject property = children.getJSONObject(n).getJSONObject("property");// 提取控件 ID、类型和标题String id = property.getString("id");String controlTypeInTable = property.getString("control");String tit = property.getJSONArray("title").getJSONObject(0).getString("text");// 填充对应字段值JSONObject value = new JSONObject();switch (tit) {case "合作项目":value.put("text", detail.getProjectName()); // 填充项目名称break;case "单价":value.put("text", detail.getUnitPrice()); // 填充单价break;case "数量":value.put("text", detail.getQuantity()); // 填充数量break;case "小计":value.put("text", detail.getSubtotal()); // 填充小计break;default:value.put("text", "未知字段"); // 其他字段使用默认值break;}// 构造当前列的数据结构JSONObject columnData = new JSONObject();columnData.put("id", id);columnData.put("control", controlTypeInTable);columnData.put("title", new JSONArray().put(new JSONObject().put("text", tit))); // 包含字段标题columnData.put("value", value);rowArray.put(columnData);}// 构造当前行数据JSONObject rowData = new JSONObject();rowData.put("list", rowArray);jsonArray.put(rowData); // 添加当前行到表格数据}// 遍历 JSON 数组for (int j = 0; j < formArray.length(); j++) {JSONObject obj = formArray.getJSONObject(j);// 判断是否是 Table 控件if ("Table".equals(obj.getString("control"))) {JSONObject value = obj.getJSONObject("value");value.put("children", jsonArray);}}}}}// 构造最终的审批请求applyData.put("contents", formArray);JSONObject auditRequest = new JSONObject();auditRequest.put("template_id", approvalTemplateDTO.getTemplate_id());auditRequest.put("creator_userid", approvalOrderDTO.getWechatUser());auditRequest.put("use_template_approver", 1);auditRequest.put("apply_data", applyData);System.out.println("构造最终的审批请求:" + auditRequest);// 调用企业微信审核接口String auditApiUrl = weChatConfig.getApprovalUrl() + "?access_token=" + getAccessToken();String res = HttpUtils.sendPost(auditApiUrl, auditRequest.toString());System.out.println("return:" + res);JSONObject jsonObject = new JSONObject(res);return jsonObject.getString("sp_no");} catch (Exception e) {e.printStackTrace();throw new ServiceException(ServiceConstants.USER_APPROVAL);}}
控件不一样,类型不一样 具体参照文档
给的例子全是value里面的参数
附带订单上传的json 格式
{"template_id": "C4ZULJy5ZkE7UuXWFu5rBfe1Xt7d91wbgpL2Rwrj1","creator_userid": "laoyou","use_template_approver": 1,"apply_data": {"contents": [{"id": "Text-1734055236654","control": "Text","value": {"text": "老友测试客户"}},{"id": "Text-1734055244339","control": "Text","value": {"text": "产品销售类"}},{"id": "Table-1734417961974","control": "Table","value": {"children": [{"list": [{"id": "Text-1734417976091","control": "Text","title": [{"text": "合作项目"}],"value": {"text": "A项目"}},{"id": "Text-1734417982652","control": "Text","title": [{"text": "单价"}],"value": {"text": 1}},{"id": "Text-1734417988404","control": "Text","title": [{"text": "数量"}],"value": {"text": 1}},{"id": "Text-1734417994187","control": "Text","title": [{"text": "小计"}],"value": {"text": 1}}]},{"list": [{"id": "Text-1734417976091","control": "Text","title": [{"text": "合作项目"}],"value": {"text": "B项目"}},{"id": "Text-1734417982652","control": "Text","title": [{"text": "单价"}],"value": {"text": 2}},{"id": "Text-1734417988404","control": "Text","title": [{"text": "数量"}],"value": {"text": 2}},{"id": "Text-1734417994187","control": "Text","title": [{"text": "小计"}],"value": {"text": 4}}]}]}},{"id": "Text-1734055362163","control": "Text","value": {"text": 5}},{"id": "Textarea-1734055383107","control": "Textarea","value": {"text": "这是一个订单"}},{"id": "File-1734055390371","control": "File","value": {"files": [{"file_id": "39EZFpTASgYAlxDf2S09ClA0TKaQcGPyQZPEQ9HbEwQN0AWwl4BLXy8MHyB5CG6yG"}]}}]}
}
加密解密下载链接
登录 - 企业微信开发者中心
相关文章:

Java系统对接企业微信审批项目流程
若依做的一个系统需求需要对接企业微信的人员去审核订单 回款之类,以下是详细步骤. 1.首先登入企业微信管理后台: 企业微信 2.找到应用管理 3.自建一个应用 4.这些数据都可以拿到 5.配置可信Ip 6.进入有两种方法让你去配置 ,第一种用公司的…...

基于Springboot人口老龄化社区服务与管理平台【附源码】
基于Springboot人口老龄化社区服务与管理平台 效果如下: 系统登陆页面 系统主页面 社区信息页面 社区文件页面 活动报名页面 走访任务管理页面 社区资讯页面 老人信息管理页面 研究背景 随着社会老龄化的加剧,老年人口比例逐渐增加,对老年…...

Dot Foods EDI 需求分析及对接流程
Dot Foods 是一家美国领先的食品和非食品产品的中间批发分销商,主要为食品服务、零售和分销行业的客户提供服务,是北美大型食品中间分销商之一。Dot Foods (以下简称 Dot)的业务模式是通过整合多个供应商的产品,为客户…...

代码随想录day24 | leetcode 93.复原IP地址 90.子集 90.子集II
93.复原IP地址 Java class Solution {List<String> result new ArrayList<String>();StringBuilder stringBuilder new StringBuilder();public List<String> restoreIpAddresses(String s) {backtracking(s, 0, 0);return result;}// number表示stringb…...

探索国产数字隔离器——测试与应用
国产数字隔离器已成为现代电子产品中的关键部件,以增强的性能和可靠性取代了传统的光耦合器。这些隔离器广泛应用于医疗设备、汽车电子、工业自动化和其他需要强大信号隔离的领域。准确测试这些设备是确保其质量和性能的基本步骤。 如何测试数字隔离器 测试数字隔离…...
IDEA无法打开插件市场的解决
1.版本 我的IDEA版本号为2020.1.4 大家可以从IDEA的help->about进行版本号的查看 2.解决 我们直接到jetbrains官网搜索你想要下载的插件 直接下载即可自动导入...

以腾讯混元模型为例,在管理平台上集成一个智能助手
背景 前几天,公司的同事们一起吃了个饭,餐桌上大家聊到大模型的落地场景。我个人在去年已经利用百度千帆平台写过案例,并发过博客(传送门👉:利用文心千帆打造一个属于自己的小师爷),…...

15.初识接口1 C#
这是一个用于实验接口的代码 适合初认识接口的人 【CSDN开头介绍】(文心一言AI生成) 在C#编程世界中,接口(Interface)扮演着至关重要的角色,它定义了一组方法,但不提供这些方法的实现。它要求所…...

探索 Python编程 调试案例:计算小程序中修复偶数的bug
在 学习Python 编程的过程里,会遇到各种各样的bug。而修复bug调试代码就像是一场充满挑战的侦探游戏。每一个隐藏的 bug 都是谜题,等待开发者去揭开真相,让程序可以顺利运行。今天,让我们通过一个实际案例,深入探索 Py…...
【Unity/HFSM】使用UnityHFSM实现输入缓冲(预输入)和打断机制
文章目录 前言预输入Animancer的InputBuffer:在UnityHFSM中实现InputBuffer: 打断机制 前言 参考Animancer在状态机中的InputBuffer,在UnityHFSM中实现类似的InputBuffer机制,同时扩展一个状态打断机制 插件介绍: A…...

Unity 圆形循环复用滚动列表
一.在上一篇垂直循环复用滚动列表的基础上,扩展延申了圆形循环复用滚动列表。实现此效果需要导入垂直循环复用滚动列表里面的类。 1.基础类 using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using …...

聚水潭数据无缝集成到金蝶云星空的实现方案
聚水潭数据集成到金蝶云星空:聚水潭调拨对接金蝶直接调拨ok 在企业信息化管理中,数据的高效流动和准确对接是实现业务流程顺畅运行的关键。本文将分享一个具体的系统对接集成案例——如何通过轻易云数据集成平台,将聚水潭的数据无缝集成到金…...

虚拟机断网没有网络,需清理内存,删除后再重启
进入NetworkManager可能没权限,设置权限777 to...

[c++11(二)]Lambda表达式和Function包装器及bind函数
1.前言 Lambda表达式着重解决的是在某种场景下使用仿函数困难的问题,而function着重解决的是函数指针的问题,它能够将其简单化。 本章重点: 本章将着重讲解lambda表达式的规则和使用场景,以及function的使用场景及bind函数的相关使…...

基于字节大模型的论文翻译(含免费源码)
基于字节大模型的论文翻译 源代码: 👏 star ✨ https://github.com/boots-coder/LLM-application 展示 项目简介 本项目是一个基于大语言模型(Large Language Model, LLM)的论文阅读与翻译辅助工具。它通过用户界面(…...

Mysql语法之DQL查询的多行函数
Mysql的多行函数和分组 目录 Mysql的多行函数和分组多行函数概念常用的多行函数 数据分组概念语法where和having的区别 语句关键字及执行顺序语句关键字执行顺序 实际操作基本语句格式和多行操作筛选语句格式 多行函数 概念 不管函数处理多少条,只返回一条记录&…...

OpenSSL 心脏滴血漏洞(CVE-2014-0160)
OpenSSL 心脏滴血漏洞(CVE-2014-0160) Openssl简介: 该漏洞在国内被译为"OpenSSL心脏出血漏洞”,因其破坏性之大和影响的范围之广,堪称网络安全里程碑事件。 OpenSSL心脏滴血漏洞的大概原理是OpenSSL在2年前引入了心跳(hearbea0机制来维特TS链接的…...

监控视频汇聚融合云平台一站式解决视频资源管理痛点
随着5G技术的广泛应用,各领域都在通信技术加持下通过海量终端设备收集了大量视频、图像等物联网数据,并通过人工智能、大数据、视频监控等技术方式来让我们的世界更安全、更高效。然而,随着数字化建设和生产经营管理活动的长期开展࿰…...

ElasticSearch 数据同步
1、同步调用 操作步骤: 管理系统新增酒店数据添加到数据库调用 ES 更新文档接口,同步数据库的数据到 ES 文档 流程图: 特点: 优点:实现简单,粗暴缺点:业务耦合度高 2、异步消息通知 操作步骤…...

MyBatis-Plus中isNull与SQL语法详解:处理空值的正确姿势
目录 前言1. 探讨2. 基本知识3. 总结 前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF 基本的Java知识推荐阅读: java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全&#x…...

RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
PostgreSQL——环境搭建
一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在࿰…...

c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...

tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...
用鸿蒙HarmonyOS5实现中国象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...