2026-06-24 f4bd1f3c89d906131495a0aca5aaf82966378510
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
package cn.iocoder.yudao.module.mp.framework.mp.core;
 
import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
import cn.iocoder.yudao.module.mp.service.handler.menu.MenuHandler;
import cn.iocoder.yudao.module.mp.service.handler.message.MessageReceiveHandler;
import cn.iocoder.yudao.module.mp.service.handler.message.MessageAutoReplyHandler;
import cn.iocoder.yudao.module.mp.service.handler.other.KfSessionHandler;
import cn.iocoder.yudao.module.mp.service.handler.other.NullHandler;
import cn.iocoder.yudao.module.mp.service.handler.other.ScanHandler;
import cn.iocoder.yudao.module.mp.service.handler.other.StoreCheckNotifyHandler;
import cn.iocoder.yudao.module.mp.service.handler.user.LocationHandler;
import cn.iocoder.yudao.module.mp.service.handler.user.SubscribeHandler;
import cn.iocoder.yudao.module.mp.service.handler.user.UnsubscribeHandler;
import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
import com.google.common.collect.Maps;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl;
import me.chanjar.weixin.mp.constant.WxMpEventConstants;
 
import java.util.List;
import java.util.Map;
 
/**
 * 默认的 {@link MpServiceFactory} 实现类
 *
 * @author 芋道源码
 */
@Slf4j
@RequiredArgsConstructor
public class DefaultMpServiceFactory implements MpServiceFactory {
 
    /**
     * 微信 appId 与 WxMpService 的映射
     */
    private volatile Map<String, WxMpService> appId2MpServices;
    /**
     * 公众号账号 id 与 WxMpService 的映射
     */
    private volatile Map<Long, WxMpService> id2MpServices;
    /**
     * 微信 appId 与 WxMpMessageRouter 的映射
     */
    private volatile Map<String, WxMpMessageRouter> mpMessageRouters;
 
    private final RedisTemplateWxRedisOps redisTemplateWxRedisOps;
    private final WxMpProperties mpProperties;
 
    // ========== 各种 Handler ==========
 
    private final MessageReceiveHandler messageReceiveHandler;
    private final KfSessionHandler kfSessionHandler;
    private final StoreCheckNotifyHandler storeCheckNotifyHandler;
    private final MenuHandler menuHandler;
    private final NullHandler nullHandler;
    private final SubscribeHandler subscribeHandler;
    private final UnsubscribeHandler unsubscribeHandler;
    private final LocationHandler locationHandler;
    private final ScanHandler scanHandler;
    private final MessageAutoReplyHandler messageAutoReplyHandler;
 
    @Override
    public void init(List<MpAccountDO> list) {
        Map<String, WxMpService> appId2MpServices = Maps.newHashMap();
        Map<Long, WxMpService> id2MpServices = Maps.newHashMap();
        Map<String, WxMpMessageRouter> mpMessageRouters = Maps.newHashMap();
        // 处理 list
        list.forEach(account -> {
            // 构建 WxMpService 对象
            WxMpService mpService = buildMpService(account);
            appId2MpServices.put(account.getAppId(), mpService);
            id2MpServices.put(account.getId(), mpService);
            // 构建 WxMpMessageRouter 对象
            WxMpMessageRouter mpMessageRouter = buildMpMessageRouter(mpService);
            mpMessageRouters.put(account.getAppId(), mpMessageRouter);
        });
 
        // 设置到缓存
        this.appId2MpServices = appId2MpServices;
        this.id2MpServices = id2MpServices;
        this.mpMessageRouters = mpMessageRouters;
    }
 
    @Override
    public WxMpService getMpService(Long id) {
        return id2MpServices.get(id);
    }
 
    @Override
    public WxMpService getMpService(String appId) {
        return appId2MpServices.get(appId);
    }
 
    @Override
    public WxMpMessageRouter getMpMessageRouter(String appId) {
        return mpMessageRouters.get(appId);
    }
 
    private WxMpService buildMpService(MpAccountDO account) {
        // 第一步,创建 WxMpRedisConfigImpl 对象
        WxMpRedisConfigImpl configStorage = new WxMpRedisConfigImpl(
                redisTemplateWxRedisOps, mpProperties.getConfigStorage().getKeyPrefix());
        configStorage.setAppId(account.getAppId());
        configStorage.setSecret(account.getAppSecret());
        configStorage.setToken(account.getToken());
        configStorage.setAesKey(account.getAesKey());
 
        // 第二步,创建 WxMpService 对象
        WxMpService service = new WxMpServiceImpl();
        service.setWxMpConfigStorage(configStorage);
        return service;
    }
 
    private WxMpMessageRouter buildMpMessageRouter(WxMpService mpService) {
        WxMpMessageRouter router = new WxMpMessageRouter(mpService);
        // 记录所有事件的日志(异步执行)
        router.rule().handler(messageReceiveHandler).next();
 
        // 接收客服会话管理事件
        router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
                .event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION)
                .handler(kfSessionHandler).end();
        router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
                .event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION)
                .handler(kfSessionHandler)
                .end();
        router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
                .event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION)
                .handler(kfSessionHandler).end();
 
        // 门店审核事件
        router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
                .event(WxMpEventConstants.POI_CHECK_NOTIFY)
                .handler(storeCheckNotifyHandler).end();
 
        // 自定义菜单事件
        router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
                .event(WxConsts.MenuButtonType.CLICK).handler(menuHandler).end();
 
        // 点击菜单连接事件
        router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
                .event(WxConsts.MenuButtonType.VIEW).handler(nullHandler).end();
 
        // 关注事件
        router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
                .event(WxConsts.EventType.SUBSCRIBE).handler(subscribeHandler)
                .end();
 
        // 取消关注事件
        router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
                .event(WxConsts.EventType.UNSUBSCRIBE)
                .handler(unsubscribeHandler).end();
 
        // 上报地理位置事件
        router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
                .event(WxConsts.EventType.LOCATION).handler(locationHandler)
                .end();
 
        // 接收地理位置消息
        router.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION)
                .handler(locationHandler).end();
 
        // 扫码事件
        router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
                .event(WxConsts.EventType.SCAN).handler(scanHandler).end();
 
        // 默认
        router.rule().async(false).handler(messageAutoReplyHandler).end();
        return router;
    }
 
}