当前位置: 首页 > news >正文

企业微信自建应用开发回调事件实现方案

目录

 1. 前言

2. 正文

2.1 技术方案

2.2 策略上下文

2.2 添加客户策略实现类

2.3 修改客户信息策略实现类

2.4 默认策略实现类

2.5 接收事件的实体类(可以根据事件格式的参数做修改)

2.6 实际接收回调结果的接口


近日在开发企业微信的自建应用时,涉及到一个需求需要监听企业微信的事件通知比如:删除联系,添加联系人,修改联系人等事件通知,今天给大家看一下我是怎么实现的。

 1. 前言

        在企业微信中以客户联系功能举例,客户联系的回调事件如下:

        需要注意的是只有用户在客户端或者说管理端进行操作的时候才会回调响应的事件通知,如果说通过api去进行操作的话是不会产生回调事件的。

        然后需要到我们企微后台中将应用的消息通知给打开:

        配置回调地址如下:

        需要注意的时候,在配置回调地址的时候,企微会向该url发起一个get请求来进行校验,(而实际上回调事件是post请求,所以需要有两个方式的请求)所以这个url必须是公网能够访问的,官网链接

        get请求如下:

@ApiOperation("验证回调接口")@GetMapping("/callback/external-user")public String verifyURL(@RequestParam(name = "msg_signature") final String msgSignature,@RequestParam(name = "timestamp") final String timestamp,@RequestParam(name = "nonce") final String nonce,@RequestParam(name = "echostr") final String echostr) {String sEchoStr = null;try {WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, aesKey, corpId);// 随机字符串sEchoStr = wxcpt.verifyUrl(msgSignature, timestamp, nonce, echostr);} catch (Exception e) {logger.error("error ", e);}return sEchoStr;}
我使用的依赖如下:
<dependency><groupId>com.github.liyiorg</groupId><artifactId>weixin-popular</artifactId><version>2.8.30</version>
</dependency>

2. 正文

2.1 技术方案

        为了代码以后能够更好的维护和扩展。结合企微回调事件的特点:不同的事件有不同的ChangeType,所以我这里使用策略模式来对不同的事件进行解耦操作具体如下

2.2 策略上下文

@Component
public class CallbackContext {@Autowiredprivate WechatCallbackLogService callbackLogService;private final Map<String, CallbackStrategy> callbackStrategyMap;/*** 通过不同的changeType返回不同的策略,没有选择则返回默认策略模式* @param callbackStrategyMap spring容器管理的所有CallbackStrategy类*/@Autowiredpublic CallbackContext(Map<String, CallbackStrategy> callbackStrategyMap) {this.callbackStrategyMap = callbackStrategyMap;}public void execute(WechatCallbackLog callbackBean) {CallbackStrategy callbackStrategy = callbackStrategyMap.get(callbackBean.getChangeType());if (Objects.isNull(callbackStrategy)) {callbackStrategy = callbackStrategyMap.get("default_external_contact");}//保存日志callbackStrategy.operate(callbackBean);callbackLogService.insertLog(callbackBean);}
}

2.2 添加客户策略实现类

/*** @author light pwd* @description 添加企业客户事件* @date 2024/11/25*/
@Component("add_external_contact")
public class AddExternalCallbackStrategy implements CallbackStrategy {private static final Logger LOGGER = LoggerFactory.getLogger(AddExternalCallbackStrategy.class);/*** 添加企业客户事件* changeType:add_external_contact*/@Overridepublic void operate(WechatCallbackLog callbackBean) {System.out.println("我是添加客户回调事件");}}

2.3 修改客户信息策略实现类


/*** @author light pwd* @description* @date 2024/11/25*/
@Component("edit_external_contact")
public class EditExternalCallbackStrategy implements CallbackStrategy {/*** 编辑企业客户事件:edit_external_contact* 如果备注修改了则同步修改线索的名称,如果备注为空则取昵称* 线索判断逻辑:(通过手机号Or当前员工的userId)+当前客户的externalUserId* 优先使用手机号*/@Overridepublic void operate(WechatCallbackLog callbackBean) {System.out.println("我是修改客户信息回调事件");}}

2.4 默认策略实现类

当触发没有实现的回调事件时会调用该方法


/*** @author light pwd* @description* @date 2024/11/25*/
@Component("default_external_contact")
public class DefaultCallBackStrategy implements CallbackStrategy {/***默认策略模式*/@Overridepublic void operate(WechatCallbackLog callbackBean) {callbackBean.setRemark("没有该回调的实现方法:" + callbackBean.getChangeType());}
}

2.5 接收事件的实体类(可以根据事件格式的参数做修改)


/*** @author light pwd* @description* @date 2024/11/25*/
public class WechatCallbackLog implements Serializable {private String id;private String changeType;private String userId;private Date createTime;private String event;private String toUserName;private String fromUserName;private String msgType;private String externalUserId;private String state;private String source;private String failReason;private String data;private String remark;private Date createTime1;private String errorCode;private String errMsg;/*** 回调的策略方法执行状态:0成功,1失败*/private Short status;//省略了getter和setter方法
}

2.6 实际接收回调结果的接口

@ApiOperation("实际回调请求的接口")@ResponseBody@PostMapping(value = "/callback/external-user")public Result<String> callbackApp(@RequestBody String sPostData,@RequestParam(name = "msg_signature") final String sMsgSignature,@RequestParam(name = "timestamp") final String sTimestamp,@RequestParam(name = "nonce") final String sNonce) {try {WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, aesKey, corpId);//解密String sMsg = wxcpt.decryptMsg(sMsgSignature, sTimestamp, sNonce, sPostData);//将post数据转换为mapMap<String, String> dataMap = MessageUtil.parseXml(sMsg);WechatCallbackLog callbackBean = convertToBean(dataMap);callbackContext.execute(callbackBean);logger.info("event json : {}", JSONObject.toJSONString(dataMap));} catch (Exception e) {logger.error("error ", e);}return Result.success("成功");}/*** 将回调的值转为WechatCallbackLog* @param dataMap* @return*/private WechatCallbackLog convertToBean(Map<String, String> dataMap) {String changeType = MapUtils.getString(dataMap, "ChangeType");String userId = MapUtils.getString(dataMap, "UserID");Date createTime = new Date(MapUtils.getLong(dataMap, "CreateTime") * 1000);String event = MapUtils.getString(dataMap, "Event");String toUserName = MapUtils.getString(dataMap, "ToUserName");String fromUserName = MapUtils.getString(dataMap, "FromUserName");String msgType = MapUtils.getString(dataMap, "MsgType");String externalUserId = MapUtils.getString(dataMap, "ExternalUserID");String state = MapUtils.getString(dataMap, "State");String source = MapUtils.getString(dataMap, "Source");String failReason = MapUtils.getString(dataMap, "FailReason");WechatCallbackLog callbackLog = new WechatCallbackLog();callbackLog.setChangeType(changeType);callbackLog.setCreateTime(createTime);callbackLog.setUserId(userId);callbackLog.setEvent(event);callbackLog.setToUserName(toUserName);callbackLog.setFromUserName(fromUserName);callbackLog.setMsgType(msgType);callbackLog.setExternalUserId(externalUserId);callbackLog.setState(state);callbackLog.setSource(source);callbackLog.setFailReason(failReason);callbackLog.setData(dataMap.toString());return callbackLog;}

给大家看一下我保存的回调结果日志记录

 以上就是我的实现方案,如果有问题欢迎大家评论区交流!

路在脚下,勇往直前,追求卓越,成就梦想!!

相关文章:

  • javaNIO详解
  • cv::dnn::NMSBoxes和nms-free的比较
  • 测风塔布局算法详解:基于宏观分区与微观定量选址的双阶段优化方法
  • Java数据结构——ArrayList
  • Spring 依赖冲突解决方案详解
  • SAP系统工艺路线的分配物料出现旧版包材
  • 从 0~1 保姆级 详细版 PostgreSQL 数据库安装教程
  • 理解Java一些基础(八股)
  • 红帽RHEL与国产Linux系统对比:技术、生态与自主可控的博弈
  • 如何系统地入门学习stm32?
  • 【大模型】 LangChain框架 -LangChain实现问答系统
  • [C++] 高精度加法(作用 + 模板 + 例题)
  • CSS继承
  • 游戏引擎学习第235天:在 Windows 上初始化 OpenGL
  • stm32| 中断标志位和中断挂起位 | TIM_ClearFlag 函数和TIM_ClearITPendingBit 函数
  • 云服务器性价比测评:Intel vs AMD vs Graviton
  • 绕过UI的cooke和token的验证
  • `pred_by_img.setdefault(img, [ ]).append({...})`
  • @EnableAsync+@Async源码学习笔记之五
  • springboot景区民宿网上预约系统(源码+lw+部署文档+讲解),源码可白嫖!
  • 山西一国道发生塌陷,造成4车追尾2人死亡
  • 外交部介绍中印尼“2+2”机制首次部长级会议将讨论的议题
  • 特朗普叫停已许可的海上风电,机构将美国风电前景下调40%
  • 中马签署互免签证协定,外交部:将进一步促进双边人员往来和交流合作
  • 东三省去年常住人口均已揭晓
  • 神舟二十号船箭组合体垂直转运正在进行,近日将择机发射