mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2025-05-03 20:27:46 +08:00
issue #8 添加同步回复消息的支持
This commit is contained in:
parent
dad826b0e6
commit
706230da50
20
README.md
20
README.md
@ -45,6 +45,26 @@ router.route(message);
|
||||
3. 规则的结束必须用``Rule.end()``或者``Rule.next()``,否则不会生效
|
||||
4. 具体使用可以看源代码中的``WxMessageRouterTest``单元测试,或者查看Javadoc
|
||||
|
||||
### 同步回复
|
||||
|
||||
``WxMessageRouter``默认使用异步的方式处理消息,如果要使用同步的方式处理消息,那么可以这样:
|
||||
|
||||
```java
|
||||
router
|
||||
.rule()
|
||||
.async(false)
|
||||
.handler(handler)
|
||||
.end()
|
||||
;
|
||||
|
||||
WxXmlMessage message = WxXmlMessage.fromXml(xml);
|
||||
// 获得同步的返回结果
|
||||
WxXmlMessage res = router.route(message);
|
||||
String xml = res.toXml();
|
||||
// ... 将xml写入HttpServletResponse
|
||||
```
|
||||
|
||||
|
||||
## 微信Java API
|
||||
|
||||
使用``WxService``可以调用微信API。目前已实现除“微信小店”以外的所有功能。
|
||||
|
@ -15,7 +15,8 @@ public interface WxMessageHandler {
|
||||
*
|
||||
* @param wxMessage
|
||||
* @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个
|
||||
* @return xml格式的消息,如果在异步规则里处理的话,可以返回null
|
||||
*/
|
||||
public void handle(WxXmlMessage wxMessage, Map<String, Object> context);
|
||||
public WxXmlMessage handle(WxXmlMessage wxMessage, Map<String, Object> context);
|
||||
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import chanjarster.weixin.bean.WxXmlMessage;
|
||||
|
||||
@ -37,8 +39,10 @@ import chanjarster.weixin.bean.WxXmlMessage;
|
||||
*/
|
||||
public class WxMessageRouter {
|
||||
|
||||
private List<Rule> rules = new ArrayList<Rule>();
|
||||
private final List<Rule> rules = new ArrayList<Rule>();
|
||||
|
||||
private final ExecutorService es = Executors.newCachedThreadPool();
|
||||
|
||||
/**
|
||||
* 开始一个新的Route规则
|
||||
* @return
|
||||
@ -51,21 +55,52 @@ public class WxMessageRouter {
|
||||
* 处理微信消息
|
||||
* @param wxMessage
|
||||
*/
|
||||
public void route(WxXmlMessage wxMessage) {
|
||||
for (Rule rule : rules) {
|
||||
public WxXmlMessage route(final WxXmlMessage wxMessage) {
|
||||
final List<Rule> matchRules = new ArrayList<Rule>();
|
||||
// 收集匹配的规则
|
||||
for (final Rule rule : rules) {
|
||||
if (rule.test(wxMessage)) {
|
||||
rule.service(wxMessage);
|
||||
if(!rule.reEnter) {
|
||||
break;
|
||||
}
|
||||
matchRules.add(rule);
|
||||
}
|
||||
}
|
||||
|
||||
if (matchRules.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (matchRules.get(0).async) {
|
||||
// 只要第一个是异步的,那就异步执行
|
||||
// 在另一个线程里执行
|
||||
es.submit(new Runnable() {
|
||||
public void run() {
|
||||
for (final Rule rule : matchRules) {
|
||||
rule.service(wxMessage);
|
||||
if (!rule.reEnter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
WxXmlMessage res = null;
|
||||
for (final Rule rule : matchRules) {
|
||||
// 返回最后一个匹配规则的结果
|
||||
res = rule.service(wxMessage);
|
||||
if (!rule.reEnter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static class Rule {
|
||||
|
||||
private final WxMessageRouter routerBuilder;
|
||||
|
||||
private boolean async = true;
|
||||
|
||||
private String msgType;
|
||||
|
||||
private String event;
|
||||
@ -84,6 +119,16 @@ public class WxMessageRouter {
|
||||
this.routerBuilder = routerBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否异步执行,默认是true
|
||||
* @param async
|
||||
* @return
|
||||
*/
|
||||
public Rule async(boolean async) {
|
||||
this.async = async;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果msgType等于某值
|
||||
* @param msgType
|
||||
@ -209,21 +254,22 @@ public class WxMessageRouter {
|
||||
* @param wxMessage
|
||||
* @return true 代表继续执行别的router,false 代表停止执行别的router
|
||||
*/
|
||||
protected void service(WxXmlMessage wxMessage) {
|
||||
protected WxXmlMessage service(WxXmlMessage wxMessage) {
|
||||
Map<String, Object> context = new HashMap<String, Object>();
|
||||
// 如果拦截器不通过
|
||||
for (WxMessageInterceptor interceptor : this.interceptors) {
|
||||
if (!interceptor.intercept(wxMessage, context)) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 交给handler处理
|
||||
for (WxMessageHandler interceptor : this.handlers) {
|
||||
interceptor.handle(wxMessage, context);
|
||||
WxXmlMessage res = null;
|
||||
for (WxMessageHandler handler : this.handlers) {
|
||||
// 返回最后handler的结果
|
||||
res = handler.handle(wxMessage, context);
|
||||
}
|
||||
|
||||
return;
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package chanjarster.weixin.api;
|
||||
import java.util.Map;
|
||||
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
@ -17,40 +16,78 @@ import chanjarster.weixin.bean.WxXmlMessage;
|
||||
@Test
|
||||
public class WxMessageRouterTest {
|
||||
|
||||
protected StringBuilder sb;
|
||||
protected WxMessageRouter router;
|
||||
|
||||
@BeforeMethod
|
||||
public void prepare() {
|
||||
this.sb = new StringBuilder();
|
||||
this.router = new WxMessageRouter();
|
||||
@Test(enabled = false)
|
||||
public void prepare(boolean async, StringBuffer sb, WxMessageRouter router) {
|
||||
router
|
||||
.rule()
|
||||
.async(async)
|
||||
.msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1").content("CONTENT_1")
|
||||
.handler(new WxEchoMessageHandler(sb, "COMBINE_4"))
|
||||
.end()
|
||||
.rule()
|
||||
.async(async)
|
||||
.msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1")
|
||||
.handler(new WxEchoMessageHandler(sb, "COMBINE_3"))
|
||||
.end()
|
||||
.rule()
|
||||
.async(async)
|
||||
.msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK)
|
||||
.handler(new WxEchoMessageHandler(sb, "COMBINE_2"))
|
||||
.end()
|
||||
.rule().msgType(WxConsts.XML_MSG_TEXT).handler(new WxEchoMessageHandler(sb, WxConsts.XML_MSG_TEXT)).end()
|
||||
.rule().event(WxConsts.EVT_CLICK).handler(new WxEchoMessageHandler(sb, WxConsts.EVT_CLICK)).end()
|
||||
.rule().eventKey("KEY_1").handler(new WxEchoMessageHandler(sb, "KEY_1")).end()
|
||||
.rule().content("CONTENT_1").handler(new WxEchoMessageHandler(sb, "CONTENT_1")).end()
|
||||
.rule().handler(new WxEchoMessageHandler(sb, "ALL")).end();
|
||||
.rule().async(async).msgType(WxConsts.XML_MSG_TEXT).handler(new WxEchoMessageHandler(sb, WxConsts.XML_MSG_TEXT)).end()
|
||||
.rule().async(async).event(WxConsts.EVT_CLICK).handler(new WxEchoMessageHandler(sb, WxConsts.EVT_CLICK)).end()
|
||||
.rule().async(async).eventKey("KEY_1").handler(new WxEchoMessageHandler(sb, "KEY_1")).end()
|
||||
.rule().async(async).content("CONTENT_1").handler(new WxEchoMessageHandler(sb, "CONTENT_1")).end()
|
||||
.rule().async(async).handler(new WxEchoMessageHandler(sb, "ALL")).end();
|
||||
;
|
||||
}
|
||||
|
||||
@Test(dataProvider="messages-1")
|
||||
public void testSimple(WxXmlMessage message, String expected) {
|
||||
public void testSync(WxXmlMessage message, String expected) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
WxMessageRouter router = new WxMessageRouter();
|
||||
prepare(false, sb, router);
|
||||
router.route(message);
|
||||
Assert.assertEquals(sb.toString(), expected);
|
||||
}
|
||||
|
||||
@Test(dataProvider="messages-1")
|
||||
public void testAsync(WxXmlMessage message, String expected) throws InterruptedException {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
WxMessageRouter router = new WxMessageRouter();
|
||||
prepare(true, sb, router);
|
||||
router.route(message);
|
||||
Thread.sleep(500l);
|
||||
Assert.assertEquals(sb.toString(), expected);
|
||||
}
|
||||
|
||||
public void testConcurrency() throws InterruptedException {
|
||||
final WxMessageRouter router = new WxMessageRouter();
|
||||
router.rule().handler(new WxMessageHandler() {
|
||||
@Override
|
||||
public WxXmlMessage handle(WxXmlMessage wxMessage, Map<String, Object> context) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}).end();
|
||||
|
||||
final WxXmlMessage m = new WxXmlMessage();
|
||||
Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
router.route(m);
|
||||
try {
|
||||
Thread.sleep(1000l);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
};
|
||||
for (int i = 0; i < 10; i++) {
|
||||
new Thread(r).start();
|
||||
}
|
||||
|
||||
Thread.sleep(1000l * 2);
|
||||
}
|
||||
@DataProvider(name="messages-1")
|
||||
public Object[][] messages2() {
|
||||
WxXmlMessage message1 = new WxXmlMessage();
|
||||
@ -98,17 +135,18 @@ public class WxMessageRouterTest {
|
||||
|
||||
public static class WxEchoMessageHandler implements WxMessageHandler {
|
||||
|
||||
private StringBuilder sb;
|
||||
private StringBuffer sb;
|
||||
private String echoStr;
|
||||
|
||||
public WxEchoMessageHandler(StringBuilder sb, String echoStr) {
|
||||
public WxEchoMessageHandler(StringBuffer sb, String echoStr) {
|
||||
this.sb = sb;
|
||||
this.echoStr = echoStr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(WxXmlMessage wxMessage, Map<String, Object> context) {
|
||||
public WxXmlMessage handle(WxXmlMessage wxMessage, Map<String, Object> context) {
|
||||
sb.append(this.echoStr).append(',');
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user