mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2025-06-28 13:16:19 +08:00
add menu support
This commit is contained in:
parent
0a3e136605
commit
189f285259
@ -2,3 +2,6 @@ weixin-java
|
|||||||
===========
|
===========
|
||||||
|
|
||||||
微信java开发工具集
|
微信java开发工具集
|
||||||
|
|
||||||
|
## 执行测试
|
||||||
|
将 ''src/test/resources/test-config.sample.xml'' 改成 ''test-config.xml'' 并设置appId, secret, 一个过期的accessToken
|
||||||
|
@ -7,7 +7,7 @@ import chanjarster.weixin.bean.WxAccessToken;
|
|||||||
* @author chanjarster
|
* @author chanjarster
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public interface WxConfigProvider {
|
public interface WxConfigStorage {
|
||||||
|
|
||||||
public void updateAccessToken(WxAccessToken accessToken);
|
public void updateAccessToken(WxAccessToken accessToken);
|
||||||
|
|
@ -2,13 +2,14 @@ package chanjarster.weixin.api;
|
|||||||
|
|
||||||
public class WxConsts {
|
public class WxConsts {
|
||||||
|
|
||||||
public static final String TEXT = "text";
|
public static final String MSG_TEXT = "text";
|
||||||
public static final String IMAGE = "image";
|
public static final String MSG_IMAGE = "image";
|
||||||
public static final String VOICE = "voice";
|
public static final String MSG_VOICE = "voice";
|
||||||
public static final String MUSIC = "music";
|
public static final String MSG_MUSIC = "music";
|
||||||
public static final String VIDEO = "video";
|
public static final String MSG_VIDEO = "video";
|
||||||
public static final String NEWS = "news";
|
public static final String MSG_NEWS = "news";
|
||||||
public static final String LOCATION = "location";
|
public static final String MSG_LOCATION = "location";
|
||||||
public static final String LINK = "link";
|
public static final String MSG_LINK = "link";
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,11 @@ package chanjarster.weixin.api;
|
|||||||
import chanjarster.weixin.bean.WxAccessToken;
|
import chanjarster.weixin.bean.WxAccessToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基于内存的微信配置provider
|
* 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化
|
||||||
* @author chanjarster
|
* @author chanjarster
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class WxMemoryConfigProvider implements WxConfigProvider {
|
public class WxInMemoryConfigStorage implements WxConfigStorage {
|
||||||
|
|
||||||
protected String appId;
|
protected String appId;
|
||||||
protected String secret;
|
protected String secret;
|
||||||
@ -44,4 +44,24 @@ public class WxMemoryConfigProvider implements WxConfigProvider {
|
|||||||
return this.expiresIn;
|
return this.expiresIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAppId(String appId) {
|
||||||
|
this.appId = appId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSecret(String secret) {
|
||||||
|
this.secret = secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToken(String token) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccessToken(String accessToken) {
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpiresIn(int expiresIn) {
|
||||||
|
this.expiresIn = expiresIn;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -11,6 +11,11 @@ import chanjarster.weixin.bean.WxXmlMessage;
|
|||||||
*/
|
*/
|
||||||
public interface WxMessageHandler {
|
public interface WxMessageHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param wxMessage
|
||||||
|
* @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个
|
||||||
|
*/
|
||||||
public void handle(WxXmlMessage wxMessage, Map<String, Object> context);
|
public void handle(WxXmlMessage wxMessage, Map<String, Object> context);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,32 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import chanjarster.weixin.api.WxMessageRouterTest.WxEchoMessageHandler;
|
||||||
import chanjarster.weixin.bean.WxXmlMessage;
|
import chanjarster.weixin.bean.WxXmlMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信消息路由器,通过代码化的配置,把来自微信的消息交给某个的handler处理
|
* <pre>
|
||||||
|
* 微信消息路由器,通过代码化的配置,把来自微信的消息交给handler处理
|
||||||
|
*
|
||||||
|
* 使用方法:
|
||||||
|
* 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#reEnter()}
|
||||||
|
* </pre>
|
||||||
* @author qianjia
|
* @author qianjia
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -20,7 +42,7 @@ public class WxMessageRouter {
|
|||||||
* 开始一个新的Route规则
|
* 开始一个新的Route规则
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Rule start() {
|
public Rule rule() {
|
||||||
return new Rule(this);
|
return new Rule(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +71,7 @@ public class WxMessageRouter {
|
|||||||
|
|
||||||
private String content;
|
private String content;
|
||||||
|
|
||||||
private boolean forward = false;
|
private boolean reEnter = false;
|
||||||
|
|
||||||
private List<WxMessageHandler> handlers = new ArrayList<WxMessageHandler>();
|
private List<WxMessageHandler> handlers = new ArrayList<WxMessageHandler>();
|
||||||
|
|
||||||
@ -100,11 +122,11 @@ public class WxMessageRouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 如果本规则命中,在执行完handler后,还会接着给后面的Rule执行
|
* 将消息交给后面的Rule处理
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Rule forward() {
|
public Rule reEnter() {
|
||||||
this.forward = true;
|
this.reEnter = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +197,7 @@ public class WxMessageRouter {
|
|||||||
// 如果拦截器不通过
|
// 如果拦截器不通过
|
||||||
for (WxMessageInterceptor interceptor : this.interceptors) {
|
for (WxMessageInterceptor interceptor : this.interceptors) {
|
||||||
if (!interceptor.intercept(wxMessage, context)) {
|
if (!interceptor.intercept(wxMessage, context)) {
|
||||||
return this.forward;
|
return this.reEnter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,7 +206,7 @@ public class WxMessageRouter {
|
|||||||
interceptor.handle(wxMessage, context);
|
interceptor.handle(wxMessage, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.forward;
|
return this.reEnter;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,45 +10,58 @@ import chanjarster.weixin.exception.WxErrorException;
|
|||||||
public interface WxService {
|
public interface WxService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 刷新access_token,这个方法是线程安全的
|
* <pre>
|
||||||
* 且在高并发情况下只会刷新一次,而不是刷新多次
|
* 获取access_token,本方法线程安全
|
||||||
* 在非必要情况下不要主动调用此方法
|
* 且在多线程同时刷新时只刷新一次,避免超出1200次的调用次数上限
|
||||||
* 本service的所有方法都会在access_token过期的情况下调用此方法
|
|
||||||
*
|
*
|
||||||
|
* 另:本service的所有方法都会在access_token过期是调用此方法
|
||||||
|
*
|
||||||
|
* 程序员在非必要情况下尽量不要主动调用此方法
|
||||||
|
|
||||||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取access_token
|
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取access_token
|
||||||
|
* </pre>
|
||||||
* @throws WxErrorException
|
* @throws WxErrorException
|
||||||
*/
|
*/
|
||||||
public void refreshAccessToken() throws WxErrorException;
|
public void refreshAccessToken() throws WxErrorException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* <pre>
|
||||||
* 发送客服消息
|
* 发送客服消息
|
||||||
|
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息
|
||||||
|
* </pre>
|
||||||
* @param message
|
* @param message
|
||||||
* @return
|
|
||||||
* @throws WxErrorException
|
* @throws WxErrorException
|
||||||
*/
|
*/
|
||||||
public String sendCustomMessage(WxCustomMessage message) throws WxErrorException;
|
public String sendCustomMessage(WxCustomMessage message) throws WxErrorException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建菜单
|
* <pre>
|
||||||
|
* 自定义菜单创建接口
|
||||||
|
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单创建接口
|
||||||
|
* </pre>
|
||||||
* @param menu
|
* @param menu
|
||||||
* @return
|
|
||||||
* @throws WxErrorException
|
* @throws WxErrorException
|
||||||
*/
|
*/
|
||||||
public String createMenu(WxMenu menu) throws WxErrorException;
|
public String createMenu(WxMenu menu) throws WxErrorException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除菜单
|
* <pre>
|
||||||
* @return
|
* 自定义菜单删除接口
|
||||||
|
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单删除接口
|
||||||
|
* </pre>
|
||||||
* @throws WxErrorException
|
* @throws WxErrorException
|
||||||
*/
|
*/
|
||||||
public String deleteMenu() throws WxErrorException;
|
public String deleteMenu() throws WxErrorException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得菜单
|
* <pre>
|
||||||
|
* 自定义菜单查询接口
|
||||||
|
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单查询接口
|
||||||
|
* </pre>
|
||||||
* @return
|
* @return
|
||||||
* @throws WxErrorException
|
* @throws WxErrorException
|
||||||
*/
|
*/
|
||||||
public WxMenu getMenu() throws WxErrorException;
|
public WxMenu getMenu() throws WxErrorException;
|
||||||
|
|
||||||
public void setWxConfigProvider(WxConfigProvider wxConfigProvider);
|
public void setWxConfigProvider(WxConfigStorage wxConfigProvider);
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
package chanjarster.weixin.api;
|
package chanjarster.weixin.api;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.http.Consts;
|
||||||
import org.apache.http.client.ClientProtocolException;
|
import org.apache.http.client.ClientProtocolException;
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.http.client.methods.HttpGet;
|
||||||
import org.apache.http.client.methods.HttpPost;
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.entity.ContentType;
|
||||||
import org.apache.http.entity.StringEntity;
|
import org.apache.http.entity.StringEntity;
|
||||||
import org.apache.http.impl.client.BasicResponseHandler;
|
import org.apache.http.impl.client.BasicResponseHandler;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
@ -19,6 +20,7 @@ import chanjarster.weixin.bean.WxCustomMessage;
|
|||||||
import chanjarster.weixin.bean.WxError;
|
import chanjarster.weixin.bean.WxError;
|
||||||
import chanjarster.weixin.bean.WxMenu;
|
import chanjarster.weixin.bean.WxMenu;
|
||||||
import chanjarster.weixin.exception.WxErrorException;
|
import chanjarster.weixin.exception.WxErrorException;
|
||||||
|
import chanjarster.weixin.util.Utf8StringResponseHandler;
|
||||||
|
|
||||||
public class WxServiceImpl implements WxService {
|
public class WxServiceImpl implements WxService {
|
||||||
|
|
||||||
@ -31,9 +33,7 @@ public class WxServiceImpl implements WxService {
|
|||||||
|
|
||||||
protected static final CloseableHttpClient httpclient = HttpClients.createDefault();
|
protected static final CloseableHttpClient httpclient = HttpClients.createDefault();
|
||||||
|
|
||||||
protected static final Charset UTF8 = Charset.forName("UTF-8");
|
protected WxConfigStorage wxConfigProvider;
|
||||||
|
|
||||||
protected WxConfigProvider wxConfigProvider;
|
|
||||||
|
|
||||||
public void refreshAccessToken() throws WxErrorException {
|
public void refreshAccessToken() throws WxErrorException {
|
||||||
if (!GLOBAL_ACCESS_TOKEN_REFRESH_FLAG.getAndSet(true)) {
|
if (!GLOBAL_ACCESS_TOKEN_REFRESH_FLAG.getAndSet(true)) {
|
||||||
@ -46,6 +46,10 @@ public class WxServiceImpl implements WxService {
|
|||||||
HttpGet httpGet = new HttpGet(url);
|
HttpGet httpGet = new HttpGet(url);
|
||||||
CloseableHttpResponse response = httpclient.execute(httpGet);
|
CloseableHttpResponse response = httpclient.execute(httpGet);
|
||||||
String resultContent = new BasicResponseHandler().handleResponse(response);
|
String resultContent = new BasicResponseHandler().handleResponse(response);
|
||||||
|
WxError error = WxError.fromJson(resultContent);
|
||||||
|
if (error.getErrcode() != 0) {
|
||||||
|
throw new WxErrorException(error);
|
||||||
|
}
|
||||||
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
|
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
|
||||||
wxConfigProvider.updateAccessToken(accessToken.getAccess_token(), accessToken.getExpires_in());
|
wxConfigProvider.updateAccessToken(accessToken.getAccess_token(), accessToken.getExpires_in());
|
||||||
} catch (ClientProtocolException e) {
|
} catch (ClientProtocolException e) {
|
||||||
@ -68,17 +72,35 @@ public class WxServiceImpl implements WxService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送客服消息
|
|
||||||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息
|
|
||||||
* @param message
|
|
||||||
* @throws WxErrorException
|
|
||||||
*/
|
|
||||||
public String sendCustomMessage(WxCustomMessage message) throws WxErrorException {
|
public String sendCustomMessage(WxCustomMessage message) throws WxErrorException {
|
||||||
String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send";
|
String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send";
|
||||||
return post(url, message.toJson());
|
return post(url, message.toJson());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String createMenu(WxMenu menu) throws WxErrorException {
|
||||||
|
String url = "https://api.weixin.qq.com/cgi-bin/menu/create";
|
||||||
|
return post(url, menu.toJson());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String deleteMenu() throws WxErrorException {
|
||||||
|
String url = "https://api.weixin.qq.com/cgi-bin/menu/delete";
|
||||||
|
return get(url, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WxMenu getMenu() throws WxErrorException {
|
||||||
|
String url = "https://api.weixin.qq.com/cgi-bin/menu/get";
|
||||||
|
try {
|
||||||
|
String resultContent = get(url, null);
|
||||||
|
return WxMenu.fromJson(resultContent);
|
||||||
|
} catch (WxErrorException e) {
|
||||||
|
// 46003 不存在的菜单数据
|
||||||
|
if (e.getError().getErrcode() == 46003) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected String post(String uri, String data) throws WxErrorException {
|
protected String post(String uri, String data) throws WxErrorException {
|
||||||
return execute("POST", uri, data);
|
return execute("POST", uri, data);
|
||||||
}
|
}
|
||||||
@ -106,20 +128,26 @@ public class WxServiceImpl implements WxService {
|
|||||||
String resultContent = null;
|
String resultContent = null;
|
||||||
if ("POST".equals(method)) {
|
if ("POST".equals(method)) {
|
||||||
HttpPost httpPost = new HttpPost(uriWithAccessToken);
|
HttpPost httpPost = new HttpPost(uriWithAccessToken);
|
||||||
StringEntity entity = new StringEntity(data, UTF8);
|
if (data != null) {
|
||||||
httpPost.setEntity(entity);
|
StringEntity entity = new StringEntity(data, Consts.UTF_8);
|
||||||
|
httpPost.setEntity(entity);
|
||||||
|
}
|
||||||
CloseableHttpResponse response = httpclient.execute(httpPost);
|
CloseableHttpResponse response = httpclient.execute(httpPost);
|
||||||
resultContent = new BasicResponseHandler().handleResponse(response);
|
resultContent = Utf8StringResponseHandler.INSTANCE.handleResponse(response);
|
||||||
} else if ("GET".equals(method)) {
|
} else if ("GET".equals(method)) {
|
||||||
|
if (data != null) {
|
||||||
|
uriWithAccessToken += uriWithAccessToken.endsWith("&") ? data : '&' + data;
|
||||||
|
}
|
||||||
HttpGet httpGet = new HttpGet(uriWithAccessToken);
|
HttpGet httpGet = new HttpGet(uriWithAccessToken);
|
||||||
CloseableHttpResponse response = httpclient.execute(httpGet);
|
CloseableHttpResponse response = httpclient.execute(httpGet);
|
||||||
resultContent = new BasicResponseHandler().handleResponse(response);
|
response.setHeader("Content-Type", ContentType.APPLICATION_JSON.toString());
|
||||||
|
resultContent = Utf8StringResponseHandler.INSTANCE.handleResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
WxError error = WxError.fromJson(resultContent);
|
WxError error = WxError.fromJson(resultContent);
|
||||||
/*
|
/*
|
||||||
* 关于微信返回错误码 详情请看 http://mp.weixin.qq.com/wiki/index.php?title=全局返回码说明
|
* 发生以下情况时尝试刷新access_token
|
||||||
* 40001 微信图片不对
|
* 40001 获取access_token时AppSecret错误,或者access_token无效
|
||||||
* 42001 access_token超时
|
* 42001 access_token超时
|
||||||
*/
|
*/
|
||||||
if (error.getErrcode() == 42001 || error.getErrcode() == 40001) {
|
if (error.getErrcode() == 42001 || error.getErrcode() == 40001) {
|
||||||
@ -137,36 +165,7 @@ public class WxServiceImpl implements WxService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void setWxConfigProvider(WxConfigStorage wxConfigProvider) {
|
||||||
*
|
|
||||||
* @param menu
|
|
||||||
* @throws WxErrorException
|
|
||||||
*/
|
|
||||||
public String createMenu(WxMenu menu) throws WxErrorException {
|
|
||||||
// TODO
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @throws WxErrorException
|
|
||||||
*/
|
|
||||||
public String deleteMenu() throws WxErrorException {
|
|
||||||
// TODO
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* @throws WxErrorException
|
|
||||||
*/
|
|
||||||
public WxMenu getMenu() throws WxErrorException {
|
|
||||||
// TODO
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWxConfigProvider(WxConfigProvider wxConfigProvider) {
|
|
||||||
this.wxConfigProvider = wxConfigProvider;
|
this.wxConfigProvider = wxConfigProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,108 @@
|
|||||||
package chanjarster.weixin.bean;
|
package chanjarster.weixin.bean;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import chanjarster.weixin.util.WxGsonBuilder;
|
import chanjarster.weixin.util.WxGsonBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信错误码说明
|
||||||
|
* http://mp.weixin.qq.com/wiki/index.php?title=全局返回码说明
|
||||||
|
* @author chanjarster
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class WxError {
|
public class WxError {
|
||||||
|
|
||||||
private int errcode;
|
protected static final Map<Integer, String> errMap = new HashMap<Integer, String>();
|
||||||
|
|
||||||
private String errmsg;
|
static {
|
||||||
|
errMap.put(-1, "系统繁忙");
|
||||||
|
errMap.put(0, "请求成功");
|
||||||
|
errMap.put(40001, "获取access_token时AppSecret错误,或者access_token无效");
|
||||||
|
errMap.put(40002, "不合法的凭证类型");
|
||||||
|
errMap.put(40003, "不合法的OpenID");
|
||||||
|
errMap.put(40004, "不合法的媒体文件类型");
|
||||||
|
errMap.put(40005, "不合法的文件类型");
|
||||||
|
errMap.put(40006, "不合法的文件大小");
|
||||||
|
errMap.put(40007, "不合法的媒体文件id");
|
||||||
|
errMap.put(40008, "不合法的消息类型");
|
||||||
|
errMap.put(40009, "不合法的图片文件大小");
|
||||||
|
errMap.put(40010, "不合法的语音文件大小");
|
||||||
|
errMap.put(40011, "不合法的视频文件大小");
|
||||||
|
errMap.put(40012, "不合法的缩略图文件大小");
|
||||||
|
errMap.put(40013, "不合法的APPID");
|
||||||
|
errMap.put(40014, "不合法的access_token");
|
||||||
|
errMap.put(40015, "不合法的菜单类型");
|
||||||
|
errMap.put(40016, "不合法的按钮个数");
|
||||||
|
errMap.put(40017, "不合法的按钮个数");
|
||||||
|
errMap.put(40018, "不合法的按钮名字长度");
|
||||||
|
errMap.put(40019, "不合法的按钮KEY长度");
|
||||||
|
errMap.put(40020, "不合法的按钮URL长度");
|
||||||
|
errMap.put(40021, "不合法的菜单版本号");
|
||||||
|
errMap.put(40022, "不合法的子菜单级数");
|
||||||
|
errMap.put(40023, "不合法的子菜单按钮个数");
|
||||||
|
errMap.put(40024, "不合法的子菜单按钮类型");
|
||||||
|
errMap.put(40025, "不合法的子菜单按钮名字长度");
|
||||||
|
errMap.put(40026, "不合法的子菜单按钮KEY长度");
|
||||||
|
errMap.put(40027, "不合法的子菜单按钮URL长度");
|
||||||
|
errMap.put(40028, "不合法的自定义菜单使用用户");
|
||||||
|
errMap.put(40029, "不合法的oauth_code");
|
||||||
|
errMap.put(40030, "不合法的refresh_token");
|
||||||
|
errMap.put(40031, "不合法的openid列表");
|
||||||
|
errMap.put(40032, "不合法的openid列表长度");
|
||||||
|
errMap.put(40033, "不合法的请求字符,不能包含\\uxxxx格式的字符");
|
||||||
|
errMap.put(40035, "不合法的参数");
|
||||||
|
errMap.put(40038, "不合法的请求格式");
|
||||||
|
errMap.put(40039, "不合法的URL长度");
|
||||||
|
errMap.put(40050, "不合法的分组id");
|
||||||
|
errMap.put(40051, "分组名字不合法");
|
||||||
|
errMap.put(41001, "缺少access_token参数");
|
||||||
|
errMap.put(41002, "缺少appid参数");
|
||||||
|
errMap.put(41003, "缺少refresh_token参数");
|
||||||
|
errMap.put(41004, "缺少secret参数");
|
||||||
|
errMap.put(41005, "缺少多媒体文件数据");
|
||||||
|
errMap.put(41006, "缺少media_id参数");
|
||||||
|
errMap.put(41007, "缺少子菜单数据");
|
||||||
|
errMap.put(41008, "缺少oauth code");
|
||||||
|
errMap.put(41009, "缺少openid");
|
||||||
|
errMap.put(42001, "access_token超时");
|
||||||
|
errMap.put(42002, "refresh_token超时");
|
||||||
|
errMap.put(42003, "oauth_code超时");
|
||||||
|
errMap.put(43001, "需要GET请求");
|
||||||
|
errMap.put(43002, "需要POST请求");
|
||||||
|
errMap.put(43003, "需要HTTPS请求");
|
||||||
|
errMap.put(43004, "需要接收者关注");
|
||||||
|
errMap.put(43005, "需要好友关系");
|
||||||
|
errMap.put(44001, "多媒体文件为空");
|
||||||
|
errMap.put(44002, "POST的数据包为空");
|
||||||
|
errMap.put(44003, "图文消息内容为空");
|
||||||
|
errMap.put(44004, "文本消息内容为空");
|
||||||
|
errMap.put(45001, "多媒体文件大小超过限制");
|
||||||
|
errMap.put(45002, "消息内容超过限制");
|
||||||
|
errMap.put(45003, "标题字段超过限制");
|
||||||
|
errMap.put(45004, "描述字段超过限制");
|
||||||
|
errMap.put(45005, "链接字段超过限制");
|
||||||
|
errMap.put(45006, "图片链接字段超过限制");
|
||||||
|
errMap.put(45007, "语音播放时间超过限制");
|
||||||
|
errMap.put(45008, "图文消息超过限制");
|
||||||
|
errMap.put(45009, "接口调用超过限制");
|
||||||
|
errMap.put(45010, "创建菜单个数超过限制");
|
||||||
|
errMap.put(45015, "回复时间超过限制");
|
||||||
|
errMap.put(45016, "系统分组,不允许修改");
|
||||||
|
errMap.put(45017, "分组名字过长");
|
||||||
|
errMap.put(45018, "分组数量超过上限");
|
||||||
|
errMap.put(46001, "不存在媒体数据");
|
||||||
|
errMap.put(46002, "不存在的菜单版本");
|
||||||
|
errMap.put(46003, "不存在的菜单数据");
|
||||||
|
errMap.put(46004, "不存在的用户");
|
||||||
|
errMap.put(47001, "解析JSON/XML内容错误");
|
||||||
|
errMap.put(48001, "api功能未授权");
|
||||||
|
errMap.put(50001, "用户未授权该api");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int errcode;
|
||||||
|
|
||||||
|
protected String errmsg;
|
||||||
|
|
||||||
public int getErrcode() {
|
public int getErrcode() {
|
||||||
return errcode;
|
return errcode;
|
||||||
@ -24,14 +120,17 @@ public class WxError {
|
|||||||
this.errmsg = errmsg;
|
this.errmsg = errmsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return errMap.get(errcode);
|
||||||
|
}
|
||||||
|
|
||||||
public static WxError fromJson(String json) {
|
public static WxError fromJson(String json) {
|
||||||
return WxGsonBuilder.create().fromJson(json, WxError.class);
|
return WxGsonBuilder.create().fromJson(json, WxError.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "{ errcode=" + errcode + ", errmsg=" + errmsg + "}";
|
return "微信错误 errcode=" + errcode + ", errmsg=" + errmsg + ", description=" + getDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package chanjarster.weixin.bean;
|
|||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import javax.management.RuntimeErrorException;
|
||||||
import javax.xml.bind.JAXBException;
|
import javax.xml.bind.JAXBException;
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
@ -291,27 +292,24 @@ public class WxXmlMessage {
|
|||||||
try {
|
try {
|
||||||
return XmlTransformer.toXml(WxXmlMessage.class, this);
|
return XmlTransformer.toXml(WxXmlMessage.class, this);
|
||||||
} catch (JAXBException e) {
|
} catch (JAXBException e) {
|
||||||
e.printStackTrace();
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WxXmlMessage fromXml(String xml) {
|
public static WxXmlMessage fromXml(String xml) {
|
||||||
try {
|
try {
|
||||||
return XmlTransformer.fromXml(WxXmlMessage.class, xml);
|
return XmlTransformer.fromXml(WxXmlMessage.class, xml);
|
||||||
} catch (JAXBException e) {
|
} catch (JAXBException e) {
|
||||||
e.printStackTrace();
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WxXmlMessage fromXml(InputStream is) {
|
public static WxXmlMessage fromXml(InputStream is) {
|
||||||
try {
|
try {
|
||||||
return XmlTransformer.fromXml(WxXmlMessage.class, is);
|
return XmlTransformer.fromXml(WxXmlMessage.class, is);
|
||||||
} catch (JAXBException e) {
|
} catch (JAXBException e) {
|
||||||
e.printStackTrace();
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package chanjarster.weixin.util;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.http.Consts;
|
||||||
|
import org.apache.http.HttpEntity;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.StatusLine;
|
||||||
|
import org.apache.http.client.HttpResponseException;
|
||||||
|
import org.apache.http.client.ResponseHandler;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* copy from {@link org.apache.http.impl.client.BasicResponseHandler}
|
||||||
|
* @author chanjarster
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Utf8StringResponseHandler implements ResponseHandler<String> {
|
||||||
|
|
||||||
|
public static final ResponseHandler<String> INSTANCE = new Utf8StringResponseHandler();
|
||||||
|
|
||||||
|
public String handleResponse(final HttpResponse response) throws HttpResponseException, IOException {
|
||||||
|
final StatusLine statusLine = response.getStatusLine();
|
||||||
|
final HttpEntity entity = response.getEntity();
|
||||||
|
if (statusLine.getStatusCode() >= 300) {
|
||||||
|
EntityUtils.consume(entity);
|
||||||
|
throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
|
||||||
|
}
|
||||||
|
return entity == null ? null : EntityUtils.toString(entity, Consts.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -32,25 +32,25 @@ public class WxCustomMessageGsonAdapter implements JsonSerializer<WxCustomMessag
|
|||||||
messageJson.addProperty("touser", message.getTouser());
|
messageJson.addProperty("touser", message.getTouser());
|
||||||
messageJson.addProperty("msgtype", message.getMsgtype());
|
messageJson.addProperty("msgtype", message.getMsgtype());
|
||||||
|
|
||||||
if (WxConsts.TEXT.equals(message.getMsgtype())) {
|
if (WxConsts.MSG_TEXT.equals(message.getMsgtype())) {
|
||||||
JsonObject text = new JsonObject();
|
JsonObject text = new JsonObject();
|
||||||
text.addProperty("content", message.getContent());
|
text.addProperty("content", message.getContent());
|
||||||
messageJson.add("text", text);
|
messageJson.add("text", text);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WxConsts.IMAGE.equals(message.getMsgtype())) {
|
if (WxConsts.MSG_IMAGE.equals(message.getMsgtype())) {
|
||||||
JsonObject image = new JsonObject();
|
JsonObject image = new JsonObject();
|
||||||
image.addProperty("media_id", message.getMedia_id());
|
image.addProperty("media_id", message.getMedia_id());
|
||||||
messageJson.add("image", image);
|
messageJson.add("image", image);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WxConsts.VOICE.equals(message.getMsgtype())) {
|
if (WxConsts.MSG_VOICE.equals(message.getMsgtype())) {
|
||||||
JsonObject voice = new JsonObject();
|
JsonObject voice = new JsonObject();
|
||||||
voice.addProperty("media_id", message.getMedia_id());
|
voice.addProperty("media_id", message.getMedia_id());
|
||||||
messageJson.add("voice", voice);
|
messageJson.add("voice", voice);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WxConsts.VIDEO.equals(message.getMsgtype())) {
|
if (WxConsts.MSG_VIDEO.equals(message.getMsgtype())) {
|
||||||
JsonObject video = new JsonObject();
|
JsonObject video = new JsonObject();
|
||||||
video.addProperty("media_id", message.getMedia_id());
|
video.addProperty("media_id", message.getMedia_id());
|
||||||
video.addProperty("thumb_media_id", message.getThumb_media_id());
|
video.addProperty("thumb_media_id", message.getThumb_media_id());
|
||||||
@ -59,7 +59,7 @@ public class WxCustomMessageGsonAdapter implements JsonSerializer<WxCustomMessag
|
|||||||
messageJson.add("video", video);
|
messageJson.add("video", video);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WxConsts.MUSIC.equals(message.getMsgtype())) {
|
if (WxConsts.MSG_MUSIC.equals(message.getMsgtype())) {
|
||||||
JsonObject music = new JsonObject();
|
JsonObject music = new JsonObject();
|
||||||
music.addProperty("title", message.getTitle());
|
music.addProperty("title", message.getTitle());
|
||||||
music.addProperty("description", message.getDescription());
|
music.addProperty("description", message.getDescription());
|
||||||
@ -69,7 +69,7 @@ public class WxCustomMessageGsonAdapter implements JsonSerializer<WxCustomMessag
|
|||||||
messageJson.add("music", music);
|
messageJson.add("music", music);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WxConsts.NEWS.equals(message.getMsgtype())) {
|
if (WxConsts.MSG_NEWS.equals(message.getMsgtype())) {
|
||||||
JsonArray articleJsonArray = new JsonArray();
|
JsonArray articleJsonArray = new JsonArray();
|
||||||
for (WxArticle article : message.getArticles()) {
|
for (WxArticle article : message.getArticles()) {
|
||||||
JsonObject articleJson = new JsonObject();
|
JsonObject articleJson = new JsonObject();
|
||||||
|
@ -59,8 +59,14 @@ public class WxMenuGsonAdapter implements JsonSerializer<WxMenu>, JsonDeserializ
|
|||||||
}
|
}
|
||||||
|
|
||||||
public WxMenu deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
public WxMenu deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||||
|
/*
|
||||||
|
* 操蛋的微信
|
||||||
|
* 创建菜单时是 { button : ... }
|
||||||
|
* 查询菜单时是 { menu : { button : ... } }
|
||||||
|
*/
|
||||||
WxMenu menu = new WxMenu();
|
WxMenu menu = new WxMenu();
|
||||||
JsonArray buttonsJson = json.getAsJsonObject().get("button").getAsJsonArray();
|
JsonObject menuJson = json.getAsJsonObject().get("menu").getAsJsonObject();
|
||||||
|
JsonArray buttonsJson = menuJson.get("button").getAsJsonArray();
|
||||||
for (int i = 0; i < buttonsJson.size(); i++) {
|
for (int i = 0; i < buttonsJson.size(); i++) {
|
||||||
JsonObject buttonJson = buttonsJson.get(i).getAsJsonObject();
|
JsonObject buttonJson = buttonsJson.get(i).getAsJsonObject();
|
||||||
WxMenuButton button = convertFromJson(buttonJson);
|
WxMenuButton button = convertFromJson(buttonJson);
|
||||||
|
@ -11,6 +11,8 @@ import javax.xml.bind.JAXBException;
|
|||||||
import javax.xml.bind.Marshaller;
|
import javax.xml.bind.Marshaller;
|
||||||
import javax.xml.bind.Unmarshaller;
|
import javax.xml.bind.Unmarshaller;
|
||||||
|
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
|
||||||
import com.sun.xml.bind.marshaller.CharacterEscapeHandler;
|
import com.sun.xml.bind.marshaller.CharacterEscapeHandler;
|
||||||
|
|
||||||
public class XmlTransformer {
|
public class XmlTransformer {
|
||||||
@ -32,7 +34,9 @@ public class XmlTransformer {
|
|||||||
public static <T> T fromXml(Class<T> clazz, InputStream is) throws JAXBException {
|
public static <T> T fromXml(Class<T> clazz, InputStream is) throws JAXBException {
|
||||||
JAXBContext context = JAXBContext.newInstance(clazz);
|
JAXBContext context = JAXBContext.newInstance(clazz);
|
||||||
Unmarshaller um = context.createUnmarshaller();
|
Unmarshaller um = context.createUnmarshaller();
|
||||||
T object = (T) um.unmarshal(is);
|
InputSource inputSource = new InputSource(is);
|
||||||
|
inputSource.setEncoding("utf-8");
|
||||||
|
T object = (T) um.unmarshal(inputSource);
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,48 @@
|
|||||||
package chanjarster.weixin.api;
|
package chanjarster.weixin.api;
|
||||||
|
|
||||||
// TODO
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.testng.Assert;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import chanjarster.weixin.bean.WxXmlMessage;
|
||||||
|
|
||||||
|
@Test
|
||||||
public class WxMessageRouterTest {
|
public class WxMessageRouterTest {
|
||||||
|
|
||||||
|
public void testSimple() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
WxMessageRouter router = new WxMessageRouter();
|
||||||
|
router
|
||||||
|
.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()
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
WxXmlMessage message = new WxXmlMessage();
|
||||||
|
message.setMsgType(WxConsts.MSG_TEXT);
|
||||||
|
router.route(message);
|
||||||
|
Assert.assertEquals(sb.toString(), WxConsts.MSG_TEXT + ",");
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class WxEchoMessageHandler implements WxMessageHandler {
|
||||||
|
|
||||||
|
private StringBuilder sb;
|
||||||
|
private String echoStr;
|
||||||
|
|
||||||
|
public WxEchoMessageHandler(StringBuilder sb, String echoStr) {
|
||||||
|
this.sb = sb;
|
||||||
|
this.echoStr = echoStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(WxXmlMessage wxMessage, Map<String, Object> context) {
|
||||||
|
sb.append(this.echoStr).append(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,68 +9,117 @@ import javax.xml.bind.annotation.XmlRootElement;
|
|||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.testng.Assert;
|
import org.testng.Assert;
|
||||||
|
import org.testng.annotations.BeforeTest;
|
||||||
import org.testng.annotations.DataProvider;
|
import org.testng.annotations.DataProvider;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
import chanjarster.weixin.api.WxConsts;
|
|
||||||
import chanjarster.weixin.api.WxMemoryConfigProvider;
|
|
||||||
import chanjarster.weixin.api.WxService;
|
|
||||||
import chanjarster.weixin.api.WxServiceImpl;
|
|
||||||
import chanjarster.weixin.bean.WxCustomMessage;
|
import chanjarster.weixin.bean.WxCustomMessage;
|
||||||
|
import chanjarster.weixin.bean.WxMenu;
|
||||||
|
import chanjarster.weixin.bean.WxMenu.WxMenuButton;
|
||||||
import chanjarster.weixin.exception.WxErrorException;
|
import chanjarster.weixin.exception.WxErrorException;
|
||||||
import chanjarster.weixin.util.XmlTransformer;
|
import chanjarster.weixin.util.XmlTransformer;
|
||||||
|
|
||||||
public class WxServiceTest {
|
public class WxServiceTest {
|
||||||
|
|
||||||
@Test(dataProvider = "configs")
|
private WxServiceImpl wxService;
|
||||||
public void testRefreshAccessToken(WxTestConfigProvider config) throws WxErrorException {
|
|
||||||
String before = config.getAccessToken();
|
@BeforeTest
|
||||||
|
public void prepare() throws JAXBException {
|
||||||
WxService wxService = new WxServiceImpl();
|
InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml");
|
||||||
wxService.setWxConfigProvider(config);
|
WxXmlConfigStorage config1 = XmlTransformer.fromXml(WxXmlConfigStorage.class, is1);
|
||||||
|
this.wxService = new WxServiceImpl();
|
||||||
|
this.wxService.setWxConfigProvider(config1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRefreshAccessToken() throws WxErrorException {
|
||||||
|
WxConfigStorage configProvider = wxService.wxConfigProvider;
|
||||||
|
String before = configProvider.getAccessToken();
|
||||||
wxService.refreshAccessToken();
|
wxService.refreshAccessToken();
|
||||||
|
|
||||||
String after = config.getAccessToken();
|
String after = configProvider.getAccessToken();
|
||||||
|
|
||||||
Assert.assertNotEquals(before, after);
|
Assert.assertNotEquals(before, after);
|
||||||
Assert.assertTrue(StringUtils.isNotBlank(after));
|
Assert.assertTrue(StringUtils.isNotBlank(after));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(dataProvider = "configs")
|
@Test(dependsOnMethods = "testRefreshAccessToken", enabled = false)
|
||||||
public void sendCustomMessage(WxTestConfigProvider config) throws WxErrorException {
|
public void sendCustomMessage() throws WxErrorException {
|
||||||
WxService wxService = new WxServiceImpl();
|
WxXmlConfigStorage configProvider = (WxXmlConfigStorage) wxService.wxConfigProvider;
|
||||||
wxService.setWxConfigProvider(config);
|
|
||||||
|
|
||||||
WxCustomMessage message = new WxCustomMessage();
|
WxCustomMessage message = new WxCustomMessage();
|
||||||
message.setMsgtype(WxConsts.TEXT);
|
message.setMsgtype(WxConsts.MSG_TEXT);
|
||||||
message.setTouser(config.getOpenId());
|
message.setTouser(configProvider.getOpenId());
|
||||||
message.setContent("欢迎使用教务系统微信公众号\n下面\n<a href=\"http://192.168.1.249:9180/eams-rc/login.action\">Hello World</a>");
|
message.setContent("欢迎使用教务系统微信公众号\n下面\n<a href=\"http://www.baidu.com\">Hello World</a>");
|
||||||
|
|
||||||
wxService.sendCustomMessage(message);
|
wxService.sendCustomMessage(message);
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* 返回新的access_token
|
@Test(dataProvider = "menu", enabled = true, dependsOnMethods = "testRefreshAccessToken")
|
||||||
* @return
|
public void testCreateMenu(WxMenu wxMenu) throws WxErrorException {
|
||||||
* @throws JAXBException
|
wxService.createMenu(wxMenu);
|
||||||
*/
|
}
|
||||||
@DataProvider(name = "configs")
|
|
||||||
public Object[][] getConfig() throws JAXBException {
|
@Test(dependsOnMethods = { "testRefreshAccessToken" , "testCreateMenu"})
|
||||||
/**
|
public void testGetMenu() throws WxErrorException {
|
||||||
* 将 src/test/resources/test-config.sample.xml 改成 test-config.xml 并设置appId, secret, 一个过期的accessToken
|
Assert.assertNotNull(wxService.getMenu());
|
||||||
*/
|
}
|
||||||
// 没有access_token
|
|
||||||
InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml");
|
@Test(dependsOnMethods = { "testRefreshAccessToken", "testGetMenu" }, enabled = false)
|
||||||
WxTestConfigProvider config1 = XmlTransformer.fromXml(WxTestConfigProvider.class, is1);
|
public void testDeleteMenu() throws WxErrorException {
|
||||||
|
wxService.deleteMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
@DataProvider(name="menu")
|
||||||
|
public Object[][] getMenu() throws JAXBException {
|
||||||
|
WxMenu menu = new WxMenu();
|
||||||
|
WxMenuButton button1 = new WxMenuButton();
|
||||||
|
button1.setType("click");
|
||||||
|
button1.setName("今日歌曲");
|
||||||
|
button1.setKey("V1001_TODAY_MUSIC");
|
||||||
|
|
||||||
|
WxMenuButton button2 = new WxMenuButton();
|
||||||
|
button2.setType("click");
|
||||||
|
button2.setName("歌手简介");
|
||||||
|
button2.setKey("V1001_TODAY_SINGER");
|
||||||
|
|
||||||
|
WxMenuButton button3 = new WxMenuButton();
|
||||||
|
button3.setName("菜单");
|
||||||
|
|
||||||
|
menu.getButton().add(button1);
|
||||||
|
menu.getButton().add(button2);
|
||||||
|
menu.getButton().add(button3);
|
||||||
|
|
||||||
|
WxMenuButton button31 = new WxMenuButton();
|
||||||
|
button31.setType("view");
|
||||||
|
button31.setName("搜索");
|
||||||
|
button31.setUrl("http://www.soso.com/");
|
||||||
|
|
||||||
|
WxMenuButton button32 = new WxMenuButton();
|
||||||
|
button32.setType("view");
|
||||||
|
button32.setName("视频");
|
||||||
|
button32.setUrl("http://v.qq.com/");
|
||||||
|
|
||||||
|
WxMenuButton button33 = new WxMenuButton();
|
||||||
|
button33.setType("click");
|
||||||
|
button33.setName("赞一下我们");
|
||||||
|
button33.setKey("V1001_GOOD");
|
||||||
|
|
||||||
|
button3.getSub_button().add(button31);
|
||||||
|
button3.getSub_button().add(button32);
|
||||||
|
button3.getSub_button().add(button33);
|
||||||
|
|
||||||
return new Object[][] {
|
return new Object[][] {
|
||||||
new Object[] {
|
new Object[] {
|
||||||
config1
|
menu
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@XmlRootElement(name = "xml")
|
@XmlRootElement(name = "xml")
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
public static class WxTestConfigProvider extends WxMemoryConfigProvider {
|
public static class WxXmlConfigStorage extends WxInMemoryConfigStorage {
|
||||||
|
|
||||||
protected String openId;
|
protected String openId;
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ public class WxCustomMessageTest {
|
|||||||
public void testTextReply() {
|
public void testTextReply() {
|
||||||
WxCustomMessage reply = new WxCustomMessage();
|
WxCustomMessage reply = new WxCustomMessage();
|
||||||
reply.setTouser("OPENID");
|
reply.setTouser("OPENID");
|
||||||
reply.setMsgtype(WxConsts.TEXT);
|
reply.setMsgtype(WxConsts.MSG_TEXT);
|
||||||
reply.setContent("sfsfdsdf");
|
reply.setContent("sfsfdsdf");
|
||||||
Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}");
|
Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}");
|
||||||
}
|
}
|
||||||
@ -21,7 +21,7 @@ public class WxCustomMessageTest {
|
|||||||
public void testImageReply() {
|
public void testImageReply() {
|
||||||
WxCustomMessage reply = new WxCustomMessage();
|
WxCustomMessage reply = new WxCustomMessage();
|
||||||
reply.setTouser("OPENID");
|
reply.setTouser("OPENID");
|
||||||
reply.setMsgtype(WxConsts.IMAGE);
|
reply.setMsgtype(WxConsts.MSG_IMAGE);
|
||||||
reply.setMedia_id("MEDIA_ID");
|
reply.setMedia_id("MEDIA_ID");
|
||||||
Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}");
|
Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}");
|
||||||
}
|
}
|
||||||
@ -29,7 +29,7 @@ public class WxCustomMessageTest {
|
|||||||
public void testVoiceReply() {
|
public void testVoiceReply() {
|
||||||
WxCustomMessage reply = new WxCustomMessage();
|
WxCustomMessage reply = new WxCustomMessage();
|
||||||
reply.setTouser("OPENID");
|
reply.setTouser("OPENID");
|
||||||
reply.setMsgtype(WxConsts.VOICE);
|
reply.setMsgtype(WxConsts.MSG_VOICE);
|
||||||
reply.setMedia_id("MEDIA_ID");
|
reply.setMedia_id("MEDIA_ID");
|
||||||
Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"voice\",\"voice\":{\"media_id\":\"MEDIA_ID\"}}");
|
Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"voice\",\"voice\":{\"media_id\":\"MEDIA_ID\"}}");
|
||||||
}
|
}
|
||||||
@ -37,7 +37,7 @@ public class WxCustomMessageTest {
|
|||||||
public void testVideoReply() {
|
public void testVideoReply() {
|
||||||
WxCustomMessage reply = new WxCustomMessage();
|
WxCustomMessage reply = new WxCustomMessage();
|
||||||
reply.setTouser("OPENID");
|
reply.setTouser("OPENID");
|
||||||
reply.setMsgtype(WxConsts.VIDEO);
|
reply.setMsgtype(WxConsts.MSG_VIDEO);
|
||||||
reply.setMedia_id("MEDIA_ID");
|
reply.setMedia_id("MEDIA_ID");
|
||||||
reply.setThumb_media_id("MEDIA_ID");
|
reply.setThumb_media_id("MEDIA_ID");
|
||||||
reply.setTitle("TITLE");
|
reply.setTitle("TITLE");
|
||||||
@ -48,7 +48,7 @@ public class WxCustomMessageTest {
|
|||||||
public void testMusicReply() {
|
public void testMusicReply() {
|
||||||
WxCustomMessage reply = new WxCustomMessage();
|
WxCustomMessage reply = new WxCustomMessage();
|
||||||
reply.setTouser("OPENID");
|
reply.setTouser("OPENID");
|
||||||
reply.setMsgtype(WxConsts.MUSIC);
|
reply.setMsgtype(WxConsts.MSG_MUSIC);
|
||||||
reply.setThumb_media_id("MEDIA_ID");
|
reply.setThumb_media_id("MEDIA_ID");
|
||||||
reply.setDescription("DESCRIPTION");
|
reply.setDescription("DESCRIPTION");
|
||||||
reply.setTitle("TITLE");
|
reply.setTitle("TITLE");
|
||||||
@ -60,7 +60,7 @@ public class WxCustomMessageTest {
|
|||||||
public void testNewsReply() {
|
public void testNewsReply() {
|
||||||
WxCustomMessage reply = new WxCustomMessage();
|
WxCustomMessage reply = new WxCustomMessage();
|
||||||
reply.setTouser("OPENID");
|
reply.setTouser("OPENID");
|
||||||
reply.setMsgtype(WxConsts.NEWS);
|
reply.setMsgtype(WxConsts.MSG_NEWS);
|
||||||
|
|
||||||
WxArticle article1 = new WxArticle();
|
WxArticle article1 = new WxArticle();
|
||||||
article1.setUrl("URL");
|
article1.setUrl("URL");
|
||||||
@ -77,7 +77,6 @@ public class WxCustomMessageTest {
|
|||||||
reply.getArticles().add(article2);
|
reply.getArticles().add(article2);
|
||||||
|
|
||||||
|
|
||||||
System.out.println(reply.toJson());
|
|
||||||
Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"news\",\"articles\":[{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"},{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}]}");
|
Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"news\",\"articles\":[{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"},{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}]}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package chanjarster.weixin.bean;
|
package chanjarster.weixin.bean;
|
||||||
|
|
||||||
import org.apache.http.util.Asserts;
|
|
||||||
import org.testng.Assert;
|
import org.testng.Assert;
|
||||||
import org.testng.annotations.DataProvider;
|
import org.testng.annotations.DataProvider;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
@ -10,13 +9,13 @@ import chanjarster.weixin.bean.WxMenu.WxMenuButton;
|
|||||||
@Test
|
@Test
|
||||||
public class WxMenuTest {
|
public class WxMenuTest {
|
||||||
|
|
||||||
@Test(dataProvider="json")
|
@Test(dataProvider="wxReturnMenu")
|
||||||
public void testFromJson(String json) {
|
public void testFromJson(String json) {
|
||||||
WxMenu menu = WxMenu.fromJson(json);
|
WxMenu menu = WxMenu.fromJson(json);
|
||||||
Assert.assertEquals(menu.getButton().size(), 3);
|
Assert.assertEquals(menu.getButton().size(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(dataProvider="json")
|
@Test(dataProvider="wxPushMenu")
|
||||||
public void testToJson(String json) {
|
public void testToJson(String json) {
|
||||||
WxMenu menu = new WxMenu();
|
WxMenu menu = new WxMenu();
|
||||||
WxMenuButton button1 = new WxMenuButton();
|
WxMenuButton button1 = new WxMenuButton();
|
||||||
@ -55,12 +54,20 @@ public class WxMenuTest {
|
|||||||
button3.getSub_button().add(button32);
|
button3.getSub_button().add(button32);
|
||||||
button3.getSub_button().add(button33);
|
button3.getSub_button().add(button33);
|
||||||
|
|
||||||
System.out.println(menu.toJson());
|
|
||||||
Assert.assertEquals(menu.toJson(), json);
|
Assert.assertEquals(menu.toJson(), json);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DataProvider(name="json")
|
@Test(dataProvider="wxReturnMenu")
|
||||||
public Object[][] getMenuJson() {
|
public Object[][] wxReturnMenu() {
|
||||||
|
Object[][] res = menuJson();
|
||||||
|
String json = "{ \"menu\" : " + res[0][0] + " }";
|
||||||
|
return new Object[][] {
|
||||||
|
new Object[] { json }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@DataProvider(name="wxPushMenu")
|
||||||
|
public Object[][] menuJson() {
|
||||||
String json =
|
String json =
|
||||||
"{"
|
"{"
|
||||||
+"\"button\":["
|
+"\"button\":["
|
||||||
|
@ -40,7 +40,7 @@ public class WxXmlMessageTest {
|
|||||||
Assert.assertEquals(wxMessage.getToUserName(), "toUser");
|
Assert.assertEquals(wxMessage.getToUserName(), "toUser");
|
||||||
Assert.assertEquals(wxMessage.getFromUserName(), "fromUser");
|
Assert.assertEquals(wxMessage.getFromUserName(), "fromUser");
|
||||||
Assert.assertEquals(wxMessage.getCreateTime(), new Long(1348831860l));
|
Assert.assertEquals(wxMessage.getCreateTime(), new Long(1348831860l));
|
||||||
Assert.assertEquals(wxMessage.getMsgType(), WxConsts.TEXT);
|
Assert.assertEquals(wxMessage.getMsgType(), WxConsts.MSG_TEXT);
|
||||||
Assert.assertEquals(wxMessage.getContent(), "this is a test");
|
Assert.assertEquals(wxMessage.getContent(), "this is a test");
|
||||||
Assert.assertEquals(wxMessage.getMsgId(), new Long(1234567890123456l));
|
Assert.assertEquals(wxMessage.getMsgId(), new Long(1234567890123456l));
|
||||||
Assert.assertEquals(wxMessage.getPicUrl(), "this is a url");
|
Assert.assertEquals(wxMessage.getPicUrl(), "this is a url");
|
||||||
@ -67,7 +67,7 @@ public class WxXmlMessageTest {
|
|||||||
wxMessage.setToUserName("toUser");
|
wxMessage.setToUserName("toUser");
|
||||||
wxMessage.setFromUserName("fromUser");
|
wxMessage.setFromUserName("fromUser");
|
||||||
wxMessage.setCreateTime(new Long(1348831860l));
|
wxMessage.setCreateTime(new Long(1348831860l));
|
||||||
wxMessage.setMsgType(WxConsts.TEXT);
|
wxMessage.setMsgType(WxConsts.MSG_TEXT);
|
||||||
wxMessage.setContent("this is a test");
|
wxMessage.setContent("this is a test");
|
||||||
wxMessage.setMsgId(new Long(1234567890123456l));
|
wxMessage.setMsgId(new Long(1234567890123456l));
|
||||||
wxMessage.setPicUrl("this is a url");
|
wxMessage.setPicUrl("this is a url");
|
||||||
|
Loading…
Reference in New Issue
Block a user