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

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

目录

 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;}

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

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

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

http://www.xdnf.cn/news/535.html

相关文章:

  • AI文生图工具推荐
  • swift-12-Error处理、关联类型、assert、泛型_
  • Java ThreadPoolExecutor 深度解析:从原理到实战
  • 编译Spring源码时遇到的错误
  • HDMI如何进行插入检测
  • QML中的3D功能--纹理应用
  • Linux字符设备驱动
  • ZLMediaKit 和 SRS的区别,哪个更好用?
  • 在Qt和OSG中动态改变部分3D模型数据
  • 大模型API中转平台选择指南:如何找到优质稳定的服务
  • 压滤机与锡泥产生效率
  • OzGIS:地理信息分析与处理软件
  • C语言用if else求三个数最小值的一题多解
  • c++冒泡排序实现
  • Java Web 之 简介 100问
  • 大模型时代:机遇与风险并存的AI革命
  • Java Stream API 实践指南:从基础操作到高效用法
  • 【操作系统原理03】处理机调度与死锁
  • 运筹学之模拟退火
  • 生成模型StackGAN模型详解
  • 高效的项目构建:用 Makefile 自动化你的构建过程
  • Mybatis源码01-SpringBoot启动时mybatis加载过程
  • U-Boot 启动过程详解
  • 杂记-2025年4月19日
  • Linux压缩与解压命令完全指南:tar.gz、zip等格式详解
  • JAVA 继承
  • 【EDA软件】【设计约束和分析操作方法】
  • 【AI提示词】经济学家
  • 使用Ingress发布应用程序
  • MySQL——事务