mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2026-02-17 05:48:12 +08:00
22
.travis.yml
22
.travis.yml
@@ -1,12 +1,26 @@
|
||||
language: java
|
||||
sudo: false
|
||||
install: true
|
||||
addons:
|
||||
sonarqube:
|
||||
token:
|
||||
secure: "834110c7191f97ecb226970c46dcaff8e681da5a"
|
||||
|
||||
jdk:
|
||||
- oraclejdk7
|
||||
|
||||
script: "mvn clean package -Dmaven.test.skip=true"
|
||||
|
||||
- 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
|
||||
=====================================
|
||||
[](https://maven-badges.herokuapp.com/maven-central/com.github.binarywang/weixin-java-parent)
|
||||
[](https://travis-ci.org/wechat-group/weixin-java-tools)
|
||||
[](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(推荐点击按钮入群: [](http://shang.qq.com/wpa/qunwpa?idkey=731dc3e7ea31ebe25376cc1a791445468612c63fd0e9e05399b088ec81fd9e15) 或 [](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. 目前最新版本号为 [](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");
|
||||
|
||||
Reference in New Issue
Block a user