@@ -1,12 +1,26 @@ | |||
language: java | |||
jdk: | |||
- oraclejdk7 | |||
script: "mvn clean package -Dmaven.test.skip=true" | |||
sudo: false | |||
install: true | |||
addons: | |||
sonarqube: | |||
token: | |||
secure: "834110c7191f97ecb226970c46dcaff8e681da5a" | |||
jdk: | |||
- oraclejdk8 | |||
#script: "mvn clean package -Dmaven.test.skip=true" | |||
script: | |||
- mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar | |||
branches: | |||
only: | |||
- develop | |||
cache: | |||
directories: | |||
- '$HOME/.m2/repository' | |||
- '$HOME/.sonar/cache' | |||
notifications: | |||
email: | |||
@@ -1,7 +1,7 @@ | |||
Weixin Java Tools 微信公众号/企业号开发Java SDK | |||
===================================== | |||
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.binarywang/weixin-java-parent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.binarywang/weixin-java-parent) | |||
[![Build Status](https://travis-ci.org/wechat-group/weixin-java-tools.svg?branch=develop)](https://travis-ci.org/wechat-group/weixin-java-tools) | |||
[![Build Status](https://travis-ci.org/Wechat-Group/weixin-java-tools.svg?branch=develop)](https://travis-ci.org/Wechat-Group/weixin-java-tools) | |||
### 注意: | |||
1. ***本项目Fork自chanjarster/weixin-java-tools,但由于原项目已停止维护,故单独维护和发布,且发布到maven上的groupId也会不同,详细信息见下文。*** | |||
@@ -13,7 +13,7 @@ Weixin Java Tools 微信公众号/企业号开发Java SDK | |||
## 开发交流方式及注意事项: | |||
1. QQ群:343954419(推荐点击按钮入群: [![Join QQ Group](http://pub.idqqimg.com/wpa/images/group.png)](http://shang.qq.com/wpa/qunwpa?idkey=731dc3e7ea31ebe25376cc1a791445468612c63fd0e9e05399b088ec81fd9e15) 或 [![Join QQ Group](http://pub.idqqimg.com/wpa/images/group.png)](http://jq.qq.com/?_wv=1027&k=40lRskK),如果无反应,可以自行搜索群号进行添加 ) | |||
1. 由于群容量有限即将爆满,现开启付费入群模式,并不定期清理长时间不活跃人士; | |||
1. 由于群容量有限,即将爆满,故开启付费入群模式以保证只有真实交流需求的人进入,并为保证群的活跃度,将不定期清理长时间不活跃的同学; | |||
1. 微信群: 因微信群已达到100人限制,故如有想加入微信群的,请入QQ群后联系管理员,提供微信号以便邀请加入; | |||
1. 新手提问前,请先阅读此文章:http://t.cn/RV93MRB | |||
1. 寻求帮助时需贴代码或大长串异常信息的,请利用http://paste.ubuntu.com | |||
@@ -25,12 +25,12 @@ Weixin Java Tools 微信公众号/企业号开发Java SDK | |||
=========== | |||
## 版本说明 | |||
1. 本项目定为每月发布一次正式版,版本号格式为X.X.0(如2.1.0,2.2.0等),月初或月底发布新版本,遇到重大问题需修复会及时提交新版本,欢迎大家随时提交Pull Request; | |||
1. 本项目定为每两个月发布一次正式版,版本号格式为X.X.0(如2.1.0,2.2.0等),月底发布新版本,遇到重大问题需修复会及时提交新版本,欢迎大家随时提交Pull Request; | |||
1. BUG修复和新特性一般会先发布成小版本作为临时版本(如2.0.1,2.0.2等,即尾号不为0,以区别于正式版); | |||
1. 目前最新版本号为 [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.binarywang/weixin-java-parent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.binarywang/weixin-java-parent) ,也可以通过访问链接 [【公众号】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-mp%22) 、[【企业号】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-cp%22) | |||
分别查看所有最新的版本。 | |||
## Maven & Gradle | |||
## Maven & Gradle 最新正式版本 | |||
* 公众号(订阅号、服务号): | |||
@@ -20,8 +20,7 @@ public class WxError implements Serializable { | |||
private String json; | |||
public static WxError fromJson(String json) { | |||
WxError error = WxGsonBuilder.create().fromJson(json, WxError.class); | |||
return error; | |||
return WxGsonBuilder.create().fromJson(json, WxError.class); | |||
} | |||
public static Builder newBuilder() { | |||
@@ -11,12 +11,12 @@ public class StandardSession implements WxSession, InternalSession { | |||
/** | |||
* The string manager for this package. | |||
*/ | |||
protected static final StringManager sm = | |||
StringManager.getManager(Constants.Package); | |||
protected static final StringManager sm = StringManager.getManager(Constants.Package); | |||
/** | |||
* Type array. | |||
*/ | |||
protected static final String EMPTY_ARRAY[] = new String[0]; | |||
private static final String[] EMPTY_ARRAY = new String[0]; | |||
// ------------------------------ WxSession | |||
protected Map<String, Object> attributes = new ConcurrentHashMap<>(); | |||
/** | |||
@@ -71,20 +71,23 @@ public class StandardSession implements WxSession, InternalSession { | |||
@Override | |||
public Object getAttribute(String name) { | |||
if (!isValidInternal()) | |||
if (!isValidInternal()) { | |||
throw new IllegalStateException | |||
(sm.getString("sessionImpl.getAttribute.ise")); | |||
(sm.getString("sessionImpl.getAttribute.ise")); | |||
} | |||
if (name == null) return null; | |||
if (name == null) { | |||
return null; | |||
} | |||
return (this.attributes.get(name)); | |||
return this.attributes.get(name); | |||
} | |||
@Override | |||
public Enumeration<String> getAttributeNames() { | |||
if (!isValidInternal()) | |||
throw new IllegalStateException | |||
(sm.getString("sessionImpl.getAttributeNames.ise")); | |||
if (!isValidInternal()) { | |||
throw new IllegalStateException(sm.getString("sessionImpl.getAttributeNames.ise")); | |||
} | |||
Set<String> names = new HashSet<>(); | |||
names.addAll(this.attributes.keySet()); | |||
@@ -94,9 +97,9 @@ public class StandardSession implements WxSession, InternalSession { | |||
@Override | |||
public void setAttribute(String name, Object value) { | |||
// Name cannot be null | |||
if (name == null) | |||
throw new IllegalArgumentException | |||
(sm.getString("sessionImpl.setAttribute.namenull")); | |||
if (name == null) { | |||
throw new IllegalArgumentException(sm.getString("sessionImpl.setAttribute.namenull")); | |||
} | |||
// Null value is the same as removeAttribute() | |||
if (value == null) { | |||
@@ -105,9 +108,9 @@ public class StandardSession implements WxSession, InternalSession { | |||
} | |||
// Validate our current state | |||
if (!isValidInternal()) | |||
throw new IllegalStateException(sm.getString( | |||
"sessionImpl.setAttribute.ise", getIdInternal())); | |||
if (!isValidInternal()) { | |||
throw new IllegalStateException(sm.getString("sessionImpl.setAttribute.ise", getIdInternal())); | |||
} | |||
this.attributes.put(name, value); | |||
@@ -121,8 +124,7 @@ public class StandardSession implements WxSession, InternalSession { | |||
@Override | |||
public void invalidate() { | |||
if (!isValidInternal()) | |||
throw new IllegalStateException | |||
(sm.getString("sessionImpl.invalidate.ise")); | |||
throw new IllegalStateException(sm.getString("sessionImpl.invalidate.ise")); | |||
// Cause this session to expire | |||
expire(); | |||
@@ -131,12 +133,11 @@ public class StandardSession implements WxSession, InternalSession { | |||
@Override | |||
public WxSession getSession() { | |||
if (this.facade == null) { | |||
this.facade = new StandardSessionFacade(this); | |||
} | |||
return (this.facade); | |||
return this.facade; | |||
} | |||
/** | |||
@@ -185,12 +186,14 @@ public class StandardSession implements WxSession, InternalSession { | |||
@Override | |||
public String getIdInternal() { | |||
return (this.id); | |||
return this.id; | |||
} | |||
protected void removeAttributeInternal(String name) { | |||
// Avoid NPE | |||
if (name == null) return; | |||
if (name == null) { | |||
return; | |||
} | |||
// Remove this attribute from our collection | |||
this.attributes.remove(name); | |||
@@ -202,19 +205,22 @@ public class StandardSession implements WxSession, InternalSession { | |||
// Check to see if session has already been invalidated. | |||
// Do not check expiring at this point as expire should not return until | |||
// isValid is false | |||
if (!this.isValid) | |||
if (!this.isValid) { | |||
return; | |||
} | |||
synchronized (this) { | |||
// Check again, now we are inside the sync so this code only runs once | |||
// Double check locking - isValid needs to be volatile | |||
// The check of expiring is to ensure that an infinite loop is not | |||
// entered as per bug 56339 | |||
if (this.expiring || !this.isValid) | |||
if (this.expiring || !this.isValid) { | |||
return; | |||
} | |||
if (this.manager == null) | |||
if (this.manager == null) { | |||
return; | |||
} | |||
// Mark this session as "being expired" | |||
this.expiring = true; | |||
@@ -230,9 +236,9 @@ public class StandardSession implements WxSession, InternalSession { | |||
this.expiring = false; | |||
// Unbind any objects associated with this session | |||
String keys[] = keys(); | |||
for (int i = 0; i < keys.length; i++) { | |||
removeAttributeInternal(keys[i]); | |||
String[] keys = keys(); | |||
for (String key : keys) { | |||
removeAttributeInternal(key); | |||
} | |||
} | |||
@@ -273,13 +279,15 @@ public class StandardSession implements WxSession, InternalSession { | |||
@Override | |||
public void setId(String id) { | |||
if ((this.id != null) && (this.manager != null)) | |||
if ((this.id != null) && (this.manager != null)) { | |||
this.manager.remove(this); | |||
} | |||
this.id = id; | |||
if (this.manager != null) | |||
if (this.manager != null) { | |||
this.manager.add(this); | |||
} | |||
} | |||
/** | |||
@@ -295,21 +303,41 @@ public class StandardSession implements WxSession, InternalSession { | |||
@Override | |||
public boolean equals(Object o) { | |||
if (this == o) return true; | |||
if (!(o instanceof StandardSession)) return false; | |||
if (this == o) { | |||
return true; | |||
} | |||
if (!(o instanceof StandardSession)) { | |||
return false; | |||
} | |||
StandardSession session = (StandardSession) o; | |||
if (this.creationTime != session.creationTime) return false; | |||
if (this.expiring != session.expiring) return false; | |||
if (this.isValid != session.isValid) return false; | |||
if (this.maxInactiveInterval != session.maxInactiveInterval) return false; | |||
if (this.thisAccessedTime != session.thisAccessedTime) return false; | |||
if (!this.accessCount.equals(session.accessCount)) return false; | |||
if (!this.attributes.equals(session.attributes)) return false; | |||
if (!this.facade.equals(session.facade)) return false; | |||
if (!this.id.equals(session.id)) return false; | |||
return this.manager.equals(session.manager); | |||
if (this.creationTime != session.creationTime) { | |||
return false; | |||
} | |||
if (this.expiring != session.expiring) { | |||
return false; | |||
} | |||
if (this.isValid != session.isValid) { | |||
return false; | |||
} | |||
if (this.maxInactiveInterval != session.maxInactiveInterval) { | |||
return false; | |||
} | |||
if (this.thisAccessedTime != session.thisAccessedTime) { | |||
return false; | |||
} | |||
if (this.accessCount.get() != session.accessCount.get()) { | |||
return false; | |||
} | |||
if (!this.attributes.equals(session.attributes)) { | |||
return false; | |||
} | |||
if (!this.facade.equals(session.facade)) { | |||
return false; | |||
} | |||
return this.id.equals(session.id) && this.manager.equals(session.manager); | |||
} | |||
@@ -538,8 +538,16 @@ public class WxCpServiceImpl implements WxCpService { | |||
int retryTimes = 0; | |||
do { | |||
try { | |||
return executeInternal(executor, uri, data); | |||
T result = this.executeInternal(executor, uri, data); | |||
this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}",uri, data, result); | |||
return result; | |||
} catch (WxErrorException e) { | |||
if (retryTimes + 1 > this.maxRetryTimes) { | |||
this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); | |||
//最后一次重试失败后,直接抛出异常,不再等待 | |||
throw new RuntimeException("微信服务端异常,超出重试次数"); | |||
} | |||
WxError error = e.getError(); | |||
/* | |||
* -1 系统繁忙, 1000ms后重试 | |||
@@ -547,8 +555,7 @@ public class WxCpServiceImpl implements WxCpService { | |||
if (error.getErrorCode() == -1) { | |||
int sleepMillis = this.retrySleepMillis * (1 << retryTimes); | |||
try { | |||
this.log.debug("微信系统繁忙,{}ms 后重试(第{}次)", sleepMillis, | |||
retryTimes + 1); | |||
this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); | |||
Thread.sleep(sleepMillis); | |||
} catch (InterruptedException e1) { | |||
throw new RuntimeException(e1); | |||
@@ -557,8 +564,9 @@ public class WxCpServiceImpl implements WxCpService { | |||
throw e; | |||
} | |||
} | |||
} while (++retryTimes < this.maxRetryTimes); | |||
} while (retryTimes++ < this.maxRetryTimes); | |||
this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); | |||
throw new RuntimeException("微信服务端异常,超出重试次数"); | |||
} | |||
@@ -572,8 +580,7 @@ public class WxCpServiceImpl implements WxCpService { | |||
uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken; | |||
try { | |||
return executor.execute(getHttpclient(), this.httpProxy, | |||
uriWithAccessToken, data); | |||
return executor.execute(getHttpclient(), this.httpProxy, uriWithAccessToken, data); | |||
} catch (WxErrorException e) { | |||
WxError error = e.getError(); | |||
/* | |||
@@ -586,11 +593,14 @@ public class WxCpServiceImpl implements WxCpService { | |||
this.configStorage.expireAccessToken(); | |||
return execute(executor, uri, data); | |||
} | |||
if (error.getErrorCode() != 0) { | |||
this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, error); | |||
throw new WxErrorException(error); | |||
} | |||
return null; | |||
} catch (IOException e) { | |||
this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uri, data, e.getMessage()); | |||
throw new RuntimeException(e); | |||
} | |||
} | |||
@@ -1,17 +1,16 @@ | |||
package me.chanjar.weixin.cp.api; | |||
import me.chanjar.weixin.common.bean.result.WxError; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
import me.chanjar.weixin.common.util.http.RequestExecutor; | |||
import org.testng.annotations.DataProvider; | |||
import org.testng.annotations.Test; | |||
import java.util.concurrent.ExecutionException; | |||
import java.util.concurrent.ExecutorService; | |||
import java.util.concurrent.Executors; | |||
import java.util.concurrent.Future; | |||
import org.testng.annotations.DataProvider; | |||
import org.testng.annotations.Test; | |||
import me.chanjar.weixin.common.bean.result.WxError; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
import me.chanjar.weixin.common.util.http.RequestExecutor; | |||
@Test | |||
public class WxCpBusyRetryTest { | |||
@@ -23,6 +22,7 @@ public class WxCpBusyRetryTest { | |||
protected synchronized <T, E> T executeInternal( | |||
RequestExecutor<T, E> executor, String uri, E data) | |||
throws WxErrorException { | |||
this.log.info("Executed"); | |||
WxError error = new WxError(); | |||
error.setErrorCode(-1); | |||
throw new WxErrorException(error); | |||
@@ -0,0 +1,80 @@ | |||
package me.chanjar.weixin.mp.api; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
import me.chanjar.weixin.mp.bean.device.*; | |||
/** | |||
* Created by keungtung on 10/12/2016. | |||
*/ | |||
public interface WxMpDeviceService { | |||
/** | |||
* <pre> | |||
* 主动发送消息给设备 | |||
* 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-3 | |||
* </pre> | |||
*/ | |||
TransMsgResp transMsg(WxDeviceMsg msg) throws WxErrorException; | |||
/** | |||
* <pre> | |||
* 获取一组新的deviceid和设备二维码 | |||
* 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-6 | |||
* </pre> | |||
* @param productId 产品id | |||
* @return 返回WxDeviceQrCodeResult | |||
*/ | |||
WxDeviceQrCodeResult getQrCode(String productId) throws WxErrorException; | |||
/** | |||
* <pre> | |||
* 将device id及其属性信息提交公众平台进行授权 | |||
* 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-6 | |||
* </pre> | |||
* @param wxDeviceAuthorize 授权请求对象 | |||
* @return WxDeviceAuthorizeResult | |||
*/ | |||
WxDeviceAuthorizeResult authorize(WxDeviceAuthorize wxDeviceAuthorize) throws WxErrorException; | |||
/** | |||
* <pre> | |||
* 第三方后台绑定成功后,通知公众平台 | |||
* 详情请见:http://iot.weixin.qq.com/wiki/new/index.html/page=3-4-7 | |||
* </pre> | |||
* @param wxDeviceBind 绑定请求对象 | |||
* @return WxDeviceBindResult | |||
*/ | |||
WxDeviceBindResult bind(WxDeviceBind wxDeviceBind) throws WxErrorException; | |||
/** | |||
* <pre> | |||
* 强制绑定用户和设备 | |||
* 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-7 | |||
* </pre> | |||
* @param wxDeviceBind 强制绑定请求对象 | |||
* @return WxDeviceBindResult | |||
*/ | |||
WxDeviceBindResult compelBind(WxDeviceBind wxDeviceBind) throws WxErrorException; | |||
/** | |||
* <pre> | |||
* 第三方确认用户和设备的解绑操作 | |||
* 详情请见:http://iot.weixin.qq.com/wiki/new/index.html/page=3-4-7 | |||
* </pre> | |||
* @param wxDeviceBind 绑定请求对象 | |||
* @return WxDeviceBidResult | |||
*/ | |||
WxDeviceBindResult unbind(WxDeviceBind wxDeviceBind) throws WxErrorException; | |||
/** | |||
* <pre> | |||
* 强制解绑用户和设备 | |||
* 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-7 | |||
* </pre> | |||
* @param wxDeviceBind 强制解绑请求对象 | |||
* @return WxDeviceBindResult | |||
*/ | |||
WxDeviceBindResult compelUnbind(WxDeviceBind wxDeviceBind) throws WxErrorException; | |||
} |
@@ -345,4 +345,11 @@ public interface WxMpService { | |||
* @return WxMpTemplateMsgService | |||
*/ | |||
WxMpTemplateMsgService getTemplateMsgService(); | |||
/** | |||
* 返回硬件平台相关接口方法的实现类对象,以方便调用其各个接口 | |||
* | |||
* @return WxMpDeviceService | |||
*/ | |||
WxMpDeviceService getDeviceService(); | |||
} |
@@ -0,0 +1,72 @@ | |||
package me.chanjar.weixin.mp.api.impl; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
import me.chanjar.weixin.mp.api.WxMpDeviceService; | |||
import me.chanjar.weixin.mp.api.WxMpService; | |||
import me.chanjar.weixin.mp.bean.device.*; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
/** | |||
* Created by keungtung on 10/12/2016. | |||
*/ | |||
public class WxMpDeviceServiceImpl implements WxMpDeviceService { | |||
private static final String API_URL_PREFIX = "https://api.weixin.qq.com/device"; | |||
private static Logger log = LoggerFactory.getLogger(WxMpMenuServiceImpl.class); | |||
private WxMpService wxMpService; | |||
WxMpDeviceServiceImpl(WxMpService wxMpService) { | |||
this.wxMpService = wxMpService; | |||
} | |||
@Override | |||
public TransMsgResp transMsg(WxDeviceMsg msg) throws WxErrorException { | |||
String url = API_URL_PREFIX + "/transmsg"; | |||
String response = this.wxMpService.post(url,msg.toJson()); | |||
return TransMsgResp.fromJson(response); | |||
} | |||
@Override | |||
public WxDeviceQrCodeResult getQrCode(String productId) throws WxErrorException { | |||
String url = API_URL_PREFIX + "/getqrcode"; | |||
String response = this.wxMpService.get(url, "product_id=" + productId); | |||
return WxDeviceQrCodeResult.fromJson(response); | |||
} | |||
@Override | |||
public WxDeviceAuthorizeResult authorize(WxDeviceAuthorize wxDeviceAuthorize) throws WxErrorException { | |||
String url = API_URL_PREFIX + "/authorize_device"; | |||
String response = this.wxMpService.post(url,wxDeviceAuthorize.toJson()); | |||
return WxDeviceAuthorizeResult.fromJson(response); | |||
} | |||
@Override | |||
public WxDeviceBindResult bind(WxDeviceBind wxDeviceBind) throws WxErrorException { | |||
String url = API_URL_PREFIX + "/bind"; | |||
String response = this.wxMpService.post(url,wxDeviceBind.toJson()); | |||
return WxDeviceBindResult.fromJson(response); | |||
} | |||
@Override | |||
public WxDeviceBindResult compelBind(WxDeviceBind wxDeviceBind) throws WxErrorException { | |||
String url = API_URL_PREFIX + "/compel_bind"; | |||
String response = this.wxMpService.post(url,wxDeviceBind.toJson()); | |||
return WxDeviceBindResult.fromJson(response); | |||
} | |||
@Override | |||
public WxDeviceBindResult unbind(WxDeviceBind wxDeviceBind) throws WxErrorException { | |||
String url = API_URL_PREFIX + "/unbind?"; | |||
String response = this.wxMpService.post(url, wxDeviceBind.toJson()); | |||
return WxDeviceBindResult.fromJson(response); | |||
} | |||
@Override | |||
public WxDeviceBindResult compelUnbind(WxDeviceBind wxDeviceBind) throws WxErrorException { | |||
String url = API_URL_PREFIX + "/compel_unbind?"; | |||
String response = this.wxMpService.post(url, wxDeviceBind.toJson()); | |||
return WxDeviceBindResult.fromJson(response); | |||
} | |||
} | |||
@@ -62,6 +62,8 @@ public class WxMpServiceImpl implements WxMpService { | |||
private WxMpTemplateMsgService templateMsgService = new WxMpTemplateMsgServiceImpl(this); | |||
private WxMpDeviceService deviceService = new WxMpDeviceServiceImpl(this); | |||
private CloseableHttpClient httpClient; | |||
private HttpHost httpProxy; | |||
@@ -367,12 +369,18 @@ public class WxMpServiceImpl implements WxMpService { | |||
this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}",uri, data, result); | |||
return result; | |||
} catch (WxErrorException e) { | |||
if (retryTimes + 1 > this.maxRetryTimes) { | |||
this.log.warn("重试达到最大次数【{}】", maxRetryTimes); | |||
//最后一次重试失败后,直接抛出异常,不再等待 | |||
throw new RuntimeException("微信服务端异常,超出重试次数"); | |||
} | |||
WxError error = e.getError(); | |||
// -1 系统繁忙, 1000ms后重试 | |||
if (error.getErrorCode() == -1) { | |||
int sleepMillis = this.retrySleepMillis * (1 << retryTimes); | |||
try { | |||
this.log.debug("微信系统繁忙,{}ms 后重试(第{}次)", sleepMillis, retryTimes + 1); | |||
this.log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); | |||
Thread.sleep(sleepMillis); | |||
} catch (InterruptedException e1) { | |||
throw new RuntimeException(e1); | |||
@@ -381,8 +389,9 @@ public class WxMpServiceImpl implements WxMpService { | |||
throw e; | |||
} | |||
} | |||
} while (++retryTimes < this.maxRetryTimes); | |||
} while (retryTimes++ < this.maxRetryTimes); | |||
this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); | |||
throw new RuntimeException("微信服务端异常,超出重试次数"); | |||
} | |||
@@ -540,4 +549,8 @@ public class WxMpServiceImpl implements WxMpService { | |||
return this.templateMsgService; | |||
} | |||
@Override | |||
public WxMpDeviceService getDeviceService() { | |||
return this.deviceService; | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
package me.chanjar.weixin.mp.bean.device; | |||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||
/** | |||
* Created by keungtung on 14/12/2016. | |||
*/ | |||
public abstract class AbstractDeviceBean { | |||
public String toJson() { | |||
return WxGsonBuilder.create().toJson(this); | |||
} | |||
} |
@@ -0,0 +1,60 @@ | |||
package me.chanjar.weixin.mp.bean.device; | |||
import com.google.gson.annotations.SerializedName; | |||
/** | |||
* Created by keungtung on 10/12/2016. | |||
*/ | |||
public class BaseResp extends AbstractDeviceBean{ | |||
@SerializedName("base_info") | |||
private BaseInfo baseInfo; | |||
@SerializedName("errcode") | |||
private Integer errCode; | |||
@SerializedName("errmsg") | |||
private String errMsg; | |||
public Integer getErrCode() { | |||
return errCode; | |||
} | |||
public void setErrCode(Integer errCode) { | |||
this.errCode = errCode; | |||
} | |||
public BaseInfo getBaseInfo() { | |||
return baseInfo; | |||
} | |||
public void setBaseInfo(BaseInfo baseInfo) { | |||
this.baseInfo = baseInfo; | |||
} | |||
public String getErrMsg() { | |||
return errMsg; | |||
} | |||
public void setErrMsg(String errMsg) { | |||
this.errMsg = errMsg; | |||
} | |||
private class BaseInfo { | |||
private String device_type; | |||
private String device_id; | |||
public String getDevice_type() { | |||
return device_type; | |||
} | |||
public void setDevice_type(String device_type) { | |||
this.device_type = device_type; | |||
} | |||
public String getDevice_id() { | |||
return device_id; | |||
} | |||
public void setDevice_id(String device_id) { | |||
this.device_id = device_id; | |||
} | |||
} | |||
} |
@@ -0,0 +1,30 @@ | |||
package me.chanjar.weixin.mp.bean.device; | |||
import com.google.gson.annotations.SerializedName; | |||
/** | |||
* Created by keungtung on 10/12/2016. | |||
*/ | |||
public class RespMsg extends AbstractDeviceBean{ | |||
@SerializedName("ret_code") | |||
private Integer retCode; | |||
@SerializedName("error_info") | |||
private String errorInfo; | |||
public Integer getRetCode() { | |||
return retCode; | |||
} | |||
public void setRetCode(Integer retCode) { | |||
this.retCode = retCode; | |||
} | |||
public String getErrorInfo() { | |||
return errorInfo; | |||
} | |||
public void setErrorInfo(String errorInfo) { | |||
this.errorInfo = errorInfo; | |||
} | |||
} |
@@ -0,0 +1,53 @@ | |||
package me.chanjar.weixin.mp.bean.device; | |||
import com.google.gson.annotations.SerializedName; | |||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||
/** | |||
* Created by keungtung on 14/12/2016. | |||
*/ | |||
public class TransMsgResp extends AbstractDeviceBean{ | |||
private Integer ret; | |||
@SerializedName("ret_info") | |||
private String retInfo; | |||
@SerializedName("errcode") | |||
private Integer errCode; | |||
@SerializedName("errmsg") | |||
private String errMsg; | |||
public static TransMsgResp fromJson(String json) { | |||
return WxGsonBuilder.create().fromJson(json, TransMsgResp.class); | |||
} | |||
public Integer getRet() { | |||
return ret; | |||
} | |||
public void setRet(Integer ret) { | |||
this.ret = ret; | |||
} | |||
public String getRetInfo() { | |||
return retInfo; | |||
} | |||
public void setRetInfo(String retInfo) { | |||
this.retInfo = retInfo; | |||
} | |||
public Integer getErrCode() { | |||
return errCode; | |||
} | |||
public void setErrCode(Integer errCode) { | |||
this.errCode = errCode; | |||
} | |||
public String getErrMsg() { | |||
return errMsg; | |||
} | |||
public void setErrMsg(String errMsg) { | |||
this.errMsg = errMsg; | |||
} | |||
} |
@@ -0,0 +1,117 @@ | |||
package me.chanjar.weixin.mp.bean.device; | |||
import com.google.gson.annotations.SerializedName; | |||
/** | |||
* Created by keungtung on 10/12/2016. | |||
*/ | |||
public class WxDevice { | |||
private String id; | |||
private String mac; | |||
@SerializedName("connect_protocol") | |||
private String connectProtocol; | |||
@SerializedName("auth_key") | |||
private String authKey; | |||
@SerializedName("close_strategy") | |||
private String closeStrategy; | |||
@SerializedName("conn_strategy") | |||
private String connStrategy; | |||
@SerializedName("crypt_method") | |||
private String cryptMethod; | |||
@SerializedName("auth_ver") | |||
private String authVer; | |||
@SerializedName("manu_mac_pos") | |||
private String manuMacPos; | |||
@SerializedName("ser_mac_pos") | |||
private String serMacPos; | |||
@SerializedName("ble_simple_protocol") | |||
private String bleSimpleProtocol; | |||
public String getId() { | |||
return id; | |||
} | |||
public void setId(String id) { | |||
this.id = id; | |||
} | |||
public String getMac() { | |||
return mac; | |||
} | |||
public void setMac(String mac) { | |||
this.mac = mac; | |||
} | |||
public String getConnectProtocol() { | |||
return connectProtocol; | |||
} | |||
public void setConnectProtocol(String connectProtocol) { | |||
this.connectProtocol = connectProtocol; | |||
} | |||
public String getAuthKey() { | |||
return authKey; | |||
} | |||
public void setAuthKey(String authKey) { | |||
this.authKey = authKey; | |||
} | |||
public String getCloseStrategy() { | |||
return closeStrategy; | |||
} | |||
public void setCloseStrategy(String closeStrategy) { | |||
this.closeStrategy = closeStrategy; | |||
} | |||
public String getConnStrategy() { | |||
return connStrategy; | |||
} | |||
public void setConnStrategy(String connStrategy) { | |||
this.connStrategy = connStrategy; | |||
} | |||
public String getCryptMethod() { | |||
return cryptMethod; | |||
} | |||
public void setCryptMethod(String cryptMethod) { | |||
this.cryptMethod = cryptMethod; | |||
} | |||
public String getAuthVer() { | |||
return authVer; | |||
} | |||
public void setAuthVer(String authVer) { | |||
this.authVer = authVer; | |||
} | |||
public String getManuMacPos() { | |||
return manuMacPos; | |||
} | |||
public void setManuMacPos(String manuMacPos) { | |||
this.manuMacPos = manuMacPos; | |||
} | |||
public String getSerMacPos() { | |||
return serMacPos; | |||
} | |||
public void setSerMacPos(String serMacPos) { | |||
this.serMacPos = serMacPos; | |||
} | |||
public String getBleSimpleProtocol() { | |||
return bleSimpleProtocol; | |||
} | |||
public void setBleSimpleProtocol(String bleSimpleProtocol) { | |||
this.bleSimpleProtocol = bleSimpleProtocol; | |||
} | |||
} |
@@ -0,0 +1,47 @@ | |||
package me.chanjar.weixin.mp.bean.device; | |||
import com.google.gson.annotations.SerializedName; | |||
import java.util.Arrays; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
/** | |||
* Created by keungtung on 10/12/2016. | |||
*/ | |||
public class WxDeviceAuthorize extends AbstractDeviceBean { | |||
@SerializedName("device_num") | |||
private String deviceNum; | |||
@SerializedName("op_type") | |||
private String opType; | |||
@SerializedName("device_list") | |||
private List<WxDevice> deviceList = new LinkedList<>(); | |||
public String getDeviceNum() { | |||
return deviceNum; | |||
} | |||
public void setDeviceNum(String deviceNum) { | |||
this.deviceNum = deviceNum; | |||
} | |||
public String getOpType() { | |||
return opType; | |||
} | |||
public void setOpType(String opType) { | |||
this.opType = opType; | |||
} | |||
public List<WxDevice> getDeviceList() { | |||
return deviceList; | |||
} | |||
public void setDeviceList(List<WxDevice> deviceList) { | |||
this.deviceList = deviceList; | |||
} | |||
public void addDevice(WxDevice... devices) { | |||
this.deviceList.addAll(Arrays.asList(devices)); | |||
} | |||
} |
@@ -0,0 +1,24 @@ | |||
package me.chanjar.weixin.mp.bean.device; | |||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||
import java.util.List; | |||
/** | |||
* Created by keungtung on 10/12/2016. | |||
*/ | |||
public class WxDeviceAuthorizeResult extends AbstractDeviceBean{ | |||
private List<BaseResp> resp; | |||
public static WxDeviceAuthorizeResult fromJson(String response) { | |||
return WxGsonBuilder.create().fromJson(response, WxDeviceAuthorizeResult.class); | |||
} | |||
public List<BaseResp> getResp() { | |||
return resp; | |||
} | |||
public void setResp(List<BaseResp> resp) { | |||
this.resp = resp; | |||
} | |||
} |
@@ -0,0 +1,38 @@ | |||
package me.chanjar.weixin.mp.bean.device; | |||
import com.google.gson.annotations.SerializedName; | |||
/** | |||
* Created by keungtung on 10/12/2016. | |||
*/ | |||
public class WxDeviceBind extends AbstractDeviceBean{ | |||
private String ticket; | |||
@SerializedName("device_id") | |||
private String deviceId; | |||
@SerializedName("openid") | |||
private String openId; | |||
public String getTicket() { | |||
return ticket; | |||
} | |||
public void setTicket(String ticket) { | |||
this.ticket = ticket; | |||
} | |||
public String getDeviceId() { | |||
return deviceId; | |||
} | |||
public void setDeviceId(String deviceId) { | |||
this.deviceId = deviceId; | |||
} | |||
public String getOpenId() { | |||
return openId; | |||
} | |||
public void setOpenId(String openId) { | |||
this.openId = openId; | |||
} | |||
} |
@@ -0,0 +1,24 @@ | |||
package me.chanjar.weixin.mp.bean.device; | |||
import com.google.gson.annotations.SerializedName; | |||
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; | |||
/** | |||
* Created by keungtung on 10/12/2016. | |||
*/ | |||
public class WxDeviceBindResult extends AbstractDeviceBean{ | |||
@SerializedName("base_resp") | |||
private BaseResp baseResp; | |||
public static WxDeviceBindResult fromJson(String json) { | |||
return WxMpGsonBuilder.create().fromJson(json, WxDeviceBindResult.class); | |||
} | |||
public BaseResp getBaseResp() { | |||
return baseResp; | |||
} | |||
public void setBaseResp(BaseResp baseResp) { | |||
this.baseResp = baseResp; | |||
} | |||
} |
@@ -0,0 +1,54 @@ | |||
package me.chanjar.weixin.mp.bean.device; | |||
import com.google.gson.annotations.SerializedName; | |||
import me.chanjar.weixin.common.util.ToStringUtils; | |||
/** | |||
* Created by keungtung on 10/12/2016. | |||
*/ | |||
public class WxDeviceMsg extends AbstractDeviceBean{ | |||
@SerializedName("device_type") | |||
private String deviceType; | |||
@SerializedName("device_id") | |||
private String deviceId; | |||
@SerializedName("open_id") | |||
private String openId; | |||
private String content; | |||
@Override | |||
public String toString() { | |||
return ToStringUtils.toSimpleString(this); | |||
} | |||
public String getDeviceType() { | |||
return deviceType; | |||
} | |||
public void setDeviceType(String deviceType) { | |||
this.deviceType = deviceType; | |||
} | |||
public String getDeviceId() { | |||
return deviceId; | |||
} | |||
public void setDeviceId(String deviceId) { | |||
this.deviceId = deviceId; | |||
} | |||
public String getOpenId() { | |||
return openId; | |||
} | |||
public void setOpenId(String openId) { | |||
this.openId = openId; | |||
} | |||
public String getContent() { | |||
return content; | |||
} | |||
public void setContent(String content) { | |||
this.content = content; | |||
} | |||
} |
@@ -0,0 +1,54 @@ | |||
package me.chanjar.weixin.mp.bean.device; | |||
import com.google.gson.annotations.SerializedName; | |||
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; | |||
/** | |||
* Created by keungtung on 10/12/2016. | |||
*/ | |||
public class WxDeviceQrCodeResult extends AbstractDeviceBean{ | |||
@SerializedName("deviceid") | |||
private String deviceId; | |||
@SerializedName("qrticket") | |||
private String qrTicket; | |||
@SerializedName("devicelicence") | |||
private String deviceLicence; | |||
@SerializedName("resp_msg") | |||
private RespMsg respMsg; | |||
public static WxDeviceQrCodeResult fromJson(String json) { | |||
return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxDeviceQrCodeResult.class); | |||
} | |||
public String getDeviceLicence() { | |||
return deviceLicence; | |||
} | |||
public void setDeviceLicence(String deviceLicence) { | |||
this.deviceLicence = deviceLicence; | |||
} | |||
public RespMsg getRespMsg() { | |||
return respMsg; | |||
} | |||
public void setRespMsg(RespMsg respMsg) { | |||
this.respMsg = respMsg; | |||
} | |||
public String getDeviceId() { | |||
return deviceId; | |||
} | |||
public void setDeviceId(String deviceId) { | |||
this.deviceId = deviceId; | |||
} | |||
public String getQrTicket() { | |||
return qrTicket; | |||
} | |||
public void setQrTicket(String qrTicket) { | |||
this.qrTicket = qrTicket; | |||
} | |||
} |
@@ -1,17 +1,16 @@ | |||
package me.chanjar.weixin.mp.api; | |||
import java.util.concurrent.ExecutionException; | |||
import java.util.concurrent.ExecutorService; | |||
import java.util.concurrent.Executors; | |||
import java.util.concurrent.Future; | |||
import org.testng.annotations.DataProvider; | |||
import org.testng.annotations.Test; | |||
import me.chanjar.weixin.common.bean.result.WxError; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
import me.chanjar.weixin.common.util.http.RequestExecutor; | |||
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; | |||
import org.testng.annotations.DataProvider; | |||
import org.testng.annotations.Test; | |||
import java.util.concurrent.ExecutionException; | |||
import java.util.concurrent.ExecutorService; | |||
import java.util.concurrent.Executors; | |||
import java.util.concurrent.Future; | |||
@Test | |||
public class WxMpBusyRetryTest { | |||
@@ -24,6 +23,7 @@ public class WxMpBusyRetryTest { | |||
protected synchronized <T, E> T executeInternal( | |||
RequestExecutor<T, E> executor, String uri, E data) | |||
throws WxErrorException { | |||
this.log.info("Executed"); | |||
WxError error = new WxError(); | |||
error.setErrorCode(-1); | |||
throw new WxErrorException(error); | |||
@@ -32,9 +32,7 @@ public class WxMpBusyRetryTest { | |||
service.setMaxRetryTimes(3); | |||
service.setRetrySleepMillis(500); | |||
return new Object[][] { | |||
new Object[] { service } | |||
}; | |||
return new Object[][] { { service } }; | |||
} | |||
@Test(dataProvider = "getService", expectedExceptions = RuntimeException.class) | |||
@@ -0,0 +1,40 @@ | |||
package me.chanjar.weixin.mp.api.impl; | |||
import com.google.inject.Inject; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
import me.chanjar.weixin.mp.api.ApiTestModule; | |||
import me.chanjar.weixin.mp.api.WxMpService; | |||
import me.chanjar.weixin.mp.bean.device.WxDeviceQrCodeResult; | |||
import org.testng.annotations.DataProvider; | |||
import org.testng.annotations.Guice; | |||
import org.testng.annotations.Test; | |||
/** | |||
* Created by keungtung on 14/12/2016. | |||
*/ | |||
@Test(groups = "deviceApi") | |||
@Guice(modules = ApiTestModule.class) | |||
public class WxMpDeviceServiceImplTest { | |||
@Inject | |||
protected WxMpService wxService; | |||
@Test(dataProvider = "productId") | |||
public void testGetQrcode(String productId) { | |||
try { | |||
WxDeviceQrCodeResult result = wxService.getDeviceService().getQrCode(productId); | |||
println(result.toJson()); | |||
} catch (WxErrorException e) { | |||
println(e.getMessage()); | |||
} | |||
} | |||
private void println(String content) { | |||
System.out.println(content); | |||
} | |||
@DataProvider(name = "productId") | |||
public Object[][] getProductId() { | |||
return new Object[][]{new Object[]{"25639"}}; | |||
} | |||
} |
@@ -10,63 +10,63 @@ public class WxMpXmlMessageTest { | |||
public void testFromXml() { | |||
String xml = "<xml>" | |||
+ "<ToUserName><![CDATA[toUser]]></ToUserName>" | |||
+ "<FromUserName><![CDATA[fromUser]]></FromUserName> " | |||
+ "<CreateTime>1348831860</CreateTime>" | |||
+ "<MsgType><![CDATA[text]]></MsgType>" | |||
+ "<Content><![CDATA[this is a test]]></Content>" | |||
+ "<MsgId>1234567890123456</MsgId>" | |||
+ "<PicUrl><![CDATA[this is a url]]></PicUrl>" | |||
+ "<MediaId><![CDATA[media_id]]></MediaId>" | |||
+ "<Format><![CDATA[Format]]></Format>" | |||
+ "<ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId>" | |||
+ "<Location_X>23.134521</Location_X>" | |||
+ "<Location_Y>113.358803</Location_Y>" | |||
+ "<Scale>20</Scale>" | |||
+ "<Label><![CDATA[位置信息]]></Label>" | |||
+ "<Description><![CDATA[公众平台官网链接]]></Description>" | |||
+ "<Url><![CDATA[url]]></Url>" | |||
+ "<Title><![CDATA[公众平台官网链接]]></Title>" | |||
+ "<Event><![CDATA[subscribe]]></Event>" | |||
+ "<EventKey><![CDATA[qrscene_123123]]></EventKey>" | |||
+ "<Ticket><![CDATA[TICKET]]></Ticket>" | |||
+ "<Latitude>23.137466</Latitude>" | |||
+ "<Longitude>113.352425</Longitude>" | |||
+ "<Precision>119.385040</Precision>" | |||
+ "<ScanCodeInfo>" | |||
+ " <ScanType><![CDATA[qrcode]]></ScanType>" | |||
+ " <ScanResult><![CDATA[1]]></ScanResult>" | |||
+ "</ScanCodeInfo>" | |||
+ "<SendPicsInfo>" | |||
+ " <Count>1</Count>\n" | |||
+ " <PicList>" | |||
+ " <item>" | |||
+ " <PicMd5Sum><![CDATA[1b5f7c23b5bf75682a53e7b6d163e185]]></PicMd5Sum>" | |||
+ " </item>" | |||
+ " </PicList>" | |||
+ "</SendPicsInfo>" | |||
+ "<SendLocationInfo>" | |||
+ " <Location_X><![CDATA[23]]></Location_X>\n" | |||
+ " <Location_Y><![CDATA[113]]></Location_Y>\n" | |||
+ " <Scale><![CDATA[15]]></Scale>\n" | |||
+ " <Label><![CDATA[ 广州市海珠区客村艺苑路 106号]]></Label>\n" | |||
+ " <Poiname><![CDATA[wo de poi]]></Poiname>\n" | |||
+ "</SendLocationInfo>" | |||
+ "</xml>"; | |||
+ "<ToUserName><![CDATA[toUser]]></ToUserName>" | |||
+ "<FromUserName><![CDATA[fromUser]]></FromUserName> " | |||
+ "<CreateTime>1348831860</CreateTime>" | |||
+ "<MsgType><![CDATA[text]]></MsgType>" | |||
+ "<Content><![CDATA[this is a test]]></Content>" | |||
+ "<MsgId>1234567890123456</MsgId>" | |||
+ "<PicUrl><![CDATA[this is a url]]></PicUrl>" | |||
+ "<MediaId><![CDATA[media_id]]></MediaId>" | |||
+ "<Format><![CDATA[Format]]></Format>" | |||
+ "<ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId>" | |||
+ "<Location_X>23.134521</Location_X>" | |||
+ "<Location_Y>113.358803</Location_Y>" | |||
+ "<Scale>20</Scale>" | |||
+ "<Label><![CDATA[位置信息]]></Label>" | |||
+ "<Description><![CDATA[公众平台官网链接]]></Description>" | |||
+ "<Url><![CDATA[url]]></Url>" | |||
+ "<Title><![CDATA[公众平台官网链接]]></Title>" | |||
+ "<Event><![CDATA[subscribe]]></Event>" | |||
+ "<EventKey><![CDATA[qrscene_123123]]></EventKey>" | |||
+ "<Ticket><![CDATA[TICKET]]></Ticket>" | |||
+ "<Latitude>23.137466</Latitude>" | |||
+ "<Longitude>113.352425</Longitude>" | |||
+ "<Precision>119.385040</Precision>" | |||
+ "<ScanCodeInfo>" | |||
+ " <ScanType><![CDATA[qrcode]]></ScanType>" | |||
+ " <ScanResult><![CDATA[1]]></ScanResult>" | |||
+ "</ScanCodeInfo>" | |||
+ "<SendPicsInfo>" | |||
+ " <Count>1</Count>\n" | |||
+ " <PicList>" | |||
+ " <item>" | |||
+ " <PicMd5Sum><![CDATA[1b5f7c23b5bf75682a53e7b6d163e185]]></PicMd5Sum>" | |||
+ " </item>" | |||
+ " </PicList>" | |||
+ "</SendPicsInfo>" | |||
+ "<SendLocationInfo>" | |||
+ " <Location_X><![CDATA[23]]></Location_X>\n" | |||
+ " <Location_Y><![CDATA[113]]></Location_Y>\n" | |||
+ " <Scale><![CDATA[15]]></Scale>\n" | |||
+ " <Label><![CDATA[ 广州市海珠区客村艺苑路 106号]]></Label>\n" | |||
+ " <Poiname><![CDATA[wo de poi]]></Poiname>\n" | |||
+ "</SendLocationInfo>" | |||
+ "</xml>"; | |||
WxMpXmlMessage wxMessage = WxMpXmlMessage.fromXml(xml); | |||
Assert.assertEquals(wxMessage.getToUser(), "toUser"); | |||
Assert.assertEquals(wxMessage.getFromUser(), "fromUser"); | |||
Assert.assertEquals(wxMessage.getCreateTime(), new Long(1348831860l)); | |||
Assert.assertEquals(wxMessage.getCreateTime(), new Long(1348831860L)); | |||
Assert.assertEquals(wxMessage.getMsgType(), WxConsts.XML_MSG_TEXT); | |||
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.getMediaId(), "media_id"); | |||
Assert.assertEquals(wxMessage.getFormat(), "Format"); | |||
Assert.assertEquals(wxMessage.getThumbMediaId(), "thumb_media_id"); | |||
Assert.assertEquals(wxMessage.getLocationX(), new Double(23.134521d)); | |||
Assert.assertEquals(wxMessage.getLocationY(), new Double(113.358803d)); | |||
Assert.assertEquals(wxMessage.getScale(), new Double(20)); | |||
Assert.assertEquals(wxMessage.getLocationX(), 23.134521d); | |||
Assert.assertEquals(wxMessage.getLocationY(), 113.358803d); | |||
Assert.assertEquals(wxMessage.getScale(), 20d); | |||
Assert.assertEquals(wxMessage.getLabel(), "位置信息"); | |||
Assert.assertEquals(wxMessage.getDescription(), "公众平台官网链接"); | |||
Assert.assertEquals(wxMessage.getUrl(), "url"); | |||
@@ -74,12 +74,12 @@ public class WxMpXmlMessageTest { | |||
Assert.assertEquals(wxMessage.getEvent(), "subscribe"); | |||
Assert.assertEquals(wxMessage.getEventKey(), "qrscene_123123"); | |||
Assert.assertEquals(wxMessage.getTicket(), "TICKET"); | |||
Assert.assertEquals(wxMessage.getLatitude(), new Double(23.137466)); | |||
Assert.assertEquals(wxMessage.getLongitude(), new Double(113.352425)); | |||
Assert.assertEquals(wxMessage.getPrecision(), new Double(119.385040)); | |||
Assert.assertEquals(wxMessage.getLatitude(), 23.137466); | |||
Assert.assertEquals(wxMessage.getLongitude(), 113.352425); | |||
Assert.assertEquals(wxMessage.getPrecision(), 119.385040); | |||
Assert.assertEquals(wxMessage.getScanCodeInfo().getScanType(), "qrcode"); | |||
Assert.assertEquals(wxMessage.getScanCodeInfo().getScanResult(), "1"); | |||
Assert.assertEquals(wxMessage.getSendPicsInfo().getCount(), new Long(1l)); | |||
Assert.assertEquals(wxMessage.getSendPicsInfo().getCount(), new Long(1L)); | |||
Assert.assertEquals(wxMessage.getSendPicsInfo().getPicList().get(0).getPicMd5Sum(), "1b5f7c23b5bf75682a53e7b6d163e185"); | |||
Assert.assertEquals(wxMessage.getSendLocationInfo().getLocationX(), "23"); | |||
Assert.assertEquals(wxMessage.getSendLocationInfo().getLocationY(), "113"); | |||
@@ -91,63 +91,63 @@ public class WxMpXmlMessageTest { | |||
public void testFromXml2() { | |||
String xml = "<xml>" | |||
+ "<ToUserName><![CDATA[toUser]]></ToUserName>" | |||
+ "<FromUserName><![CDATA[fromUser]]></FromUserName> " | |||
+ "<CreateTime>1348831860</CreateTime>" | |||
+ "<MsgType><![CDATA[text]]></MsgType>" | |||
+ "<Content><![CDATA[this is a test]]></Content>" | |||
+ "<MsgID>1234567890123456</MsgID>" | |||
+ "<PicUrl><![CDATA[this is a url]]></PicUrl>" | |||
+ "<MediaId><![CDATA[media_id]]></MediaId>" | |||
+ "<Format><![CDATA[Format]]></Format>" | |||
+ "<ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId>" | |||
+ "<Location_X>23.134521</Location_X>" | |||
+ "<Location_Y>113.358803</Location_Y>" | |||
+ "<Scale>20</Scale>" | |||
+ "<Label><![CDATA[位置信息]]></Label>" | |||
+ "<Description><![CDATA[公众平台官网链接]]></Description>" | |||
+ "<Url><![CDATA[url]]></Url>" | |||
+ "<Title><![CDATA[公众平台官网链接]]></Title>" | |||
+ "<Event><![CDATA[subscribe]]></Event>" | |||
+ "<EventKey><![CDATA[qrscene_123123]]></EventKey>" | |||
+ "<Ticket><![CDATA[TICKET]]></Ticket>" | |||
+ "<Latitude>23.137466</Latitude>" | |||
+ "<Longitude>113.352425</Longitude>" | |||
+ "<Precision>119.385040</Precision>" | |||
+ "<ScanCodeInfo>" | |||
+ " <ScanType><![CDATA[qrcode]]></ScanType>" | |||
+ " <ScanResult><![CDATA[1]]></ScanResult>" | |||
+ "</ScanCodeInfo>" | |||
+ "<SendPicsInfo>" | |||
+ " <Count>1</Count>\n" | |||
+ " <PicList>" | |||
+ " <item>" | |||
+ " <PicMd5Sum><![CDATA[1b5f7c23b5bf75682a53e7b6d163e185]]></PicMd5Sum>" | |||
+ " </item>" | |||
+ " </PicList>" | |||
+ "</SendPicsInfo>" | |||
+ "<SendLocationInfo>" | |||
+ " <Location_X><![CDATA[23]]></Location_X>\n" | |||
+ " <Location_Y><![CDATA[113]]></Location_Y>\n" | |||
+ " <Scale><![CDATA[15]]></Scale>\n" | |||
+ " <Label><![CDATA[ 广州市海珠区客村艺苑路 106号]]></Label>\n" | |||
+ " <Poiname><![CDATA[wo de poi]]></Poiname>\n" | |||
+ "</SendLocationInfo>" | |||
+ "</xml>"; | |||
+ "<ToUserName><![CDATA[toUser]]></ToUserName>" | |||
+ "<FromUserName><![CDATA[fromUser]]></FromUserName> " | |||
+ "<CreateTime>1348831860</CreateTime>" | |||
+ "<MsgType><![CDATA[text]]></MsgType>" | |||
+ "<Content><![CDATA[this is a test]]></Content>" | |||
+ "<MsgID>1234567890123456</MsgID>" | |||
+ "<PicUrl><![CDATA[this is a url]]></PicUrl>" | |||
+ "<MediaId><![CDATA[media_id]]></MediaId>" | |||
+ "<Format><![CDATA[Format]]></Format>" | |||
+ "<ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId>" | |||
+ "<Location_X>23.134521</Location_X>" | |||
+ "<Location_Y>113.358803</Location_Y>" | |||
+ "<Scale>20</Scale>" | |||
+ "<Label><![CDATA[位置信息]]></Label>" | |||
+ "<Description><![CDATA[公众平台官网链接]]></Description>" | |||
+ "<Url><![CDATA[url]]></Url>" | |||
+ "<Title><![CDATA[公众平台官网链接]]></Title>" | |||
+ "<Event><![CDATA[subscribe]]></Event>" | |||
+ "<EventKey><![CDATA[qrscene_123123]]></EventKey>" | |||
+ "<Ticket><![CDATA[TICKET]]></Ticket>" | |||
+ "<Latitude>23.137466</Latitude>" | |||
+ "<Longitude>113.352425</Longitude>" | |||
+ "<Precision>119.385040</Precision>" | |||
+ "<ScanCodeInfo>" | |||
+ " <ScanType><![CDATA[qrcode]]></ScanType>" | |||
+ " <ScanResult><![CDATA[1]]></ScanResult>" | |||
+ "</ScanCodeInfo>" | |||
+ "<SendPicsInfo>" | |||
+ " <Count>1</Count>\n" | |||
+ " <PicList>" | |||
+ " <item>" | |||
+ " <PicMd5Sum><![CDATA[1b5f7c23b5bf75682a53e7b6d163e185]]></PicMd5Sum>" | |||
+ " </item>" | |||
+ " </PicList>" | |||
+ "</SendPicsInfo>" | |||
+ "<SendLocationInfo>" | |||
+ " <Location_X><![CDATA[23]]></Location_X>\n" | |||
+ " <Location_Y><![CDATA[113]]></Location_Y>\n" | |||
+ " <Scale><![CDATA[15]]></Scale>\n" | |||
+ " <Label><![CDATA[ 广州市海珠区客村艺苑路 106号]]></Label>\n" | |||
+ " <Poiname><![CDATA[wo de poi]]></Poiname>\n" | |||
+ "</SendLocationInfo>" | |||
+ "</xml>"; | |||
WxMpXmlMessage wxMessage = WxMpXmlMessage.fromXml(xml); | |||
Assert.assertEquals(wxMessage.getToUser(), "toUser"); | |||
Assert.assertEquals(wxMessage.getFromUser(), "fromUser"); | |||
Assert.assertEquals(wxMessage.getCreateTime(), new Long(1348831860l)); | |||
Assert.assertEquals(wxMessage.getCreateTime(), new Long(1348831860L)); | |||
Assert.assertEquals(wxMessage.getMsgType(), WxConsts.XML_MSG_TEXT); | |||
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.getMediaId(), "media_id"); | |||
Assert.assertEquals(wxMessage.getFormat(), "Format"); | |||
Assert.assertEquals(wxMessage.getThumbMediaId(), "thumb_media_id"); | |||
Assert.assertEquals(wxMessage.getLocationX(), new Double(23.134521d)); | |||
Assert.assertEquals(wxMessage.getLocationY(), new Double(113.358803d)); | |||
Assert.assertEquals(wxMessage.getScale(), new Double(20)); | |||
Assert.assertEquals(wxMessage.getLocationX(), 23.134521d); | |||
Assert.assertEquals(wxMessage.getLocationY(), 113.358803d); | |||
Assert.assertEquals(wxMessage.getScale(), 20d); | |||
Assert.assertEquals(wxMessage.getLabel(), "位置信息"); | |||
Assert.assertEquals(wxMessage.getDescription(), "公众平台官网链接"); | |||
Assert.assertEquals(wxMessage.getUrl(), "url"); | |||
@@ -155,12 +155,12 @@ public class WxMpXmlMessageTest { | |||
Assert.assertEquals(wxMessage.getEvent(), "subscribe"); | |||
Assert.assertEquals(wxMessage.getEventKey(), "qrscene_123123"); | |||
Assert.assertEquals(wxMessage.getTicket(), "TICKET"); | |||
Assert.assertEquals(wxMessage.getLatitude(), new Double(23.137466)); | |||
Assert.assertEquals(wxMessage.getLongitude(), new Double(113.352425)); | |||
Assert.assertEquals(wxMessage.getPrecision(), new Double(119.385040)); | |||
Assert.assertEquals(wxMessage.getLatitude(), 23.137466); | |||
Assert.assertEquals(wxMessage.getLongitude(), 113.352425); | |||
Assert.assertEquals(wxMessage.getPrecision(), 119.385040); | |||
Assert.assertEquals(wxMessage.getScanCodeInfo().getScanType(), "qrcode"); | |||
Assert.assertEquals(wxMessage.getScanCodeInfo().getScanResult(), "1"); | |||
Assert.assertEquals(wxMessage.getSendPicsInfo().getCount(), new Long(1l)); | |||
Assert.assertEquals(wxMessage.getSendPicsInfo().getCount(), new Long(1L)); | |||
Assert.assertEquals(wxMessage.getSendPicsInfo().getPicList().get(0).getPicMd5Sum(), "1b5f7c23b5bf75682a53e7b6d163e185"); | |||
Assert.assertEquals(wxMessage.getSendLocationInfo().getLocationX(), "23"); | |||
Assert.assertEquals(wxMessage.getSendLocationInfo().getLocationY(), "113"); | |||