开发高端网站建设,百度推广 网站要备案吗,网站内容转载,全国猎头公司前十名若依做的一个系统需求需要对接企业微信的人员去审核订单 回款之类#xff0c;以下是详细步骤.
1.首先登入企业微信管理后台#xff1a;
企业微信
2.找到应用管理 3.自建一个应用 4.这些数据都可以拿到 5.配置可信Ip 6.进入有两种方法让你去配置 #xff0c;第一种用公司的…
若依做的一个系统需求需要对接企业微信的人员去审核订单 回款之类以下是详细步骤.
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: 3WMVpackage 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 ListUserInfo 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);// 获取订单项目列表ListOrdersProjectListDTO 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}]}}]}
}
加密解密下载链接
登录 - 企业微信开发者中心