0
# Message Handling
1
2
Complete message processing framework including routing, handling, and response building for WeChat Official Account messaging.
3
4
## Message Router
5
6
```java { .api }
7
class WxMpMessageRouter {
8
// Rule creation and configuration
9
WxMpMessageRouterRule rule();
10
11
// Message routing
12
WxMpXmlOutMessage route(WxMpXmlMessage message);
13
WxMpXmlOutMessage route(WxMpXmlMessage message, Map<String, Object> context);
14
WxMpXmlOutMessage route(WxMpXmlMessage message, Map<String, Object> context,
15
WxMpService wxMpService, WxSessionManager sessionManager);
16
}
17
18
class WxMpMessageRouterRule {
19
// Message type matching
20
WxMpMessageRouterRule msgType(String msgType);
21
WxMpMessageRouterRule event(String event);
22
WxMpMessageRouterRule eventKey(String eventKey);
23
WxMpMessageRouterRule eventKeyRegex(String regex);
24
WxMpMessageRouterRule content(String content);
25
WxMpMessageRouterRule rContent(String regexContent);
26
27
// User matching
28
WxMpMessageRouterRule fromUser(String fromUser);
29
30
// Custom matching
31
WxMpMessageRouterRule matcher(WxMpMessageMatcher matcher);
32
33
// Handler assignment
34
WxMpMessageRouterRule handler(WxMpMessageHandler handler);
35
WxMpMessageRouterRule handler(WxMpMessageHandler handler, WxMpMessageHandler... handlers);
36
37
// Processing configuration
38
WxMpMessageRouterRule async(boolean async);
39
WxMpMessageRouterRule interceptor(WxMpMessageInterceptor interceptor);
40
WxMpMessageRouterRule interceptor(WxMpMessageInterceptor interceptor, WxMpMessageInterceptor... interceptors);
41
42
// Rule completion
43
WxMpMessageRouter end();
44
}
45
```
46
47
## Message Handler Interface
48
49
```java { .api }
50
interface WxMpMessageHandler {
51
WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
52
Map<String, Object> context,
53
WxMpService wxMpService,
54
WxSessionManager sessionManager) throws WxErrorException;
55
}
56
57
interface WxMpMessageInterceptor {
58
boolean intercept(WxMpXmlMessage wxMessage,
59
Map<String, Object> context,
60
WxMpService wxMpService,
61
WxSessionManager sessionManager) throws WxErrorException;
62
}
63
64
interface WxMpMessageMatcher {
65
boolean match(WxMpXmlMessage message);
66
}
67
```
68
69
## Incoming Message Model
70
71
```java { .api }
72
class WxMpXmlMessage implements Serializable {
73
// Basic message fields
74
private String toUser;
75
private String fromUser;
76
private Long createTime;
77
private String msgType;
78
private Long msgId;
79
80
// Text message
81
private String content;
82
83
// Image message
84
private String picUrl;
85
private String mediaId;
86
87
// Voice message
88
private String format;
89
private String recognition;
90
91
// Video message
92
private String thumbMediaId;
93
94
// Location message
95
private String locationX;
96
private String locationY;
97
private String scale;
98
private String label;
99
100
// Link message
101
private String title;
102
private String description;
103
private String url;
104
105
// Event message
106
private String event;
107
private String eventKey;
108
private String ticket;
109
private String latitude;
110
private String longitude;
111
private String precision;
112
113
// Menu events
114
private Long menuId;
115
116
// Scan events
117
private String scanCodeInfo;
118
private String scanType;
119
private String scanResult;
120
121
// Photo events
122
private String sendPicsInfo;
123
private Integer count;
124
private List<SendPicsInfo.Item> picList;
125
126
// Location events
127
private String sendLocationInfo;
128
private String locationName;
129
private String address;
130
131
// All fields map for extensibility
132
private Map<String, Object> allFieldsMap;
133
134
// Static factory methods
135
public static WxMpXmlMessage fromXml(String xml);
136
public static WxMpXmlMessage fromXml(InputStream is);
137
public static WxMpXmlMessage fromEncryptedXml(String xml, WxMpConfigStorage config, String timestamp, String nonce, String msgSignature);
138
public static WxMpXmlMessage fromEncryptedXml(InputStream is, WxMpConfigStorage config, String timestamp, String nonce, String msgSignature);
139
140
// Getters and setters for all fields
141
public String getToUser();
142
public void setToUser(String toUser);
143
public String getFromUser();
144
public void setFromUser(String fromUser);
145
public Long getCreateTime();
146
public void setCreateTime(Long createTime);
147
public String getMsgType();
148
public void setMsgType(String msgType);
149
public String getContent();
150
public void setContent(String content);
151
public Long getMsgId();
152
public void setMsgId(Long msgId);
153
public String getPicUrl();
154
public void setPicUrl(String picUrl);
155
public String getMediaId();
156
public void setMediaId(String mediaId);
157
public String getFormat();
158
public void setFormat(String format);
159
public String getThumbMediaId();
160
public void setThumbMediaId(String thumbMediaId);
161
public String getLocationX();
162
public void setLocationX(String locationX);
163
public String getLocationY();
164
public void setLocationY(String locationY);
165
public String getScale();
166
public void setScale(String scale);
167
public String getLabel();
168
public void setLabel(String label);
169
public String getTitle();
170
public void setTitle(String title);
171
public String getDescription();
172
public void setDescription(String description);
173
public String getUrl();
174
public void setUrl(String url);
175
public String getEvent();
176
public void setEvent(String event);
177
public String getEventKey();
178
public void setEventKey(String eventKey);
179
public String getTicket();
180
public void setTicket(String ticket);
181
public String getLatitude();
182
public void setLatitude(String latitude);
183
public String getLongitude();
184
public void setLongitude(String longitude);
185
public String getPrecision();
186
public void setPrecision(String precision);
187
public String getRecognition();
188
public void setRecognition(String recognition);
189
}
190
```
191
192
## Outgoing Message Models
193
194
```java { .api }
195
abstract class WxMpXmlOutMessage {
196
protected String toUserName;
197
protected String fromUserName;
198
protected Long createTime;
199
protected String msgType;
200
201
// Abstract methods
202
public abstract String toXml();
203
204
// Common methods
205
public String getToUserName();
206
public void setToUserName(String toUserName);
207
public String getFromUserName();
208
public void setFromUserName(String fromUserName);
209
public Long getCreateTime();
210
public void setCreateTime(Long createTime);
211
public String getMsgType();
212
public void setMsgType(String msgType);
213
}
214
215
class WxMpXmlOutTextMessage extends WxMpXmlOutMessage {
216
private String content;
217
218
public String getContent();
219
public void setContent(String content);
220
}
221
222
class WxMpXmlOutImageMessage extends WxMpXmlOutMessage {
223
private String mediaId;
224
225
public String getMediaId();
226
public void setMediaId(String mediaId);
227
}
228
229
class WxMpXmlOutVoiceMessage extends WxMpXmlOutMessage {
230
private String mediaId;
231
232
public String getMediaId();
233
public void setMediaId(String mediaId);
234
}
235
236
class WxMpXmlOutVideoMessage extends WxMpXmlOutMessage {
237
private String mediaId;
238
private String title;
239
private String description;
240
241
public String getMediaId();
242
public void setMediaId(String mediaId);
243
public String getTitle();
244
public void setTitle(String title);
245
public String getDescription();
246
public void setDescription(String description);
247
}
248
249
class WxMpXmlOutMusicMessage extends WxMpXmlOutMessage {
250
private String title;
251
private String description;
252
private String musicUrl;
253
private String hqMusicUrl;
254
private String thumbMediaId;
255
256
public String getTitle();
257
public void setTitle(String title);
258
public String getDescription();
259
public void setDescription(String description);
260
public String getMusicUrl();
261
public void setMusicUrl(String musicUrl);
262
public String getHqMusicUrl();
263
public void setHqMusicUrl(String hqMusicUrl);
264
public String getThumbMediaId();
265
public void setThumbMediaId(String thumbMediaId);
266
}
267
268
class WxMpXmlOutNewsMessage extends WxMpXmlOutMessage {
269
private List<WxMpXmlOutNewsMessage.Item> articles;
270
271
public List<Item> getArticles();
272
public void setArticles(List<Item> articles);
273
public void addArticle(Item item);
274
275
public static class Item {
276
private String title;
277
private String description;
278
private String picUrl;
279
private String url;
280
281
public String getTitle();
282
public void setTitle(String title);
283
public String getDescription();
284
public void setDescription(String description);
285
public String getPicUrl();
286
public void setPicUrl(String picUrl);
287
public String getUrl();
288
public void setUrl(String url);
289
}
290
}
291
```
292
293
## Message Builders
294
295
```java { .api }
296
class TextBuilder {
297
public static WxMpXmlOutTextMessage build(String content, WxMpXmlMessage wxMessage);
298
}
299
300
class ImageBuilder {
301
public static WxMpXmlOutImageMessage build(String mediaId, WxMpXmlMessage wxMessage);
302
}
303
304
class VoiceBuilder {
305
public static WxMpXmlOutVoiceMessage build(String mediaId, WxMpXmlMessage wxMessage);
306
}
307
308
class VideoBuilder {
309
public static WxMpXmlOutVideoMessage build(String mediaId, String title, String description, WxMpXmlMessage wxMessage);
310
}
311
312
class MusicBuilder {
313
public static WxMpXmlOutMusicMessage build(String title, String description,
314
String musicUrl, String hqMusicUrl,
315
String thumbMediaId, WxMpXmlMessage wxMessage);
316
}
317
318
class NewsBuilder {
319
public static WxMpXmlOutNewsMessage build(List<WxMpXmlOutNewsMessage.Item> articles, WxMpXmlMessage wxMessage);
320
}
321
```
322
323
## Message Constants
324
325
```java { .api }
326
// Message types from WxConsts
327
public static final String XmlMsgType = "MsgType";
328
public static final String TEXT = "text";
329
public static final String IMAGE = "image";
330
public static final String VOICE = "voice";
331
public static final String VIDEO = "video";
332
public static final String SHORTVIDEO = "shortvideo";
333
public static final String LOCATION = "location";
334
public static final String LINK = "link";
335
public static final String EVENT = "event";
336
public static final String MUSIC = "music";
337
public static final String NEWS = "news";
338
public static final String TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service";
339
public static final String DEVICE_TEXT = "device_text";
340
public static final String DEVICE_EVENT = "device_event";
341
public static final String DEVICE_STATUS = "device_status";
342
public static final String HARDWARE = "hardware";
343
344
// Event types
345
public static final String Event = "Event";
346
public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
347
public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
348
public static final String EVENT_TYPE_SCAN = "SCAN";
349
public static final String EVENT_TYPE_LOCATION = "LOCATION";
350
public static final String EVENT_TYPE_CLICK = "CLICK";
351
public static final String EVENT_TYPE_VIEW = "VIEW";
352
public static final String EVENT_TYPE_MASSSENDJOBFINISH = "MASSSENDJOBFINISH";
353
public static final String EVENT_TYPE_TEMPLATESENDJOBFINISH = "TEMPLATESENDJOBFINISH";
354
public static final String EVENT_TYPE_SCANCODE_PUSH = "scancode_push";
355
public static final String EVENT_TYPE_SCANCODE_WAITMSG = "scancode_waitmsg";
356
public static final String EVENT_TYPE_PIC_SYSPHOTO = "pic_sysphoto";
357
public static final String EVENT_TYPE_PIC_PHOTO_OR_ALBUM = "pic_photo_or_album";
358
public static final String EVENT_TYPE_PIC_WEIXIN = "pic_weixin";
359
public static final String EVENT_TYPE_LOCATION_SELECT = "location_select";
360
```
361
362
## Usage Examples
363
364
### Basic Message Router Setup
365
366
```java
367
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
368
import me.chanjar.weixin.mp.api.WxMpMessageHandler;
369
import me.chanjar.weixin.common.api.WxConsts;
370
371
// Create message router
372
WxMpMessageRouter router = new WxMpMessageRouter(wxService);
373
374
// Handle text messages
375
router.rule()
376
.msgType(WxConsts.XmlMsgType.TEXT)
377
.handler(new TextMessageHandler())
378
.end();
379
380
// Handle subscribe events
381
router.rule()
382
.msgType(WxConsts.XmlMsgType.EVENT)
383
.event(WxConsts.EventType.SUBSCRIBE)
384
.handler(new SubscribeHandler())
385
.end();
386
387
// Handle menu click events
388
router.rule()
389
.msgType(WxConsts.XmlMsgType.EVENT)
390
.event(WxConsts.EventType.CLICK)
391
.eventKey("MENU_KEY_HELP")
392
.handler(new HelpMenuHandler())
393
.end();
394
395
// Route incoming message
396
WxMpXmlOutMessage response = router.route(incomingMessage);
397
```
398
399
### Custom Message Handlers
400
401
```java
402
public class TextMessageHandler implements WxMpMessageHandler {
403
@Override
404
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
405
Map<String, Object> context,
406
WxMpService wxMpService,
407
WxSessionManager sessionManager) throws WxErrorException {
408
409
String content = wxMessage.getContent();
410
411
if ("help".equalsIgnoreCase(content)) {
412
return TextBuilder.build("Help information here", wxMessage);
413
} else if (content.startsWith("weather")) {
414
// Handle weather query
415
String weatherInfo = getWeatherInfo(content);
416
return TextBuilder.build(weatherInfo, wxMessage);
417
} else {
418
return TextBuilder.build("Echo: " + content, wxMessage);
419
}
420
}
421
422
private String getWeatherInfo(String query) {
423
// Weather service implementation
424
return "Weather information for " + query;
425
}
426
}
427
428
public class SubscribeHandler implements WxMpMessageHandler {
429
@Override
430
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
431
Map<String, Object> context,
432
WxMpService wxMpService,
433
WxSessionManager sessionManager) throws WxErrorException {
434
435
// Welcome new subscriber
436
String welcomeMessage = "Welcome to our WeChat Official Account! " +
437
"Send 'help' for available commands.";
438
439
return TextBuilder.build(welcomeMessage, wxMessage);
440
}
441
}
442
```
443
444
### Advanced Router Configuration
445
446
```java
447
// Complex routing with multiple conditions
448
router.rule()
449
.msgType(WxConsts.XmlMsgType.TEXT)
450
.rContent("(?i)^(hi|hello|hey).*") // Case-insensitive greeting regex
451
.handler(new GreetingHandler())
452
.end();
453
454
// Handle different users differently
455
router.rule()
456
.msgType(WxConsts.XmlMsgType.TEXT)
457
.fromUser("admin_openid")
458
.handler(new AdminHandler())
459
.end();
460
461
// Custom matcher
462
router.rule()
463
.matcher(message -> {
464
// Custom logic for complex conditions
465
return message.getContent() != null &&
466
message.getContent().contains("urgent");
467
})
468
.handler(new UrgentMessageHandler())
469
.async(true) // Handle asynchronously
470
.end();
471
472
// Interceptor for logging
473
router.rule()
474
.msgType(WxConsts.XmlMsgType.TEXT)
475
.interceptor((wxMessage, context, wxMpService, sessionManager) -> {
476
System.out.println("Processing message from: " + wxMessage.getFromUser());
477
return true; // Continue processing
478
})
479
.handler(new LoggedTextHandler())
480
.end();
481
```
482
483
### Rich Message Responses
484
485
```java
486
public class MenuHandler implements WxMpMessageHandler {
487
@Override
488
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
489
Map<String, Object> context,
490
WxMpService wxMpService,
491
WxSessionManager sessionManager) throws WxErrorException {
492
493
String eventKey = wxMessage.getEventKey();
494
495
switch (eventKey) {
496
case "MENU_NEWS":
497
return buildNewsMessage(wxMessage);
498
case "MENU_IMAGE":
499
return buildImageMessage(wxMessage);
500
case "MENU_VOICE":
501
return buildVoiceMessage(wxMessage);
502
default:
503
return TextBuilder.build("Unknown menu option", wxMessage);
504
}
505
}
506
507
private WxMpXmlOutNewsMessage buildNewsMessage(WxMpXmlMessage wxMessage) {
508
List<WxMpXmlOutNewsMessage.Item> articles = new ArrayList<>();
509
510
WxMpXmlOutNewsMessage.Item item1 = new WxMpXmlOutNewsMessage.Item();
511
item1.setTitle("Latest News");
512
item1.setDescription("Check out our latest updates");
513
item1.setPicUrl("https://example.com/image1.jpg");
514
item1.setUrl("https://example.com/news/1");
515
articles.add(item1);
516
517
WxMpXmlOutNewsMessage.Item item2 = new WxMpXmlOutNewsMessage.Item();
518
item2.setTitle("Product Updates");
519
item2.setDescription("New features available now");
520
item2.setPicUrl("https://example.com/image2.jpg");
521
item2.setUrl("https://example.com/news/2");
522
articles.add(item2);
523
524
return NewsBuilder.build(articles, wxMessage);
525
}
526
527
private WxMpXmlOutImageMessage buildImageMessage(WxMpXmlMessage wxMessage) {
528
return ImageBuilder.build("media_id_123", wxMessage);
529
}
530
531
private WxMpXmlOutVoiceMessage buildVoiceMessage(WxMpXmlMessage wxMessage) {
532
return VoiceBuilder.build("voice_media_id_456", wxMessage);
533
}
534
}
535
```
536
537
### Event Handling
538
539
```java
540
// QR code scan events
541
router.rule()
542
.msgType(WxConsts.XmlMsgType.EVENT)
543
.event(WxConsts.EventType.SCAN)
544
.handler(new QrScanHandler())
545
.end();
546
547
// Location events
548
router.rule()
549
.msgType(WxConsts.XmlMsgType.EVENT)
550
.event(WxConsts.EventType.LOCATION)
551
.handler(new LocationHandler())
552
.end();
553
554
public class QrScanHandler implements WxMpMessageHandler {
555
@Override
556
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
557
Map<String, Object> context,
558
WxMpService wxMpService,
559
WxSessionManager sessionManager) throws WxErrorException {
560
561
String eventKey = wxMessage.getEventKey();
562
String ticket = wxMessage.getTicket();
563
564
// Process QR code scan
565
String response = processQrScan(eventKey, ticket, wxMessage.getFromUser());
566
567
return TextBuilder.build(response, wxMessage);
568
}
569
570
private String processQrScan(String eventKey, String ticket, String fromUser) {
571
// QR code processing logic
572
return "QR code scanned: " + eventKey;
573
}
574
}
575
```
576
577
### Message Parsing
578
579
```java
580
// Parse incoming XML message
581
String xmlData = "..."; // Received from WeChat
582
WxMpXmlMessage message = WxMpXmlMessage.fromXml(xmlData);
583
584
// Parse encrypted message
585
WxMpXmlMessage encryptedMessage = WxMpXmlMessage.fromEncryptedXml(
586
xmlData, config, timestamp, nonce, msgSignature);
587
588
// Access message data
589
System.out.println("Message type: " + message.getMsgType());
590
System.out.println("From user: " + message.getFromUser());
591
System.out.println("Content: " + message.getContent());
592
```
593
594
### Session Management
595
596
```java
597
public class StatefulHandler implements WxMpMessageHandler {
598
@Override
599
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
600
Map<String, Object> context,
601
WxMpService wxMpService,
602
WxSessionManager sessionManager) throws WxErrorException {
603
604
String fromUser = wxMessage.getFromUser();
605
WxSession session = sessionManager.getSession(fromUser);
606
607
// Get session attribute
608
String state = (String) session.getAttribute("conversation_state");
609
610
if ("waiting_for_name".equals(state)) {
611
// Process name input
612
String name = wxMessage.getContent();
613
session.setAttribute("user_name", name);
614
session.setAttribute("conversation_state", "waiting_for_age");
615
616
return TextBuilder.build("Thanks " + name + "! What's your age?", wxMessage);
617
} else if ("waiting_for_age".equals(state)) {
618
// Process age input
619
String age = wxMessage.getContent();
620
String name = (String) session.getAttribute("user_name");
621
622
session.removeAttribute("conversation_state");
623
624
return TextBuilder.build(
625
"Nice to meet you, " + name + " (" + age + " years old)!",
626
wxMessage
627
);
628
} else {
629
// Start conversation
630
session.setAttribute("conversation_state", "waiting_for_name");
631
return TextBuilder.build("What's your name?", wxMessage);
632
}
633
}
634
}
635
```
636
637
## Error Handling
638
639
```java
640
public class SafeMessageHandler implements WxMpMessageHandler {
641
@Override
642
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
643
Map<String, Object> context,
644
WxMpService wxMpService,
645
WxSessionManager sessionManager) throws WxErrorException {
646
try {
647
// Message processing logic
648
return processMessage(wxMessage, wxMpService);
649
} catch (Exception e) {
650
// Log error
651
System.err.println("Error processing message: " + e.getMessage());
652
653
// Return safe fallback response
654
return TextBuilder.build(
655
"Sorry, there was an error processing your message. Please try again later.",
656
wxMessage
657
);
658
}
659
}
660
661
private WxMpXmlOutMessage processMessage(WxMpXmlMessage wxMessage, WxMpService wxMpService) {
662
// Actual processing logic
663
return TextBuilder.build("Processed successfully", wxMessage);
664
}
665
}
666
```