mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2025-04-05 17:38:05 +08:00
微信消息路由器,及单元测试代码
This commit is contained in:
parent
189f285259
commit
ed3cdfcecd
49
README.md
49
README.md
@ -1,7 +1,48 @@
|
||||
weixin-java
|
||||
weixin-tools
|
||||
===========
|
||||
|
||||
微信java开发工具集
|
||||
微信java开发工具,本项目提供了两个主要特性:微信消息路由器、微信Java API
|
||||
|
||||
## 执行测试
|
||||
将 ''src/test/resources/test-config.sample.xml'' 改成 ''test-config.xml'' 并设置appId, secret, 一个过期的accessToken
|
||||
## 微信消息路由器
|
||||
|
||||
你可以使用``WxMessageRouter``来对微信推送过来的消息、事件进行路由,交给特定的``WxMessageHandler``处理。
|
||||
|
||||
使用方法:
|
||||
|
||||
```java
|
||||
WxMessageRouter router = new WxMessageRouter();
|
||||
router
|
||||
.rule()
|
||||
.msgType("MSG_TYPE").event("EVENT").eventKey("EVENT_KEY").content("CONTENT")
|
||||
.interceptor(interceptor, ...).handler(handler, ...)
|
||||
.end()
|
||||
.rule()
|
||||
// 另外一个匹配规则
|
||||
.end()
|
||||
;
|
||||
|
||||
// 将WxXmlMessage交给消息路由器
|
||||
router.route(message);
|
||||
```
|
||||
|
||||
说明:
|
||||
1. 配置路由规则时要按照从细到粗的原则,否则可能消息可能会被提前处理
|
||||
2. 默认情况下消息只会被处理一次,除非使用 {@link Rule#next()}
|
||||
3. 规则的结束必须用{@link Rule#end()}或者{@link Rule#next()},否则不会生效
|
||||
|
||||
## 微信Java API
|
||||
|
||||
使用``WxService``可以调用微信API。目前实现了以下功能,其余功能以后陆续补充:
|
||||
|
||||
1. 发送客服消息
|
||||
1. 创建自定义菜单
|
||||
1. 删除自定义菜单
|
||||
1. 查询自定义菜单
|
||||
1. 刷新access_token
|
||||
|
||||
## 如何执行单元测试
|
||||
将 ``src/test/resources/test-config.sample.xml`` 改成 ``test-config.xml`` 设置appId, secret, accessToken(可选), openId
|
||||
|
||||
```bash
|
||||
mvn clean test
|
||||
```
|
||||
|
2
pom.xml
2
pom.xml
@ -4,7 +4,7 @@
|
||||
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>chanjarster.weixin</groupId>
|
||||
<artifactId>weixin-java</artifactId>
|
||||
<artifactId>weixin-toolset</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<name>WeiXin Java Toolset</name>
|
||||
<url>https://github.com/chanjarster/weixin-java</url>
|
||||
|
@ -10,6 +10,14 @@ public class WxConsts {
|
||||
public static final String MSG_NEWS = "news";
|
||||
public static final String MSG_LOCATION = "location";
|
||||
public static final String MSG_LINK = "link";
|
||||
public static final String MSG_EVENT = "event";
|
||||
|
||||
public static final String EVT_SUBSCRIBE = "subscribe";
|
||||
public static final String EVT_UNSUBSCRIBE = "unsubscribe";
|
||||
public static final String EVT_SCAN = "SCAN";
|
||||
public static final String EVT_LOCATION = "LOCATION";
|
||||
public static final String EVT_CLICK = "LOCATION";
|
||||
public static final String EVT_VIEW = "VIEW";
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import java.util.Map;
|
||||
import chanjarster.weixin.bean.WxXmlMessage;
|
||||
|
||||
/**
|
||||
* 处理微信推送消息的处理器
|
||||
* 处理微信推送消息的处理器接口
|
||||
* @author chanjarster
|
||||
*
|
||||
*/
|
||||
|
@ -5,13 +5,17 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import chanjarster.weixin.api.WxMessageRouterTest.WxEchoMessageHandler;
|
||||
import chanjarster.weixin.bean.WxXmlMessage;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 微信消息路由器,通过代码化的配置,把来自微信的消息交给handler处理
|
||||
*
|
||||
* 说明:
|
||||
* 1. 配置路由规则时要按照从细到粗的原则,否则可能消息可能会被提前处理
|
||||
* 2. 默认情况下消息只会被处理一次,除非使用 {@link Rule#next()}
|
||||
* 3. 规则的结束必须用{@link Rule#end()}或者{@link Rule#next()},否则不会生效
|
||||
*
|
||||
* 使用方法:
|
||||
* WxMessageRouter router = new WxMessageRouter();
|
||||
* router
|
||||
@ -27,9 +31,6 @@ import chanjarster.weixin.bean.WxXmlMessage;
|
||||
* // 将WxXmlMessage交给消息路由器
|
||||
* router.route(message);
|
||||
*
|
||||
* 说明:
|
||||
* 1. 配置路由规则时要按照从细到粗的原则
|
||||
* 2. 默认情况下消息只会被处理一次,除非使用 {@link Rule#reEnter()}
|
||||
* </pre>
|
||||
* @author qianjia
|
||||
*
|
||||
@ -52,9 +53,11 @@ public class WxMessageRouter {
|
||||
*/
|
||||
public void route(WxXmlMessage wxMessage) {
|
||||
for (Rule rule : rules) {
|
||||
boolean doNext = rule.service(wxMessage);
|
||||
if (!doNext) {
|
||||
break;
|
||||
if (rule.test(wxMessage)) {
|
||||
boolean reEnter = rule.service(wxMessage);
|
||||
if (!reEnter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -122,16 +125,16 @@ public class WxMessageRouter {
|
||||
}
|
||||
|
||||
/**
|
||||
* 将消息交给后面的Rule处理
|
||||
* 设置微信消息拦截器
|
||||
* @param interceptor
|
||||
* @return
|
||||
*/
|
||||
public Rule reEnter() {
|
||||
this.reEnter = true;
|
||||
return this;
|
||||
public Rule interceptor(WxMessageInterceptor interceptor) {
|
||||
return interceptor(interceptor, (WxMessageInterceptor[]) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加interceptor
|
||||
* 设置微信消息拦截器
|
||||
* @param interceptor
|
||||
* @param otherInterceptors
|
||||
* @return
|
||||
@ -147,10 +150,20 @@ public class WxMessageRouter {
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加handler
|
||||
* 设置微信消息处理器
|
||||
* @param handler
|
||||
* @return
|
||||
*/
|
||||
public Rule handler(WxMessageHandler handler) {
|
||||
return handler(handler, (WxMessageHandler[]) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置微信消息处理器
|
||||
* @param handler
|
||||
* @param otherHandlers
|
||||
* @return
|
||||
*/
|
||||
public Rule handler(WxMessageHandler handler, WxMessageHandler... otherHandlers) {
|
||||
this.handlers.add(handler);
|
||||
if (otherHandlers != null && otherHandlers.length > 0) {
|
||||
@ -162,7 +175,7 @@ public class WxMessageRouter {
|
||||
}
|
||||
|
||||
/**
|
||||
* 规则结束
|
||||
* 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则
|
||||
* @return
|
||||
*/
|
||||
public WxMessageRouter end() {
|
||||
@ -170,6 +183,15 @@ public class WxMessageRouter {
|
||||
return this.routerBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 规则结束,但是消息还会进入其他规则
|
||||
* @return
|
||||
*/
|
||||
public WxMessageRouter next() {
|
||||
this.reEnter = true;
|
||||
return end();
|
||||
}
|
||||
|
||||
protected boolean test(WxXmlMessage wxMessage) {
|
||||
return
|
||||
(this.msgType == null || this.msgType.equals(wxMessage.getMsgType()))
|
||||
@ -188,11 +210,6 @@ public class WxMessageRouter {
|
||||
* @return true 代表继续执行别的router,false 代表停止执行别的router
|
||||
*/
|
||||
protected boolean service(WxXmlMessage wxMessage) {
|
||||
// 如果不匹配本规则,那么接着执行后面的Rule
|
||||
if (!test(wxMessage)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Map<String, Object> context = new HashMap<String, Object>();
|
||||
// 如果拦截器不通过
|
||||
for (WxMessageInterceptor interceptor : this.interceptors) {
|
||||
|
@ -20,7 +20,7 @@ import chanjarster.weixin.bean.WxCustomMessage;
|
||||
import chanjarster.weixin.bean.WxError;
|
||||
import chanjarster.weixin.bean.WxMenu;
|
||||
import chanjarster.weixin.exception.WxErrorException;
|
||||
import chanjarster.weixin.util.Utf8StringResponseHandler;
|
||||
import chanjarster.weixin.util.Utf8ResponseHandler;
|
||||
|
||||
public class WxServiceImpl implements WxService {
|
||||
|
||||
@ -133,7 +133,7 @@ public class WxServiceImpl implements WxService {
|
||||
httpPost.setEntity(entity);
|
||||
}
|
||||
CloseableHttpResponse response = httpclient.execute(httpPost);
|
||||
resultContent = Utf8StringResponseHandler.INSTANCE.handleResponse(response);
|
||||
resultContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
|
||||
} else if ("GET".equals(method)) {
|
||||
if (data != null) {
|
||||
uriWithAccessToken += uriWithAccessToken.endsWith("&") ? data : '&' + data;
|
||||
@ -141,7 +141,7 @@ public class WxServiceImpl implements WxService {
|
||||
HttpGet httpGet = new HttpGet(uriWithAccessToken);
|
||||
CloseableHttpResponse response = httpclient.execute(httpGet);
|
||||
response.setHeader("Content-Type", ContentType.APPLICATION_JSON.toString());
|
||||
resultContent = Utf8StringResponseHandler.INSTANCE.handleResponse(response);
|
||||
resultContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
|
||||
}
|
||||
|
||||
WxError error = WxError.fromJson(resultContent);
|
||||
|
@ -15,9 +15,9 @@ import org.apache.http.util.EntityUtils;
|
||||
* @author chanjarster
|
||||
*
|
||||
*/
|
||||
public class Utf8StringResponseHandler implements ResponseHandler<String> {
|
||||
public class Utf8ResponseHandler implements ResponseHandler<String> {
|
||||
|
||||
public static final ResponseHandler<String> INSTANCE = new Utf8StringResponseHandler();
|
||||
public static final ResponseHandler<String> INSTANCE = new Utf8ResponseHandler();
|
||||
|
||||
public String handleResponse(final HttpResponse response) throws HttpResponseException, IOException {
|
||||
final StatusLine statusLine = response.getStatusLine();
|
@ -3,30 +3,97 @@ 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;
|
||||
|
||||
import chanjarster.weixin.bean.WxXmlMessage;
|
||||
|
||||
@Test
|
||||
public class WxMessageRouterTest {
|
||||
|
||||
public void testSimple() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
WxMessageRouter router = new WxMessageRouter();
|
||||
|
||||
protected StringBuilder sb;
|
||||
protected WxMessageRouter router;
|
||||
|
||||
@BeforeMethod
|
||||
public void prepare() {
|
||||
this.sb = new StringBuilder();
|
||||
this.router = new WxMessageRouter();
|
||||
router
|
||||
.rule()
|
||||
.msgType(WxConsts.MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1").content("CONTENT_1")
|
||||
.handler(new WxEchoMessageHandler(sb, "COMBINE_4"))
|
||||
.end()
|
||||
.rule()
|
||||
.msgType(WxConsts.MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1")
|
||||
.handler(new WxEchoMessageHandler(sb, "COMBINE_3"))
|
||||
.end()
|
||||
.rule()
|
||||
.msgType(WxConsts.MSG_TEXT).event(WxConsts.EVT_CLICK)
|
||||
.handler(new WxEchoMessageHandler(sb, "COMBINE_2"))
|
||||
.end()
|
||||
.rule().msgType(WxConsts.MSG_TEXT).handler(new WxEchoMessageHandler(sb, WxConsts.MSG_TEXT)).end()
|
||||
.rule().msgType(WxConsts.MSG_IMAGE).handler(new WxEchoMessageHandler(sb, WxConsts.MSG_IMAGE)).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();
|
||||
;
|
||||
|
||||
|
||||
WxXmlMessage message = new WxXmlMessage();
|
||||
message.setMsgType(WxConsts.MSG_TEXT);
|
||||
router.route(message);
|
||||
Assert.assertEquals(sb.toString(), WxConsts.MSG_TEXT + ",");
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test(dataProvider="messages-1")
|
||||
public void testSimple(WxXmlMessage message, String expected) {
|
||||
router.route(message);
|
||||
Assert.assertEquals(sb.toString(), expected);
|
||||
}
|
||||
|
||||
@Test()
|
||||
public void test() {
|
||||
|
||||
}
|
||||
@DataProvider(name="messages-1")
|
||||
public Object[][] messages2() {
|
||||
WxXmlMessage message1 = new WxXmlMessage();
|
||||
message1.setMsgType(WxConsts.MSG_TEXT);
|
||||
|
||||
WxXmlMessage message2 = new WxXmlMessage();
|
||||
message2.setEvent(WxConsts.EVT_CLICK);
|
||||
|
||||
WxXmlMessage message3 = new WxXmlMessage();
|
||||
message3.setEventKey("KEY_1");
|
||||
|
||||
WxXmlMessage message4 = new WxXmlMessage();
|
||||
message4.setContent("CONTENT_1");
|
||||
|
||||
WxXmlMessage message5 = new WxXmlMessage();
|
||||
message5.setContent("BLA");
|
||||
|
||||
WxXmlMessage c2 = new WxXmlMessage();
|
||||
c2.setMsgType(WxConsts.MSG_TEXT);
|
||||
c2.setEvent(WxConsts.EVT_CLICK);
|
||||
|
||||
WxXmlMessage c3 = new WxXmlMessage();
|
||||
c3.setMsgType(WxConsts.MSG_TEXT);
|
||||
c3.setEvent(WxConsts.EVT_CLICK);
|
||||
c3.setEventKey("KEY_1");
|
||||
|
||||
WxXmlMessage c4 = new WxXmlMessage();
|
||||
c4.setMsgType(WxConsts.MSG_TEXT);
|
||||
c4.setEvent(WxConsts.EVT_CLICK);
|
||||
c4.setEventKey("KEY_1");
|
||||
c4.setContent("CONTENT_1");
|
||||
|
||||
return new Object[][] {
|
||||
new Object[] { message1, WxConsts.MSG_TEXT + "," },
|
||||
new Object[] { message2, WxConsts.EVT_CLICK + "," },
|
||||
new Object[] { message3, "KEY_1," },
|
||||
new Object[] { message4, "CONTENT_1," },
|
||||
new Object[] { message5, "ALL," },
|
||||
new Object[] { c2, "COMBINE_2," },
|
||||
new Object[] { c3, "COMBINE_3," },
|
||||
new Object[] { c4, "COMBINE_4," }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public static class WxEchoMessageHandler implements WxMessageHandler {
|
||||
|
||||
|
@ -43,18 +43,18 @@ public class WxServiceTest {
|
||||
Assert.assertTrue(StringUtils.isNotBlank(after));
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "testRefreshAccessToken", enabled = false)
|
||||
@Test(dependsOnMethods = "testRefreshAccessToken")
|
||||
public void sendCustomMessage() throws WxErrorException {
|
||||
WxXmlConfigStorage configProvider = (WxXmlConfigStorage) wxService.wxConfigProvider;
|
||||
WxCustomMessage message = new WxCustomMessage();
|
||||
message.setMsgtype(WxConsts.MSG_TEXT);
|
||||
message.setTouser(configProvider.getOpenId());
|
||||
message.setContent("欢迎使用教务系统微信公众号\n下面\n<a href=\"http://www.baidu.com\">Hello World</a>");
|
||||
message.setContent("欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>");
|
||||
|
||||
wxService.sendCustomMessage(message);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "menu", enabled = true, dependsOnMethods = "testRefreshAccessToken")
|
||||
@Test(dataProvider = "menu", dependsOnMethods = "testRefreshAccessToken")
|
||||
public void testCreateMenu(WxMenu wxMenu) throws WxErrorException {
|
||||
wxService.createMenu(wxMenu);
|
||||
}
|
||||
@ -64,7 +64,7 @@ public class WxServiceTest {
|
||||
Assert.assertNotNull(wxService.getMenu());
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = { "testRefreshAccessToken", "testGetMenu" }, enabled = false)
|
||||
@Test(dependsOnMethods = { "testRefreshAccessToken", "testGetMenu" })
|
||||
public void testDeleteMenu() throws WxErrorException {
|
||||
wxService.deleteMenu();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user