diff --git a/pom.xml b/pom.xml index 77cb441c65..deccbf833f 100644 --- a/pom.xml +++ b/pom.xml @@ -1,11 +1,11 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" + xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 4.0.0 com.github.binarywang weixin-java-parent - 1.3.5 + 2.0.0-SNAPSHOT pom WeiXin Java Tools - Parent 微信公众号、企业号上级POM @@ -39,7 +39,6 @@ weixin-java-common weixin-java-cp weixin-java-mp - spring-demo @@ -50,6 +49,13 @@ 1.7.10 1.1.2 3.6.7 + 2.8.0 + 2.7 + 3.4 + 2.5 + 1.10 + 9.3.0.M0 + 9.3.10.v20160621 @@ -82,20 +88,30 @@ com.google.code.gson gson - 2.2.2 + ${gson.version} commons-codec commons-codec - 1.9 + ${commons-codec.version} commons-io commons-io - 2.4 + ${commons-io.version} + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} - + @@ -125,13 +141,13 @@ org.eclipse.jetty jetty-server - 9.3.0.M0 + ${jetty.version} test org.eclipse.jetty jetty-servlet - 9.3.0.M0 + ${jetty.version} test @@ -149,16 +165,16 @@ - - doclint-java8-disable - - [1.8,) - - - -Xdoclint:none - - - + + doclint-java8-disable + + [1.8,) + + + -Xdoclint:none + + + release @@ -220,6 +236,9 @@ org.apache.maven.plugins maven-surefire-plugin 2.17 + + true + diff --git a/spring-demo/pom.xml b/spring-demo/pom.xml deleted file mode 100644 index 9e09bf2b88..0000000000 --- a/spring-demo/pom.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - 4.0.0 - - com.github.binarywang - weixin-java-parent - 1.3.5 - - spring-demo - war - WeiXin Java Tools - demo with spring - spring demo - https://github.com/binarywang/weixin-java-tools - - - - com.github.binarywang - weixin-java-common - ${project.version} - - - - diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index f618841f1d..517fc604f3 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang weixin-java-parent - 1.3.5 + 2.0.0-SNAPSHOT weixin-java-common diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java index 85efcd3fa5..0c9661d2f0 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java @@ -11,6 +11,7 @@ public class WxConsts { public static final String XML_MSG_TEXT = "text"; public static final String XML_MSG_IMAGE = "image"; public static final String XML_MSG_VOICE = "voice"; + public static final String XML_MSG_SHORTVIDEO = "shortvideo"; public static final String XML_MSG_VIDEO = "video"; public static final String XML_MSG_NEWS = "news"; public static final String XML_MSG_MUSIC = "music"; @@ -20,7 +21,7 @@ public class WxConsts { public static final String XML_TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service"; /////////////////////// - // 主动发送消息的消息类型 + // 主动发送消息(即客服消息)的消息类型 /////////////////////// public static final String CUSTOM_MSG_TEXT = "text"; public static final String CUSTOM_MSG_IMAGE = "image"; @@ -103,6 +104,10 @@ public class WxConsts { public static final String EVT_USER_ENTER_SESSION_FROM_CARD = "user_enter_session_from_card"; public static final String EVT_CARD_SKU_REMIND = "card_sku_remind"; // 库存报警 + public static final String EVT_KF_CREATE_SESSION = "kf_create_session"; // 客服接入会话 + public static final String EVT_KF_CLOSE_SESSION = "kf_close_session"; // 客服关闭会话 + public static final String EVT_KF_SWITCH_SESSION = "kf_switch_session"; // 客服转接会话 + /////////////////////// // 上传多媒体文件的类型 /////////////////////// @@ -133,13 +138,17 @@ public class WxConsts { /** 扫码推事件且弹出“消息接收中”提示框 */ public static final String BUTTON_SCANCODE_WAITMSG = "scancode_waitmsg"; /** 弹出系统拍照发图 */ - public static final String PIC_SYSPHOTO = "pic_sysphoto"; + public static final String BUTTON_PIC_SYSPHOTO = "pic_sysphoto"; /** 弹出拍照或者相册发图 */ - public static final String PIC_PHOTO_OR_ALBUM = "pic_photo_or_album"; + public static final String BUTTON_PIC_PHOTO_OR_ALBUM = "pic_photo_or_album"; /** 弹出微信相册发图器 */ - public static final String PIC_WEIXIN = "pic_weixin"; + public static final String BUTTON_PIC_WEIXIN = "pic_weixin"; /** 弹出地理位置选择器 */ - public static final String LOCATION_SELECT = "location_select"; + public static final String BUTTON_LOCATION_SELECT = "location_select"; + /** 下发消息(除文本消息) */ + public static final String BUTTON_MEDIA_ID = "media_id"; + /** 跳转图文消息URL */ + public static final String BUTTON_VIEW_LIMITED = "view_limited"; /////////////////////// // oauth2网页授权的scope diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxMenu.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxMenu.java index 7df05a48db..d236f62b3f 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxMenu.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxMenu.java @@ -1,14 +1,14 @@ package me.chanjar.weixin.common.bean; -import me.chanjar.weixin.common.util.json.WxGsonBuilder; -import org.apache.commons.codec.Charsets; - import java.io.InputStream; import java.io.InputStreamReader; import java.io.Serializable; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + /** * 企业号菜单 * @author Daniel Qian @@ -45,8 +45,6 @@ public String toJson() { /** * 要用 http://mp.weixin.qq.com/wiki/16/ff9b7b85220e1396ffa16794a9d95adc.html 格式来反序列化 * 相比 http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html 的格式,外层多套了一个menu - * @param json - * @return */ public static WxMenu fromJson(String json) { return WxGsonBuilder.create().fromJson(json, WxMenu.class); @@ -55,11 +53,9 @@ public static WxMenu fromJson(String json) { /** * 要用 http://mp.weixin.qq.com/wiki/16/ff9b7b85220e1396ffa16794a9d95adc.html 格式来反序列化 * 相比 http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html 的格式,外层多套了一个menu - * @param is - * @return */ public static WxMenu fromJson(InputStream is) { - return WxGsonBuilder.create().fromJson(new InputStreamReader(is, Charsets.UTF_8), WxMenu.class); + return WxGsonBuilder.create().fromJson(new InputStreamReader(is, StandardCharsets.UTF_8), WxMenu.class); } @Override @@ -195,7 +191,7 @@ public void setLanguage(String language) { this.language = language; } - @Override + @Override public String toString() { return "matchrule:{" + "tag_id='" + tagId + '\'' + diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSessionManager.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSessionManager.java index 262d9fe4f9..9f74162eef 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSessionManager.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSessionManager.java @@ -4,16 +4,11 @@ public interface WxSessionManager { /** * 获取某个sessionId对应的session,如果sessionId没有对应的session,则新建一个并返回。 - * @param sessionId - * @return */ public WxSession getSession(String sessionId); /** * 获取某个sessionId对应的session,如果sessionId没有对应的session,若create为true则新建一个,否则返回null。 - * @param sessionId - * @param create - * @return */ public WxSession getSession(String sessionId, boolean create); diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java index bd6ec15eeb..38a6c28db6 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java @@ -12,9 +12,6 @@ public class SHA1 { /** * 串接arr参数,生成sha1 digest - * - * @param arr - * @return */ public static String gen(String... arr) throws NoSuchAlgorithmException { Arrays.sort(arr); @@ -27,9 +24,6 @@ public static String gen(String... arr) throws NoSuchAlgorithmException { /** * 用&串接arr参数,生成sha1 digest - * - * @param arr - * @return */ public static String genWithAmple(String... arr) throws NoSuchAlgorithmException { Arrays.sort(arr); diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java index a8fa9e15f7..874133349f 100755 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java @@ -35,16 +35,16 @@ public class WxCryptUtil { private static final Base64 base64 = new Base64(); private static final Charset CHARSET = Charset.forName("utf-8"); - private static final ThreadLocal builderLocal = - new ThreadLocal() { - @Override protected DocumentBuilder initialValue() { - try { - return DocumentBuilderFactory.newInstance().newDocumentBuilder(); - } catch (ParserConfigurationException exc) { - throw new IllegalArgumentException(exc); - } - } - }; + private static final ThreadLocal builderLocal = new ThreadLocal() { + @Override + protected DocumentBuilder initialValue() { + try { + return DocumentBuilderFactory.newInstance().newDocumentBuilder(); + } catch (ParserConfigurationException exc) { + throw new IllegalArgumentException(exc); + } + } + }; protected byte[] aesKey; protected String token; @@ -61,7 +61,8 @@ public WxCryptUtil() { * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey * @param appidOrCorpid 公众平台appid/corpid */ - public WxCryptUtil(String token, String encodingAesKey, String appidOrCorpid) { + public WxCryptUtil(String token, String encodingAesKey, + String appidOrCorpid) { this.token = token; this.appidOrCorpid = appidOrCorpid; this.aesKey = Base64.decodeBase64(encodingAesKey + "="); @@ -105,7 +106,8 @@ protected String encrypt(String randomStr, String plainText) { ByteGroup byteCollector = new ByteGroup(); byte[] randomStringBytes = randomStr.getBytes(CHARSET); byte[] plainTextBytes = plainText.getBytes(CHARSET); - byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder(plainTextBytes.length); + byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder( + plainTextBytes.length); byte[] appIdBytes = appidOrCorpid.getBytes(CHARSET); // randomStr + networkBytesOrder + text + appid @@ -154,7 +156,8 @@ protected String encrypt(String randomStr, String plainText) { * @param encryptedXml 密文,对应POST请求的数据 * @return 解密后的原文 */ - public String decrypt(String msgSignature, String timeStamp, String nonce, String encryptedXml) { + public String decrypt(String msgSignature, String timeStamp, String nonce, + String encryptedXml) { // 密钥,公众账号的app corpSecret // 提取密文 String cipherText = extractEncryptPart(encryptedXml); @@ -186,7 +189,8 @@ public String decrypt(String cipherText) { // 设置解密模式为AES的CBC模式 Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES"); - IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16)); + IvParameterSpec iv = new IvParameterSpec( + Arrays.copyOfRange(aesKey, 0, 16)); cipher.init(Cipher.DECRYPT_MODE, key_spec, iv); // 使用BASE64对密文进行解码 @@ -208,9 +212,10 @@ public String decrypt(String cipherText) { int xmlLength = bytesNetworkOrder2Number(networkOrder); - xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET); - from_appid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), + xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET); + from_appid = new String( + Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET); } catch (Exception e) { throw new RuntimeException(e); } @@ -224,34 +229,32 @@ public String decrypt(String cipherText) { } - /** - * 微信公众号支付签名算法(详见:http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=4_3) - * @param packageParams 原始参数 - * @param signKey 加密Key(即 商户Key) - * @param charset 编码 - * @return 签名字符串 - */ - public static String createSign(Map packageParams, String signKey) { - SortedMap sortedMap = new TreeMap(); - sortedMap.putAll(packageParams); - - List keys = new ArrayList(packageParams.keySet()); - Collections.sort(keys); - - - StringBuffer toSign = new StringBuffer(); - for (String key : keys) { - String value = packageParams.get(key); - if (null != value && !"".equals(value) && !"sign".equals(key) - && !"key".equals(key)) { - toSign.append(key + "=" + value + "&"); - } - } - toSign.append("key=" + signKey); - String sign = DigestUtils.md5Hex(toSign.toString()) - .toUpperCase(); - return sign; + /** + * 微信公众号支付签名算法(详见:http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=4_3) + * @param packageParams 原始参数 + * @param signKey 加密Key(即 商户Key) + * @return 签名字符串 + */ + public static String createSign(Map packageParams, + String signKey) { + SortedMap sortedMap = new TreeMap(); + sortedMap.putAll(packageParams); + + List keys = new ArrayList(packageParams.keySet()); + Collections.sort(keys); + + StringBuffer toSign = new StringBuffer(); + for (String key : keys) { + String value = packageParams.get(key); + if (null != value && !"".equals(value) && !"sign".equals(key) + && !"key".equals(key)) { + toSign.append(key + "=" + value + "&"); + } } + toSign.append("key=" + signKey); + String sign = DigestUtils.md5Hex(toSign.toString()).toUpperCase(); + return sign; + } /** * 将一个数字转换成生成4个字节的网络字节序bytes数组 @@ -283,8 +286,6 @@ private int bytesNetworkOrder2Number(byte[] bytesInNetworkOrder) { /** * 随机生成16位字符串 - * - * @return */ private String genRandomStr() { String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; @@ -306,14 +307,12 @@ private String genRandomStr() { * @param nonce 随机字符串 * @return 生成的xml字符串 */ - private String generateXml(String encrypt, String signature, String timestamp, String nonce) { - String format = - "\n" - + "\n" - + "\n" - + "%3$s\n" - + "\n" - + ""; + private String generateXml(String encrypt, String signature, String timestamp, + String nonce) { + String format = "\n" + "\n" + + "\n" + + "%3$s\n" + "\n" + + ""; return String.format(format, encrypt, signature, timestamp, nonce); } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java index 718f33e631..35c50e3ff9 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java @@ -14,8 +14,6 @@ public class FileUtils { * @param name 文件名 * @param ext 扩展名 * @param tmpDirFile 临时文件夹目录 - * @return - * @throws IOException */ public static File createTmpFile(InputStream inputStream, String name, String ext, File tmpDirFile) throws IOException { FileOutputStream fos = null; @@ -56,8 +54,6 @@ public static File createTmpFile(InputStream inputStream, String name, String ex * @param inputStream * @param name 文件名 * @param ext 扩展名 - * @return - * @throws IOException */ public static File createTmpFile(InputStream inputStream, String name, String ext) throws IOException { return createTmpFile(inputStream, name, ext, null); diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/ApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/ApacheHttpClientBuilder.java index 1bd6a98cbe..c821d86c60 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/ApacheHttpClientBuilder.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/ApacheHttpClientBuilder.java @@ -17,35 +17,30 @@ public interface ApacheHttpClientBuilder { /** * 代理服务器地址 * @param httpProxyHost - * @return */ ApacheHttpClientBuilder httpProxyHost(String httpProxyHost); /** * 代理服务器端口 * @param httpProxyPort - * @return */ ApacheHttpClientBuilder httpProxyPort(int httpProxyPort); /** * 代理服务器用户名 * @param httpProxyUsername - * @return */ ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername); /** * 代理服务器密码 * @param httpProxyPassword - * @return */ ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword); /** * ssl连接socket工厂 * @param sslConnectionSocketFactory - * @return */ ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory); } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java index b0d498a345..1172a2fcbf 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java @@ -22,7 +22,6 @@ public interface RequestExecutor { * @param httpProxy http代理对象,如果没有配置代理则为空 * @param uri uri * @param data 数据 - * @return * @throws WxErrorException * @throws ClientProtocolException * @throws IOException diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index 5c1e44db70..654ba365fb 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang weixin-java-parent - 1.3.5 + 2.0.0-SNAPSHOT weixin-java-cp diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageMatcher.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageMatcher.java index 184a5324cb..09fbdd2103 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageMatcher.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageMatcher.java @@ -9,8 +9,6 @@ public interface WxCpMessageMatcher { /** * 消息是否匹配某种模式 - * @param message - * @return */ public boolean match(WxCpXmlMessage message); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java index 2c3722f469..96b4e77de5 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java @@ -124,7 +124,6 @@ List getRules() { /** * 开始一个新的Route规则 - * @return */ public WxCpMessageRouterRule rule() { return new WxCpMessageRouterRule(this); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java index cf453938ef..6d68332309 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java @@ -48,7 +48,6 @@ protected WxCpMessageRouterRule(WxCpMessageRouter routerBuilder) { * 设置是否异步执行,默认是true * * @param async - * @return */ public WxCpMessageRouterRule async(boolean async) { this.async = async; @@ -59,7 +58,6 @@ public WxCpMessageRouterRule async(boolean async) { * 如果agentId匹配 * * @param agentId - * @return */ public WxCpMessageRouterRule agentId(Integer agentId) { this.agentId = agentId; @@ -70,7 +68,6 @@ public WxCpMessageRouterRule agentId(Integer agentId) { * 如果msgType等于某值 * * @param msgType - * @return */ public WxCpMessageRouterRule msgType(String msgType) { this.msgType = msgType; @@ -81,7 +78,6 @@ public WxCpMessageRouterRule msgType(String msgType) { * 如果event等于某值 * * @param event - * @return */ public WxCpMessageRouterRule event(String event) { this.event = event; @@ -92,7 +88,6 @@ public WxCpMessageRouterRule event(String event) { * 如果eventKey等于某值 * * @param eventKey - * @return */ public WxCpMessageRouterRule eventKey(String eventKey) { this.eventKey = eventKey; @@ -103,7 +98,6 @@ public WxCpMessageRouterRule eventKey(String eventKey) { * 如果content等于某值 * * @param content - * @return */ public WxCpMessageRouterRule content(String content) { this.content = content; @@ -114,7 +108,6 @@ public WxCpMessageRouterRule content(String content) { * 如果content匹配该正则表达式 * * @param regex - * @return */ public WxCpMessageRouterRule rContent(String regex) { this.rContent = regex; @@ -125,7 +118,6 @@ public WxCpMessageRouterRule rContent(String regex) { * 如果fromUser等于某值 * * @param fromUser - * @return */ public WxCpMessageRouterRule fromUser(String fromUser) { this.fromUser = fromUser; @@ -136,7 +128,6 @@ public WxCpMessageRouterRule fromUser(String fromUser) { * 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 * * @param matcher - * @return */ public WxCpMessageRouterRule matcher(WxCpMessageMatcher matcher) { this.matcher = matcher; @@ -147,7 +138,6 @@ public WxCpMessageRouterRule matcher(WxCpMessageMatcher matcher) { * 设置微信消息拦截器 * * @param interceptor - * @return */ public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor) { return interceptor(interceptor, (WxCpMessageInterceptor[]) null); @@ -158,7 +148,6 @@ public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor) { * * @param interceptor * @param otherInterceptors - * @return */ public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor, WxCpMessageInterceptor... otherInterceptors) { this.interceptors.add(interceptor); @@ -174,7 +163,6 @@ public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor, WxC * 设置微信消息处理器 * * @param handler - * @return */ public WxCpMessageRouterRule handler(WxCpMessageHandler handler) { return handler(handler, (WxCpMessageHandler[]) null); @@ -185,7 +173,6 @@ public WxCpMessageRouterRule handler(WxCpMessageHandler handler) { * * @param handler * @param otherHandlers - * @return */ public WxCpMessageRouterRule handler(WxCpMessageHandler handler, WxCpMessageHandler... otherHandlers) { this.handlers.add(handler); @@ -200,7 +187,6 @@ public WxCpMessageRouterRule handler(WxCpMessageHandler handler, WxCpMessageHand /** * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 * - * @return */ public WxCpMessageRouter end() { this.routerBuilder.getRules().add(this); @@ -210,7 +196,6 @@ public WxCpMessageRouter end() { /** * 规则结束,但是消息还会进入其他规则 * - * @return */ public WxCpMessageRouter next() { this.reEnter = true; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java index 78e75a7603..33de577d00 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java @@ -32,7 +32,6 @@ public interface WxCpService { * @param timestamp * @param nonce * @param data 微信传输过来的数据,有可能是echoStr,有可能是xml消息 - * @return */ boolean checkSignature(String msgSignature, String timestamp, String nonce, String data); @@ -49,7 +48,6 @@ public interface WxCpService { /** * 获取access_token, 不强制刷新access_token * @see #getAccessToken(boolean) - * @return * @throws WxErrorException */ String getAccessToken() throws WxErrorException; @@ -63,7 +61,6 @@ public interface WxCpService { * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取access_token * * @param forceRefresh 强制刷新 - * @return * @throws me.chanjar.weixin.common.exception.WxErrorException */ String getAccessToken(boolean forceRefresh) throws WxErrorException; @@ -71,7 +68,6 @@ public interface WxCpService { /** * 获得jsapi_ticket,不强制刷新jsapi_ticket * @see #getJsapiTicket(boolean) - * @return * @throws WxErrorException */ public String getJsapiTicket() throws WxErrorException; @@ -84,7 +80,6 @@ public interface WxCpService { * 详情请见:http://qydev.weixin.qq.com/wiki/index.php?title=微信JS接口#.E9.99.84.E5.BD.951-JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95 * * @param forceRefresh 强制刷新 - * @return * @throws WxErrorException */ public String getJsapiTicket(boolean forceRefresh) throws WxErrorException; @@ -96,7 +91,6 @@ public interface WxCpService { * 详情请见:http://qydev.weixin.qq.com/wiki/index.php?title=微信JS接口#.E9.99.84.E5.BD.951-JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95 * * @param url url - * @return */ public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException; @@ -136,7 +130,7 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * * @return 保存到本地的临时文件 * @throws WxErrorException - * @params media_id + * @param media_id */ File mediaDownload(String media_id) throws WxErrorException; @@ -216,7 +210,6 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * * @see #menuGet(String) * - * @return * @throws WxErrorException */ WxMenu menuGet() throws WxErrorException; @@ -231,7 +224,6 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * @see #menuGet() * * @param agentId 企业号应用的id - * @return * @throws WxErrorException */ WxMenu menuGet(String agentId) throws WxErrorException; @@ -255,7 +247,6 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口 * * - * @return * @throws WxErrorException */ List departGet() throws WxErrorException; @@ -291,7 +282,6 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * @param departId 必填。部门id * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 - * @return * @throws WxErrorException */ List userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; @@ -306,7 +296,6 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * @param departId 必填。部门id * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 - * @return * @throws WxErrorException */ List departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; @@ -350,7 +339,6 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * 获取用户 * * @param userid - * @return * @throws WxErrorException */ WxCpUser userGet(String userid) throws WxErrorException; @@ -359,7 +347,6 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * 创建标签 * * @param tagName - * @return */ String tagCreate(String tagName) throws WxErrorException; @@ -381,7 +368,6 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i /** * 获得标签列表 * - * @return */ List tagGet() throws WxErrorException; @@ -389,7 +375,6 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * 获取标签成员 * * @param tagId - * @return */ List tagGetUsers(String tagId) throws WxErrorException; @@ -478,7 +463,6 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 * @param url * @param queryParam - * @return * @throws WxErrorException */ String get(String url, String queryParam) throws WxErrorException; @@ -487,7 +471,6 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求 * @param url * @param postData - * @return * @throws WxErrorException */ String post(String url, String postData) throws WxErrorException; @@ -503,7 +486,6 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * @param data * @param * @param - * @return * @throws WxErrorException */ T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; @@ -536,7 +518,6 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i /** * 获取某个sessionId对应的session,如果sessionId没有对应的session,则新建一个并返回。 * @param id id可以为任意字符串,建议使用FromUserName作为id - * @return */ WxSession getSession(String id); @@ -544,7 +525,6 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * 获取某个sessionId对应的session,如果sessionId没有对应的session,若create为true则新建一个,否则返回null。 * @param id id可以为任意字符串,建议使用FromUserName作为id * @param create - * @return */ WxSession getSession(String id, boolean create); @@ -556,25 +536,24 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * @param sessionManager */ void setSessionManager(WxSessionManager sessionManager); - + /** * 上传部门列表覆盖企业号上的部门信息 * @param mediaId * @throws WxErrorException */ String replaceParty(String mediaId) throws WxErrorException; - + /** * 上传用户列表覆盖企业号上的用户信息 * @param mediaId * @throws WxErrorException */ String replaceUser(String mediaId) throws WxErrorException; - + /** * 获取异步任务结果 * @param joinId - * @return * @throws WxErrorException */ String getTaskResult(String joinId) throws WxErrorException; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java index 46e5692920..1cf517abd7 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java @@ -510,12 +510,6 @@ public String post(String url, String postData) throws WxErrorException { /** * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 - * - * @param executor - * @param uri - * @param data - * @return - * @throws WxErrorException */ public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { int retryTimes = 0; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java index 8e69027a46..25734aef85 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java @@ -28,7 +28,7 @@ public class WxCpMessage implements Serializable { private String hqMusicUrl; private String safe; private List articles = new ArrayList(); - + public String getToUser() { return toUser; } @@ -63,7 +63,7 @@ public void setAgentId(String agentId) { public String getMsgType() { return msgType; } - + public String getSafe() { return safe; } @@ -135,18 +135,18 @@ public List getArticles() { public void setArticles(List articles) { this.articles = articles; } - + public String toJson() { return WxCpGsonBuilder.INSTANCE.create().toJson(this); } - + public static class WxArticle { - + private String title; private String description; private String url; private String picUrl; - + public String getTitle() { return title; } @@ -171,12 +171,11 @@ public String getPicUrl() { public void setPicUrl(String picUrl) { this.picUrl = picUrl; } - + } - + /** * 获得文本消息builder - * @return */ public static TextBuilder TEXT() { return new TextBuilder(); @@ -184,7 +183,6 @@ public static TextBuilder TEXT() { /** * 获得图片消息builder - * @return */ public static ImageBuilder IMAGE() { return new ImageBuilder(); @@ -192,23 +190,20 @@ public static ImageBuilder IMAGE() { /** * 获得语音消息builder - * @return */ public static VoiceBuilder VOICE() { return new VoiceBuilder(); } - + /** * 获得视频消息builder - * @return */ public static VideoBuilder VIDEO() { return new VideoBuilder(); } - + /** * 获得图文消息builder - * @return */ public static NewsBuilder NEWS() { return new NewsBuilder(); @@ -216,10 +211,9 @@ public static NewsBuilder NEWS() { /** * 获得文件消息builder - * @return */ public static FileBuilder FILE() { return new FileBuilder(); } - + } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java index 469bb0bdb3..eaf926e2a2 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java @@ -198,7 +198,6 @@ public void setCreateTime(Long createTime) { * {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_EVENT} * * - * @return */ public String getMsgType() { return msgType; @@ -404,7 +403,6 @@ protected static WxCpXmlMessage fromXml(InputStream is) { * @param timestamp * @param nonce * @param msgSignature - * @return */ public static WxCpXmlMessage fromEncryptedXml( String encryptedXml, @@ -542,7 +540,6 @@ public static class ScanCodeInfo { /** * 扫描类型,一般是qrcode - * @return */ public String getScanType() { @@ -555,7 +552,6 @@ public void setScanType(String scanType) { /** * 扫描结果,即二维码对应的字符串信息 - * @return */ public String getScanResult() { return scanResult; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java index 641a572d4b..eccfbecd39 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java @@ -14,14 +14,14 @@ public abstract class WxCpXmlOutMessage { @XStreamAlias("ToUserName") @XStreamConverter(value=XStreamCDataConverter.class) protected String toUserName; - + @XStreamAlias("FromUserName") @XStreamConverter(value=XStreamCDataConverter.class) protected String fromUserName; - + @XStreamAlias("CreateTime") protected Long createTime; - + @XStreamAlias("MsgType") @XStreamConverter(value=XStreamCDataConverter.class) protected String msgType; @@ -57,14 +57,13 @@ public String getMsgType() { public void setMsgType(String msgType) { this.msgType = msgType; } - + protected String toXml() { return XStreamTransformer.toXml((Class)this.getClass(), this); } /** * 转换成加密的xml格式 - * @return */ public String toEncryptedXml(WxCpConfigStorage wxCpConfigStorage) { String plainXml = toXml(); @@ -74,7 +73,6 @@ public String toEncryptedXml(WxCpConfigStorage wxCpConfigStorage) { /** * 获得文本消息builder - * @return */ public static TextBuilder TEXT() { return new TextBuilder(); @@ -82,7 +80,6 @@ public static TextBuilder TEXT() { /** * 获得图片消息builder - * @return */ public static ImageBuilder IMAGE() { return new ImageBuilder(); @@ -90,23 +87,20 @@ public static ImageBuilder IMAGE() { /** * 获得语音消息builder - * @return */ public static VoiceBuilder VOICE() { return new VoiceBuilder(); } - + /** * 获得视频消息builder - * @return */ public static VideoBuilder VIDEO() { return new VideoBuilder(); } - + /** * 获得图文消息builder - * @return */ public static NewsBuilder NEWS() { return new NewsBuilder(); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java index 12dd89921e..9bcd5edacb 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java @@ -14,10 +14,6 @@ public class XStreamTransformer { /** * xml -> pojo - * - * @param clazz - * @param xml - * @return */ @SuppressWarnings("unchecked") public static T fromXml(Class clazz, String xml) { @@ -43,9 +39,6 @@ public static void register(Class clz,XStream xStream){ /** * pojo -> xml * - * @param clazz - * @param object - * @return */ public static String toXml(Class clazz, T object) { return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object); diff --git a/weixin-java-demo-with-spring/.gitignore b/weixin-java-demo-with-spring/.gitignore new file mode 100644 index 0000000000..22f500b062 --- /dev/null +++ b/weixin-java-demo-with-spring/.gitignore @@ -0,0 +1 @@ +*.pmd diff --git a/weixin-java-demo-with-spring/README.md b/weixin-java-demo-with-spring/README.md new file mode 100644 index 0000000000..1268e693a9 --- /dev/null +++ b/weixin-java-demo-with-spring/README.md @@ -0,0 +1,7 @@ +#### 本Demo使用Spring MVC 框架实现微信公众号后台管理功能,支持多公众号,欢迎帮忙维护添加新功能,或提供更好的实现。 +### 1. 配置 + 复制/src/main/resources/wx-gzh1.properties.template 生成wx-gzh1.properties 文件,填写相关配置; + 复制/src/main/resources/wx-gzh2.properties.template 生成wx-gzh2.properties 文件,填写相关配置. + +### 2. 使用maven运行demo程序 + mvn jetty:run diff --git a/weixin-java-demo-with-spring/pom.xml b/weixin-java-demo-with-spring/pom.xml new file mode 100644 index 0000000000..e416798ef8 --- /dev/null +++ b/weixin-java-demo-with-spring/pom.xml @@ -0,0 +1,91 @@ + + + 4.0.0 + + com.github.binarywang + weixin-java-parent + 2.0.0-SNAPSHOT + + weixin-java-demo-with-spring + war + WeiXin Java Tools - DemoWithSpring + spring demo + https://github.com/binarywang/weixin-java-tools + + 4.3.0.RELEASE + 4.1.0.RELEASE + 19.0 + 1.7.2 + 1.8.9 + 1.2.6 + 3.4 + 9.3.10.v20160621 + + + + + com.github.binarywang + weixin-java-mp + ${project.version} + + + + com.alibaba + fastjson + ${fastjson.version} + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + com.google.guava + guava + ${guava.version} + + + org.slf4j + slf4j-log4j12 + ${slf4j.version} + + + org.springframework + spring-webmvc + ${spring.version} + + + org.springframework + spring-web + ${spring.version} + + + org.springframework.security + spring-security-core + ${spring-security.version} + + + + org.aspectj + aspectjrt + ${aspectj.version} + + + org.aspectj + aspectjweaver + ${aspectj.version} + + + + + + + org.eclipse.jetty + jetty-maven-plugin + ${jetty-maven-plugin.version} + + + + diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/aop/ControllerLogAspect.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/aop/ControllerLogAspect.java new file mode 100644 index 0000000000..8a836908c5 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/aop/ControllerLogAspect.java @@ -0,0 +1,80 @@ +package com.github.binarywang.demo.spring.aop; + +import org.apache.commons.lang3.ArrayUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.After; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.CodeSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; + +/** + * + * @author Binary Wang + * + */ +@Aspect +@Component +public class ControllerLogAspect { + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Pointcut("within(com.github.binarywang.demo.spring..*.controller..*)") + public void inController() { + } + + @Pointcut("execution(public * com.github.binarywang.demo.spring..*.controller..*.*(..))") + public void controller() { + } + + @Before("inController()") + public void writeBeforeLog(JoinPoint jp) { + this.debugInController(jp, "Start"); + } + + @After("inController()") + public void writeAfterLog(JoinPoint jp) { + this.debugInController(jp, "End"); + } + + private void debugInController(JoinPoint jp, String msg) { + String userName = getLoginUserName(); + + this.logger.debug("\n【{}】{}.{}() {} ", userName, + jp.getTarget() + .getClass().getSimpleName(), jp.getSignature().getName(), msg); + } + + private static String getLoginUserName() { + Authentication authentication = SecurityContextHolder.getContext() + .getAuthentication(); + if (authentication != null) { + return authentication.getName(); + } + + return "Anonymous"; + } + + @Before("controller()") + public void writeParams(JoinPoint jp) { + String[] names = ((CodeSignature) jp.getSignature()) + .getParameterNames(); + Object[] args = jp.getArgs(); + + if (ArrayUtils.isEmpty(names)) { + return; + } + + StringBuilder sb = new StringBuilder("Arguments: "); + for (int i = 0; i < names.length; i++) { + sb.append(names[i] + " = " + args[i] + ","); + } + + debugInController(jp, sb.toString()); + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/builder/AbstractBuilder.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/builder/AbstractBuilder.java new file mode 100644 index 0000000000..bf019b4b20 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/builder/AbstractBuilder.java @@ -0,0 +1,21 @@ +package com.github.binarywang.demo.spring.builder; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.binarywang.demo.spring.service.BaseWxService; + +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; + +/** + * + * @author Binary Wang + * + */ +public abstract class AbstractBuilder { + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + public abstract WxMpXmlOutMessage build(String content, + WxMpXmlMessage wxMessage, BaseWxService service) ; +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/builder/ImageBuilder.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/builder/ImageBuilder.java new file mode 100644 index 0000000000..882671258c --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/builder/ImageBuilder.java @@ -0,0 +1,27 @@ +package com.github.binarywang.demo.spring.builder; + +import com.github.binarywang.demo.spring.service.BaseWxService; + +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutImageMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; + +/** + * + * @author Binary Wang + * + */ +public class ImageBuilder extends AbstractBuilder { + + @Override + public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage, + BaseWxService service) { + + WxMpXmlOutImageMessage m = WxMpXmlOutMessage.IMAGE().mediaId(content) + .fromUser(wxMessage.getToUserName()).toUser(wxMessage.getFromUserName()) + .build(); + + return m; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/builder/TextBuilder.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/builder/TextBuilder.java new file mode 100644 index 0000000000..551f6ca79a --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/builder/TextBuilder.java @@ -0,0 +1,25 @@ +package com.github.binarywang.demo.spring.builder; + +import com.github.binarywang.demo.spring.service.BaseWxService; + +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutTextMessage; + +/** + * + * @author Binary Wang + * + */ +public class TextBuilder extends AbstractBuilder { + + @Override + public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage, + BaseWxService service) { + WxMpXmlOutTextMessage m = WxMpXmlOutMessage.TEXT().content(content) + .fromUser(wxMessage.getToUserName()).toUser(wxMessage.getFromUserName()) + .build(); + return m; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxAccountEnum.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxAccountEnum.java new file mode 100644 index 0000000000..c82aab9e42 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxAccountEnum.java @@ -0,0 +1,41 @@ +package com.github.binarywang.demo.spring.config; + +/** + * 公众号标识的枚举类 + * @author Binary Wang + * + */ +public enum WxAccountEnum { + GZH1(1, "公众号1"), + GZH2(2, "公众号2"); + + private int pubid; + private String name; + + private WxAccountEnum(int pubid, String name) { + this.name = name; + this.pubid = pubid; + } + + public int getPubid() { + return this.pubid; + } + + public String getName() { + return this.name; + } + + public static int queryPubid(String wxCode) { + return WxAccountEnum.valueOf(wxCode.toUpperCase()).getPubid(); + } + + public static String queryWxCode(int pubid) { + for (WxAccountEnum e : values()) { + if (e.getPubid() == pubid) { + return e.name().toLowerCase(); + } + } + + return null; + } +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxConfig.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxConfig.java new file mode 100644 index 0000000000..782f240510 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxConfig.java @@ -0,0 +1,23 @@ +package com.github.binarywang.demo.spring.config; + +/** + * 微信配置的抽象实现类 + * @author Binary Wang + * + */ +public abstract class WxConfig { + public abstract String getToken(); + + public abstract String getAppid(); + + public abstract String getAppsecret(); + + public abstract String getAesKey(); + + public abstract WxAccountEnum getWxAccountEnum(); + + public int getPubId() { + return getWxAccountEnum().getPubid(); + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxGzh1Config.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxGzh1Config.java new file mode 100644 index 0000000000..c1cfc01c72 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxGzh1Config.java @@ -0,0 +1,50 @@ +package com.github.binarywang.demo.spring.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +/** + * + * @author Binary Wang + * + */ +@Configuration +public class WxGzh1Config extends WxConfig { + @Value("#{gzh1WxProperties.wx_token}") + private String token; + + @Value("#{gzh1WxProperties.wx_appid}") + private String appid; + + @Value("#{gzh1WxProperties.wx_appsecret}") + private String appsecret; + + @Value("#{gzh1WxProperties.wx_aeskey}") + private String aesKey; + + @Override + public String getToken() { + return this.token; + } + + @Override + public String getAppid() { + return this.appid; + } + + @Override + public String getAppsecret() { + return this.appsecret; + } + + @Override + public String getAesKey() { + return this.aesKey; + } + + @Override + public WxAccountEnum getWxAccountEnum() { + return WxAccountEnum.GZH1; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxGzh2Config.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxGzh2Config.java new file mode 100644 index 0000000000..8c593909c6 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxGzh2Config.java @@ -0,0 +1,50 @@ +package com.github.binarywang.demo.spring.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +/** + * + * @author Binary Wang + * + */ +@Configuration +public class WxGzh2Config extends WxConfig { + @Value("#{gzh2WxProperties.wx_token}") + private String token; + + @Value("#{gzh2WxProperties.wx_appid}") + private String appid; + + @Value("#{gzh2WxProperties.wx_appsecret}") + private String appsecret; + + @Value("#{gzh2WxProperties.wx_aeskey}") + private String aesKey; + + @Override + public String getToken() { + return this.token; + } + + @Override + public String getAppid() { + return this.appid; + } + + @Override + public String getAppsecret() { + return this.appsecret; + } + + @Override + public String getAesKey() { + return this.aesKey; + } + + @Override + public WxAccountEnum getWxAccountEnum() { + return WxAccountEnum.GZH2; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/controller/AbstractWxPortalController.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/controller/AbstractWxPortalController.java new file mode 100644 index 0000000000..dba3f84066 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/controller/AbstractWxPortalController.java @@ -0,0 +1,80 @@ +package com.github.binarywang.demo.spring.controller; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.github.binarywang.demo.spring.service.BaseWxService; + +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; + +/** + * + * @author Binary Wang + * + */ +public abstract class AbstractWxPortalController { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @RequestMapping(method = RequestMethod.GET, produces = "text/plain;charset=utf-8") + public @ResponseBody String authGet( + @RequestParam("signature") String signature, + @RequestParam("timestamp") String timestamp, + @RequestParam("nonce") String nonce, + @RequestParam("echostr") String echostr) { + this.logger.info("\n接收到来自微信服务器的认证消息:[{},{},{},{}]", + signature, timestamp, nonce, echostr); + + if (this.getWxService().checkSignature(timestamp, nonce, signature)) { + return echostr; + } + + return "非法请求"; + } + + @RequestMapping(method = RequestMethod.POST, produces = "application/xml; charset=UTF-8") + public @ResponseBody String post(@RequestBody String requestBody, + @RequestParam("signature") String signature, + @RequestParam("encrypt_type") String encType, + @RequestParam("msg_signature") String msgSignature, + @RequestParam("timestamp") String timestamp, + @RequestParam("nonce") String nonce) { + this.logger.info("\n接收微信请求:[{},{},{},{},{}]\n{} ", + signature, encType, msgSignature, timestamp, nonce, requestBody); + + String out = null; + if (encType == null) { + // 明文传输的消息 + WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody); + WxMpXmlOutMessage outMessage = this.getWxService().route(inMessage); + if (outMessage == null) { + return ""; + } + out = outMessage.toXml(); + }else if ("aes".equals(encType)) { + // aes加密的消息 + WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, + this.getWxService().getWxMpConfigStorage(), timestamp, nonce, msgSignature); + this.logger.debug("\n消息解密后内容为:\n{} ", inMessage.toString()); + WxMpXmlOutMessage outMessage = this.getWxService().route(inMessage); + if (outMessage == null) { + return ""; + } + + out = outMessage.toEncryptedXml(this.getWxService().getWxMpConfigStorage()); + } + + this.logger.debug("\n组装回复信息:{}", out); + + return out; + } + + protected abstract BaseWxService getWxService(); + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/controller/Gzh1WxPortalController.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/controller/Gzh1WxPortalController.java new file mode 100644 index 0000000000..cea1315228 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/controller/Gzh1WxPortalController.java @@ -0,0 +1,26 @@ +package com.github.binarywang.demo.spring.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.github.binarywang.demo.spring.service.BaseWxService; +import com.github.binarywang.demo.spring.service.Gzh1WxService; + +/** + * 第一个公众号的微信交互接口 + * @author Binary Wang + * + */ +@RestController +@RequestMapping("/api/gzh1/portal") +public class Gzh1WxPortalController extends AbstractWxPortalController{ + @Autowired + private Gzh1WxService wxService; + + @Override + protected BaseWxService getWxService() { + return this.wxService; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/controller/Gzh2WxPortalController.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/controller/Gzh2WxPortalController.java new file mode 100644 index 0000000000..d982ad46b5 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/controller/Gzh2WxPortalController.java @@ -0,0 +1,26 @@ +package com.github.binarywang.demo.spring.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.github.binarywang.demo.spring.service.BaseWxService; +import com.github.binarywang.demo.spring.service.Gzh2WxService; + +/** + * 第二个公众号的微信交互接口 + * @author Binary Wang + * + */ +@RestController +@RequestMapping("/api/gzh2/portal") +public class Gzh2WxPortalController extends AbstractWxPortalController{ + @Autowired + private Gzh2WxService wxService; + + @Override + protected BaseWxService getWxService() { + return this.wxService; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/dto/WxMenuKey.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/dto/WxMenuKey.java new file mode 100644 index 0000000000..99b4cb680c --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/dto/WxMenuKey.java @@ -0,0 +1,44 @@ +package com.github.binarywang.demo.spring.dto; + +import org.apache.commons.lang3.builder.ToStringBuilder; + +/** + * 菜单的dto对象 + * @author Binary Wang + * + */ +public class WxMenuKey { + private String type; + private String content; + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + + public WxMenuKey() { + + } + + public WxMenuKey(String type, String content) { + this.type = type; + this.content = content; + } + + public String getType() { + return this.type; + } + + public void setType(String type) { + this.type = type; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/AbstractHandler.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/AbstractHandler.java new file mode 100644 index 0000000000..7e4e1642df --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/AbstractHandler.java @@ -0,0 +1,23 @@ +package com.github.binarywang.demo.spring.handler; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.binarywang.demo.spring.config.WxConfig; +import com.google.gson.Gson; + +import me.chanjar.weixin.mp.api.WxMpMessageHandler; + +/** + * + * @author Binary Wang + * + */ +public abstract class AbstractHandler implements WxMpMessageHandler { + + protected Logger logger = LoggerFactory.getLogger(getClass()); + protected final Gson gson = new Gson(); + + protected abstract WxConfig getWxConfig(); + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/KfSessionHandler.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/KfSessionHandler.java new file mode 100644 index 0000000000..dac1be8057 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/KfSessionHandler.java @@ -0,0 +1,36 @@ +package com.github.binarywang.demo.spring.handler; + +import java.util.Map; + +import org.springframework.stereotype.Component; + +import com.github.binarywang.demo.spring.config.WxConfig; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; + +/** + * + * @author Binary Wang + * + */ +@Component +public class KfSessionHandler extends AbstractHandler{ + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) throws WxErrorException { + //TODO 对会话做处理 + return null; + } + + @Override + protected WxConfig getWxConfig() { + return null; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/LocationHandler.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/LocationHandler.java new file mode 100644 index 0000000000..2a03ee7635 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/LocationHandler.java @@ -0,0 +1,47 @@ +package com.github.binarywang.demo.spring.handler; + +import java.util.Map; + +import com.github.binarywang.demo.spring.builder.TextBuilder; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; + +/** + * + * @author Binary Wang + * + */ +public abstract class LocationHandler extends AbstractHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) throws WxErrorException { + if (wxMessage.getMsgType().equals(WxConsts.XML_MSG_LOCATION)) { + //TODO 接收处理用户发送的地理位置消息 + try { + String content = "感谢反馈,您的的地理位置已收到!"; + return new TextBuilder().build(content, wxMessage, null); + } catch (Exception e) { + this.logger.error("位置消息接收处理失败", e); + return null; + } + } + + //上报地理位置事件 + this.logger.info("\n上报地理位置 。。。 "); + this.logger.info("\n纬度 : " + wxMessage.getLatitude()); + this.logger.info("\n经度 : " + wxMessage.getLongitude()); + this.logger.info("\n精度 : " + String.valueOf(wxMessage.getPrecision())); + + //TODO 可以将用户地理位置信息保存到本地数据库,以便以后使用 + + return null; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/LogHandler.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/LogHandler.java new file mode 100644 index 0000000000..7d9bc02c25 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/LogHandler.java @@ -0,0 +1,34 @@ +package com.github.binarywang.demo.spring.handler; + +import java.util.Map; + +import org.springframework.stereotype.Component; + +import com.github.binarywang.demo.spring.config.WxConfig; + +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; + +/** + * + * @author Binary Wang + * + */ +@Component +public class LogHandler extends AbstractHandler { + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + this.logger.info("\n接收到请求消息,内容:【{}】", wxMessage.toString()); + return null; + } + + @Override + protected WxConfig getWxConfig() { + return null; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/MenuHandler.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/MenuHandler.java new file mode 100644 index 0000000000..45d5c9788a --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/MenuHandler.java @@ -0,0 +1,71 @@ +package com.github.binarywang.demo.spring.handler; + +import java.util.Map; + +import com.alibaba.fastjson.JSON; +import com.github.binarywang.demo.spring.builder.AbstractBuilder; +import com.github.binarywang.demo.spring.builder.ImageBuilder; +import com.github.binarywang.demo.spring.builder.TextBuilder; +import com.github.binarywang.demo.spring.dto.WxMenuKey; +import com.github.binarywang.demo.spring.service.BaseWxService; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; + +/** + * + * @author Binary Wang + * + */ +public abstract class MenuHandler extends AbstractHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + BaseWxService weixinService = (BaseWxService) wxMpService; + + String key = wxMessage.getEventKey(); + WxMenuKey menuKey = null; + try { + menuKey = JSON.parseObject(key, WxMenuKey.class); + } catch (Exception e) { + return WxMpXmlOutMessage.TEXT().content(key) + .fromUser(wxMessage.getToUserName()) + .toUser(wxMessage.getFromUserName()).build(); + } + + AbstractBuilder builder = null; + switch (menuKey.getType()) { + case WxConsts.XML_MSG_TEXT: + builder = new TextBuilder(); + break; + case WxConsts.XML_MSG_IMAGE: + builder = new ImageBuilder(); + break; + case WxConsts.XML_MSG_VOICE: + break; + case WxConsts.XML_MSG_VIDEO: + break; + case WxConsts.XML_MSG_NEWS: + break; + default: + break; + } + + if (builder != null) { + try { + return builder.build(menuKey.getContent(), wxMessage, weixinService); + } catch (Exception e) { + this.logger.error(e.getMessage(), e); + } + } + + return null; + + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/MsgHandler.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/MsgHandler.java new file mode 100644 index 0000000000..7519420db8 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/MsgHandler.java @@ -0,0 +1,48 @@ +package com.github.binarywang.demo.spring.handler; + +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; + +import com.github.binarywang.demo.spring.builder.TextBuilder; +import com.github.binarywang.demo.spring.service.BaseWxService; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; + +/** + * + * @author Binary Wang + * + */ +public abstract class MsgHandler extends AbstractHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + + BaseWxService weixinService = (BaseWxService) wxMpService; + + if (!wxMessage.getMsgType().equals(WxConsts.XML_MSG_EVENT)) { + //TODO 可以选择将消息保存到本地 + } + + //当用户输入关键词如“你好”,“客服”等,并且有客服在线时,把消息转发给在线客服 + if (StringUtils.startsWithAny(wxMessage.getContent(), "你好", "客服") + && weixinService.hasKefuOnline()) { + return WxMpXmlOutMessage + .TRANSFER_CUSTOMER_SERVICE().fromUser(wxMessage.getToUserName()) + .toUser(wxMessage.getFromUserName()).build(); + } + + //TODO 组装回复消息 + String content = "回复信息内容"; + return new TextBuilder().build(content, wxMessage, weixinService); + + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/NullHandler.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/NullHandler.java new file mode 100644 index 0000000000..ac828f52ab --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/NullHandler.java @@ -0,0 +1,34 @@ +package com.github.binarywang.demo.spring.handler; + +import java.util.Map; + +import org.springframework.stereotype.Component; + +import com.github.binarywang.demo.spring.config.WxConfig; + +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; + +/** + * + * @author Binary Wang + * + */ +@Component +public class NullHandler extends AbstractHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + return null; + } + + @Override + protected WxConfig getWxConfig() { + return null; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/ScanHandler.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/ScanHandler.java new file mode 100644 index 0000000000..91267d4d4d --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/ScanHandler.java @@ -0,0 +1,10 @@ +package com.github.binarywang.demo.spring.handler; + +/** + * + * @author Binary Wang + * + */ +public abstract class ScanHandler extends AbstractHandler { + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/SubscribeHandler.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/SubscribeHandler.java new file mode 100644 index 0000000000..78049f4419 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/SubscribeHandler.java @@ -0,0 +1,61 @@ +package com.github.binarywang.demo.spring.handler; + +import com.github.binarywang.demo.spring.builder.TextBuilder; +import com.github.binarywang.demo.spring.service.BaseWxService; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.bean.result.WxMpUser; + +import java.util.Map; + +/** + * + * @author Binary Wang + * + */ +public abstract class SubscribeHandler extends AbstractHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, WxMpService wxMpService, + WxSessionManager sessionManager) throws WxErrorException { + + this.logger.info("新关注用户 OPENID: " + wxMessage.getFromUserName()); + + BaseWxService weixinService = (BaseWxService) wxMpService; + + // 获取微信用户基本信息 + WxMpUser userWxInfo = weixinService.getUserService().userInfo(wxMessage.getFromUserName(), null); + + if (userWxInfo != null) { + // TODO 可以添加关注用户到本地 + } + + WxMpXmlOutMessage responseResult = null; + try { + responseResult = handleSpecial(wxMessage); + } catch (Exception e) { + this.logger.error(e.getMessage(), e); + } + + if (responseResult != null) { + return responseResult; + } + + try { + return new TextBuilder().build("感谢关注", wxMessage, weixinService); + } catch (Exception e) { + this.logger.error(e.getMessage(), e); + } + + return null; + } + + /** + * 处理特殊请求,比如如果是扫码进来的,可以做相应处理 + */ + protected abstract WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage) throws Exception; + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/UnsubscribeHandler.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/UnsubscribeHandler.java new file mode 100644 index 0000000000..44daaa1826 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/UnsubscribeHandler.java @@ -0,0 +1,27 @@ +package com.github.binarywang.demo.spring.handler; + +import java.util.Map; + +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; + +/** + * + * @author Binary Wang + * + */ +public abstract class UnsubscribeHandler extends AbstractHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + String openId = wxMessage.getFromUserName(); + this.logger.info("取消关注用户 OPENID: " + openId); + // TODO 可以更新本地数据库为取消关注状态 + return null; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1LocationHandler.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1LocationHandler.java new file mode 100644 index 0000000000..efe4a72744 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1LocationHandler.java @@ -0,0 +1,23 @@ +package com.github.binarywang.demo.spring.handler.gzh1; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import com.github.binarywang.demo.spring.config.WxConfig; +import com.github.binarywang.demo.spring.config.WxGzh1Config; +import com.github.binarywang.demo.spring.handler.LocationHandler; + +@Component +@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class Gzh1LocationHandler extends LocationHandler { + @Autowired + private WxGzh1Config wxConfig; + + @Override + protected WxConfig getWxConfig() { + return this.wxConfig; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1MenuHandler.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1MenuHandler.java new file mode 100644 index 0000000000..33382366f2 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1MenuHandler.java @@ -0,0 +1,23 @@ +package com.github.binarywang.demo.spring.handler.gzh1; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import com.github.binarywang.demo.spring.config.WxConfig; +import com.github.binarywang.demo.spring.config.WxGzh1Config; +import com.github.binarywang.demo.spring.handler.MenuHandler; + +@Component +@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class Gzh1MenuHandler extends MenuHandler { + @Autowired + private WxGzh1Config wxConfig; + + @Override + protected WxConfig getWxConfig() { + return this.wxConfig; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1MsgHandler.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1MsgHandler.java new file mode 100644 index 0000000000..8810b64358 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1MsgHandler.java @@ -0,0 +1,23 @@ +package com.github.binarywang.demo.spring.handler.gzh1; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import com.github.binarywang.demo.spring.config.WxConfig; +import com.github.binarywang.demo.spring.config.WxGzh1Config; +import com.github.binarywang.demo.spring.handler.MsgHandler; + +@Component +@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class Gzh1MsgHandler extends MsgHandler { + @Autowired + private WxGzh1Config wxConfig; + + @Override + protected WxConfig getWxConfig() { + return this.wxConfig; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1SubscribeHandler.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1SubscribeHandler.java new file mode 100644 index 0000000000..367a5d8b43 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1SubscribeHandler.java @@ -0,0 +1,32 @@ +package com.github.binarywang.demo.spring.handler.gzh1; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import com.github.binarywang.demo.spring.config.WxConfig; +import com.github.binarywang.demo.spring.config.WxGzh1Config; +import com.github.binarywang.demo.spring.handler.SubscribeHandler; + +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; + +@Component +@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class Gzh1SubscribeHandler extends SubscribeHandler { + @Autowired + private WxGzh1Config wxConfig; + + @Override + protected WxConfig getWxConfig() { + return this.wxConfig; + } + + @Override + protected WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage) + throws Exception { + return null; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1UnSubscribeHandler.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1UnSubscribeHandler.java new file mode 100644 index 0000000000..f55d39d448 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1UnSubscribeHandler.java @@ -0,0 +1,23 @@ +package com.github.binarywang.demo.spring.handler.gzh1; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import com.github.binarywang.demo.spring.config.WxConfig; +import com.github.binarywang.demo.spring.config.WxGzh1Config; +import com.github.binarywang.demo.spring.handler.UnsubscribeHandler; + +@Component +@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class Gzh1UnSubscribeHandler extends UnsubscribeHandler { + @Autowired + private WxGzh1Config wxConfig; + + @Override + protected WxConfig getWxConfig() { + return this.wxConfig; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/service/BaseWxService.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/service/BaseWxService.java new file mode 100644 index 0000000000..4b629eaa6c --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/service/BaseWxService.java @@ -0,0 +1,138 @@ +package com.github.binarywang.demo.spring.service; + +import com.github.binarywang.demo.spring.config.WxConfig; +import com.github.binarywang.demo.spring.handler.*; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage; +import me.chanjar.weixin.mp.api.WxMpMessageRouter; +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfOnlineList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.PostConstruct; + +/** + * + * @author Binary Wang + * + */ +public abstract class BaseWxService extends WxMpServiceImpl { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + protected LogHandler logHandler; + + @Autowired + protected NullHandler nullHandler; + + @Autowired + protected KfSessionHandler kfSessionHandler; + + private WxMpMessageRouter router; + + protected abstract WxConfig getServerConfig(); + + protected abstract MenuHandler getMenuHandler(); + + protected abstract SubscribeHandler getSubscribeHandler(); + + protected abstract UnsubscribeHandler getUnsubscribeHandler(); + + protected abstract AbstractHandler getLocationHandler(); + + protected abstract MsgHandler getMsgHandler(); + + protected abstract AbstractHandler getScanHandler(); + + @PostConstruct + public void init() { + final WxMpInMemoryConfigStorage config = new WxMpInMemoryConfigStorage(); + config.setAppId(this.getServerConfig().getAppid());// 设置微信公众号的appid + config.setSecret(this.getServerConfig().getAppsecret());// 设置微信公众号的app corpSecret + config.setToken(this.getServerConfig().getToken());// 设置微信公众号的token + config.setAesKey(this.getServerConfig().getAesKey());// 设置消息加解密密钥 + super.setWxMpConfigStorage(config); + + this.refreshRouter(); + } + + private void refreshRouter() { + + final WxMpMessageRouter newRouter = new WxMpMessageRouter(this); + + // 记录所有事件的日志 + newRouter.rule().handler(this.logHandler).next(); + + // 接收客服会话管理事件 + newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT) + .event(WxConsts.EVT_KF_CREATE_SESSION).handler(this.kfSessionHandler).end(); + + newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT) + .event(WxConsts.EVT_KF_CLOSE_SESSION).handler(this.kfSessionHandler).end(); + + newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT) + .event(WxConsts.EVT_KF_SWITCH_SESSION).handler(this.kfSessionHandler).end(); + + // 自定义菜单事件 + newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT) + .event(WxConsts.BUTTON_CLICK).handler(this.getMenuHandler()).end(); + + // 点击菜单连接事件 + newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT) + .event(WxConsts.BUTTON_VIEW).handler(this.nullHandler).end(); + + // 关注事件 + newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT) + .event(WxConsts.EVT_SUBSCRIBE).handler(this.getSubscribeHandler()) + .end(); + + // 取消关注事件 + newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT) + .event(WxConsts.EVT_UNSUBSCRIBE).handler(this.getUnsubscribeHandler()) + .end(); + + // 上报地理位置事件 + newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT) + .event(WxConsts.EVT_LOCATION).handler(this.getLocationHandler()).end(); + + // 接收地理位置消息 + newRouter.rule().async(false).msgType(WxConsts.XML_MSG_LOCATION) + .handler(this.getLocationHandler()).end(); + + // 扫码事件 + newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT) + .event(WxConsts.EVT_SCAN).handler(this.getScanHandler()).end(); + + // 默认 + newRouter.rule().async(false).handler(this.getMsgHandler()).end(); + + this.router = newRouter; + } + + + public WxMpXmlOutMessage route(WxMpXmlMessage message) { + try { + return this.router.route(message); + } catch (Exception e) { + this.logger.error(e.getMessage(), e); + } + + return null; + } + + public boolean hasKefuOnline() { + try { + WxMpKfOnlineList kfOnlineList = this.getKefuService().kfOnlineList(); + return kfOnlineList != null && kfOnlineList.getKfOnlineList().size() > 0; + } catch (Exception e) { + this.logger.error("获取客服在线状态异常: " + e.getMessage(), e); + } + + return false; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/service/Gzh1WxService.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/service/Gzh1WxService.java new file mode 100644 index 0000000000..1bad76ec34 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/service/Gzh1WxService.java @@ -0,0 +1,79 @@ +package com.github.binarywang.demo.spring.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.github.binarywang.demo.spring.config.WxGzh1Config; +import com.github.binarywang.demo.spring.config.WxConfig; +import com.github.binarywang.demo.spring.handler.AbstractHandler; +import com.github.binarywang.demo.spring.handler.MenuHandler; +import com.github.binarywang.demo.spring.handler.MsgHandler; +import com.github.binarywang.demo.spring.handler.SubscribeHandler; +import com.github.binarywang.demo.spring.handler.UnsubscribeHandler; +import com.github.binarywang.demo.spring.handler.gzh1.Gzh1LocationHandler; +import com.github.binarywang.demo.spring.handler.gzh1.Gzh1MenuHandler; +import com.github.binarywang.demo.spring.handler.gzh1.Gzh1MsgHandler; +import com.github.binarywang.demo.spring.handler.gzh1.Gzh1SubscribeHandler; +import com.github.binarywang.demo.spring.handler.gzh1.Gzh1UnSubscribeHandler; + +/** + * + * @author Binary Wang + * + */ +@Service +public class Gzh1WxService extends BaseWxService { + @Autowired + private WxGzh1Config wxConfig; + + @Autowired + private Gzh1LocationHandler locationHandler; + + @Autowired + private Gzh1MenuHandler menuHandler; + + @Autowired + private Gzh1MsgHandler msgHandler; + + @Autowired + private Gzh1UnSubscribeHandler unSubscribeHandler; + + @Autowired + private Gzh1SubscribeHandler subscribeHandler; + + @Override + protected WxConfig getServerConfig() { + return this.wxConfig; + } + + @Override + protected MenuHandler getMenuHandler() { + return this.menuHandler; + } + + @Override + protected SubscribeHandler getSubscribeHandler() { + return this.subscribeHandler; + } + + @Override + protected UnsubscribeHandler getUnsubscribeHandler() { + return this.unSubscribeHandler; + } + + @Override + protected AbstractHandler getLocationHandler() { + return this.locationHandler; + } + + @Override + protected MsgHandler getMsgHandler() { + return this.msgHandler; + } + + @Override + protected AbstractHandler getScanHandler() { + return null; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/service/Gzh2WxService.java b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/service/Gzh2WxService.java new file mode 100644 index 0000000000..beaeafbfa9 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/service/Gzh2WxService.java @@ -0,0 +1,66 @@ +package com.github.binarywang.demo.spring.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.github.binarywang.demo.spring.config.WxGzh2Config; +import com.github.binarywang.demo.spring.config.WxConfig; +import com.github.binarywang.demo.spring.handler.AbstractHandler; +import com.github.binarywang.demo.spring.handler.MenuHandler; +import com.github.binarywang.demo.spring.handler.MsgHandler; +import com.github.binarywang.demo.spring.handler.SubscribeHandler; +import com.github.binarywang.demo.spring.handler.UnsubscribeHandler; + +/** + * + * @author Binary Wang + * + */ +@Service +public class Gzh2WxService extends BaseWxService { + + @Autowired + private WxGzh2Config wxConfig; + + @Override + protected WxConfig getServerConfig() { + return this.wxConfig; + } + + @Override + protected MenuHandler getMenuHandler() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected SubscribeHandler getSubscribeHandler() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected UnsubscribeHandler getUnsubscribeHandler() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected AbstractHandler getLocationHandler() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected MsgHandler getMsgHandler() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected AbstractHandler getScanHandler() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/weixin-java-demo-with-spring/src/main/resources/.gitignore b/weixin-java-demo-with-spring/src/main/resources/.gitignore new file mode 100644 index 0000000000..a8697d7334 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/resources/.gitignore @@ -0,0 +1,2 @@ +/wx-gzh1.properties +/wx-gzh2.properties diff --git a/weixin-java-demo-with-spring/src/main/resources/applicationContext.xml b/weixin-java-demo-with-spring/src/main/resources/applicationContext.xml new file mode 100644 index 0000000000..f4954624f8 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/resources/applicationContext.xml @@ -0,0 +1,17 @@ + + + + + + + + + \ No newline at end of file diff --git a/weixin-java-demo-with-spring/src/main/resources/log4j.properties b/weixin-java-demo-with-spring/src/main/resources/log4j.properties new file mode 100644 index 0000000000..0f4d67788d --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/resources/log4j.properties @@ -0,0 +1,8 @@ +log4j.rootLogger=DEBUG, stdout + +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout +log4j.appender.stdout.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t]:%c:%L#%M() %m%n + +log4j.logger.org.apache.http.impl.conn.PoolingHttpClientConnectionManager=INFO \ No newline at end of file diff --git a/weixin-java-demo-with-spring/src/main/resources/spring-service-bean.xml b/weixin-java-demo-with-spring/src/main/resources/spring-service-bean.xml new file mode 100644 index 0000000000..bc5bbf9a54 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/resources/spring-service-bean.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + UTF-8 + + + + + + + + \ No newline at end of file diff --git a/weixin-java-demo-with-spring/src/main/resources/spring-servlet-common.xml b/weixin-java-demo-with-spring/src/main/resources/spring-servlet-common.xml new file mode 100644 index 0000000000..3686b979a8 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/resources/spring-servlet-common.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + text/html;charset=UTF-8 + text/plain;charset=UTF-8 + + + + + + + + + + + diff --git a/weixin-java-demo-with-spring/src/main/resources/wx-gzh1.properties.template b/weixin-java-demo-with-spring/src/main/resources/wx-gzh1.properties.template new file mode 100644 index 0000000000..302903e552 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/resources/wx-gzh1.properties.template @@ -0,0 +1,4 @@ +wx_appid= +wx_appsecret= +wx_token= +wx_aeskey= diff --git a/weixin-java-demo-with-spring/src/main/resources/wx-gzh2.properties.template b/weixin-java-demo-with-spring/src/main/resources/wx-gzh2.properties.template new file mode 100644 index 0000000000..302903e552 --- /dev/null +++ b/weixin-java-demo-with-spring/src/main/resources/wx-gzh2.properties.template @@ -0,0 +1,4 @@ +wx_appid= +wx_appsecret= +wx_token= +wx_aeskey= diff --git a/spring-demo/src/main/webapp/WEB-INF/web.xml b/weixin-java-demo-with-spring/src/main/webapp/WEB-INF/web.xml similarity index 85% rename from spring-demo/src/main/webapp/WEB-INF/web.xml rename to weixin-java-demo-with-spring/src/main/webapp/WEB-INF/web.xml index 6242f8f1f4..fd9cce94ba 100644 --- a/spring-demo/src/main/webapp/WEB-INF/web.xml +++ b/weixin-java-demo-with-spring/src/main/webapp/WEB-INF/web.xml @@ -20,14 +20,6 @@ encodingFilter /* - - springSecurityFilterChain - org.springframework.web.filter.DelegatingFilterProxy - - - springSecurityFilterChain - /v1/admin/* - org.springframework.web.context.ContextLoaderListener diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index 70e081dbb4..3aa28ed046 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang weixin-java-parent - 1.3.5 + 2.0.0-SNAPSHOT weixin-java-mp WeiXin Java Tools - MP @@ -47,6 +47,12 @@ org.eclipse.jetty jetty-servlet test + + + joda-time + joda-time + 2.9.4 + test diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGroupService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGroupService.java new file mode 100644 index 0000000000..80cadd55e9 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGroupService.java @@ -0,0 +1,69 @@ +package me.chanjar.weixin.mp.api; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.bean.WxMpGroup; + +import java.util.List; + +/** + * 用户分组相关操作接口 + * @author Binary Wang + * + */ +public interface WxMpGroupService { + + + /** + *
+   * 分组管理接口 - 创建分组
+   * 最多支持创建500个分组
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
+   * 
+ * + * @param name 分组名字(30个字符以内) + */ + public WxMpGroup groupCreate(String name) throws WxErrorException; + + /** + *
+   * 分组管理接口 - 查询所有分组
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
+   * 
+ */ + public List groupGet() throws WxErrorException; + + /** + *
+   * 分组管理接口 - 查询用户所在分组
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
+   * 
+ * + * @param openid 微信用户的openid + */ + public long userGetGroup(String openid) throws WxErrorException; + + /** + *
+   * 分组管理接口 - 修改分组名
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
+   *
+   * 如果id为0(未分组),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误
+   * 
+ * + * @param group 要更新的group,group的id,name必须设置 + */ + public void groupUpdate(WxMpGroup group) throws WxErrorException; + + /** + *
+   * 分组管理接口 - 移动用户分组
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
+   *
+   * 如果to_groupid为0(未分组),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误
+   * 
+ * + * @param openid 用户openid + * @param to_groupid 移动到的分组id + */ + public void userUpdateGroup(String openid, long to_groupid) throws WxErrorException; +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java new file mode 100644 index 0000000000..c4731cb524 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java @@ -0,0 +1,172 @@ +package me.chanjar.weixin.mp.api; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest; +import me.chanjar.weixin.mp.bean.kefu.result.*; + +import java.io.File; +import java.util.Date; + +/** + * 客服接口 , + * 命名采用kefu拼音的原因是: + * 其英文CustomerService如果再加上Service后缀显得有点啰嗦, + * 如果不加又显得表意不完整 + * + * @author Binary Wang + */ +public interface WxMpKefuService { + + //*******************客服管理接口***********************// + + /** + *
+   * 获取客服基本信息
+   * 详情请见:客服管理
+   * 接口url格式:https://api.weixin.qq.com/cgi-bin/customservice/getkflist?access_token=ACCESS_TOKEN
+   * 
+ */ + WxMpKfList kfList() throws WxErrorException; + + /** + *
+   * 获取在线客服接待信息
+   * 详情请见:客服管理
+   * 接口url格式:https://api.weixin.qq.com/cgi-bin/customservice/getonlinekflist?access_token=ACCESS_TOKEN
+   * 
+ */ + WxMpKfOnlineList kfOnlineList() throws WxErrorException; + + /** + *
+   * 添加客服账号
+   * 详情请见:客服管理
+   * 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/add?access_token=ACCESS_TOKEN
+   * 
+ */ + boolean kfAccountAdd(WxMpKfAccountRequest request) throws WxErrorException; + + /** + *
+   * 设置客服信息(即更新客服信息)
+   * 详情请见:客服管理
+   * 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/update?access_token=ACCESS_TOKEN
+   * 
+ */ + boolean kfAccountUpdate(WxMpKfAccountRequest request) throws WxErrorException; + + /** + *
+   * 设置客服信息(即更新客服信息)
+   * 详情请见:客服管理
+   * 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/inviteworker?access_token=ACCESS_TOKEN
+   * 
+ */ + boolean kfAccountInviteWorker(WxMpKfAccountRequest request) throws WxErrorException; + + /** + *
+   * 上传客服头像
+   * 详情请见:客服管理
+   * 接口url格式:http://api.weixin.qq.com/customservice/kfaccount/uploadheadimg?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT
+   * 
+ */ + boolean kfAccountUploadHeadImg(String kfAccount, File imgFile) + throws WxErrorException; + + /** + *
+   * 删除客服账号
+   * 详情请见:客服管理
+   * 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/del?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT
+   * 
+ */ + boolean kfAccountDel(String kfAccount) throws WxErrorException; + + //*******************客服会话控制接口***********************// + + /** + *
+   * 创建会话
+   * 此接口在客服和用户之间创建一个会话,如果该客服和用户会话已存在,则直接返回0。指定的客服帐号必须已经绑定微信号且在线。
+   * 详情请见:客服会话控制接口
+   * 接口url格式: https://api.weixin.qq.com/customservice/kfsession/create?access_token=ACCESS_TOKEN
+   * 
+ */ + boolean kfSessionCreate(String openid, String kfAccount) throws WxErrorException; + + /** + *
+   * 关闭会话
+   * 开发者可以使用本接口,关闭一个会话。
+   * 详情请见:客服会话控制接口
+   * 接口url格式: https://api.weixin.qq.com/customservice/kfsession/close?access_token=ACCESS_TOKEN
+   * 
+ */ + boolean kfSessionClose(String openid, String kfAccount) throws WxErrorException; + + /** + *
+   * 获取客户的会话状态
+   * 此接口获取一个客户的会话,如果不存在,则kf_account为空。
+   * 详情请见:客服会话控制接口
+   * 接口url格式: https://api.weixin.qq.com/customservice/kfsession/getsession?access_token=ACCESS_TOKEN&openid=OPENID
+   * 
+ */ + WxMpKfSessionGetResult kfSessionGet(String openid) throws WxErrorException; + + /** + *
+   * 获取客服的会话列表
+   * 开发者可以通过本接口获取某个客服正在接待的会话列表。
+   * 详情请见:客服会话控制
+   * 接口url格式: https://api.weixin.qq.com/customservice/kfsession/getsessionlist?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT
+   * 
+ */ + WxMpKfSessionList kfSessionList(String kfAccount) throws WxErrorException; + + /** + *
+   * 获取未接入会话列表
+   * 开发者可以通过本接口获取当前正在等待队列中的会话列表,此接口最多返回最早进入队列的100个未接入会话。
+   * 详情请见:客服会话控制
+   * 接口url格式: https://api.weixin.qq.com/customservice/kfsession/getwaitcase?access_token=ACCESS_TOKEN
+   * 
+ */ + WxMpKfSessionWaitCaseList kfSessionGetWaitCase() throws WxErrorException; + + //*******************获取聊天记录的接口***********************// + + /** + *
+   * 获取聊天记录(原始接口)
+   * 此接口返回的聊天记录中,对于图片、语音、视频,分别展示成文本格式的[image]、[voice]、[video]
+   * 详情请见:获取聊天记录
+   * 接口url格式: https://api.weixin.qq.com/customservice/msgrecord/getmsglist?access_token=ACCESS_TOKEN
+   * 
+ * + * @param startTime 起始时间 + * @param endTime 结束时间 + * @param msgId 消息id顺序从小到大,从1开始 + * @param number 每次获取条数,最多10000条 + * @return 聊天记录对象 + * @throws WxErrorException + */ + WxMpKfMsgList kfMsgList(Date startTime, Date endTime, Long msgId, Integer number) throws WxErrorException; + + /** + *
+   * 获取聊天记录(优化接口,返回指定时间段内所有的聊天记录)
+   * 此接口返回的聊天记录中,对于图片、语音、视频,分别展示成文本格式的[image]、[voice]、[video]
+   * 详情请见:获取聊天记录
+   * 接口url格式: https://api.weixin.qq.com/customservice/msgrecord/getmsglist?access_token=ACCESS_TOKEN
+   * 
+ * + * @param startTime 起始时间 + * @param endTime 结束时间 + * @return 聊天记录对象 + * @throws WxErrorException + */ + WxMpKfMsgList kfMsgList(Date startTime, Date endTime) throws WxErrorException; + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java new file mode 100644 index 0000000000..7254a0080d --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java @@ -0,0 +1,195 @@ +package me.chanjar.weixin.mp.api; + +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.bean.*; +import me.chanjar.weixin.mp.bean.result.*; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +/** + * Created by Binary Wang on 2016/7/21. + * 素材管理的相关接口,包括媒体管理的接口, + * 即以https://api.weixin.qq.com/cgi-bin/material + * 和 https://api.weixin.qq.com/cgi-bin/media开头的接口 + */ +public interface WxMpMaterialService { + + /** + * 新增临时素材 + * + * @param mediaType + * @param file + * @throws WxErrorException + * @see #mediaUpload(String, String, InputStream) + */ + public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException; + + /** + *
+   * 获取临时素材
+   * 本接口即为原“下载多媒体文件”接口。
+   * 根据微信文档,视频文件下载不了,会返回null
+   * 详情请见: 获取临时素材
+   * 
+ * + * @param media_id + * @return 保存到本地的临时文件 + * @throws WxErrorException + */ + public File mediaDownload(String media_id) throws WxErrorException; + + /** + *
+   * 上传图文消息内的图片获取URL
+   * 详情请见:http://mp.weixin.qq.com/wiki/15/40b6865b893947b764e2de8e4a1fb55f.html#.E4.B8.8A.E4.BC.A0.E5.9B.BE.E6.96.87.E6.B6.88.E6.81.AF.E5.86.85.E7.9A.84.E5.9B.BE.E7.89.87.E8.8E.B7.E5.8F.96URL.E3.80.90.E8.AE.A2.E9.98.85.E5.8F.B7.E4.B8.8E.E6.9C.8D.E5.8A.A1.E5.8F.B7.E8.AE.A4.E8.AF.81.E5.90.8E.E5.9D.87.E5.8F.AF.E7.94.A8.E3.80.91
+   * 
+ * + * @param file + * @return WxMediaImgUploadResult 返回图片url + * @throws WxErrorException + */ + public WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException; + + /** + *
+   * 新增临时素材
+   * 本接口即为原“上传多媒体文件”接口。
+   *
+   * 上传的多媒体文件有格式和大小限制,如下:
+   *   图片(image): 1M,支持JPG格式
+   *   语音(voice):2M,播放长度不超过60s,支持AMR\MP3格式
+   *   视频(video):10MB,支持MP4格式
+   *   缩略图(thumb):64KB,支持JPG格式
+   *
+   * 详情请见: 新增临时素材
+   * 
+ * + * @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts} + * @param fileType 文件类型,请看{@link me.chanjar.weixin.common.api.WxConsts} + * @param inputStream 输入流 + * @throws WxErrorException + */ + public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) throws WxErrorException, IOException; + + /** + *
+   * 上传非图文永久素材
+   *
+   * 上传的多媒体文件有格式和大小限制,如下:
+   *   图片(image): 图片大小不超过2M,支持bmp/png/jpeg/jpg/gif格式
+   *   语音(voice):语音大小不超过5M,长度不超过60秒,支持mp3/wma/wav/amr格式
+   *   视频(video):在上传视频素材时需要POST另一个表单,id为description,包含素材的描述信息,内容格式为JSON
+   *   缩略图(thumb):文档未说明
+   *
+   * 详情请见: http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html
+   * 
+ * + * @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts} + * @param material 上传的素材, 请看{@link me.chanjar.weixin.mp.bean.WxMpMaterial} + */ + public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException; + + /** + *
+   * 上传永久图文素材
+   *
+   * 详情请见: http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html
+   * 
+ * + * @param news 上传的图文消息, 请看{@link me.chanjar.weixin.mp.bean.WxMpMaterialNews} + */ + public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws WxErrorException; + + /** + *
+   * 下载声音或者图片永久素材
+   *
+   * 详情请见: http://mp.weixin.qq.com/wiki/4/b3546879f07623cb30df9ca0e420a5d0.html
+   * 
+ * + * @param media_id 永久素材的id + */ + public InputStream materialImageOrVoiceDownload(String media_id) throws WxErrorException; + + /** + *
+   * 获取视频永久素材的信息和下载地址
+   *
+   * 详情请见: http://mp.weixin.qq.com/wiki/4/b3546879f07623cb30df9ca0e420a5d0.html
+   * 
+ * + * @param media_id 永久素材的id + */ + public WxMpMaterialVideoInfoResult materialVideoInfo(String media_id) throws WxErrorException; + + /** + *
+   * 获取图文永久素材的信息
+   *
+   * 详情请见: http://mp.weixin.qq.com/wiki/4/b3546879f07623cb30df9ca0e420a5d0.html
+   * 
+ * + * @param media_id 永久素材的id + */ + public WxMpMaterialNews materialNewsInfo(String media_id) throws WxErrorException; + + /** + *
+   * 更新图文永久素材
+   *
+   * 详情请见: http://mp.weixin.qq.com/wiki/4/19a59cba020d506e767360ca1be29450.html
+   * 
+ * + * @param wxMpMaterialArticleUpdate 用来更新图文素材的bean, 请看{@link me.chanjar.weixin.mp.bean.WxMpMaterialArticleUpdate} + */ + public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate) throws WxErrorException; + + /** + *
+   * 删除永久素材
+   *
+   * 详情请见: http://mp.weixin.qq.com/wiki/5/e66f61c303db51a6c0f90f46b15af5f5.html
+   * 
+ * + * @param media_id 永久素材的id + */ + public boolean materialDelete(String media_id) throws WxErrorException; + + /** + *
+   * 获取各类素材总数
+   *
+   * 详情请见: http://mp.weixin.qq.com/wiki/16/8cc64f8c189674b421bee3ed403993b8.html
+   * 
+ */ + public WxMpMaterialCountResult materialCount() throws WxErrorException; + + /** + *
+   * 分页获取图文素材列表
+   *
+   * 详情请见: http://mp.weixin.qq.com/wiki/12/2108cd7aafff7f388f41f37efa710204.html
+   * 
+ * + * @param offset 从全部素材的该偏移位置开始返回,0表示从第一个素材 返回 + * @param count 返回素材的数量,取值在1到20之间 + */ + public WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count) throws WxErrorException; + + /** + *
+   * 分页获取其他媒体素材列表
+   *
+   * 详情请见: http://mp.weixin.qq.com/wiki/12/2108cd7aafff7f388f41f37efa710204.html
+   * 
+ * + * @param type 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts} + * @param offset 从全部素材的该偏移位置开始返回,0表示从第一个素材 返回 + * @param count 返回素材的数量,取值在1到20之间 + */ + public WxMpMaterialFileBatchGetResult materialFileBatchGet(String type, int offset, int count) throws WxErrorException; + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java new file mode 100644 index 0000000000..670921dbc8 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java @@ -0,0 +1,59 @@ +package me.chanjar.weixin.mp.api; + +import me.chanjar.weixin.common.bean.WxMenu; +import me.chanjar.weixin.common.exception.WxErrorException; + +/** + * 菜单相关操作接口 + * + * @author Binary Wang + */ +public interface WxMpMenuService { + + /** + *
+   * 自定义菜单创建接口
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单创建接口
+   * 如果要创建个性化菜单,请设置matchrule属性
+   * 详情请见:http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
+   * 
+ */ + public void menuCreate(WxMenu menu) throws WxErrorException; + + /** + *
+   * 自定义菜单删除接口
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单删除接口
+   * 
+ */ + public void menuDelete() throws WxErrorException; + + /** + *
+   * 删除个性化菜单接口
+   * 详情请见: http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
+   * 
+ * + * @param menuid + */ + public void menuDelete(String menuid) throws WxErrorException; + + /** + *
+   * 自定义菜单查询接口
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单查询接口
+   * 
+ */ + public WxMenu menuGet() throws WxErrorException; + + /** + *
+   * 测试个性化菜单匹配结果
+   * 详情请见: http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
+   * 
+ * + * @param userid 可以是粉丝的OpenID,也可以是粉丝的微信号。 + */ + public WxMenu menuTryMatch(String userid) throws WxErrorException; + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageMatcher.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageMatcher.java index 3d913f7819..c4e3c456e3 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageMatcher.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageMatcher.java @@ -10,7 +10,6 @@ public interface WxMpMessageMatcher { /** * 消息是否匹配某种模式 * @param message - * @return */ public boolean match(WxMpXmlMessage message); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java index 4cc7df21dd..73d0cabe7f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java @@ -124,7 +124,6 @@ List getRules() { /** * 开始一个新的Route规则 - * @return */ public WxMpMessageRouterRule rule() { return new WxMpMessageRouterRule(this); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java index 3113a19ced..eb02c6414b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java @@ -34,9 +34,9 @@ public class WxMpMessageRouterRule { private boolean reEnter = false; - private List handlers = new ArrayList(); + private List handlers = new ArrayList<>(); - private List interceptors = new ArrayList(); + private List interceptors = new ArrayList<>(); public WxMpMessageRouterRule(WxMpMessageRouter routerBuilder) { this.routerBuilder = routerBuilder; @@ -44,9 +44,6 @@ public WxMpMessageRouterRule(WxMpMessageRouter routerBuilder) { /** * 设置是否异步执行,默认是true - * - * @param async - * @return */ public WxMpMessageRouterRule async(boolean async) { this.async = async; @@ -55,9 +52,6 @@ public WxMpMessageRouterRule async(boolean async) { /** * 如果msgType等于某值 - * - * @param msgType - * @return */ public WxMpMessageRouterRule msgType(String msgType) { this.msgType = msgType; @@ -66,9 +60,6 @@ public WxMpMessageRouterRule msgType(String msgType) { /** * 如果event等于某值 - * - * @param event - * @return */ public WxMpMessageRouterRule event(String event) { this.event = event; @@ -77,9 +68,6 @@ public WxMpMessageRouterRule event(String event) { /** * 如果eventKey等于某值 - * - * @param eventKey - * @return */ public WxMpMessageRouterRule eventKey(String eventKey) { this.eventKey = eventKey; @@ -88,9 +76,6 @@ public WxMpMessageRouterRule eventKey(String eventKey) { /** * 如果content等于某值 - * - * @param content - * @return */ public WxMpMessageRouterRule content(String content) { this.content = content; @@ -99,9 +84,6 @@ public WxMpMessageRouterRule content(String content) { /** * 如果content匹配该正则表达式 - * - * @param regex - * @return */ public WxMpMessageRouterRule rContent(String regex) { this.rContent = regex; @@ -110,9 +92,6 @@ public WxMpMessageRouterRule rContent(String regex) { /** * 如果fromUser等于某值 - * - * @param fromUser - * @return */ public WxMpMessageRouterRule fromUser(String fromUser) { this.fromUser = fromUser; @@ -121,9 +100,6 @@ public WxMpMessageRouterRule fromUser(String fromUser) { /** * 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 - * - * @param matcher - * @return */ public WxMpMessageRouterRule matcher(WxMpMessageMatcher matcher) { this.matcher = matcher; @@ -132,9 +108,6 @@ public WxMpMessageRouterRule matcher(WxMpMessageMatcher matcher) { /** * 设置微信消息拦截器 - * - * @param interceptor - * @return */ public WxMpMessageRouterRule interceptor(WxMpMessageInterceptor interceptor) { return interceptor(interceptor, (WxMpMessageInterceptor[]) null); @@ -142,10 +115,6 @@ public WxMpMessageRouterRule interceptor(WxMpMessageInterceptor interceptor) { /** * 设置微信消息拦截器 - * - * @param interceptor - * @param otherInterceptors - * @return */ public WxMpMessageRouterRule interceptor(WxMpMessageInterceptor interceptor, WxMpMessageInterceptor... otherInterceptors) { this.interceptors.add(interceptor); @@ -159,9 +128,6 @@ public WxMpMessageRouterRule interceptor(WxMpMessageInterceptor interceptor, WxM /** * 设置微信消息处理器 - * - * @param handler - * @return */ public WxMpMessageRouterRule handler(WxMpMessageHandler handler) { return handler(handler, (WxMpMessageHandler[]) null); @@ -169,10 +135,6 @@ public WxMpMessageRouterRule handler(WxMpMessageHandler handler) { /** * 设置微信消息处理器 - * - * @param handler - * @param otherHandlers - * @return */ public WxMpMessageRouterRule handler(WxMpMessageHandler handler, WxMpMessageHandler... otherHandlers) { this.handlers.add(handler); @@ -186,8 +148,6 @@ public WxMpMessageRouterRule handler(WxMpMessageHandler handler, WxMpMessageHand /** * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 - * - * @return */ public WxMpMessageRouter end() { this.routerBuilder.getRules().add(this); @@ -196,8 +156,6 @@ public WxMpMessageRouter end() { /** * 规则结束,但是消息还会进入其他规则 - * - * @return */ public WxMpMessageRouter next() { this.reEnter = true; @@ -207,8 +165,6 @@ public WxMpMessageRouter next() { /** * 将微信自定义的事件修正为不区分大小写, * 比如框架定义的事件常量为click,但微信传递过来的却是CLICK - * @param wxMessage - * @return */ protected boolean test(WxMpXmlMessage wxMessage) { return @@ -243,7 +199,7 @@ protected WxMpXmlOutMessage service(WxMpXmlMessage wxMessage, try { - Map context = new HashMap(); + Map context = new HashMap<>(); // 如果拦截器不通过 for (WxMpMessageInterceptor interceptor : this.interceptors) { if (!interceptor.intercept(wxMessage, context, wxMpService, sessionManager)) { @@ -255,6 +211,9 @@ protected WxMpXmlOutMessage service(WxMpXmlMessage wxMessage, WxMpXmlOutMessage res = null; for (WxMpMessageHandler handler : this.handlers) { // 返回最后handler的结果 + if(handler == null){ + continue; + } res = handler.handle(wxMessage, context, wxMpService, sessionManager); } return res; @@ -266,11 +225,11 @@ protected WxMpXmlOutMessage service(WxMpXmlMessage wxMessage, } public WxMpMessageRouter getRouterBuilder() { - return routerBuilder; + return this.routerBuilder; } public boolean isAsync() { - return async; + return this.async; } public void setAsync(boolean async) { @@ -278,7 +237,7 @@ public void setAsync(boolean async) { } public String getFromUser() { - return fromUser; + return this.fromUser; } public void setFromUser(String fromUser) { @@ -286,7 +245,7 @@ public void setFromUser(String fromUser) { } public String getMsgType() { - return msgType; + return this.msgType; } public void setMsgType(String msgType) { @@ -294,7 +253,7 @@ public void setMsgType(String msgType) { } public String getEvent() { - return event; + return this.event; } public void setEvent(String event) { @@ -302,7 +261,7 @@ public void setEvent(String event) { } public String getEventKey() { - return eventKey; + return this.eventKey; } public void setEventKey(String eventKey) { @@ -310,7 +269,7 @@ public void setEventKey(String eventKey) { } public String getContent() { - return content; + return this.content; } public void setContent(String content) { @@ -318,7 +277,7 @@ public void setContent(String content) { } public String getrContent() { - return rContent; + return this.rContent; } public void setrContent(String rContent) { @@ -326,7 +285,7 @@ public void setrContent(String rContent) { } public WxMpMessageMatcher getMatcher() { - return matcher; + return this.matcher; } public void setMatcher(WxMpMessageMatcher matcher) { @@ -334,7 +293,7 @@ public void setMatcher(WxMpMessageMatcher matcher) { } public boolean isReEnter() { - return reEnter; + return this.reEnter; } public void setReEnter(boolean reEnter) { @@ -342,7 +301,7 @@ public void setReEnter(boolean reEnter) { } public List getHandlers() { - return handlers; + return this.handlers; } public void setHandlers(List handlers) { @@ -350,7 +309,7 @@ public void setHandlers(List handlers) { } public List getInterceptors() { - return interceptors; + return this.interceptors; } public void setInterceptors(List interceptors) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java new file mode 100644 index 0000000000..2015ae1b66 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java @@ -0,0 +1,77 @@ +package me.chanjar.weixin.mp.api; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; + +import java.io.File; + +/** + * 二维码相关操作接口 + * + * @author Binary Wang + */ +public interface WxMpQrcodeService { + + /** + *
+   * 换取临时二维码ticket
+   * 详情请见: 生成带参数的二维码
+   * 
+ * + * @param scene_id 参数。 + * @param expire_seconds 过期秒数,默认60秒,最小60秒,最大1800秒 + */ + public WxMpQrCodeTicket qrCodeCreateTmpTicket(int scene_id, Integer expire_seconds) throws WxErrorException; + + /** + *
+   * 换取永久二维码ticket
+   * 详情请见: 生成带参数的二维码
+   * 
+ * + * @param scene_id 参数。永久二维码时最大值为100000(目前参数只支持1--100000) + */ + public WxMpQrCodeTicket qrCodeCreateLastTicket(int scene_id) throws WxErrorException; + + /** + *
+   * 换取永久字符串二维码ticket
+   * 详情请见: 生成带参数的二维码
+   * 
+ * + * @param scene_str 参数。字符串类型长度现在为1到64 + */ + public WxMpQrCodeTicket qrCodeCreateLastTicket(String scene_str) throws WxErrorException; + + /** + *
+   * 换取二维码图片文件,jpg格式
+   * 详情请见: 生成带参数的二维码
+   * 
+ * + * @param ticket 二维码ticket + */ + public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException; + + /** + *
+   * 换取二维码图片url地址(可以选择是否生成压缩的网址)
+   * 详情请见: 生成带参数的二维码
+   * 
+ * + * @param ticket 二维码ticket + * @param needShortUrl 是否需要压缩的二维码地址 + */ + public String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException; + + /** + *
+   * 换取二维码图片url地址
+   * 详情请见: 生成带参数的二维码
+   * 
+ * + * @param ticket 二维码ticket + */ + public String qrCodePictureUrl(String ticket) throws WxErrorException; + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index d822fc3348..7bff302733 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -1,20 +1,13 @@ package me.chanjar.weixin.mp.api; import me.chanjar.weixin.common.bean.WxCardApiSignature; -import me.chanjar.weixin.common.bean.WxMenu; import me.chanjar.weixin.common.bean.WxJsapiSignature; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.mp.bean.*; import me.chanjar.weixin.mp.bean.result.*; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.List; import java.util.Map; /** @@ -23,23 +16,19 @@ public interface WxMpService { public static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); + /** *
    * 验证推送过来的消息的正确性
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=验证消息真实性
    * 
- * @param timestamp - * @param nonce - * @param signature - * @return */ public boolean checkSignature(String timestamp, String nonce, String signature); /** * 获取access_token, 不强制刷新access_token + * * @see #getAccessToken(boolean) - * @return - * @throws WxErrorException */ public String getAccessToken() throws WxErrorException; @@ -51,20 +40,18 @@ public interface WxMpService { * 另:本service的所有方法都会在access_token过期是调用此方法 * * 程序员在非必要情况下尽量不要主动调用此方法 - + * * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取access_token * + * * @param forceRefresh 强制刷新 - * @return - * @throws me.chanjar.weixin.common.exception.WxErrorException */ public String getAccessToken(boolean forceRefresh) throws WxErrorException; /** * 获得jsapi_ticket,不强制刷新jsapi_ticket + * * @see #getJsapiTicket(boolean) - * @return - * @throws WxErrorException */ public String getJsapiTicket() throws WxErrorException; @@ -75,9 +62,8 @@ public interface WxMpService { * * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD.951-JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95 * + * * @param forceRefresh 强制刷新 - * @return - * @throws WxErrorException */ public String getJsapiTicket(boolean forceRefresh) throws WxErrorException; @@ -87,189 +73,14 @@ public interface WxMpService { * * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD.951-JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95 * - * @param url url - * @return */ public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException; - /** - *
-   * 新增临时素材
-   * 本接口即为原“上传多媒体文件”接口。
-   *
-   * 上传的多媒体文件有格式和大小限制,如下:
-   *   图片(image): 1M,支持JPG格式
-   *   语音(voice):2M,播放长度不超过60s,支持AMR\MP3格式
-   *   视频(video):10MB,支持MP4格式
-   *   缩略图(thumb):64KB,支持JPG格式
-   *
-   * 详情请见: 新增临时素材
-   * 
- * @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts} - * @param fileType 文件类型,请看{@link me.chanjar.weixin.common.api.WxConsts} - * @param inputStream 输入流 - * @throws WxErrorException - */ - public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) throws WxErrorException, IOException; - - /** - *
-   * 上传非图文永久素材
-   *
-   * 上传的多媒体文件有格式和大小限制,如下:
-   *   图片(image): 图片大小不超过2M,支持bmp/png/jpeg/jpg/gif格式
-   *   语音(voice):语音大小不超过5M,长度不超过60秒,支持mp3/wma/wav/amr格式
-   *   视频(video):在上传视频素材时需要POST另一个表单,id为description,包含素材的描述信息,内容格式为JSON
-   *   缩略图(thumb):文档未说明
-   *
-   * 详情请见: http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html
-   * 
- * @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts} - * @param material 上传的素材, 请看{@link me.chanjar.weixin.mp.bean.WxMpMaterial} - * @return - * @throws WxErrorException - */ - public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException; - - /** - *
-   * 上传永久图文素材
-   *
-   * 详情请见: http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html
-   * 
- * @param news 上传的图文消息, 请看{@link me.chanjar.weixin.mp.bean.WxMpMaterialNews} - * @return - * @throws WxErrorException - */ - public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws WxErrorException; - - /** - *
-   * 下载声音或者图片永久素材
-   *
-   * 详情请见: http://mp.weixin.qq.com/wiki/4/b3546879f07623cb30df9ca0e420a5d0.html
-   * 
- * @param media_id 永久素材的id - * @return - * @throws WxErrorException - */ - public InputStream materialImageOrVoiceDownload(String media_id) throws WxErrorException; - - /** - *
-   * 获取视频永久素材的信息和下载地址
-   *
-   * 详情请见: http://mp.weixin.qq.com/wiki/4/b3546879f07623cb30df9ca0e420a5d0.html
-   * 
- * @param media_id 永久素材的id - * @return - * @throws WxErrorException - */ - public WxMpMaterialVideoInfoResult materialVideoInfo(String media_id) throws WxErrorException; - - /** - *
-   * 获取图文永久素材的信息
-   *
-   * 详情请见: http://mp.weixin.qq.com/wiki/4/b3546879f07623cb30df9ca0e420a5d0.html
-   * 
- * @param media_id 永久素材的id - * @return - * @throws WxErrorException - */ - public WxMpMaterialNews materialNewsInfo(String media_id) throws WxErrorException; - - /** - *
-   * 更新图文永久素材
-   *
-   * 详情请见: http://mp.weixin.qq.com/wiki/4/19a59cba020d506e767360ca1be29450.html
-   * 
- * @param wxMpMaterialArticleUpdate 用来更新图文素材的bean, 请看{@link me.chanjar.weixin.mp.bean.WxMpMaterialArticleUpdate} - * @return - * @throws WxErrorException - */ - public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate) throws WxErrorException; - - /** - *
-   * 删除永久素材
-   *
-   * 详情请见: http://mp.weixin.qq.com/wiki/5/e66f61c303db51a6c0f90f46b15af5f5.html
-   * 
- * @param media_id 永久素材的id - * @return - * @throws WxErrorException - */ - public boolean materialDelete(String media_id) throws WxErrorException; - - /** - *
-   * 获取各类素材总数
-   *
-   * 详情请见: http://mp.weixin.qq.com/wiki/16/8cc64f8c189674b421bee3ed403993b8.html
-   * 
- * @return - * @throws WxErrorException - */ - public WxMpMaterialCountResult materialCount() throws WxErrorException; - - /** - *
-   * 分页获取图文素材列表
-   *
-   * 详情请见: http://mp.weixin.qq.com/wiki/12/2108cd7aafff7f388f41f37efa710204.html
-   * 
- * @param offset 从全部素材的该偏移位置开始返回,0表示从第一个素材 返回 - * @param count 返回素材的数量,取值在1到20之间 - * @return - * @throws WxErrorException - */ - public WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count) throws WxErrorException; - - /** - *
-   * 分页获取其他媒体素材列表
-   *
-   * 详情请见: http://mp.weixin.qq.com/wiki/12/2108cd7aafff7f388f41f37efa710204.html
-   * 
- * @param type 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts} - * @param offset 从全部素材的该偏移位置开始返回,0表示从第一个素材 返回 - * @param count 返回素材的数量,取值在1到20之间 - * @return - * @throws WxErrorException - */ - public WxMpMaterialFileBatchGetResult materialFileBatchGet(String type, int offset, int count) throws WxErrorException; - - /** - * 新增临时素材 - * @see #mediaUpload(String, String, InputStream) - * @param mediaType - * @param file - * @throws WxErrorException - */ - public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException; - - /** - *
-   * 获取临时素材
-   * 本接口即为原“下载多媒体文件”接口。
-   * 根据微信文档,视频文件下载不了,会返回null
-   * 详情请见: 获取临时素材
-   * 
- * @params media_id - * @return 保存到本地的临时文件 - * @throws WxErrorException - */ - public File mediaDownload(String media_id) throws WxErrorException; - /** *
    * 发送客服消息
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息
    * 
- * @param message - * @throws WxErrorException */ public void customMessageSend(WxMpCustomMessage message) throws WxErrorException; @@ -279,6 +90,7 @@ public interface WxMpService { * * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口 * + * * @param news * @throws WxErrorException * @see #massGroupMessageSend(me.chanjar.weixin.mp.bean.WxMpMassGroupMessage) @@ -291,8 +103,7 @@ public interface WxMpService { * 上传群发用的视频,上传后才能群发视频消息 * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口 * - * @return - * @throws WxErrorException + * * @see #massGroupMessageSend(me.chanjar.weixin.mp.bean.WxMpMassGroupMessage) * @see #massOpenIdsMessageSend(me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage) */ @@ -305,9 +116,6 @@ public interface WxMpService { * 如果发送视频消息,必须先使用 {@link #massVideoUpload(me.chanjar.weixin.mp.bean.WxMpMassVideo)} 获得media_id,然后再发送 * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口 * - * @param message - * @throws WxErrorException - * @return */ public WxMpMassSendResult massGroupMessageSend(WxMpMassGroupMessage message) throws WxErrorException; @@ -318,229 +126,16 @@ public interface WxMpService { * 如果发送视频消息,必须先使用 {@link #massVideoUpload(me.chanjar.weixin.mp.bean.WxMpMassVideo)} 获得media_id,然后再发送 * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口 * - * @param message - * @return - * @throws WxErrorException */ public WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException; - /** - *
-   * 自定义菜单创建接口
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单创建接口
-   * 如果要创建个性化菜单,请设置matchrule属性
-   * 详情请见:http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
-   * 
- * @param menu - * @throws WxErrorException - */ - public void menuCreate(WxMenu menu) throws WxErrorException; - - /** - *
-   * 自定义菜单删除接口
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单删除接口
-   * 
- * @throws WxErrorException - */ - public void menuDelete() throws WxErrorException; - - /** - *
-   * 删除个性化菜单接口
-   * 详情请见: http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
-   * 
- * @param menuid - * @throws WxErrorException - */ - public void menuDelete(String menuid) throws WxErrorException; - - /** - *
-   * 自定义菜单查询接口
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单查询接口
-   * 
- * @return - * @throws WxErrorException - */ - public WxMenu menuGet() throws WxErrorException; - - /** - *
-   * 测试个性化菜单匹配结果
-   * 详情请见: http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
-   * 
- * @param userid 可以是粉丝的OpenID,也可以是粉丝的微信号。 - * @throws WxErrorException - */ - public WxMenu menuTryMatch(String userid) throws WxErrorException; - - /** - *
-   * 分组管理接口 - 创建分组
-   * 最多支持创建500个分组
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
-   * 
- * @param name 分组名字(30个字符以内) - * @throws WxErrorException - */ - public WxMpGroup groupCreate(String name) throws WxErrorException; - - /** - *
-   * 分组管理接口 - 查询所有分组
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
-   * 
- * @return - * @throws WxErrorException - */ - public List groupGet() throws WxErrorException; - - /** - *
-   * 分组管理接口 - 查询用户所在分组
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
-   * 
- * @param openid 微信用户的openid - * @throws WxErrorException - */ - public long userGetGroup(String openid) throws WxErrorException; - - /** - *
-   * 分组管理接口 - 修改分组名
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
-   *
-   * 如果id为0(未分组),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误
-   * 
- * @param group 要更新的group,group的id,name必须设置 - * @throws WxErrorException - */ - public void groupUpdate(WxMpGroup group) throws WxErrorException; - - /** - *
-   * 分组管理接口 - 移动用户分组
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
-   *
-   * 如果to_groupid为0(未分组),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误
-   * 
- * @param openid 用户openid - * @param to_groupid 移动到的分组id - * @throws WxErrorException - */ - public void userUpdateGroup(String openid, long to_groupid) throws WxErrorException; - - /** - *
-   * 设置用户备注名接口
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=设置用户备注名接口
-   * 
- * @param openid 用户openid - * @param remark 备注名 - * @throws WxErrorException - */ - public void userUpdateRemark(String openid, String remark) throws WxErrorException; - - /** - *
-   * 获取用户基本信息
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取用户基本信息
-   * 
- * @param openid 用户openid - * @param lang 语言,zh_CN 简体(默认),zh_TW 繁体,en 英语 - * @return - * @throws WxErrorException - */ - public WxMpUser userInfo(String openid, String lang) throws WxErrorException; - - /** - *
-   * 获取关注者列表
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取关注者列表
-   * 
- * @param next_openid 可选,第一个拉取的OPENID,null为从头开始拉取 - * @return - * @throws WxErrorException - */ - public WxMpUserList userList(String next_openid) throws WxErrorException; - - /** - *
-   * 换取临时二维码ticket
-   * 详情请见: 生成带参数的二维码
-   * 
- * @param scene_id 参数。 - * @param expire_seconds 过期秒数,默认60秒,最小60秒,最大1800秒 - * @return - * @throws WxErrorException - */ - public WxMpQrCodeTicket qrCodeCreateTmpTicket(int scene_id, Integer expire_seconds) throws WxErrorException; - - /** - *
-   * 换取永久二维码ticket
-   * 详情请见: 生成带参数的二维码
-   * 
- * @param scene_id 参数。永久二维码时最大值为100000(目前参数只支持1--100000) - * @return - * @throws WxErrorException - */ - public WxMpQrCodeTicket qrCodeCreateLastTicket(int scene_id) throws WxErrorException; - - /** - *
-   * 换取永久字符串二维码ticket
-   * 详情请见: 生成带参数的二维码
-   * 
- * - * @param scene_str 参数。字符串类型长度现在为1到64 - * @return - * @throws WxErrorException - */ - public WxMpQrCodeTicket qrCodeCreateLastTicket(String scene_str) throws WxErrorException; - - /** - *
-   * 换取二维码图片文件,jpg格式
-   * 详情请见: 生成带参数的二维码
-   * 
- * @param ticket 二维码ticket - * @return - * @throws WxErrorException - */ - public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException; - - /** - *
-   * 换取二维码图片url地址(可以选择是否生成压缩的网址)
-   * 详情请见: 生成带参数的二维码
-   * 
- * @param ticket 二维码ticket - * @param needShortUrl 是否需要压缩的二维码地址 - * @return - * @throws WxErrorException - */ - public String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException; - /** - *
-   * 换取二维码图片url地址
-   * 详情请见: 生成带参数的二维码
-   * 
- * @param ticket 二维码ticket - * @return - * @throws WxErrorException - */ - public String qrCodePictureUrl(String ticket) throws WxErrorException; - /** *
    * 长链接转短链接接口
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=长链接转短链接接口
    * 
+ * * @param long_url - * @return - * @throws WxErrorException */ public String shortUrl(String long_url) throws WxErrorException; @@ -549,9 +144,10 @@ public interface WxMpService { * 发送模板消息 * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=模板消息接口 * + * * @param templateMessage - * @throws WxErrorException * @return msgid + * @throws WxErrorException */ public String templateSend(WxMpTemplateMessage templateMessage) throws WxErrorException; @@ -560,9 +156,6 @@ public interface WxMpService { * 语义查询接口 * 详情请见:http://mp.weixin.qq.com/wiki/index.php?title=语义理解 * - * @param semanticQuery - * @return - * @throws WxErrorException */ WxMpSemanticQueryResult semanticQuery(WxMpSemanticQuery semanticQuery) throws WxErrorException; @@ -571,6 +164,7 @@ public interface WxMpService { * 构造oauth2授权的url连接 * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息 * + * * @param scope * @param state * @return url @@ -582,20 +176,19 @@ public interface WxMpService { * 构造oauth2授权的url连接 * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息 * - * @param redirectURI - * 用户授权完成后的重定向链接,无需urlencode, 方法内会进行encode + * + * @param redirectURI 用户授权完成后的重定向链接,无需urlencode, 方法内会进行encode * @param scope * @param state * @return url */ public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state); + /** *
    * 用code换取oauth2的access token
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息
    * 
- * @param code - * @return */ public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException; @@ -603,8 +196,6 @@ public interface WxMpService { *
    * 刷新oauth2的access token
    * 
- * @param refreshToken - * @return */ public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException; @@ -612,8 +203,9 @@ public interface WxMpService { *
    * 用oauth2获取用户信息, 当前面引导授权时的scope是snsapi_userinfo的时候才可以
    * 
+ * * @param oAuth2AccessToken - * @param lang zh_CN, zh_TW, en + * @param lang zh_CN, zh_TW, en */ public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException; @@ -621,8 +213,8 @@ public interface WxMpService { *
    * 验证oauth2的access token是否有效
    * 
+ * * @param oAuth2AccessToken - * @return */ public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken); @@ -631,50 +223,16 @@ public interface WxMpService { * 获取微信服务器IP地址 * http://mp.weixin.qq.com/wiki/0/2ad4b6bfd29f30f71d39616c2a0fcedc.html * - * @return - * @throws WxErrorException */ String[] getCallbackIP() throws WxErrorException; - /** - *
-   * 获取用户增减数据
-   * http://mp.weixin.qq.com/wiki/3/ecfed6e1a0a03b5f35e5efac98e864b7.html
-   * 
- * @param beginDate 最大时间跨度7天 - * @param endDate endDate不能早于begingDate - * @return - * @throws WxErrorException - */ - List getUserSummary(Date beginDate, Date endDate) throws WxErrorException; - - /** - *
-   * 获取累计用户数据
-   * http://mp.weixin.qq.com/wiki/3/ecfed6e1a0a03b5f35e5efac98e864b7.html
-   * 
- * @param beginDate 最大时间跨度7天 - * @param endDate endDate不能早于begingDate - * @return - * @throws WxErrorException - */ - List getUserCumulate(Date beginDate, Date endDate) throws WxErrorException; - /** * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 - * @param url - * @param queryParam - * @return - * @throws WxErrorException */ String get(String url, String queryParam) throws WxErrorException; /** * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求 - * @param url - * @param postData - * @return - * @throws WxErrorException */ String post(String url, String postData) throws WxErrorException; @@ -684,19 +242,11 @@ public interface WxMpService { * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。 * 可以参考,{@link me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor}的实现方法 * - * @param executor - * @param uri - * @param data - * @param - * @param - * @return - * @throws WxErrorException */ public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; /** * 注入 {@link WxMpConfigStorage} 的实现 - * @param wxConfigProvider */ public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider); @@ -705,7 +255,6 @@ public interface WxMpService { * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试 * 默认:1000ms * - * @param retrySleepMillis */ void setRetrySleepMillis(int retrySleepMillis); @@ -714,21 +263,20 @@ public interface WxMpService { * 设置当微信系统响应系统繁忙时,最大重试次数 * 默认:5次 * - * @param maxRetryTimes */ void setMaxRetryTimes(int maxRetryTimes); /** * 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1) * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识" - * @param openId 支付人openId + * + * @param openId 支付人openId * @param outTradeNo 商户端对应订单号 - * @param amt 金额(单位元) - * @param body 商品描述 - * @param tradeType 交易类型 JSAPI,NATIVE,APP,WAP - * @param ip 发起支付的客户端IP - * @param notifyUrl 通知地址 - * @return + * @param amt 金额(单位元) + * @param body 商品描述 + * @param tradeType 交易类型 JSAPI,NATIVE,APP,WAP + * @param ip 发起支付的客户端IP + * @param notifyUrl 通知地址 * @deprecated Use me.chanjar.weixin.mp.api.WxMpService.getPrepayId(Map) instead */ @Deprecated @@ -738,9 +286,7 @@ public interface WxMpService { * 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1) * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识" * - * @param parameters - * All required/optional parameters for weixin payment - * @return + * @param parameters All required/optional parameters for weixin payment * @throws IllegalArgumentException */ WxMpPrepayIdResult getPrepayId(Map parameters); @@ -748,25 +294,22 @@ public interface WxMpService { /** * 该接口调用“统一下单”接口,并拼装发起支付请求需要的参数 * 详见http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E5.8F.91.E8.B5.B7.E4.B8.80.E4.B8.AA.E5.BE.AE.E4.BF.A1.E6.94.AF.E4.BB.98.E8.AF.B7.E6.B1.82 - * @param parameters - * the required or optional parameters - * @return - * @throws WxErrorException + * + * @param parameters the required or optional parameters */ - Map getPayInfo(Map parameters) throws WxErrorException; - + Map getPayInfo(Map parameters) throws WxErrorException; + /** * 该接口调用“统一下单”接口,并拼装NATIVE发起支付请求需要的参数 * 详见http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E5.8F.91.E8.B5.B7.E4.B8.80.E4.B8.AA.E5.BE.AE.E4.BF.A1.E6.94.AF.E4.BB.98.E8.AF.B7.E6.B1.82 - * tradeType 交易类型 NATIVE (其他交易类型JSAPI,APP,WAP) - * @param productId 商户商品ID + * tradeType 交易类型 NATIVE (其他交易类型JSAPI,APP,WAP) + * + * @param productId 商户商品ID * @param outTradeNo 商户端对应订单号 - * @param amt 金额(单位元) - * @param body 商品描述 - * @param ip 发起支付的客户端IP - * @param notifyUrl 通知地址 - * @return - * @throws WxErrorException + * @param amt 金额(单位元) + * @param body 商品描述 + * @param ip 发起支付的客户端IP + * @param notifyUrl 通知地址 * @deprecated Use me.chanjar.weixin.mp.api.WxMpService.getPayInfo(Map) instead */ @Deprecated @@ -776,14 +319,13 @@ public interface WxMpService { * 该接口调用“统一下单”接口,并拼装JSAPI发起支付请求需要的参数 * 详见http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E5.8F.91.E8.B5.B7.E4.B8.80.E4.B8.AA.E5.BE.AE.E4.BF.A1.E6.94.AF.E4.BB.98.E8.AF.B7.E6.B1.82 * tradeType 交易类型 JSAPI(其他交易类型NATIVE,APP,WAP) - * @param openId 支付人openId + * + * @param openId 支付人openId * @param outTradeNo 商户端对应订单号 - * @param amt 金额(单位元) - * @param body 商品描述 - * @param ip 发起支付的客户端IP - * @param notifyUrl 通知地址 - * @return - * @throws WxErrorException + * @param amt 金额(单位元) + * @param body 商品描述 + * @param ip 发起支付的客户端IP + * @param notifyUrl 通知地址 * @deprecated Use me.chanjar.weixin.mp.api.WxMpService.getPayInfo(Map) instead */ @Deprecated @@ -792,6 +334,7 @@ public interface WxMpService { /** * 该接口提供所有微信支付订单的查询,当支付通知处理异常戒丢失的情冴,商户可以通过该接口查询订单支付状态。 * 详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2 + * * @param transactionId * @param outTradeNo */ @@ -800,20 +343,21 @@ public interface WxMpService { /** * 读取支付结果通知 * 详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7 + * * @param xmlData - * @return */ WxMpPayCallback getJSSDKCallbackData(String xmlData); /** * 微信支付-申请退款 * 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4 + * * @param parameters 需要传入的退款参数的Map。以下几项为参数的必须项:
- *
  • transaction_id - *
  • out_trade_no (仅在上述transaction_id为空时是必须项) - *
  • out_refund_no - *
  • total_fee - *
  • refund_fee + *
  • transaction_id + *
  • out_trade_no (仅在上述transaction_id为空时是必须项) + *
  • out_refund_no + *
  • total_fee + *
  • refund_fee * @return 退款操作结果 * @throws WxErrorException */ @@ -824,42 +368,41 @@ public interface WxMpService { * 计算Map键值对是否和签名相符, * 按照字段名的 ASCII 码从小到大排序(字典序)后,使用 URL 键值对的 格式(即 key1=value1&key2=value2...)拼接成字符串 * + * * @param kvm * @param signature - * @return */ public boolean checkJSSDKCallbackDataSignature(Map kvm, String signature); /** - * 发送微信红包给个人用户 - * - * 需要传入的必填参数如下: - * mch_billno//商户订单号 - * send_name//商户名称 - * re_openid//用户openid - * total_amount//红包总额 - * total_num//红包发放总人数 - * wishing//红包祝福语 - * client_ip//服务器Ip地址 - * act_name//活动名称 - * remark //备注 - * 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_5 - * - * 使用现金红包功能需要在xml配置文件中额外设置: - * 微信商户平台ID - * 商户平台设置的API密钥 - * - * @param parameters - * @return - * @throws WxErrorException - */ + * 发送微信红包给个人用户 + *

    + * 需要传入的必填参数如下: + * mch_billno//商户订单号 + * send_name//商户名称 + * re_openid//用户openid + * total_amount//红包总额 + * total_num//红包发放总人数 + * wishing//红包祝福语 + * client_ip//服务器Ip地址 + * act_name//活动名称 + * remark //备注 + * 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_5 + *

    + * 使用现金红包功能需要在xml配置文件中额外设置: + * 微信商户平台ID + * 商户平台设置的API密钥 + * + * @param parameters + */ public WxRedpackResult sendRedpack(Map parameters) throws WxErrorException; /** * 获得卡券api_ticket,不强制刷新卡券api_ticket - * @see #getCardApiTicket(boolean) + * * @return 卡券api_ticket * @throws WxErrorException + * @see #getCardApiTicket(boolean) */ public String getCardApiTicket() throws WxErrorException; @@ -870,6 +413,7 @@ public interface WxMpService { * * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD.954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94.9F.E6.88.90.E7.AE.97.E6.B3.95 * + * * @param forceRefresh 强制刷新 * @return 卡券api_ticket * @throws WxErrorException @@ -886,15 +430,16 @@ public interface WxMpService { * * * @param optionalSignParam 参与签名的参数数组。 - * 可以为下列字段:app_id, card_id, card_type, code, openid, location_id - *
    注意:当做wx.chooseCard调用时,必须传入app_id参与签名,否则会造成签名失败导致拉取卡券列表为空 + * 可以为下列字段:app_id, card_id, card_type, code, openid, location_id + *
    注意:当做wx.chooseCard调用时,必须传入app_id参与签名,否则会造成签名失败导致拉取卡券列表为空 * @return 卡券Api签名对象 */ public WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws - WxErrorException; + WxErrorException; /** * 卡券Code解码 + * * @param encryptCode 加密Code,通过JSSDK的chooseCard接口获得 * @return 解密后的Code * @throws WxErrorException @@ -903,14 +448,15 @@ public WxCardApiSignature createCardApiSignature(String... optionalSignParam) th /** * 卡券Code查询 - * @param cardId 卡券ID代表一类卡券 - * @param code 单张卡券的唯一标准 + * + * @param cardId 卡券ID代表一类卡券 + * @param code 单张卡券的唯一标准 * @param checkConsume 是否校验code核销状态,填入true和false时的code异常状态返回数据不同 * @return WxMpCardResult对象 * @throws WxErrorException */ public WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) - throws WxErrorException; + throws WxErrorException; /** * 卡券Code核销。核销失败会抛出异常 @@ -933,62 +479,55 @@ public WxMpCardResult queryCardCode(String cardId, String code, boolean checkCon */ public String consumeCardCode(String code, String cardId) throws WxErrorException; - /** - * 卡券Mark接口。 - * 开发者在帮助消费者核销卡券之前,必须帮助先将此code(卡券串码)与一个openid绑定(即mark住), - * 才能进一步调用核销接口,否则报错。 - * @param code 卡券的code码 - * @param cardId 卡券的ID - * @param openId 用券用户的openid - * @param isMark 是否要mark(占用)这个code,填写true或者false,表示占用或解除占用 - * @throws WxErrorException - */ + /** + * 卡券Mark接口。 + * 开发者在帮助消费者核销卡券之前,必须帮助先将此code(卡券串码)与一个openid绑定(即mark住), + * 才能进一步调用核销接口,否则报错。 + * + * @param code 卡券的code码 + * @param cardId 卡券的ID + * @param openId 用券用户的openid + * @param isMark 是否要mark(占用)这个code,填写true或者false,表示占用或解除占用 + * @throws WxErrorException + */ public void markCardCode(String code, String cardId, String openId, boolean isMark) throws - WxErrorException; + WxErrorException; /** * 查看卡券详情接口 * 详见 https://mp.weixin.qq.com/wiki/14/8dd77aeaee85f922db5f8aa6386d385e.html#.E6.9F.A5.E7.9C.8B.E5.8D.A1.E5.88.B8.E8.AF.A6.E6.83.85 + * * @param cardId 卡券的ID * @return 返回的卡券详情JSON字符串 - *
    [注] 由于返回的JSON格式过于复杂,难以定义其对应格式的Bean并且难以维护,因此只返回String格式的JSON串。 - *
    可由 com.google.gson.JsonParser#parse 等方法直接取JSON串中的某个字段。 + *
    [注] 由于返回的JSON格式过于复杂,难以定义其对应格式的Bean并且难以维护,因此只返回String格式的JSON串。 + *
    可由 com.google.gson.JsonParser#parse 等方法直接取JSON串中的某个字段。 * @throws WxErrorException */ public String getCardDetail(String cardId) throws WxErrorException; /** - *

    -     * 预览接口
    -     * 详情请见:http://mp.weixin.qq.com/wiki/15/40b6865b893947b764e2de8e4a1fb55f.html#.E9.A2.84.E8.A7.88.E6.8E.A5.E5.8F.A3.E3.80.90.E8.AE.A2.E9.98.85.E5.8F.B7.E4.B8.8E.E6.9C.8D.E5.8A.A1.E5.8F.B7.E8.AE.A4.E8.AF.81.E5.90.8E.E5.9D.87.E5.8F.AF.E7.94.A8.E3.80.91
    -     * 
    - * @param wxMpMassPreviewMessage - * @return wxMpMassSendResult - * @throws WxErrorException - */ + *
    +   * 预览接口
    +   * 详情请见:http://mp.weixin.qq.com/wiki/15/40b6865b893947b764e2de8e4a1fb55f.html#.E9.A2.84.E8.A7.88.E6.8E.A5.E5.8F.A3.E3.80.90.E8.AE.A2.E9.98.85.E5.8F.B7.E4.B8.8E.E6.9C.8D.E5.8A.A1.E5.8F.B7.E8.AE.A4.E8.AF.81.E5.90.8E.E5.9D.87.E5.8F.AF.E7.94.A8.E3.80.91
    +   * 
    + * + * @param wxMpMassPreviewMessage + * @return wxMpMassSendResult + * @throws WxErrorException + */ public WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws Exception; /** - *
    -     * 上传图文消息内的图片获取URL
    -     * 详情请见:http://mp.weixin.qq.com/wiki/15/40b6865b893947b764e2de8e4a1fb55f.html#.E4.B8.8A.E4.BC.A0.E5.9B.BE.E6.96.87.E6.B6.88.E6.81.AF.E5.86.85.E7.9A.84.E5.9B.BE.E7.89.87.E8.8E.B7.E5.8F.96URL.E3.80.90.E8.AE.A2.E9.98.85.E5.8F.B7.E4.B8.8E.E6.9C.8D.E5.8A.A1.E5.8F.B7.E8.AE.A4.E8.AF.81.E5.90.8E.E5.9D.87.E5.8F.AF.E7.94.A8.E3.80.91
    -     * 
    - * @param file - * @return WxMediaImgUploadResult 返回图片url - * @throws WxErrorException - */ - public WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException; - - /** - *
    -     * 设置所属行业
    -     * 官方文档中暂未告知响应内容
    -     * 详情请见:http://mp.weixin.qq.com/wiki/5/6dde9eaa909f83354e0094dc3ad99e05.html#.E8.AE.BE.E7.BD.AE.E6.89.80.E5.B1.9E.E8.A1.8C.E4.B8.9A
    -     * 
    - * @param wxMpIndustry - * @return JsonObject - * @throws WxErrorException - */ + *
    +   * 设置所属行业
    +   * 官方文档中暂未告知响应内容
    +   * 详情请见:http://mp.weixin.qq.com/wiki/5/6dde9eaa909f83354e0094dc3ad99e05.html#.E8.AE.BE.E7.BD.AE.E6.89.80.E5.B1.9E.E8.A1.8C.E4.B8.9A
    +   * 
    + * + * @param wxMpIndustry + * @return JsonObject + * @throws WxErrorException + */ String setIndustry(WxMpIndustry wxMpIndustry) throws WxErrorException; /*** @@ -1001,4 +540,53 @@ public void markCardCode(String code, String cardId, String openId, boolean isMa * @throws WxErrorException */ WxMpIndustry getIndustry() throws WxErrorException; + + /** + * 获取WxMpConfigStorage 对象 + * + * @return WxMpConfigStorage + */ + WxMpConfigStorage getWxMpConfigStorage(); + + /** + * 返回客服接口方法实现类,以方便调用个其各种接口 + * + * @return WxMpKefuService + */ + WxMpKefuService getKefuService(); + + /** + * 返回素材相关接口的方法实现类,以方便调用个其各种接口 + * + * @return WxMpMaterialService + */ + WxMpMaterialService getMaterialService(); + + /** + * 返回菜单相关接口的方法实现类,以方便调用个其各种接口 + * + * @return WxMpMenuService + */ + WxMpMenuService getMenuService(); + + /** + * 返回用户相关接口的方法实现类,以方便调用个其各种接口 + * + * @return WxMpUserService + */ + WxMpUserService getUserService(); + + /** + * 返回用户分组相关接口的方法实现类,以方便调用个其各种接口 + * + * @return WxMpGroupService + */ + WxMpGroupService getGroupService(); + + /** + * 返回二维码相关接口的方法实现类,以方便调用个其各种接口 + * + * @return WxMpQrcodeService + */ + WxMpQrcodeService getQrcodeService(); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java new file mode 100644 index 0000000000..818087b4a4 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java @@ -0,0 +1,72 @@ +package me.chanjar.weixin.mp.api; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.bean.result.WxMpUser; +import me.chanjar.weixin.mp.bean.result.WxMpUserCumulate; +import me.chanjar.weixin.mp.bean.result.WxMpUserList; +import me.chanjar.weixin.mp.bean.result.WxMpUserSummary; + +import java.util.Date; +import java.util.List; + +/** + * 用户管理和统计相关操作接口 + * + * @author Binary Wang + */ +public interface WxMpUserService { + + /** + *
    +   * 设置用户备注名接口
    +   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=设置用户备注名接口
    +   * 
    + * + * @param openid 用户openid + * @param remark 备注名 + */ + public void userUpdateRemark(String openid, String remark) throws WxErrorException; + + /** + *
    +   * 获取用户基本信息
    +   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取用户基本信息
    +   * 
    + * + * @param openid 用户openid + * @param lang 语言,zh_CN 简体(默认),zh_TW 繁体,en 英语 + */ + public WxMpUser userInfo(String openid, String lang) throws WxErrorException; + + /** + *
    +   * 获取关注者列表
    +   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取关注者列表
    +   * 
    + * + * @param next_openid 可选,第一个拉取的OPENID,null为从头开始拉取 + */ + public WxMpUserList userList(String next_openid) throws WxErrorException; + + /** + *
    +   * 获取用户增减数据
    +   * http://mp.weixin.qq.com/wiki/3/ecfed6e1a0a03b5f35e5efac98e864b7.html
    +   * 
    + * + * @param beginDate 最大时间跨度7天 + * @param endDate endDate不能早于begingDate + */ + List dataCubeUserSummary(Date beginDate, Date endDate) throws WxErrorException; + + /** + *
    +   * 获取累计用户数据
    +   * http://mp.weixin.qq.com/wiki/3/ecfed6e1a0a03b5f35e5efac98e864b7.html
    +   * 
    + * + * @param beginDate 最大时间跨度7天 + * @param endDate endDate不能早于begingDate + */ + List dataCubeUserCumulate(Date beginDate, Date endDate) throws WxErrorException; +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGroupServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGroupServiceImpl.java new file mode 100644 index 0000000000..ea388dea11 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGroupServiceImpl.java @@ -0,0 +1,85 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.internal.Streams; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; +import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.mp.api.WxMpGroupService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.WxMpGroup; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.StringReader; +import java.util.List; + +/** + * Created by Binary Wang on 2016/7/21. + */ +public class WxMpGroupServiceImpl implements WxMpGroupService { + private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/groups"; + private WxMpService wxMpService; + + public WxMpGroupServiceImpl(WxMpService wxMpService) { + this.wxMpService = wxMpService; + } + + @Override + public WxMpGroup groupCreate(String name) throws WxErrorException { + String url = API_URL_PREFIX + "/create"; + JsonObject json = new JsonObject(); + JsonObject groupJson = new JsonObject(); + json.add("group", groupJson); + groupJson.addProperty("name", name); + + String responseContent = this.wxMpService.execute( + new SimplePostRequestExecutor(), + url, + json.toString()); + return WxMpGroup.fromJson(responseContent); + } + + @Override + public List groupGet() throws WxErrorException { + String url = API_URL_PREFIX + "/get"; + String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null); + /* + * 操蛋的微信API,创建时返回的是 { group : { id : ..., name : ...} } + * 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] } + */ + JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); + return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("groups"), + new TypeToken>() { + }.getType()); + } + + @Override + public long userGetGroup(String openid) throws WxErrorException { + String url = API_URL_PREFIX + "/getid"; + JsonObject o = new JsonObject(); + o.addProperty("openid", openid); + String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, o.toString()); + JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); + return GsonHelper.getAsLong(tmpJsonElement.getAsJsonObject().get("groupid")); + } + + @Override + public void groupUpdate(WxMpGroup group) throws WxErrorException { + String url = API_URL_PREFIX + "/update"; + this.wxMpService.execute(new SimplePostRequestExecutor(), url, group.toJson()); + } + + @Override + public void userUpdateGroup(String openid, long to_groupid) throws WxErrorException { + String url = API_URL_PREFIX + "/members/update"; + JsonObject json = new JsonObject(); + json.addProperty("openid", openid); + json.addProperty("to_groupid", to_groupid); + this.wxMpService.execute(new SimplePostRequestExecutor(), url, json.toString()); + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java new file mode 100644 index 0000000000..6d6cf14c95 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java @@ -0,0 +1,182 @@ +package me.chanjar.weixin.mp.api.impl; + +import java.io.File; +import java.util.Date; + +import com.google.gson.JsonObject; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; +import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; +import me.chanjar.weixin.mp.api.WxMpKefuService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest; +import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfSessionRequest; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfMsgList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfOnlineList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionGetResult; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionWaitCaseList; + +/** + * + * @author Binary Wang + * + */ +public class WxMpKefuServiceImpl implements WxMpKefuService { + private static final String API_URL_PREFIX = "https://api.weixin.qq.com/customservice"; + private WxMpService wxMpService; + + public WxMpKefuServiceImpl(WxMpService wxMpService) { + this.wxMpService = wxMpService; + } + + @Override + public WxMpKfList kfList() throws WxErrorException { + String url = "https://api.weixin.qq.com/cgi-bin/customservice/getkflist"; + String responseContent = this.wxMpService + .execute(new SimpleGetRequestExecutor(), url, null); + return WxMpKfList.fromJson(responseContent); + } + + @Override + public WxMpKfOnlineList kfOnlineList() throws WxErrorException { + String url = "https://api.weixin.qq.com/cgi-bin/customservice/getonlinekflist"; + String responseContent = this.wxMpService + .execute(new SimpleGetRequestExecutor(), url, null); + return WxMpKfOnlineList.fromJson(responseContent); + } + + @Override + public boolean kfAccountAdd(WxMpKfAccountRequest request) + throws WxErrorException { + String url = API_URL_PREFIX + "/kfaccount/add"; + this.wxMpService.execute(new SimplePostRequestExecutor(), url, + request.toJson()); + return true; + } + + @Override + public boolean kfAccountUpdate(WxMpKfAccountRequest request) + throws WxErrorException { + String url = API_URL_PREFIX + "/kfaccount/update"; + this.wxMpService.execute(new SimplePostRequestExecutor(), url, + request.toJson()); + return true; + } + + @Override + public boolean kfAccountInviteWorker(WxMpKfAccountRequest request) throws WxErrorException { + String url = API_URL_PREFIX + "/kfaccount/inviteworker"; + this.wxMpService.execute(new SimplePostRequestExecutor(), url, + request.toJson()); + return true; + } + + @Override + public boolean kfAccountUploadHeadImg(String kfAccount, File imgFile) + throws WxErrorException { + String url = API_URL_PREFIX + "/kfaccount/uploadheadimg?kf_account=" + kfAccount; + this.wxMpService.execute(new MediaUploadRequestExecutor(), url, imgFile); + return true; + } + + @Override + public boolean kfAccountDel(String kfAccount) throws WxErrorException { + String url = API_URL_PREFIX + "/kfaccount/del?kf_account=" + kfAccount; + this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null); + return true; + } + + @Override + public boolean kfSessionCreate(String openid, String kfAccount) + throws WxErrorException { + WxMpKfSessionRequest request = new WxMpKfSessionRequest(kfAccount, openid); + String url = API_URL_PREFIX + "/kfsession/create"; + this.wxMpService.execute(new SimplePostRequestExecutor(), url, + request.toJson()); + return true; + } + + @Override + public boolean kfSessionClose(String openid, String kfAccount) + throws WxErrorException { + WxMpKfSessionRequest request = new WxMpKfSessionRequest(kfAccount, openid); + String url = API_URL_PREFIX + "/kfsession/close"; + this.wxMpService.execute(new SimplePostRequestExecutor(), url, + request.toJson()); + return true; + } + + @Override + public WxMpKfSessionGetResult kfSessionGet(String openid) + throws WxErrorException { + String url = API_URL_PREFIX + "/kfsession/getsession?openid=" + openid; + String responseContent = this.wxMpService + .execute(new SimpleGetRequestExecutor(), url, null); + return WxMpKfSessionGetResult.fromJson(responseContent); + } + + @Override + public WxMpKfSessionList kfSessionList(String kfAccount) + throws WxErrorException { + String url = API_URL_PREFIX + "/kfsession/getsessionlist?kf_account=" + kfAccount; + String responseContent = this.wxMpService + .execute(new SimpleGetRequestExecutor(), url, null); + return WxMpKfSessionList.fromJson(responseContent); + } + + @Override + public WxMpKfSessionWaitCaseList kfSessionGetWaitCase() + throws WxErrorException { + String url = API_URL_PREFIX + "/kfsession/getwaitcase"; + String responseContent = this.wxMpService + .execute(new SimpleGetRequestExecutor(), url, null); + return WxMpKfSessionWaitCaseList.fromJson(responseContent); + } + + @Override + public WxMpKfMsgList kfMsgList(Date startTime, Date endTime, Long msgId, Integer number) throws WxErrorException { + if(number > 10000){ + throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法参数请求,每次最多查询10000条记录!").build()); + } + + if(startTime.after(endTime)){ + throw new WxErrorException(WxError.newBuilder().setErrorMsg("起始时间不能晚于结束时间!").build()); + } + + String url = API_URL_PREFIX + "/msgrecord/getmsglist"; + + JsonObject param = new JsonObject(); + param.addProperty("starttime", startTime.getTime() / 1000); //starttime 起始时间,unix时间戳 + param.addProperty("endtime", endTime.getTime() / 1000); //endtime 结束时间,unix时间戳,每次查询时段不能超过24小时 + param.addProperty("msgid", msgId); //msgid 消息id顺序从小到大,从1开始 + param.addProperty("number", number); //number 每次获取条数,最多10000条 + + String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, param.toString()); + return WxMpKfMsgList.fromJson(responseContent); + } + + @Override + public WxMpKfMsgList kfMsgList(Date startTime, Date endTime) throws WxErrorException { + int number = 10000; + WxMpKfMsgList result = this.kfMsgList(startTime,endTime, 1L, number); + + if(result != null && result.getNumber() == number){ + Long msgId = result.getMsgId(); + WxMpKfMsgList followingResult = this.kfMsgList(startTime,endTime, msgId, number); + while(followingResult != null && followingResult.getRecords().size() > 0){ + result.getRecords().addAll(followingResult.getRecords()); + result.setNumber(result.getNumber() + followingResult.getNumber()); + result.setMsgId(followingResult.getMsgId()); + followingResult = this.kfMsgList(startTime,endTime, followingResult.getMsgId(), number); + } + } + + return result; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java new file mode 100644 index 0000000000..c6825815cd --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java @@ -0,0 +1,158 @@ +package me.chanjar.weixin.mp.api.impl; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.api.WxMpMaterialService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.WxMpMaterial; +import me.chanjar.weixin.mp.bean.WxMpMaterialArticleUpdate; +import me.chanjar.weixin.mp.bean.WxMpMaterialNews; +import me.chanjar.weixin.mp.bean.result.*; +import me.chanjar.weixin.mp.util.http.*; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * Created by Binary Wang on 2016/7/21. + */ +public class WxMpMaterialServiceImpl implements WxMpMaterialService { + private static final String MEDIA_API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/media"; + private static final String MATERIAL_API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/material"; + private WxMpService wxMpService; + + public WxMpMaterialServiceImpl(WxMpService wxMpService) { + this.wxMpService = wxMpService; + } + + @Override + public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) throws WxErrorException, IOException { + return this.mediaUpload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); + } + + @Override + public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { + String url = MEDIA_API_URL_PREFIX + "/upload?type=" + mediaType; + return this.wxMpService.execute(new MediaUploadRequestExecutor(), url, file); + } + + @Override + public File mediaDownload(String media_id) throws WxErrorException { + String url = MEDIA_API_URL_PREFIX + "/get"; + return this.wxMpService.execute(new MediaDownloadRequestExecutor(this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), url, "media_id=" + media_id); + } + + @Override + public WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException { + String url = MEDIA_API_URL_PREFIX + "/uploadimg"; + return this.wxMpService.execute(new MediaImgUploadRequestExecutor(), url, file); + } + + @Override + public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException { + String url = MATERIAL_API_URL_PREFIX + "/add_material?type=" + mediaType; + return this.wxMpService.execute(new MaterialUploadRequestExecutor(), url, material); + } + + @Override + public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws WxErrorException { + if (news == null || news.isEmpty()) { + throw new IllegalArgumentException("news is empty!"); + } + String url = MATERIAL_API_URL_PREFIX + "/add_news"; + String responseContent = this.wxMpService.post(url, news.toJson()); + return WxMpMaterialUploadResult.fromJson(responseContent); + } + + @Override + public InputStream materialImageOrVoiceDownload(String media_id) throws WxErrorException { + String url = MATERIAL_API_URL_PREFIX + "/get_material"; + return this.wxMpService.execute(new MaterialVoiceAndImageDownloadRequestExecutor(this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), url, media_id); + } + + @Override + public WxMpMaterialVideoInfoResult materialVideoInfo(String media_id) throws WxErrorException { + String url = MATERIAL_API_URL_PREFIX + "/get_material"; + return this.wxMpService.execute(new MaterialVideoInfoRequestExecutor(), url, media_id); + } + + @Override + public WxMpMaterialNews materialNewsInfo(String media_id) throws WxErrorException { + String url = MATERIAL_API_URL_PREFIX + "/get_material"; + return this.wxMpService.execute(new MaterialNewsInfoRequestExecutor(), url, media_id); + } + + @Override + public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate) throws WxErrorException { + String url = MATERIAL_API_URL_PREFIX + "/update_news"; + String responseText = this.wxMpService.post(url, wxMpMaterialArticleUpdate.toJson()); + WxError wxError = WxError.fromJson(responseText); + if (wxError.getErrorCode() == 0) { + return true; + } else { + throw new WxErrorException(wxError); + } + } + + @Override + public boolean materialDelete(String media_id) throws WxErrorException { + String url = MATERIAL_API_URL_PREFIX + "/del_material"; + return this.wxMpService.execute(new MaterialDeleteRequestExecutor(), url, media_id); + } + + @Override + public WxMpMaterialCountResult materialCount() throws WxErrorException { + String url = MATERIAL_API_URL_PREFIX + "/get_materialcount"; + String responseText = this.wxMpService.get(url, null); + WxError wxError = WxError.fromJson(responseText); + if (wxError.getErrorCode() == 0) { + return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialCountResult.class); + } else { + throw new WxErrorException(wxError); + } + } + + @Override + public WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count) throws WxErrorException { + String url = MATERIAL_API_URL_PREFIX + "/batchget_material"; + Map params = new HashMap<>(); + params.put("type", WxConsts.MATERIAL_NEWS); + params.put("offset", offset); + params.put("count", count); + String responseText = this.wxMpService.post(url, WxGsonBuilder.create().toJson(params)); + WxError wxError = WxError.fromJson(responseText); + if (wxError.getErrorCode() == 0) { + return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialNewsBatchGetResult.class); + } else { + throw new WxErrorException(wxError); + } + } + + @Override + public WxMpMaterialFileBatchGetResult materialFileBatchGet(String type, int offset, int count) throws WxErrorException { + String url = MATERIAL_API_URL_PREFIX + "/batchget_material"; + Map params = new HashMap<>(); + params.put("type", type); + params.put("offset", offset); + params.put("count", count); + String responseText = this.wxMpService.post(url, WxGsonBuilder.create().toJson(params)); + WxError wxError = WxError.fromJson(responseText); + if (wxError.getErrorCode() == 0) { + return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialFileBatchGetResult.class); + } else { + throw new WxErrorException(wxError); + } + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImpl.java new file mode 100644 index 0000000000..bfad1e06a9 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImpl.java @@ -0,0 +1,74 @@ +package me.chanjar.weixin.mp.api.impl; + +import me.chanjar.weixin.common.bean.WxMenu; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; +import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; +import me.chanjar.weixin.mp.api.WxMpMenuService; +import me.chanjar.weixin.mp.api.WxMpService; + +/** + * Created by Binary Wang on 2016/7/21. + */ +public class WxMpMenuServiceImpl implements WxMpMenuService { + private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/menu"; + + private WxMpService wxMpService; + + public WxMpMenuServiceImpl(WxMpService wxMpService) { + this.wxMpService = wxMpService; + } + + @Override + public void menuCreate(WxMenu menu) throws WxErrorException { + if (menu.getMatchRule() != null) { + String url = API_URL_PREFIX + "/addconditional"; + this.wxMpService.execute(new SimplePostRequestExecutor(), url, menu.toJson()); + } else { + String url = API_URL_PREFIX + "/create"; + this.wxMpService.execute(new SimplePostRequestExecutor(), url, menu.toJson()); + } + } + + @Override + public void menuDelete() throws WxErrorException { + String url = API_URL_PREFIX + "/delete"; + this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null); + } + + @Override + public void menuDelete(String menuid) throws WxErrorException { + String url = API_URL_PREFIX + "/delconditional"; + this.wxMpService.execute(new SimpleGetRequestExecutor(), url, "menuid=" + menuid); + } + + @Override + public WxMenu menuGet() throws WxErrorException { + String url = API_URL_PREFIX + "/get"; + try { + String resultContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null); + return WxMenu.fromJson(resultContent); + } catch (WxErrorException e) { + // 46003 不存在的菜单数据 + if (e.getError().getErrorCode() == 46003) { + return null; + } + throw e; + } + } + + @Override + public WxMenu menuTryMatch(String userid) throws WxErrorException { + String url = API_URL_PREFIX + "/trymatch"; + try { + String resultContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, "user_id=" + userid); + return WxMenu.fromJson(resultContent); + } catch (WxErrorException e) { + // 46003 不存在的菜单数据 46002 不存在的菜单版本 + if (e.getError().getErrorCode() == 46003 || e.getError().getErrorCode() == 46002) { + return null; + } + throw e; + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java new file mode 100644 index 0000000000..bb0e112cec --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java @@ -0,0 +1,102 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.gson.JsonObject; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; +import me.chanjar.weixin.mp.api.WxMpQrcodeService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import me.chanjar.weixin.mp.util.http.QrCodeRequestExecutor; + +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +/** + * Created by Binary Wang on 2016/7/21. + */ +public class WxMpQrcodeServiceImpl implements WxMpQrcodeService { + private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/qrcode"; + private WxMpService wxMpService; + + public WxMpQrcodeServiceImpl(WxMpService wxMpService) { + this.wxMpService = wxMpService; + } + + @Override + public WxMpQrCodeTicket qrCodeCreateTmpTicket(int scene_id, Integer expire_seconds) throws WxErrorException { + String url = API_URL_PREFIX + "/create"; + JsonObject json = new JsonObject(); + json.addProperty("action_name", "QR_SCENE"); + if (expire_seconds != null) { + json.addProperty("expire_seconds", expire_seconds); + } + JsonObject actionInfo = new JsonObject(); + JsonObject scene = new JsonObject(); + scene.addProperty("scene_id", scene_id); + actionInfo.add("scene", scene); + json.add("action_info", actionInfo); + String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, json.toString()); + return WxMpQrCodeTicket.fromJson(responseContent); + } + + @Override + public WxMpQrCodeTicket qrCodeCreateLastTicket(int scene_id) throws WxErrorException { + String url = API_URL_PREFIX + "/create"; + JsonObject json = new JsonObject(); + json.addProperty("action_name", "QR_LIMIT_SCENE"); + JsonObject actionInfo = new JsonObject(); + JsonObject scene = new JsonObject(); + scene.addProperty("scene_id", scene_id); + actionInfo.add("scene", scene); + json.add("action_info", actionInfo); + String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, json.toString()); + return WxMpQrCodeTicket.fromJson(responseContent); + } + + @Override + public WxMpQrCodeTicket qrCodeCreateLastTicket(String scene_str) throws WxErrorException { + String url = API_URL_PREFIX + "/create"; + JsonObject json = new JsonObject(); + json.addProperty("action_name", "QR_LIMIT_STR_SCENE"); + JsonObject actionInfo = new JsonObject(); + JsonObject scene = new JsonObject(); + scene.addProperty("scene_str", scene_str); + actionInfo.add("scene", scene); + json.add("action_info", actionInfo); + String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, json.toString()); + return WxMpQrCodeTicket.fromJson(responseContent); + } + + @Override + public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException { + String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode"; + return this.wxMpService.execute(new QrCodeRequestExecutor(), url, ticket); + } + + @Override + public String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException { + String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s"; + try { + String resultUrl = String.format(url, + URLEncoder.encode(ticket, StandardCharsets.UTF_8.name())); + if (needShortUrl) { + return this.wxMpService.shortUrl(resultUrl); + } + + return resultUrl; + } catch (UnsupportedEncodingException e) { + WxError error = WxError.newBuilder().setErrorCode(-1) + .setErrorMsg(e.getMessage()).build(); + throw new WxErrorException(error); + } + } + + @Override + public String qrCodePictureUrl(String ticket) throws WxErrorException { + return qrCodePictureUrl(ticket, false); + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java similarity index 73% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java index 18fb3aefed..8c29dd8b7d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java @@ -1,34 +1,26 @@ -package me.chanjar.weixin.mp.api; +package me.chanjar.weixin.mp.api.impl; import com.google.gson.*; import com.google.gson.internal.Streams; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.thoughtworks.xstream.XStream; -import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.bean.WxCardApiSignature; import me.chanjar.weixin.common.bean.WxJsapiSignature; -import me.chanjar.weixin.common.bean.WxMenu; import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.session.StandardSessionManager; import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.util.RandomUtils; import me.chanjar.weixin.common.util.crypto.SHA1; import me.chanjar.weixin.common.util.crypto.WxCryptUtil; -import me.chanjar.weixin.common.util.fs.FileUtils; import me.chanjar.weixin.common.util.http.*; -import me.chanjar.weixin.common.util.json.GsonHelper; -import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.common.util.xml.XStreamInitializer; +import me.chanjar.weixin.mp.api.*; import me.chanjar.weixin.mp.bean.*; import me.chanjar.weixin.mp.bean.result.*; -import me.chanjar.weixin.mp.util.http.*; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; - -import org.apache.commons.io.Charsets; import org.apache.http.Consts; import org.apache.http.HttpHost; import org.apache.http.client.ClientProtocolException; @@ -44,12 +36,8 @@ import org.slf4j.LoggerFactory; import org.slf4j.helpers.MessageFormatter; -import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.io.StringReader; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.security.NoSuchAlgorithmException; import java.util.*; import java.util.Map.Entry; @@ -74,6 +62,18 @@ public class WxMpServiceImpl implements WxMpService { protected final Object globalCardApiTicketRefreshLock = new Object(); protected WxMpConfigStorage wxMpConfigStorage; + + protected WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); + + protected WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this); + + protected WxMpMenuService menuService = new WxMpMenuServiceImpl(this); + + protected WxMpUserService userService = new WxMpUserServiceImpl(this); + + protected WxMpGroupService groupService = new WxMpGroupServiceImpl(this); + + protected WxMpQrcodeService qrCodeService = new WxMpQrcodeServiceImpl(this); protected CloseableHttpClient httpClient; @@ -195,172 +195,6 @@ public void customMessageSend(WxMpCustomMessage message) throws WxErrorException execute(new SimplePostRequestExecutor(), url, message.toJson()); } - @Override - public void menuCreate(WxMenu menu) throws WxErrorException { - if (menu.getMatchRule() != null) { - String url = "https://api.weixin.qq.com/cgi-bin/menu/addconditional"; - execute(new SimplePostRequestExecutor(), url, menu.toJson()); - } else { - String url = "https://api.weixin.qq.com/cgi-bin/menu/create"; - execute(new SimplePostRequestExecutor(), url, menu.toJson()); - } - } - - @Override - public void menuDelete() throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/menu/delete"; - execute(new SimpleGetRequestExecutor(), url, null); - } - - @Override - public void menuDelete(String menuid) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/menu/delconditional"; - execute(new SimpleGetRequestExecutor(), url, "menuid=" + menuid); - } - - @Override - public WxMenu menuGet() throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/menu/get"; - try { - String resultContent = execute(new SimpleGetRequestExecutor(), url, null); - return WxMenu.fromJson(resultContent); - } catch (WxErrorException e) { - // 46003 不存在的菜单数据 - if (e.getError().getErrorCode() == 46003) { - return null; - } - throw e; - } - } - - @Override - public WxMenu menuTryMatch(String userid) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/menu/trymatch"; - try { - String resultContent = execute(new SimpleGetRequestExecutor(), url, "user_id=" + userid); - return WxMenu.fromJson(resultContent); - } catch (WxErrorException e) { - // 46003 不存在的菜单数据 46002 不存在的菜单版本 - if (e.getError().getErrorCode() == 46003 || e.getError().getErrorCode() == 46002) { - return null; - } - throw e; - } - } - - @Override - public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) throws WxErrorException, IOException { - return mediaUpload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); - } - - @Override - public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType; - return execute(new MediaUploadRequestExecutor(), url, file); - } - - @Override - public File mediaDownload(String media_id) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/media/get"; - return execute(new MediaDownloadRequestExecutor(this.wxMpConfigStorage.getTmpDirFile()), url, "media_id=" + media_id); - } - - @Override - public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/material/add_material?type=" + mediaType; - return execute(new MaterialUploadRequestExecutor(), url, material); - } - - @Override - public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws WxErrorException { - if (news == null || news.isEmpty()) { - throw new IllegalArgumentException("news is empty!"); - } - String url = "https://api.weixin.qq.com/cgi-bin/material/add_news"; - String responseContent = post(url, news.toJson()); - return WxMpMaterialUploadResult.fromJson(responseContent); - } - - @Override - public InputStream materialImageOrVoiceDownload(String media_id) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/material/get_material"; - return execute(new MaterialVoiceAndImageDownloadRequestExecutor(this.wxMpConfigStorage.getTmpDirFile()), url, media_id); - } - - @Override - public WxMpMaterialVideoInfoResult materialVideoInfo(String media_id) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/material/get_material"; - return execute(new MaterialVideoInfoRequestExecutor(), url, media_id); - } - - @Override - public WxMpMaterialNews materialNewsInfo(String media_id) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/material/get_material"; - return execute(new MaterialNewsInfoRequestExecutor(), url, media_id); - } - - @Override - public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/material/update_news"; - String responseText = post(url, wxMpMaterialArticleUpdate.toJson()); - WxError wxError = WxError.fromJson(responseText); - if (wxError.getErrorCode() == 0) { - return true; - } else { - throw new WxErrorException(wxError); - } - } - - @Override - public boolean materialDelete(String media_id) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/material/del_material"; - return execute(new MaterialDeleteRequestExecutor(), url, media_id); - } - - @Override - public WxMpMaterialCountResult materialCount() throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/material/get_materialcount"; - String responseText = get(url, null); - WxError wxError = WxError.fromJson(responseText); - if (wxError.getErrorCode() == 0) { - return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialCountResult.class); - } else { - throw new WxErrorException(wxError); - } - } - - @Override - public WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/material/batchget_material"; - Map params = new HashMap<>(); - params.put("type", WxConsts.MATERIAL_NEWS); - params.put("offset", offset); - params.put("count", count); - String responseText = post(url, WxGsonBuilder.create().toJson(params)); - WxError wxError = WxError.fromJson(responseText); - if (wxError.getErrorCode() == 0) { - return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialNewsBatchGetResult.class); - } else { - throw new WxErrorException(wxError); - } - } - - @Override - public WxMpMaterialFileBatchGetResult materialFileBatchGet(String type, int offset, int count) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/material/batchget_material"; - Map params = new HashMap<>(); - params.put("type", type); - params.put("offset", offset); - params.put("count", count); - String responseText = post(url, WxGsonBuilder.create().toJson(params)); - WxError wxError = WxError.fromJson(responseText); - if (wxError.getErrorCode() == 0) { - return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialFileBatchGetResult.class); - } else { - throw new WxErrorException(wxError); - } - } - @Override public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException { String url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews"; @@ -389,158 +223,6 @@ public WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) return WxMpMassSendResult.fromJson(responseContent); } - @Override - public WxMpGroup groupCreate(String name) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/groups/create"; - JsonObject json = new JsonObject(); - JsonObject groupJson = new JsonObject(); - json.add("group", groupJson); - groupJson.addProperty("name", name); - - String responseContent = execute( - new SimplePostRequestExecutor(), - url, - json.toString()); - return WxMpGroup.fromJson(responseContent); - } - - @Override - public List groupGet() throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/groups/get"; - String responseContent = execute(new SimpleGetRequestExecutor(), url, null); - /* - * 操蛋的微信API,创建时返回的是 { group : { id : ..., name : ...} } - * 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] } - */ - JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); - return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("groups"), - new TypeToken>() { - }.getType()); - } - - @Override - public long userGetGroup(String openid) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/groups/getid"; - JsonObject o = new JsonObject(); - o.addProperty("openid", openid); - String responseContent = execute(new SimplePostRequestExecutor(), url, o.toString()); - JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); - return GsonHelper.getAsLong(tmpJsonElement.getAsJsonObject().get("groupid")); - } - - @Override - public void groupUpdate(WxMpGroup group) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/groups/update"; - execute(new SimplePostRequestExecutor(), url, group.toJson()); - } - - @Override - public void userUpdateGroup(String openid, long to_groupid) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/groups/members/update"; - JsonObject json = new JsonObject(); - json.addProperty("openid", openid); - json.addProperty("to_groupid", to_groupid); - execute(new SimplePostRequestExecutor(), url, json.toString()); - } - - @Override - public void userUpdateRemark(String openid, String remark) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/user/info/updateremark"; - JsonObject json = new JsonObject(); - json.addProperty("openid", openid); - json.addProperty("remark", remark); - execute(new SimplePostRequestExecutor(), url, json.toString()); - } - - @Override - public WxMpUser userInfo(String openid, String lang) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/user/info"; - lang = lang == null ? "zh_CN" : lang; - String responseContent = execute(new SimpleGetRequestExecutor(), url, "openid=" + openid + "&lang=" + lang); - return WxMpUser.fromJson(responseContent); - } - - @Override - public WxMpUserList userList(String next_openid) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/user/get"; - String responseContent = execute(new SimpleGetRequestExecutor(), url, next_openid == null ? null : "next_openid=" + next_openid); - return WxMpUserList.fromJson(responseContent); - } - - @Override - public WxMpQrCodeTicket qrCodeCreateTmpTicket(int scene_id, Integer expire_seconds) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create"; - JsonObject json = new JsonObject(); - json.addProperty("action_name", "QR_SCENE"); - if (expire_seconds != null) { - json.addProperty("expire_seconds", expire_seconds); - } - JsonObject actionInfo = new JsonObject(); - JsonObject scene = new JsonObject(); - scene.addProperty("scene_id", scene_id); - actionInfo.add("scene", scene); - json.add("action_info", actionInfo); - String responseContent = execute(new SimplePostRequestExecutor(), url, json.toString()); - return WxMpQrCodeTicket.fromJson(responseContent); - } - - @Override - public WxMpQrCodeTicket qrCodeCreateLastTicket(int scene_id) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create"; - JsonObject json = new JsonObject(); - json.addProperty("action_name", "QR_LIMIT_SCENE"); - JsonObject actionInfo = new JsonObject(); - JsonObject scene = new JsonObject(); - scene.addProperty("scene_id", scene_id); - actionInfo.add("scene", scene); - json.add("action_info", actionInfo); - String responseContent = execute(new SimplePostRequestExecutor(), url, json.toString()); - return WxMpQrCodeTicket.fromJson(responseContent); - } - - @Override - public WxMpQrCodeTicket qrCodeCreateLastTicket(String scene_str) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create"; - JsonObject json = new JsonObject(); - json.addProperty("action_name", "QR_LIMIT_STR_SCENE"); - JsonObject actionInfo = new JsonObject(); - JsonObject scene = new JsonObject(); - scene.addProperty("scene_str", scene_str); - actionInfo.add("scene", scene); - json.add("action_info", actionInfo); - String responseContent = execute(new SimplePostRequestExecutor(), url, json.toString()); - return WxMpQrCodeTicket.fromJson(responseContent); - } - - @Override - public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException { - String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode"; - return execute(new QrCodeRequestExecutor(), url, ticket); - } - - @Override - public String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException { - String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s"; - try { - String resultUrl = String.format(url, - URLEncoder.encode(ticket, Charsets.UTF_8.name())); - if(needShortUrl){ - return this.shortUrl(resultUrl); - } - - return resultUrl; - } catch (UnsupportedEncodingException e) { - WxError error = WxError.newBuilder().setErrorCode(-1) - .setErrorMsg(e.getMessage()).build(); - throw new WxErrorException(error); - } - } - - @Override - public String qrCodePictureUrl(String ticket) throws WxErrorException { - return qrCodePictureUrl(ticket, false); - } - @Override public String shortUrl(String long_url) throws WxErrorException { String url = "https://api.weixin.qq.com/cgi-bin/shorturl"; @@ -685,33 +367,6 @@ public String[] getCallbackIP() throws WxErrorException { return ipArray; } - - @Override - public List getUserSummary(Date beginDate, Date endDate) throws WxErrorException { - String url = "https://api.weixin.qq.com/datacube/getusersummary"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", SIMPLE_DATE_FORMAT.format(beginDate)); - param.addProperty("end_date", SIMPLE_DATE_FORMAT.format(endDate)); - String responseContent = post(url, param.toString()); - JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); - return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("list"), - new TypeToken>() { - }.getType()); - } - - @Override - public List getUserCumulate(Date beginDate, Date endDate) throws WxErrorException { - String url = "https://api.weixin.qq.com/datacube/getusercumulate"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", SIMPLE_DATE_FORMAT.format(beginDate)); - param.addProperty("end_date", SIMPLE_DATE_FORMAT.format(endDate)); - String responseContent = post(url, param.toString()); - JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); - return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("list"), - new TypeToken>() { - }.getType()); - } - @Override public String get(String url, String queryParam) throws WxErrorException { return execute(new SimpleGetRequestExecutor(), url, queryParam); @@ -724,12 +379,6 @@ public String post(String url, String postData) throws WxErrorException { /** * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 - * - * @param executor - * @param uri - * @param data - * @return - * @throws WxErrorException */ @Override public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { @@ -822,6 +471,11 @@ public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) { this.httpClient = apacheHttpClientBuilder.build(); } + @Override + public WxMpConfigStorage getWxMpConfigStorage() { + return this.wxMpConfigStorage; + } + @Override public void setRetrySleepMillis(int retrySleepMillis) { this.retrySleepMillis = retrySleepMillis; @@ -1347,12 +1001,6 @@ public WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPrev return WxMpMassSendResult.fromJson(responseContent); } - @Override - public WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/media/uploadimg"; - return execute(new MediaImgUploadRequestExecutor(), url, file); - } - @Override public String setIndustry(WxMpIndustry wxMpIndustry) throws WxErrorException { if (null == wxMpIndustry.getPrimaryIndustry() || null == wxMpIndustry.getPrimaryIndustry().getId() @@ -1369,4 +1017,35 @@ public WxMpIndustry getIndustry() throws WxErrorException { String responseContent = execute(new SimpleGetRequestExecutor(), url, null); return WxMpIndustry.fromJson(responseContent); } + + @Override + public WxMpKefuService getKefuService() { + return this.kefuService; + } + + @Override + public WxMpMaterialService getMaterialService() { + return this.materialService; + } + + @Override + public WxMpMenuService getMenuService() { + return this.menuService; + } + + @Override + public WxMpUserService getUserService() { + return this.userService; + } + + @Override + public WxMpGroupService getGroupService() { + return this.groupService; + } + + @Override + public WxMpQrcodeService getQrcodeService() { + return this.qrCodeService; + } + } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java new file mode 100644 index 0000000000..f2ceac3460 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java @@ -0,0 +1,83 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.internal.Streams; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; +import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.WxMpUserService; +import me.chanjar.weixin.mp.bean.result.WxMpUser; +import me.chanjar.weixin.mp.bean.result.WxMpUserCumulate; +import me.chanjar.weixin.mp.bean.result.WxMpUserList; +import me.chanjar.weixin.mp.bean.result.WxMpUserSummary; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.StringReader; +import java.util.Date; +import java.util.List; + +/** + * Created by Binary Wang on 2016/7/21. + */ +public class WxMpUserServiceImpl implements WxMpUserService { + private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/user"; + private WxMpService wxMpService; + + public WxMpUserServiceImpl(WxMpService wxMpService) { + this.wxMpService = wxMpService; + } + + @Override + public void userUpdateRemark(String openid, String remark) throws WxErrorException { + String url = API_URL_PREFIX + "/info/updateremark"; + JsonObject json = new JsonObject(); + json.addProperty("openid", openid); + json.addProperty("remark", remark); + this.wxMpService.execute(new SimplePostRequestExecutor(), url, json.toString()); + } + + @Override + public WxMpUser userInfo(String openid, String lang) throws WxErrorException { + String url = API_URL_PREFIX + "/info"; + lang = lang == null ? "zh_CN" : lang; + String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, "openid=" + openid + "&lang=" + lang); + return WxMpUser.fromJson(responseContent); + } + + @Override + public WxMpUserList userList(String next_openid) throws WxErrorException { + String url = API_URL_PREFIX + "/get"; + String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, next_openid == null ? null : "next_openid=" + next_openid); + return WxMpUserList.fromJson(responseContent); + } + + @Override + public List dataCubeUserSummary(Date beginDate, Date endDate) throws WxErrorException { + String url = "https://api.weixin.qq.com/datacube/getusersummary"; + JsonObject param = new JsonObject(); + param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate)); + param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate)); + String responseContent = this.wxMpService.post(url, param.toString()); + JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); + return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("list"), + new TypeToken>() { + }.getType()); + } + + @Override + public List dataCubeUserCumulate(Date beginDate, Date endDate) throws WxErrorException { + String url = "https://api.weixin.qq.com/datacube/getusercumulate"; + JsonObject param = new JsonObject(); + param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate)); + param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate)); + String responseContent = this.wxMpService.post(url, param.toString()); + JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); + return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("list"), + new TypeToken>() { + }.getType()); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCustomMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCustomMessage.java index a19b79bd4c..5fce97a3f3 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCustomMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCustomMessage.java @@ -13,7 +13,8 @@ * */ public class WxMpCustomMessage implements Serializable { - + private static final long serialVersionUID = -9196732086954365246L; + private String toUser; private String msgType; private String content; @@ -23,16 +24,17 @@ public class WxMpCustomMessage implements Serializable { private String description; private String musicUrl; private String hqMusicUrl; - private List articles = new ArrayList(); + private String kfAccount; + private List articles = new ArrayList<>(); public String getToUser() { - return toUser; + return this.toUser; } public void setToUser(String toUser) { this.toUser = toUser; } public String getMsgType() { - return msgType; + return this.msgType; } /** @@ -51,49 +53,49 @@ public void setMsgType(String msgType) { this.msgType = msgType; } public String getContent() { - return content; + return this.content; } public void setContent(String content) { this.content = content; } public String getMediaId() { - return mediaId; + return this.mediaId; } public void setMediaId(String mediaId) { this.mediaId = mediaId; } public String getThumbMediaId() { - return thumbMediaId; + return this.thumbMediaId; } public void setThumbMediaId(String thumbMediaId) { this.thumbMediaId = thumbMediaId; } public String getTitle() { - return title; + return this.title; } public void setTitle(String title) { this.title = title; } public String getDescription() { - return description; + return this.description; } public void setDescription(String description) { this.description = description; } public String getMusicUrl() { - return musicUrl; + return this.musicUrl; } public void setMusicUrl(String musicUrl) { this.musicUrl = musicUrl; } public String getHqMusicUrl() { - return hqMusicUrl; + return this.hqMusicUrl; } public void setHqMusicUrl(String hqMusicUrl) { this.hqMusicUrl = hqMusicUrl; } public List getArticles() { - return articles; + return this.articles; } public void setArticles(List articles) { this.articles = articles; @@ -111,25 +113,25 @@ public static class WxArticle { private String picUrl; public String getTitle() { - return title; + return this.title; } public void setTitle(String title) { this.title = title; } public String getDescription() { - return description; + return this.description; } public void setDescription(String description) { this.description = description; } public String getUrl() { - return url; + return this.url; } public void setUrl(String url) { this.url = url; } public String getPicUrl() { - return picUrl; + return this.picUrl; } public void setPicUrl(String picUrl) { this.picUrl = picUrl; @@ -139,7 +141,6 @@ public void setPicUrl(String picUrl) { /** * 获得文本消息builder - * @return */ public static TextBuilder TEXT() { return new TextBuilder(); @@ -147,7 +148,6 @@ public static TextBuilder TEXT() { /** * 获得图片消息builder - * @return */ public static ImageBuilder IMAGE() { return new ImageBuilder(); @@ -155,7 +155,6 @@ public static ImageBuilder IMAGE() { /** * 获得语音消息builder - * @return */ public static VoiceBuilder VOICE() { return new VoiceBuilder(); @@ -163,7 +162,6 @@ public static VoiceBuilder VOICE() { /** * 获得视频消息builder - * @return */ public static VideoBuilder VIDEO() { return new VideoBuilder(); @@ -171,7 +169,6 @@ public static VideoBuilder VIDEO() { /** * 获得音乐消息builder - * @return */ public static MusicBuilder MUSIC() { return new MusicBuilder(); @@ -179,10 +176,17 @@ public static MusicBuilder MUSIC() { /** * 获得图文消息builder - * @return */ public static NewsBuilder NEWS() { return new NewsBuilder(); } + public String getKfAccount() { + return kfAccount; + } + + public void setKfAccount(String kfAccount) { + this.kfAccount = kfAccount; + } + } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java index 7ef2535ca3..38bd8ea7f0 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java @@ -12,8 +12,9 @@ * @author chanjarster */ public class WxMpMassOpenIdsMessage implements Serializable { + private static final long serialVersionUID = -8022910911104788999L; - private List toUsers = new ArrayList(); + private List toUsers = new ArrayList<>(); private String msgType; private String content; private String mediaId; @@ -23,7 +24,7 @@ public WxMpMassOpenIdsMessage() { } public String getMsgType() { - return msgType; + return this.msgType; } /** @@ -43,7 +44,7 @@ public void setMsgType(String msgType) { } public String getContent() { - return content; + return this.content; } public void setContent(String content) { @@ -51,7 +52,7 @@ public void setContent(String content) { } public String getMediaId() { - return mediaId; + return this.mediaId; } public void setMediaId(String mediaId) { @@ -64,10 +65,9 @@ public String toJson() { /** * OpenId列表,最多支持10,000个 - * @return */ public List getToUsers() { - return toUsers; + return this.toUsers; } /** diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlMessage.java index 9f42ffc701..823558fe79 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlMessage.java @@ -1,18 +1,24 @@ package me.chanjar.weixin.mp.bean; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import me.chanjar.weixin.mp.util.json.WxLongTimeJsonSerializer; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamConverter; + import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.mp.util.crypto.WxMpCryptUtil; import me.chanjar.weixin.mp.util.xml.XStreamTransformer; -import org.apache.commons.io.IOUtils; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; /** *
    @@ -28,46 +34,49 @@
     @XStreamAlias("xml")
     public class WxMpXmlMessage implements Serializable {
     
    +  private static final long serialVersionUID = -3586245291677274914L;
    +
       ///////////////////////
       // 以下都是微信推送过来的消息的xml的element所对应的属性
       ///////////////////////
     
       @XStreamAlias("ToUserName")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String toUserName;
     
       @XStreamAlias("FromUserName")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String fromUserName;
     
       @XStreamAlias("CreateTime")
    +  @JsonSerialize(using = WxLongTimeJsonSerializer.class)
       private Long createTime;
     
       @XStreamAlias("MsgType")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String msgType;
     
       @XStreamAlias("Content")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String content;
     
       @XStreamAlias("MsgId")
       private Long msgId;
     
       @XStreamAlias("PicUrl")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String picUrl;
     
       @XStreamAlias("MediaId")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String mediaId;
     
       @XStreamAlias("Format")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String format;
     
       @XStreamAlias("ThumbMediaId")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String thumbMediaId;
     
       @XStreamAlias("Location_X")
    @@ -80,31 +89,31 @@ public class WxMpXmlMessage implements Serializable {
       private Double scale;
     
       @XStreamAlias("Label")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String label;
     
       @XStreamAlias("Title")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String title;
     
       @XStreamAlias("Description")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String description;
     
       @XStreamAlias("Url")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String url;
     
       @XStreamAlias("Event")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String event;
     
       @XStreamAlias("EventKey")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String eventKey;
     
       @XStreamAlias("Ticket")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String ticket;
     
       @XStreamAlias("Latitude")
    @@ -117,7 +126,7 @@ public class WxMpXmlMessage implements Serializable {
       private Double precision;
     
       @XStreamAlias("Recognition")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String recognition;
     
       ///////////////////////////////////////
    @@ -127,7 +136,7 @@ public class WxMpXmlMessage implements Serializable {
        * 群发的结果
        */
       @XStreamAlias("Status")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String status;
       /**
        * group_id下粉丝数;或者openid_list中的粉丝数
    @@ -150,26 +159,45 @@ public class WxMpXmlMessage implements Serializable {
       @XStreamAlias("ErrorCount")
       private Integer errorCount;
     
    +  ///////////////////////////////////////
    +  // 客服会话管理相关事件推送
    +  ///////////////////////////////////////
    +  /**
    +   * 创建或关闭客服会话时的客服帐号
    +   */
    +  @XStreamAlias("KfAccount")
    +  private String kfAccount;
    +  /**
    +   * 转接客服会话时的转入客服帐号
    +   */
    +  @XStreamAlias("ToKfAccount")
    +  private String toKfAccount;
    +  /**
    +   * 转接客服会话时的转出客服帐号
    +   */
    +  @XStreamAlias("FromKfAccount")
    +  private String fromKfAccount;
    +
       ///////////////////////////////////////
       // 卡券相关事件推送
       ///////////////////////////////////////
       @XStreamAlias("CardId")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String cardId;
     
       @XStreamAlias("FriendUserName")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String friendUserName;
     
       @XStreamAlias("IsGiveByFriend")
       private Integer isGiveByFriend; // 是否为转赠,1代表是,0代表否
     
       @XStreamAlias("UserCardCode")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String userCardCode;
     
       @XStreamAlias("OldUserCardCode")
    -  @XStreamConverter(value=XStreamCDataConverter.class)
    +  @XStreamConverter(value = XStreamCDataConverter.class)
       private String oldUserCardCode;
     
       @XStreamAlias("OuterId")
    @@ -185,7 +213,7 @@ public class WxMpXmlMessage implements Serializable {
       private SendLocationInfo sendLocationInfo = new SendLocationInfo();
     
       public String getToUserName() {
    -    return toUserName;
    +    return this.toUserName;
       }
     
       public void setToUserName(String toUserName) {
    @@ -193,7 +221,7 @@ public void setToUserName(String toUserName) {
       }
     
       public Long getCreateTime() {
    -    return createTime;
    +    return this.createTime;
       }
     
       public void setCreateTime(Long createTime) {
    @@ -212,10 +240,9 @@ public void setCreateTime(Long createTime) {
        * {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_EVENT}
        * 
    * - * @return */ public String getMsgType() { - return msgType; + return this.msgType; } /** @@ -236,7 +263,7 @@ public void setMsgType(String msgType) { } public String getContent() { - return content; + return this.content; } public void setContent(String content) { @@ -244,7 +271,7 @@ public void setContent(String content) { } public Long getMsgId() { - return msgId; + return this.msgId; } public void setMsgId(Long msgId) { @@ -252,7 +279,7 @@ public void setMsgId(Long msgId) { } public String getPicUrl() { - return picUrl; + return this.picUrl; } public void setPicUrl(String picUrl) { @@ -260,7 +287,7 @@ public void setPicUrl(String picUrl) { } public String getMediaId() { - return mediaId; + return this.mediaId; } public void setMediaId(String mediaId) { @@ -268,7 +295,7 @@ public void setMediaId(String mediaId) { } public String getFormat() { - return format; + return this.format; } public void setFormat(String format) { @@ -276,7 +303,7 @@ public void setFormat(String format) { } public String getThumbMediaId() { - return thumbMediaId; + return this.thumbMediaId; } public void setThumbMediaId(String thumbMediaId) { @@ -284,7 +311,7 @@ public void setThumbMediaId(String thumbMediaId) { } public Double getLocationX() { - return locationX; + return this.locationX; } public void setLocationX(Double locationX) { @@ -292,7 +319,7 @@ public void setLocationX(Double locationX) { } public Double getLocationY() { - return locationY; + return this.locationY; } public void setLocationY(Double locationY) { @@ -300,7 +327,7 @@ public void setLocationY(Double locationY) { } public Double getScale() { - return scale; + return this.scale; } public void setScale(Double scale) { @@ -308,7 +335,7 @@ public void setScale(Double scale) { } public String getLabel() { - return label; + return this.label; } public void setLabel(String label) { @@ -316,7 +343,7 @@ public void setLabel(String label) { } public String getTitle() { - return title; + return this.title; } public void setTitle(String title) { @@ -324,7 +351,7 @@ public void setTitle(String title) { } public String getDescription() { - return description; + return this.description; } public void setDescription(String description) { @@ -332,7 +359,7 @@ public void setDescription(String description) { } public String getUrl() { - return url; + return this.url; } public void setUrl(String url) { @@ -340,7 +367,7 @@ public void setUrl(String url) { } public String getEvent() { - return event; + return this.event; } public void setEvent(String event) { @@ -348,7 +375,7 @@ public void setEvent(String event) { } public String getEventKey() { - return eventKey; + return this.eventKey; } public void setEventKey(String eventKey) { @@ -356,7 +383,7 @@ public void setEventKey(String eventKey) { } public String getTicket() { - return ticket; + return this.ticket; } public void setTicket(String ticket) { @@ -364,7 +391,7 @@ public void setTicket(String ticket) { } public Double getLatitude() { - return latitude; + return this.latitude; } public void setLatitude(Double latitude) { @@ -372,7 +399,7 @@ public void setLatitude(Double latitude) { } public Double getLongitude() { - return longitude; + return this.longitude; } public void setLongitude(Double longitude) { @@ -380,7 +407,7 @@ public void setLongitude(Double longitude) { } public Double getPrecision() { - return precision; + return this.precision; } public void setPrecision(Double precision) { @@ -388,7 +415,7 @@ public void setPrecision(Double precision) { } public String getRecognition() { - return recognition; + return this.recognition; } public void setRecognition(String recognition) { @@ -396,7 +423,7 @@ public void setRecognition(String recognition) { } public String getFromUserName() { - return fromUserName; + return this.fromUserName; } public void setFromUserName(String fromUserName) { @@ -419,30 +446,29 @@ public static WxMpXmlMessage fromXml(InputStream is) { * @param timestamp * @param nonce * @param msgSignature - * @return */ - public static WxMpXmlMessage fromEncryptedXml( - String encryptedXml, - WxMpConfigStorage wxMpConfigStorage, - String timestamp, String nonce, String msgSignature) { + public static WxMpXmlMessage fromEncryptedXml(String encryptedXml, + WxMpConfigStorage wxMpConfigStorage, String timestamp, String nonce, + String msgSignature) { WxMpCryptUtil cryptUtil = new WxMpCryptUtil(wxMpConfigStorage); - String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, encryptedXml); + String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, + encryptedXml); return fromXml(plainText); } - public static WxMpXmlMessage fromEncryptedXml( - InputStream is, - WxMpConfigStorage wxMpConfigStorage, - String timestamp, String nonce, String msgSignature) { + public static WxMpXmlMessage fromEncryptedXml(InputStream is, + WxMpConfigStorage wxMpConfigStorage, String timestamp, String nonce, + String msgSignature) { try { - return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxMpConfigStorage, timestamp, nonce, msgSignature); + return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxMpConfigStorage, + timestamp, nonce, msgSignature); } catch (IOException e) { throw new RuntimeException(e); } } public String getStatus() { - return status; + return this.status; } public void setStatus(String status) { @@ -450,7 +476,7 @@ public void setStatus(String status) { } public Integer getTotalCount() { - return totalCount; + return this.totalCount; } public void setTotalCount(Integer totalCount) { @@ -458,7 +484,7 @@ public void setTotalCount(Integer totalCount) { } public Integer getFilterCount() { - return filterCount; + return this.filterCount; } public void setFilterCount(Integer filterCount) { @@ -466,7 +492,7 @@ public void setFilterCount(Integer filterCount) { } public Integer getSentCount() { - return sentCount; + return this.sentCount; } public void setSentCount(Integer sentCount) { @@ -474,7 +500,7 @@ public void setSentCount(Integer sentCount) { } public Integer getErrorCount() { - return errorCount; + return this.errorCount; } public void setErrorCount(Integer errorCount) { @@ -482,7 +508,7 @@ public void setErrorCount(Integer errorCount) { } public String getCardId() { - return cardId; + return this.cardId; } public void setCardId(String cardId) { @@ -490,7 +516,7 @@ public void setCardId(String cardId) { } public String getFriendUserName() { - return friendUserName; + return this.friendUserName; } public void setFriendUserName(String friendUserName) { @@ -498,7 +524,7 @@ public void setFriendUserName(String friendUserName) { } public Integer getIsGiveByFriend() { - return isGiveByFriend; + return this.isGiveByFriend; } public void setIsGiveByFriend(Integer isGiveByFriend) { @@ -506,7 +532,7 @@ public void setIsGiveByFriend(Integer isGiveByFriend) { } public String getUserCardCode() { - return userCardCode; + return this.userCardCode; } public void setUserCardCode(String userCardCode) { @@ -514,7 +540,7 @@ public void setUserCardCode(String userCardCode) { } public String getOldUserCardCode() { - return oldUserCardCode; + return this.oldUserCardCode; } public void setOldUserCardCode(String oldUserCardCode) { @@ -522,7 +548,7 @@ public void setOldUserCardCode(String oldUserCardCode) { } public Integer getOuterId() { - return outerId; + return this.outerId; } public void setOuterId(Integer outerId) { @@ -530,7 +556,7 @@ public void setOuterId(Integer outerId) { } public WxMpXmlMessage.ScanCodeInfo getScanCodeInfo() { - return scanCodeInfo; + return this.scanCodeInfo; } public void setScanCodeInfo(WxMpXmlMessage.ScanCodeInfo scanCodeInfo) { @@ -538,7 +564,7 @@ public void setScanCodeInfo(WxMpXmlMessage.ScanCodeInfo scanCodeInfo) { } public WxMpXmlMessage.SendPicsInfo getSendPicsInfo() { - return sendPicsInfo; + return this.sendPicsInfo; } public void setSendPicsInfo(WxMpXmlMessage.SendPicsInfo sendPicsInfo) { @@ -546,31 +572,59 @@ public void setSendPicsInfo(WxMpXmlMessage.SendPicsInfo sendPicsInfo) { } public WxMpXmlMessage.SendLocationInfo getSendLocationInfo() { - return sendLocationInfo; + return this.sendLocationInfo; } - public void setSendLocationInfo(WxMpXmlMessage.SendLocationInfo sendLocationInfo) { + public void setSendLocationInfo( + WxMpXmlMessage.SendLocationInfo sendLocationInfo) { this.sendLocationInfo = sendLocationInfo; } + public String getKfAccount() { + return this.kfAccount; + } + + public void setKfAccount(String kfAccount) { + this.kfAccount = kfAccount; + } + + public String getToKfAccount() { + return this.toKfAccount; + } + + public void setToKfAccount(String toKfAccount) { + this.toKfAccount = toKfAccount; + } + + public String getFromKfAccount() { + return this.fromKfAccount; + } + + public void setFromKfAccount(String fromKfAccount) { + this.fromKfAccount = fromKfAccount; + } + @XStreamAlias("ScanCodeInfo") public static class ScanCodeInfo { + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } @XStreamAlias("ScanType") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String scanType; @XStreamAlias("ScanResult") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String scanResult; /** * 扫描类型,一般是qrcode - * @return */ public String getScanType() { - return scanType; + return this.scanType; } public void setScanType(String scanType) { @@ -579,10 +633,9 @@ public void setScanType(String scanType) { /** * 扫描结果,即二维码对应的字符串信息 - * @return */ public String getScanResult() { - return scanResult; + return this.scanResult; } public void setScanResult(String scanResult) { @@ -593,15 +646,19 @@ public void setScanResult(String scanResult) { @XStreamAlias("SendPicsInfo") public static class SendPicsInfo { + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } @XStreamAlias("Count") private Long count; @XStreamAlias("PicList") - protected final List picList = new ArrayList(); + protected final List picList = new ArrayList<>(); public Long getCount() { - return count; + return this.count; } public void setCount(Long count) { @@ -609,18 +666,23 @@ public void setCount(Long count) { } public List getPicList() { - return picList; + return this.picList; } @XStreamAlias("item") public static class Item { + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, + ToStringStyle.JSON_STYLE); + } @XStreamAlias("PicMd5Sum") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String picMd5Sum; public String getPicMd5Sum() { - return picMd5Sum; + return this.picMd5Sum; } public void setPicMd5Sum(String picMd5Sum) { @@ -633,27 +695,32 @@ public void setPicMd5Sum(String picMd5Sum) { public static class SendLocationInfo { @XStreamAlias("Location_X") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String locationX; @XStreamAlias("Location_Y") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String locationY; @XStreamAlias("Scale") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String scale; @XStreamAlias("Label") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String label; @XStreamAlias("Poiname") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String poiname; + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } + public String getLocationX() { - return locationX; + return this.locationX; } public void setLocationX(String locationX) { @@ -661,7 +728,7 @@ public void setLocationX(String locationX) { } public String getLocationY() { - return locationY; + return this.locationY; } public void setLocationY(String locationY) { @@ -669,7 +736,7 @@ public void setLocationY(String locationY) { } public String getScale() { - return scale; + return this.scale; } public void setScale(String scale) { @@ -677,7 +744,7 @@ public void setScale(String scale) { } public String getLabel() { - return label; + return this.label; } public void setLabel(String label) { @@ -685,7 +752,7 @@ public void setLabel(String label) { } public String getPoiname() { - return poiname; + return this.poiname; } public void setPoiname(String poiname) { @@ -695,44 +762,6 @@ public void setPoiname(String poiname) { @Override public String toString() { - return "WxMpXmlMessage{" + - "toUserName='" + toUserName + '\'' + - ", fromUserName='" + fromUserName + '\'' + - ", createTime=" + createTime + - ", msgType='" + msgType + '\'' + - ", content='" + content + '\'' + - ", msgId=" + msgId + - ", picUrl='" + picUrl + '\'' + - ", mediaId='" + mediaId + '\'' + - ", format='" + format + '\'' + - ", thumbMediaId='" + thumbMediaId + '\'' + - ", locationX=" + locationX + - ", locationY=" + locationY + - ", scale=" + scale + - ", label='" + label + '\'' + - ", title='" + title + '\'' + - ", description='" + description + '\'' + - ", url='" + url + '\'' + - ", event='" + event + '\'' + - ", eventKey='" + eventKey + '\'' + - ", ticket='" + ticket + '\'' + - ", latitude=" + latitude + - ", longitude=" + longitude + - ", precision=" + precision + - ", recognition='" + recognition + '\'' + - ", status='" + status + '\'' + - ", totalCount=" + totalCount + - ", filterCount=" + filterCount + - ", sentCount=" + sentCount + - ", errorCount=" + errorCount + - ", cardId='" + cardId + '\'' + - ", isGiveByFriend=" + isGiveByFriend + - ", userCardCode='" + userCardCode + '\'' + - ", oldUserCardCode='" + oldUserCardCode + '\'' + - ", outerId=" + outerId + - ", scanCodeInfo=" + scanCodeInfo + - ", sendPicsInfo=" + sendPicsInfo + - ", sendLocationInfo=" + sendLocationInfo + - '}'; + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMessage.java index bca8c143d8..2eb6818b30 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMessage.java @@ -13,6 +13,8 @@ @XStreamAlias("xml") public abstract class WxMpXmlOutMessage implements Serializable { + private static final long serialVersionUID = -381382011286216263L; + @XStreamAlias("ToUserName") @XStreamConverter(value=XStreamCDataConverter.class) protected String toUserName; @@ -29,7 +31,7 @@ public abstract class WxMpXmlOutMessage implements Serializable { protected String msgType; public String getToUserName() { - return toUserName; + return this.toUserName; } public void setToUserName(String toUserName) { @@ -37,7 +39,7 @@ public void setToUserName(String toUserName) { } public String getFromUserName() { - return fromUserName; + return this.fromUserName; } public void setFromUserName(String fromUserName) { @@ -45,7 +47,7 @@ public void setFromUserName(String fromUserName) { } public Long getCreateTime() { - return createTime; + return this.createTime; } public void setCreateTime(Long createTime) { @@ -53,7 +55,7 @@ public void setCreateTime(Long createTime) { } public String getMsgType() { - return msgType; + return this.msgType; } public void setMsgType(String msgType) { @@ -61,12 +63,11 @@ public void setMsgType(String msgType) { } public String toXml() { - return XStreamTransformer.toXml((Class) this.getClass(), this); + return XStreamTransformer.toXml((Class) this.getClass(), this); } /** * 转换成加密的xml格式 - * @return */ public String toEncryptedXml(WxMpConfigStorage wxMpConfigStorage) { String plainXml = toXml(); @@ -76,7 +77,6 @@ public String toEncryptedXml(WxMpConfigStorage wxMpConfigStorage) { /** * 获得文本消息builder - * @return */ public static TextBuilder TEXT() { return new TextBuilder(); @@ -84,7 +84,6 @@ public static TextBuilder TEXT() { /** * 获得图片消息builder - * @return */ public static ImageBuilder IMAGE() { return new ImageBuilder(); @@ -92,7 +91,6 @@ public static ImageBuilder IMAGE() { /** * 获得语音消息builder - * @return */ public static VoiceBuilder VOICE() { return new VoiceBuilder(); @@ -100,7 +98,6 @@ public static VoiceBuilder VOICE() { /** * 获得视频消息builder - * @return */ public static VideoBuilder VIDEO() { return new VideoBuilder(); @@ -108,7 +105,6 @@ public static VideoBuilder VIDEO() { /** * 获得音乐消息builder - * @return */ public static MusicBuilder MUSIC() { return new MusicBuilder(); @@ -116,15 +112,13 @@ public static MusicBuilder MUSIC() { /** * 获得图文消息builder - * @return */ public static NewsBuilder NEWS() { return new NewsBuilder(); } - /** + + /** * 获得客服消息builder - * - * @return */ public static TransferCustomerServiceBuilder TRANSFER_CUSTOMER_SERVICE() { return new TransferCustomerServiceBuilder(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutTransferCustomerServiceMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutTransferCustomerServiceMessage.java index 67c3d28e25..a1a48bbe92 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutTransferCustomerServiceMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutTransferCustomerServiceMessage.java @@ -7,6 +7,8 @@ @XStreamAlias("xml") public class WxMpXmlOutTransferCustomerServiceMessage extends WxMpXmlOutMessage { + private static final long serialVersionUID = 1850903037285841322L; + @XStreamAlias("TransInfo") protected TransInfo transInfo; @@ -15,7 +17,7 @@ public WxMpXmlOutTransferCustomerServiceMessage() { } public TransInfo getTransInfo() { - return transInfo; + return this.transInfo; } public void setTransInfo(TransInfo transInfo) { @@ -30,7 +32,7 @@ public static class TransInfo { private String kfAccount; public String getKfAccount() { - return kfAccount; + return this.kfAccount; } public void setKfAccount(String kfAccount) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfAccountRequest.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfAccountRequest.java new file mode 100644 index 0000000000..b1f0fac8f0 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfAccountRequest.java @@ -0,0 +1,105 @@ +package me.chanjar.weixin.mp.bean.kefu.request; + +import java.io.Serializable; + +import org.apache.commons.lang3.builder.ToStringBuilder; + +import com.google.gson.annotations.SerializedName; + +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +public class WxMpKfAccountRequest implements Serializable { + private static final long serialVersionUID = -5451863610674856927L; + + /** + * kf_account 完整客服账号,格式为:账号前缀@公众号微信号 + */ + @SerializedName("kf_account") + private String kfAccount; + + /** + * nickname 客服昵称,最长6个汉字或12个英文字符 + */ + @SerializedName("nickname") + private String nickName; + + /** + * invite_wx 接收绑定邀请的客服微信号 + */ + @SerializedName("invite_wx") + private String inviteWx; + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + + public String toJson() { + return WxMpGsonBuilder.INSTANCE.create().toJson(this); + } + + public String getKfAccount() { + return this.kfAccount; + } + + public void setKfAccount(String kfAccount) { + this.kfAccount = kfAccount; + } + + public String getNickName() { + return this.nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public static Builder builder() { + return new Builder(); + } + + public String getInviteWx() { + return this.inviteWx; + } + + public void setInviteWx(String inviteWx) { + this.inviteWx = inviteWx; + } + + public static class Builder { + private String kfAccount; + private String nickName; + private String inviteWx; + + public Builder kfAccount(String kfAccount) { + this.kfAccount = kfAccount; + return this; + } + + public Builder nickName(String nickName) { + this.nickName = nickName; + return this; + } + + public Builder inviteWx(String inviteWx) { + this.inviteWx = inviteWx; + return this; + } + + public Builder from(WxMpKfAccountRequest origin) { + this.kfAccount(origin.kfAccount); + this.nickName(origin.nickName); + this.inviteWx(origin.inviteWx); + return this; + } + + public WxMpKfAccountRequest build() { + WxMpKfAccountRequest m = new WxMpKfAccountRequest(); + m.kfAccount = this.kfAccount; + m.nickName = this.nickName; + m.inviteWx = this.inviteWx; + return m; + } + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfSessionRequest.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfSessionRequest.java new file mode 100644 index 0000000000..e821916efe --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfSessionRequest.java @@ -0,0 +1,49 @@ +package me.chanjar.weixin.mp.bean.kefu.request; + +import java.io.Serializable; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.google.gson.annotations.SerializedName; + +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +public class WxMpKfSessionRequest implements Serializable { + private static final long serialVersionUID = -5451863610674856927L; + + /** + * kf_account 完整客服账号,格式为:账号前缀@公众号微信号 + */ + @SerializedName("kf_account") + private String kfAccount; + + /** + * openid 客户openid + */ + @SerializedName("openid") + private String openid; + + public WxMpKfSessionRequest(String kfAccount, String openid) { + this.kfAccount = kfAccount; + this.openid = openid; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } + + public String toJson() { + return WxMpGsonBuilder.INSTANCE.create().toJson(this); + } + + public String getKfAccount() { + return this.kfAccount; + } + + public void setKfAccount(String kfAccount) { + this.kfAccount = kfAccount; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfInfo.java new file mode 100644 index 0000000000..37154aa4ba --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfInfo.java @@ -0,0 +1,164 @@ +package me.chanjar.weixin.mp.bean.kefu.result; + +import java.io.Serializable; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +/** + * 客服基本信息以及客服在线状态信息 + * @author Binary Wang + * + */ +public class WxMpKfInfo implements Serializable { + private static final long serialVersionUID = -5877300750666022290L; + + /** + * kf_account 完整客服账号,格式为:账号前缀@公众号微信号 + */ + @SerializedName("kf_account") + private String account; + + /** + * kf_headimgurl 客服头像地址 + */ + @SerializedName("kf_headimgurl") + private String headImgUrl; + + /** + * kf_id 客服工号 + */ + @SerializedName("kf_id") + private String id; + + /** + * kf_nick 客服昵称 + */ + @SerializedName("kf_nick") + private String nick; + + /** + * kf_wx 如果客服帐号已绑定了客服人员微信号,则此处显示微信号 + */ + @SerializedName("kf_wx") + private String wxAccount; + + /** + * invite_wx 如果客服帐号尚未绑定微信号,但是已经发起了一个绑定邀请,则此处显示绑定邀请的微信号 + */ + @SerializedName("invite_wx") + private String inviteWx; + + /** + * invite_expire_time 如果客服帐号尚未绑定微信号,但是已经发起过一个绑定邀请,则此处显示为邀请的过期时间,为unix 时间戳 + */ + @SerializedName("invite_expire_time") + private Long inviteExpireTime; + + /** + * invite_status 邀请的状态,有等待确认“waiting”,被拒绝“rejected”,过期“expired” + */ + @SerializedName("invite_status") + private String inviteStatus; + + /** + * status 客服在线状态,目前为:1、web 在线 + */ + @SerializedName("status") + private Integer status; + + /** + * accepted_case 客服当前正在接待的会话数 + */ + @Expose + @SerializedName("accepted_case") + private Integer acceptedCase; + + public Integer getStatus() { + return this.status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getAcceptedCase() { + return this.acceptedCase; + } + + public void setAcceptedCase(Integer acceptedCase) { + this.acceptedCase = acceptedCase; + } + + public String getAccount() { + return this.account; + } + + public void setAccount(String account) { + this.account = account; + } + + public String getHeadImgUrl() { + return this.headImgUrl; + } + + public void setHeadImgUrl(String headImgUrl) { + this.headImgUrl = headImgUrl; + } + + public String getId() { + return this.id; + } + + public void setId(String id) { + this.id = id; + } + + public String getNick() { + return this.nick; + } + + public void setNick(String nick) { + this.nick = nick; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } + + public String getWxAccount() { + return this.wxAccount; + } + + public void setWxAccount(String wxAccount) { + this.wxAccount = wxAccount; + } + + public String getInviteWx() { + return this.inviteWx; + } + + public void setInviteWx(String inviteWx) { + this.inviteWx = inviteWx; + } + + public Long getInviteExpireTime() { + return this.inviteExpireTime; + } + + public void setInviteExpireTime(Long inviteExpireTime) { + this.inviteExpireTime = inviteExpireTime; + } + + public String getInviteStatus() { + return this.inviteStatus; + } + + public void setInviteStatus(String inviteStatus) { + this.inviteStatus = inviteStatus; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfList.java new file mode 100644 index 0000000000..062ff9ac9b --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfList.java @@ -0,0 +1,36 @@ +package me.chanjar.weixin.mp.bean.kefu.result; + +import java.util.List; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.google.gson.annotations.SerializedName; + +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +/** + * + * @author Binary Wang + * + */ +public class WxMpKfList { + @SerializedName("kf_list") + private List kfList; + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } + + public List getKfList() { + return this.kfList; + } + + public void setKfList(List kfList) { + this.kfList = kfList; + } + + public static WxMpKfList fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpKfList.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgList.java new file mode 100644 index 0000000000..5078a2e5cf --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgList.java @@ -0,0 +1,55 @@ +package me.chanjar.weixin.mp.bean.kefu.result; + +import com.google.gson.annotations.SerializedName; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import java.util.List; + +/** + * Created by Binary Wang on 2016/7/15. + */ +public class WxMpKfMsgList { + @SerializedName("recordlist") + private List records; + + @SerializedName("number") + private Integer number; + + @SerializedName("msgid") + private Long msgId; + + public List getRecords() { + return records; + } + + public void setRecords(List records) { + this.records = records; + } + + public Integer getNumber() { + return number; + } + + public void setNumber(Integer number) { + this.number = number; + } + + public Long getMsgId() { + return msgId; + } + + public void setMsgId(Long msgId) { + this.msgId = msgId; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } + + public static WxMpKfMsgList fromJson(String responseContent) { + return WxMpGsonBuilder.INSTANCE.create().fromJson(responseContent, WxMpKfMsgList.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgRecord.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgRecord.java new file mode 100644 index 0000000000..00b7771e5a --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgRecord.java @@ -0,0 +1,87 @@ +package me.chanjar.weixin.mp.bean.kefu.result; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.google.gson.annotations.SerializedName; +import me.chanjar.weixin.mp.util.json.WxLongTimeJsonSerializer; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * Created by Binary Wang on 2016/7/18. + */ +public class WxMpKfMsgRecord { + /** + * worker 完整客服帐号,格式为:帐号前缀@公众号微信号 + */ + @SerializedName("worker") + private String worker; + + /** + * openid 用户标识 + */ + @SerializedName("openid") + private String openid; + + /** + * opercode 操作码,2002(客服发送信息),2003(客服接收消息) + */ + @SerializedName("opercode") + private Integer operateCode; + + /** + * text 聊天记录 + */ + @SerializedName("text") + private String text; + + /** + * time 操作时间,unix时间戳 + */ + @SerializedName("time") + @JsonSerialize(using = WxLongTimeJsonSerializer.class) + private Long time; + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } + public String getWorker() { + return worker; + } + + public void setWorker(String worker) { + this.worker = worker; + } + + public String getOpenid() { + return openid; + } + + public void setOpenid(String openid) { + this.openid = openid; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public Long getTime() { + return time; + } + + public void setTime(Long time) { + this.time = time; + } + + public Integer getOperateCode() { + return operateCode; + } + + public void setOperateCode(Integer operateCode) { + this.operateCode = operateCode; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfOnlineList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfOnlineList.java new file mode 100644 index 0000000000..b4a418f671 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfOnlineList.java @@ -0,0 +1,36 @@ +package me.chanjar.weixin.mp.bean.kefu.result; + +import java.util.List; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.google.gson.annotations.SerializedName; + +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +/** + * + * @author Binary Wang + * + */ +public class WxMpKfOnlineList { + @SerializedName("kf_online_list") + private List kfOnlineList; + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } + + public List getKfOnlineList() { + return this.kfOnlineList; + } + + public void setKfOnlineList(List kfOnlineList) { + this.kfOnlineList = kfOnlineList; + } + + public static WxMpKfOnlineList fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpKfOnlineList.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSession.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSession.java new file mode 100644 index 0000000000..e29f45b802 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSession.java @@ -0,0 +1,76 @@ +package me.chanjar.weixin.mp.bean.kefu.result; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.google.gson.annotations.SerializedName; + +/** + * + * @author Binary Wang + * + */ +public class WxMpKfSession { + /** + * kf_account 正在接待的客服,为空表示没有人在接待 + */ + @SerializedName("kf_account") + private String kfAccount; + + /** + * createtime 会话接入的时间,UNIX时间戳 + * 该返回值 存在于 获取客服会话列表接口 + */ + @SerializedName("createtime") + private long createTime; + + /** + * latest_time 粉丝的最后一条消息的时间,UNIX时间戳 + * 该返回值 存在于 获取未接入会话列表接口 + */ + @SerializedName("latest_time") + private long latestTime; + + /** + * openid 客户openid + */ + @SerializedName("openid") + private String openid; + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } + + public String getKfAccount() { + return this.kfAccount; + } + + public void setKfAccount(String kfAccount) { + this.kfAccount = kfAccount; + } + + public long getCreateTime() { + return this.createTime; + } + + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + + public String getOpenid() { + return this.openid; + } + + public void setOpenid(String openid) { + this.openid = openid; + } + + public long getLatestTime() { + return this.latestTime; + } + + public void setLatestTime(long latestTime) { + this.latestTime = latestTime; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionGetResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionGetResult.java new file mode 100644 index 0000000000..22a6cf24ac --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionGetResult.java @@ -0,0 +1,53 @@ +package me.chanjar.weixin.mp.bean.kefu.result; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.google.gson.annotations.SerializedName; + +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +/** + * + * @author Binary Wang + * + */ +public class WxMpKfSessionGetResult { + /** + * kf_account 正在接待的客服,为空表示没有人在接待 + */ + @SerializedName("kf_account") + private String kfAccount; + + /** + * createtime 会话接入的时间 ,UNIX时间戳 + */ + @SerializedName("createtime") + private long createTime; + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } + + public static WxMpKfSessionGetResult fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpKfSessionGetResult.class); + } + + public String getKfAccount() { + return this.kfAccount; + } + + public void setKfAccount(String kfAccount) { + this.kfAccount = kfAccount; + } + + public long getCreateTime() { + return this.createTime; + } + + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionList.java new file mode 100644 index 0000000000..dea7e2434e --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionList.java @@ -0,0 +1,41 @@ +package me.chanjar.weixin.mp.bean.kefu.result; + +import java.util.List; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.google.gson.annotations.SerializedName; + +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +/** + * + * @author Binary Wang + * + */ +public class WxMpKfSessionList { + /** + * 会话列表 + */ + @SerializedName("sessionlist") + private List kfSessionList; + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } + + public static WxMpKfSessionList fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson(json, + WxMpKfSessionList.class); + } + + public List getKfSessionList() { + return this.kfSessionList; + } + + public void setKfSessionList(List kfSessionList) { + this.kfSessionList = kfSessionList; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionWaitCaseList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionWaitCaseList.java new file mode 100644 index 0000000000..dc2ab06b4e --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionWaitCaseList.java @@ -0,0 +1,48 @@ +package me.chanjar.weixin.mp.bean.kefu.result; + +import java.util.List; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.google.gson.annotations.SerializedName; + +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +/** + * + * @author Binary Wang + * + */ +public class WxMpKfSessionWaitCaseList { + /** + * count 未接入会话数量 + */ + @SerializedName("count") + private Long count; + + /** + * waitcaselist 未接入会话列表,最多返回100条数据 + */ + @SerializedName("waitcaselist") + private List kfSessionWaitCaseList; + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } + + public static WxMpKfSessionWaitCaseList fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson(json, + WxMpKfSessionWaitCaseList.class); + } + + public List getKfSessionWaitCaseList() { + return this.kfSessionWaitCaseList; + } + + public void setKfSessionWaitCaseList(List kfSessionWaitCaseList) { + this.kfSessionWaitCaseList = kfSessionWaitCaseList; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/TransferCustomerServiceBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/TransferCustomerServiceBuilder.java index d004eb566a..87ec3a047f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/TransferCustomerServiceBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/TransferCustomerServiceBuilder.java @@ -14,18 +14,18 @@ public final class TransferCustomerServiceBuilder extends BaseBuilder { private String kfAccount; - public TransferCustomerServiceBuilder kfAccount(String kfAccount) { - this.kfAccount = kfAccount; + public TransferCustomerServiceBuilder kfAccount(String kf) { + this.kfAccount = kf; return this; } - + @Override public WxMpXmlOutTransferCustomerServiceMessage build() { WxMpXmlOutTransferCustomerServiceMessage m = new WxMpXmlOutTransferCustomerServiceMessage(); setCommon(m); - if(StringUtils.isNotBlank(kfAccount)){ + if(StringUtils.isNotBlank(this.kfAccount)){ WxMpXmlOutTransferCustomerServiceMessage.TransInfo transInfo = new WxMpXmlOutTransferCustomerServiceMessage.TransInfo(); - transInfo.setKfAccount(kfAccount); + transInfo.setKfAccount(this.kfAccount); m.setTransInfo(transInfo); } return m; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpQrCodeTicket.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpQrCodeTicket.java index 562820c374..537b771c5c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpQrCodeTicket.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpQrCodeTicket.java @@ -45,4 +45,9 @@ public void setUrl(String url) { public static WxMpQrCodeTicket fromJson(String json) { return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpQrCodeTicket.class); } + + @Override + public String toString() { + return WxMpGsonBuilder.INSTANCE.create().toJson(this); + } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserList.java index 489d5bedb1..842f13270d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserList.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserList.java @@ -44,4 +44,9 @@ public void setNextOpenId(String nextOpenId) { public static WxMpUserList fromJson(String json) { return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpUserList.class); } + + @Override + public String toString() { + return WxMpGsonBuilder.INSTANCE.create().toJson(this); + } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxLongTimeJsonSerializer.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxLongTimeJsonSerializer.java new file mode 100644 index 0000000000..309c4b119c --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxLongTimeJsonSerializer.java @@ -0,0 +1,24 @@ +package me.chanjar.weixin.mp.util.json; + +import java.io.IOException; +import java.text.SimpleDateFormat; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +/** + * Created by Binary Wang on 2016/7/13. + */ +public class WxLongTimeJsonSerializer extends JsonSerializer { + private static SimpleDateFormat DF = new SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss"); + + @Override + public void serialize(Long value, JsonGenerator gen, + SerializerProvider serializers) + throws IOException, JsonProcessingException { + gen.writeString(DF.format(value * 1000)); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCustomMessageGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCustomMessageGsonAdapter.java index 3dc0515d59..4e72752a6f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCustomMessageGsonAdapter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCustomMessageGsonAdapter.java @@ -14,6 +14,8 @@ import java.lang.reflect.Type; +import org.apache.commons.lang3.StringUtils; + public class WxMpCustomMessageGsonAdapter implements JsonSerializer { public JsonElement serialize(WxMpCustomMessage message, Type typeOfSrc, JsonSerializationContext context) { @@ -73,6 +75,12 @@ public JsonElement serialize(WxMpCustomMessage message, Type typeOfSrc, JsonSeri messageJson.add("news", newsJsonObject); } + if (StringUtils.isNotBlank(message.getKfAccount())){ + JsonObject newsJsonObject = new JsonObject(); + newsJsonObject.addProperty("kf_account", message.getKfAccount()); + messageJson.add("customservice", newsJsonObject); + } + return messageJson; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/xml/XStreamTransformer.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/xml/XStreamTransformer.java index 254f2147ce..472bac55b9 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/xml/XStreamTransformer.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/xml/XStreamTransformer.java @@ -14,10 +14,6 @@ public class XStreamTransformer { /** * xml -> pojo - * - * @param clazz - * @param xml - * @return */ @SuppressWarnings("unchecked") public static T fromXml(Class clazz, String xml) { @@ -43,10 +39,6 @@ public static void register(Class clz,XStream xStream){ /** * pojo -> xml - * - * @param clazz - * @param object - * @return */ public static String toXml(Class clazz, T object) { return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object); diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/ApiTestModule.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/ApiTestModule.java index e6df8e3439..4980facad3 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/ApiTestModule.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/ApiTestModule.java @@ -1,24 +1,34 @@ package me.chanjar.weixin.mp.api; +import java.io.IOException; +import java.io.InputStream; + +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; +import org.apache.commons.lang3.builder.ToStringBuilder; + import com.google.inject.Binder; import com.google.inject.Module; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.annotations.XStreamAlias; -import me.chanjar.weixin.common.util.xml.XStreamInitializer; -import java.io.InputStream; +import me.chanjar.weixin.common.util.xml.XStreamInitializer; public class ApiTestModule implements Module { @Override public void configure(Binder binder) { - InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml"); - WxXmlMpInMemoryConfigStorage config = fromXml(WxXmlMpInMemoryConfigStorage.class, is1); - WxMpServiceImpl wxService = new WxMpServiceImpl(); - wxService.setWxMpConfigStorage(config); + try (InputStream is1 = ClassLoader + .getSystemResourceAsStream("test-config.xml")) { + WxXmlMpInMemoryConfigStorage config = fromXml( + WxXmlMpInMemoryConfigStorage.class, is1); + WxMpServiceImpl wxService = new WxMpServiceImpl(); + wxService.setWxMpConfigStorage(config); - binder.bind(WxMpServiceImpl.class).toInstance(wxService); - binder.bind(WxMpConfigStorage.class).toInstance(config); + binder.bind(WxMpServiceImpl.class).toInstance(wxService); + binder.bind(WxMpConfigStorage.class).toInstance(config); + } catch (IOException e) { + e.printStackTrace(); + } } public static T fromXml(Class clazz, InputStream is) { @@ -29,22 +39,33 @@ public static T fromXml(Class clazz, InputStream is) { } @XStreamAlias("xml") - public static class WxXmlMpInMemoryConfigStorage extends WxMpInMemoryConfigStorage { - - protected String openId; + public static class WxXmlMpInMemoryConfigStorage + extends WxMpInMemoryConfigStorage { + + private String openId; + private String kfAccount; public String getOpenId() { - return openId; + return this.openId; } + public void setOpenId(String openId) { this.openId = openId; } + @Override public String toString() { - return "SimpleWxConfigProvider [appId=" + appId + ", secret=" + secret + ", accessToken=" + accessToken - + ", expiresTime=" + expiresTime + ", token=" + token + ", openId=" + openId + "]"; + return ToStringBuilder.reflectionToString(this); + } + + public String getKfAccount() { + return this.kfAccount; } - + + public void setKfAccount(String kfAccount) { + this.kfAccount = kfAccount; + } + } - + } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBaseAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBaseAPITest.java index 49d056af2f..7caaee5078 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBaseAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBaseAPITest.java @@ -3,6 +3,7 @@ import com.google.inject.Inject; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.StringUtils; +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; import org.testng.Assert; import org.testng.annotations.Guice; import org.testng.annotations.Test; @@ -20,7 +21,7 @@ public class WxMpBaseAPITest { protected WxMpServiceImpl wxService; public void testRefreshAccessToken() throws WxErrorException { - WxMpConfigStorage configStorage = this.wxService.wxMpConfigStorage; + WxMpConfigStorage configStorage = this.wxService.getWxMpConfigStorage(); String before = configStorage.getAccessToken(); this.wxService.getAccessToken(false); diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java index 2e16723aed..c9edbdc534 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java @@ -3,6 +3,7 @@ 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; diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpCustomMessageAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpCustomMessageAPITest.java index d0d9cde23c..4cca2e3c67 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpCustomMessageAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpCustomMessageAPITest.java @@ -3,6 +3,7 @@ import com.google.inject.Inject; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; import me.chanjar.weixin.mp.bean.WxMpCustomMessage; import org.testng.annotations.Guice; import org.testng.annotations.Test; @@ -12,7 +13,7 @@ * @author chanjarster * */ -@Test(groups="customMessageAPI", dependsOnGroups = "baseAPI") +@Test(groups="customMessageAPI") @Guice(modules = ApiTestModule.class) public class WxMpCustomMessageAPITest { @@ -20,13 +21,24 @@ public class WxMpCustomMessageAPITest { protected WxMpServiceImpl wxService; public void testSendCustomMessage() throws WxErrorException { - ApiTestModule.WxXmlMpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.wxMpConfigStorage; + ApiTestModule.WxXmlMpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.getWxMpConfigStorage(); WxMpCustomMessage message = new WxMpCustomMessage(); message.setMsgType(WxConsts.CUSTOM_MSG_TEXT); message.setToUser(configStorage.getOpenId()); message.setContent("欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World"); - wxService.customMessageSend(message); + this.wxService.customMessageSend(message); + } + + public void testSendCustomMessageWithKfAccount() throws WxErrorException { + ApiTestModule.WxXmlMpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.getWxMpConfigStorage(); + WxMpCustomMessage message = new WxMpCustomMessage(); + message.setMsgType(WxConsts.CUSTOM_MSG_TEXT); + message.setToUser(configStorage.getOpenId()); + message.setKfAccount(configStorage.getKfAccount()); + message.setContent("欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World"); + + this.wxService.customMessageSend(message); } } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpJsAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpJsAPITest.java index 16506caa9f..dacc2ab8a7 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpJsAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpJsAPITest.java @@ -3,13 +3,12 @@ import com.google.inject.Inject; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.crypto.SHA1; -import me.chanjar.weixin.mp.bean.WxMpGroup; +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; import org.testng.Assert; import org.testng.annotations.Guice; import org.testng.annotations.Test; import java.security.NoSuchAlgorithmException; -import java.util.List; /** * 测试jsapi ticket接口 diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMassMessageAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMassMessageAPITest.java index 73ebd1e2d3..5b50b5a44e 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMassMessageAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMassMessageAPITest.java @@ -4,6 +4,7 @@ import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; import me.chanjar.weixin.mp.bean.WxMpMassGroupMessage; import me.chanjar.weixin.mp.bean.WxMpMassNews; import me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage; @@ -33,7 +34,7 @@ public class WxMpMassMessageAPITest { @Test public void testTextMassOpenIdsMessageSend() throws WxErrorException { // 发送群发消息 - ApiTestModule.WxXmlMpInMemoryConfigStorage configProvider = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.wxMpConfigStorage; + ApiTestModule.WxXmlMpInMemoryConfigStorage configProvider = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.getWxMpConfigStorage(); WxMpMassOpenIdsMessage massMessage = new WxMpMassOpenIdsMessage(); massMessage.setMsgType(WxConsts.MASS_MSG_TEXT); massMessage.setContent("测试群发消息\n欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World"); @@ -47,7 +48,7 @@ public void testTextMassOpenIdsMessageSend() throws WxErrorException { @Test(dataProvider="massMessages") public void testMediaMassOpenIdsMessageSend(String massMsgType, String mediaId) throws WxErrorException, IOException { // 发送群发消息 - ApiTestModule.WxXmlMpInMemoryConfigStorage configProvider = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.wxMpConfigStorage; + ApiTestModule.WxXmlMpInMemoryConfigStorage configProvider = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.getWxMpConfigStorage(); WxMpMassOpenIdsMessage massMessage = new WxMpMassOpenIdsMessage(); massMessage.setMsgType(massMsgType); massMessage.setMediaId(mediaId); @@ -63,7 +64,7 @@ public void testTextMassGroupMessageSend() throws WxErrorException { WxMpMassGroupMessage massMessage = new WxMpMassGroupMessage(); massMessage.setMsgtype(WxConsts.MASS_MSG_TEXT); massMessage.setContent("测试群发消息\n欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World"); - massMessage.setGroupId(wxService.groupGet().get(0).getId()); + massMessage.setGroupId(wxService.getGroupService().groupGet().get(0).getId()); WxMpMassSendResult massResult = wxService.massGroupMessageSend(massMessage); Assert.assertNotNull(massResult); @@ -75,7 +76,7 @@ public void testMediaMassGroupMessageSend(String massMsgType, String mediaId) th WxMpMassGroupMessage massMessage = new WxMpMassGroupMessage(); massMessage.setMsgtype(massMsgType); massMessage.setMediaId(mediaId); - massMessage.setGroupId(wxService.groupGet().get(0).getId()); + massMessage.setGroupId(wxService.getGroupService().groupGet().get(0).getId()); WxMpMassSendResult massResult = wxService.massGroupMessageSend(massMessage); Assert.assertNotNull(massResult); @@ -91,7 +92,7 @@ public Object[][] massMessages() throws WxErrorException, IOException { { // 上传视频到媒体库 InputStream inputStream = ClassLoader.getSystemResourceAsStream("mm.mp4"); - WxMediaUploadResult uploadMediaRes = wxService.mediaUpload(WxConsts.MEDIA_VIDEO, WxConsts.FILE_MP4, inputStream); + WxMediaUploadResult uploadMediaRes = wxService.getMaterialService().mediaUpload(WxConsts.MEDIA_VIDEO, WxConsts.FILE_MP4, inputStream); Assert.assertNotNull(uploadMediaRes); Assert.assertNotNull(uploadMediaRes.getMediaId()); @@ -110,7 +111,7 @@ public Object[][] massMessages() throws WxErrorException, IOException { */ { InputStream inputStream = ClassLoader.getSystemResourceAsStream("mm.jpeg"); - WxMediaUploadResult uploadMediaRes = wxService.mediaUpload(WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, inputStream); + WxMediaUploadResult uploadMediaRes = wxService.getMaterialService().mediaUpload(WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, inputStream); Assert.assertNotNull(uploadMediaRes); Assert.assertNotNull(uploadMediaRes.getMediaId()); messages[1] = new Object[] { WxConsts.MASS_MSG_IMAGE, uploadMediaRes.getMediaId() }; @@ -120,7 +121,7 @@ public Object[][] massMessages() throws WxErrorException, IOException { */ { InputStream inputStream = ClassLoader.getSystemResourceAsStream("mm.mp3"); - WxMediaUploadResult uploadMediaRes = wxService.mediaUpload(WxConsts.MEDIA_VOICE, WxConsts.FILE_MP3, inputStream); + WxMediaUploadResult uploadMediaRes = wxService.getMaterialService().mediaUpload(WxConsts.MEDIA_VOICE, WxConsts.FILE_MP3, inputStream); Assert.assertNotNull(uploadMediaRes); Assert.assertNotNull(uploadMediaRes.getMediaId()); messages[2] = new Object[] { WxConsts.MASS_MSG_VOICE, uploadMediaRes.getMediaId() }; @@ -131,7 +132,7 @@ public Object[][] massMessages() throws WxErrorException, IOException { { // 上传照片到媒体库 InputStream inputStream = ClassLoader.getSystemResourceAsStream("mm.jpeg"); - WxMediaUploadResult uploadMediaRes = wxService.mediaUpload(WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, inputStream); + WxMediaUploadResult uploadMediaRes = wxService.getMaterialService().mediaUpload(WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, inputStream); Assert.assertNotNull(uploadMediaRes); Assert.assertNotNull(uploadMediaRes.getMediaId()); diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMediaAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMediaAPITest.java deleted file mode 100644 index b2fbc85144..0000000000 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMediaAPITest.java +++ /dev/null @@ -1,73 +0,0 @@ -package me.chanjar.weixin.mp.api; - -import com.google.inject.Inject; -import me.chanjar.weixin.common.api.WxConsts; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; -import me.chanjar.weixin.common.exception.WxErrorException; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - -/** - * 测试多媒体文件上传下载 - * @author chanjarster - * - */ -@Test(groups="mediaAPI", dependsOnGroups="baseAPI") -@Guice(modules = ApiTestModule.class) -public class WxMpMediaAPITest { - - @Inject - protected WxMpServiceImpl wxService; - - private List media_ids = new ArrayList<>(); - - @Test(dataProvider="uploadMedia") - public void testUploadMedia(String mediaType, String fileType, String fileName) throws WxErrorException, IOException { - try(InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName)){ - WxMediaUploadResult res = this.wxService.mediaUpload(mediaType, fileType, inputStream); - Assert.assertNotNull(res.getType()); - Assert.assertNotNull(res.getCreatedAt()); - Assert.assertTrue(res.getMediaId() != null || res.getThumbMediaId() != null); - - if (res.getMediaId() != null) { - this.media_ids.add(res.getMediaId()); - } - - if (res.getThumbMediaId() != null) { - this.media_ids.add(res.getThumbMediaId()); - } - } - } - - @DataProvider - public Object[][] uploadMedia() { - return new Object[][] { - new Object[] { WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, "mm.jpeg" }, - new Object[] { WxConsts.MEDIA_VOICE, WxConsts.FILE_MP3, "mm.mp3" }, - new Object[] { WxConsts.MEDIA_VIDEO, WxConsts.FILE_MP4, "mm.mp4" }, - new Object[] { WxConsts.MEDIA_THUMB, WxConsts.FILE_JPG, "mm.jpeg" } - }; - } - - @Test(dependsOnMethods = { "testUploadMedia" }, dataProvider="downloadMedia") - public void testDownloadMedia(String media_id) throws WxErrorException { - this.wxService.mediaDownload(media_id); - } - - @DataProvider - public Object[][] downloadMedia() { - Object[][] params = new Object[this.media_ids.size()][]; - for (int i = 0; i < this.media_ids.size(); i++) { - params[i] = new Object[] { this.media_ids.get(i) }; - } - return params; - } - -} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMiscAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMiscAPITest.java index 5f2a73926d..3d80836f9f 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMiscAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMiscAPITest.java @@ -1,37 +1,20 @@ package me.chanjar.weixin.mp.api; import com.google.inject.Inject; -import me.chanjar.weixin.common.api.WxConsts; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.session.WxSession; -import me.chanjar.weixin.mp.bean.WxMpMassGroupMessage; -import me.chanjar.weixin.mp.bean.WxMpMassNews; -import me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage; -import me.chanjar.weixin.mp.bean.WxMpMassVideo; -import me.chanjar.weixin.mp.bean.result.WxMpMassSendResult; -import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult; -import me.chanjar.weixin.mp.bean.result.WxMpUserCumulate; -import me.chanjar.weixin.mp.bean.result.WxMpUserSummary; +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; import org.testng.Assert; -import org.testng.annotations.DataProvider; import org.testng.annotations.Guice; import org.testng.annotations.Test; -import java.io.IOException; -import java.io.InputStream; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.Arrays; -import java.util.Date; -import java.util.List; /** * * @author chanjarster * */ -@Test(groups = "miscAPI", dependsOnGroups = { "baseAPI"}) +@Test(groups = "miscAPI") @Guice(modules = ApiTestModule.class) public class WxMpMiscAPITest { @@ -46,24 +29,4 @@ public void testGetCallbackIP() throws WxErrorException { Assert.assertNotEquals(ipArray.length, 0); } - @Test - public void testGetUserSummary() throws WxErrorException, ParseException { - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); - Date beginDate = simpleDateFormat.parse("2015-01-01"); - Date endDate = simpleDateFormat.parse("2015-01-02"); - List summaries = wxService.getUserSummary(beginDate, endDate); - System.out.println(summaries); - Assert.assertNotNull(summaries); - } - - @Test - public void testGetUserCumulate() throws WxErrorException, ParseException { - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); - Date beginDate = simpleDateFormat.parse("2015-01-01"); - Date endDate = simpleDateFormat.parse("2015-01-02"); - List cumulates = wxService.getUserCumulate(beginDate, endDate); - System.out.println(cumulates); - Assert.assertNotNull(cumulates); - } - } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpShortUrlAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpShortUrlAPITest.java index fb97f2d4ec..091f62eeb4 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpShortUrlAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpShortUrlAPITest.java @@ -2,6 +2,7 @@ import com.google.inject.Inject; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; import org.testng.Assert; import org.testng.annotations.Guice; import org.testng.annotations.Test; @@ -11,7 +12,7 @@ * * @author chanjarster */ -@Test(groups = "shortURLAPI", dependsOnGroups = { "baseAPI" }) +@Test(groups = "shortURLAPI") @Guice(modules = ApiTestModule.class) public class WxMpShortUrlAPITest { diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpUserAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpUserAPITest.java deleted file mode 100644 index fa978c57bc..0000000000 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpUserAPITest.java +++ /dev/null @@ -1,53 +0,0 @@ -package me.chanjar.weixin.mp.api; - -import com.google.inject.Inject; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.mp.bean.result.WxMpUser; -import me.chanjar.weixin.mp.bean.result.WxMpUserList; -import org.testng.Assert; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; - -/** - * 测试用户相关的接口 - * @author chanjarster - * - */ -@Test(groups = "userAPI", dependsOnGroups = { "baseAPI", "groupAPI" }) -@Guice(modules = ApiTestModule.class) -public class WxMpUserAPITest { - - @Inject - protected WxMpServiceImpl wxService; - - public void testUserUpdateRemark() throws WxErrorException { - ApiTestModule.WxXmlMpInMemoryConfigStorage configProvider = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.wxMpConfigStorage; - wxService.userUpdateRemark(configProvider.getOpenId(), "测试备注名"); - } - - public void testUserInfo() throws WxErrorException { - ApiTestModule.WxXmlMpInMemoryConfigStorage configProvider = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.wxMpConfigStorage; - WxMpUser user = wxService.userInfo(configProvider.getOpenId(), null); - Assert.assertNotNull(user); - } - - public void testUserList() throws WxErrorException { - WxMpUserList wxMpUserList = wxService.userList(null); - Assert.assertNotNull(wxMpUserList); - Assert.assertFalse(wxMpUserList.getCount() == -1); - Assert.assertFalse(wxMpUserList.getTotal() == -1); - Assert.assertFalse(wxMpUserList.getOpenIds().size() == -1); - } - - public void testGroupQueryUserGroup() throws WxErrorException { - ApiTestModule.WxXmlMpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.wxMpConfigStorage; - long groupid = wxService.userGetGroup(configStorage.getOpenId()); - Assert.assertTrue(groupid != -1l); - } - - public void getGroupMoveUser() throws WxErrorException { - ApiTestModule.WxXmlMpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.wxMpConfigStorage; - wxService.userUpdateGroup(configStorage.getOpenId(), wxService.groupGet().get(3).getId()); - } - -} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpGroupAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGroupServiceImplTest.java similarity index 73% rename from weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpGroupAPITest.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGroupServiceImplTest.java index 4397e05701..f2dd8f645f 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpGroupAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGroupServiceImplTest.java @@ -1,7 +1,8 @@ -package me.chanjar.weixin.mp.api; +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.bean.WxMpGroup; import org.testng.Assert; import org.testng.annotations.Guice; @@ -14,9 +15,9 @@ * * @author chanjarster */ -@Test(groups = "groupAPI", dependsOnGroups = "baseAPI") +@Test(groups = "groupAPI") @Guice(modules = ApiTestModule.class) -public class WxMpGroupAPITest { +public class WxMpGroupServiceImplTest { @Inject protected WxMpServiceImpl wxService; @@ -24,13 +25,13 @@ public class WxMpGroupAPITest { protected WxMpGroup group; public void testGroupCreate() throws WxErrorException { - WxMpGroup res = wxService.groupCreate("测试分组1"); + WxMpGroup res = this.wxService.getGroupService().groupCreate("测试分组1"); Assert.assertEquals(res.getName(), "测试分组1"); } @Test(dependsOnMethods="testGroupCreate") public void testGroupGet() throws WxErrorException { - List groupList = wxService.groupGet(); + List groupList = this.wxService.getGroupService().groupGet(); Assert.assertNotNull(groupList); Assert.assertTrue(groupList.size() > 0); for (WxMpGroup g : groupList) { @@ -42,7 +43,7 @@ public void testGroupGet() throws WxErrorException { @Test(dependsOnMethods={"testGroupGet", "testGroupCreate"}) public void getGroupUpdate() throws WxErrorException { group.setName("分组改名"); - wxService.groupUpdate(group); + this.wxService.getGroupService().groupUpdate(group); } } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImplTest.java new file mode 100644 index 0000000000..c1812ab064 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImplTest.java @@ -0,0 +1,169 @@ +package me.chanjar.weixin.mp.api.impl; + +import java.io.File; +import java.util.Date; + +import org.joda.time.DateTime; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +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.ApiTestModule.WxXmlMpInMemoryConfigStorage; +import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfInfo; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfMsgList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfOnlineList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionGetResult; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionWaitCaseList; + +/** + * 测试客服相关接口 + * @author Binary Wang + * + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMpKefuServiceImplTest { + + @Inject + protected WxMpServiceImpl wxService; + + public void testKfList() throws WxErrorException { + WxMpKfList kfList = this.wxService.getKefuService().kfList(); + Assert.assertNotNull(kfList); + for (WxMpKfInfo k : kfList.getKfList()) { + System.err.println(k); + } + } + + public void testKfOnlineList() throws WxErrorException { + WxMpKfOnlineList kfOnlineList = this.wxService.getKefuService() + .kfOnlineList(); + Assert.assertNotNull(kfOnlineList); + for (WxMpKfInfo k : kfOnlineList.getKfOnlineList()) { + System.err.println(k); + } + } + + @DataProvider + public Object[][] getKfAccount() { + WxXmlMpInMemoryConfigStorage configStorage = (WxXmlMpInMemoryConfigStorage) this.wxService + .getWxMpConfigStorage(); + return new Object[][] { { configStorage.getKfAccount() } }; + } + + @Test(dataProvider = "getKfAccount") + public void testKfAccountAdd(String kfAccount) throws WxErrorException { + WxMpKfAccountRequest request = WxMpKfAccountRequest.builder() + .kfAccount(kfAccount).nickName("我晕").build(); + Assert.assertTrue(this.wxService.getKefuService().kfAccountAdd(request)); + } + + @Test(dependsOnMethods = { + "testKfAccountAdd" }, dataProvider = "getKfAccount") + public void testKfAccountUpdate(String kfAccount) throws WxErrorException { + WxMpKfAccountRequest request = WxMpKfAccountRequest.builder() + .kfAccount(kfAccount).nickName("我晕").build(); + Assert.assertTrue(this.wxService.getKefuService().kfAccountUpdate(request)); + } + + @Test(dependsOnMethods = { + "testKfAccountAdd" }, dataProvider = "getKfAccount") + public void testKfAccountInviteWorker(String kfAccount) throws WxErrorException { + WxMpKfAccountRequest request = WxMpKfAccountRequest.builder() + .kfAccount(kfAccount).inviteWx("www_ucredit_com").build(); + Assert.assertTrue(this.wxService.getKefuService().kfAccountInviteWorker(request)); + } + + @Test(dependsOnMethods = { + "testKfAccountUpdate" }, dataProvider = "getKfAccount") + public void testKfAccountUploadHeadImg(String kfAccount) + throws WxErrorException { + File imgFile = new File("src\\test\\resources\\mm.jpeg"); + boolean result = this.wxService.getKefuService() + .kfAccountUploadHeadImg(kfAccount, imgFile); + Assert.assertTrue(result); + } + + @Test(dataProvider = "getKfAccount") + public void testKfAccountDel(String kfAccount) throws WxErrorException { + boolean result = this.wxService.getKefuService().kfAccountDel(kfAccount); + Assert.assertTrue(result); + } + + @DataProvider + public Object[][] getKfAccountAndOpenid() { + WxXmlMpInMemoryConfigStorage configStorage = (WxXmlMpInMemoryConfigStorage) this.wxService + .getWxMpConfigStorage(); + return new Object[][] { + { configStorage.getKfAccount(), configStorage.getOpenId() } }; + } + + @Test(dataProvider = "getKfAccountAndOpenid") + public void testKfSessionCreate(String kfAccount, String openid) + throws WxErrorException { + boolean result = this.wxService.getKefuService().kfSessionCreate(openid, + kfAccount); + Assert.assertTrue(result); + } + + @Test(dataProvider = "getKfAccountAndOpenid") + public void testKfSessionClose(String kfAccount, String openid) + throws WxErrorException { + boolean result = this.wxService.getKefuService().kfSessionClose(openid, + kfAccount); + Assert.assertTrue(result); + } + + @Test(dataProvider = "getKfAccountAndOpenid") + public void testKfSessionGet(String kfAccount, + String openid) throws WxErrorException { + WxMpKfSessionGetResult result = this.wxService.getKefuService() + .kfSessionGet(openid); + Assert.assertNotNull(result); + System.err.println(result); + } + + @Test(dataProvider = "getKfAccount") + public void testKfSessionList(String kfAccount) throws WxErrorException { + WxMpKfSessionList result = this.wxService.getKefuService() + .kfSessionList(kfAccount); + Assert.assertNotNull(result); + System.err.println(result); + } + + @Test + public void testKfSessionGetWaitCase() throws WxErrorException { + WxMpKfSessionWaitCaseList result = this.wxService.getKefuService() + .kfSessionGetWaitCase(); + Assert.assertNotNull(result); + System.err.println(result); + } + + @Test + public void testKfMsgList() throws WxErrorException, JsonProcessingException { + Date startTime = DateTime.now().minusDays(1).toDate(); + Date endTime = DateTime.now().minusDays(0).toDate(); + WxMpKfMsgList result = this.wxService.getKefuService().kfMsgList(startTime,endTime, 1L, 50); + Assert.assertNotNull(result); + System.err.println(new ObjectMapper().writeValueAsString(result)); + } + + @Test + public void testKfMsgListAll() throws WxErrorException, JsonProcessingException { + Date startTime = DateTime.now().minusDays(1).toDate(); + Date endTime = DateTime.now().minusDays(0).toDate(); + WxMpKfMsgList result = this.wxService.getKefuService().kfMsgList(startTime,endTime); + Assert.assertNotNull(result); + System.err.println(new ObjectMapper().writeValueAsString(result)); + } +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMaterialAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java similarity index 64% rename from weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMaterialAPITest.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java index 8e145e15c3..6ab7c7c477 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMaterialAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java @@ -1,9 +1,11 @@ -package me.chanjar.weixin.mp.api; +package me.chanjar.weixin.mp.api.impl; import com.google.inject.Inject; import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.mp.api.ApiTestModule; import me.chanjar.weixin.mp.bean.WxMpMaterial; import me.chanjar.weixin.mp.bean.WxMpMaterialArticleUpdate; import me.chanjar.weixin.mp.bean.WxMpMaterialNews; @@ -20,14 +22,15 @@ import java.util.*; /** - * 测试多媒体文件上传下载 + * 素材管理相关接口的测试 * + * @author chanjarster * @author codepiano + * @author Binary Wang */ @Test(groups = "materialAPI") @Guice(modules = ApiTestModule.class) -public class WxMpMaterialAPITest { - +public class WxMpMaterialServiceImplTest { @Inject protected WxMpServiceImpl wxService; @@ -41,10 +44,20 @@ public class WxMpMaterialAPITest { // 先查询保存测试开始前永久素材数据 private WxMpMaterialCountResult wxMaterialCountResultBeforeTest; - @Test(dataProvider = "uploadMaterial") + @DataProvider + public Object[][] uploadMedia() { + return new Object[][] { + new Object[] { WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, "mm.jpeg" }, + new Object[] { WxConsts.MEDIA_VOICE, WxConsts.FILE_MP3, "mm.mp3" }, + new Object[] { WxConsts.MEDIA_VIDEO, WxConsts.FILE_MP4, "mm.mp4" }, + new Object[] { WxConsts.MEDIA_THUMB, WxConsts.FILE_JPG, "mm.jpeg" } + }; + } + + @Test(dataProvider = "uploadMedia") public void testUploadMaterial(String mediaType, String fileType, String fileName) throws WxErrorException, IOException { if (wxMaterialCountResultBeforeTest == null) { - wxMaterialCountResultBeforeTest = wxService.materialCount(); + wxMaterialCountResultBeforeTest = this.wxService.getMaterialService().materialCount(); } InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName); File tempFile = FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType); @@ -55,7 +68,7 @@ public void testUploadMaterial(String mediaType, String fileType, String fileNam wxMaterial.setVideoTitle("title"); wxMaterial.setVideoIntroduction("test video description"); } - WxMpMaterialUploadResult res = wxService.materialFileUpload(mediaType, wxMaterial); + WxMpMaterialUploadResult res = this.wxService.getMaterialService().materialFileUpload(mediaType, wxMaterial); Assert.assertNotNull(res.getMediaId()); if (WxConsts.MEDIA_IMAGE.equals(mediaType) || WxConsts.MEDIA_THUMB.equals(mediaType)) { Assert.assertNotNull(res.getUrl()); @@ -69,6 +82,8 @@ public void testUploadMaterial(String mediaType, String fileType, String fileNam materialInfo.put("length", tempFile.length()); materialInfo.put("filename", tempFile.getName()); media_ids.put(res.getMediaId(), materialInfo); + + System.out.println(res); } @Test(dependsOnMethods = {"testUploadMaterial"}) @@ -88,14 +103,14 @@ public void testAddNews() throws WxErrorException { // 多图文消息 WxMpMaterialNews wxMpMaterialNewsMultiple = new WxMpMaterialNews(); - WxMpMaterialNews.WxMpMaterialNewsArticle wxMpMaterialNewsArticleMutiple1 = new WxMpMaterialNews.WxMpMaterialNewsArticle(); - wxMpMaterialNewsArticleMutiple1.setAuthor("author1"); - wxMpMaterialNewsArticleMutiple1.setThumbMediaId(thumbMediaId); - wxMpMaterialNewsArticleMutiple1.setTitle("multi title1"); - wxMpMaterialNewsArticleMutiple1.setContent("content 1"); - wxMpMaterialNewsArticleMutiple1.setContentSourceUrl("content url"); - wxMpMaterialNewsArticleMutiple1.setShowCoverPic(true); - wxMpMaterialNewsArticleMutiple1.setDigest(""); + WxMpMaterialNews.WxMpMaterialNewsArticle wxMpMaterialNewsArticleMultiple1 = new WxMpMaterialNews.WxMpMaterialNewsArticle(); + wxMpMaterialNewsArticleMultiple1.setAuthor("author1"); + wxMpMaterialNewsArticleMultiple1.setThumbMediaId(thumbMediaId); + wxMpMaterialNewsArticleMultiple1.setTitle("multi title1"); + wxMpMaterialNewsArticleMultiple1.setContent("content 1"); + wxMpMaterialNewsArticleMultiple1.setContentSourceUrl("content url"); + wxMpMaterialNewsArticleMultiple1.setShowCoverPic(true); + wxMpMaterialNewsArticleMultiple1.setDigest(""); WxMpMaterialNews.WxMpMaterialNewsArticle wxMpMaterialNewsArticleMultiple2 = new WxMpMaterialNews.WxMpMaterialNewsArticle(); wxMpMaterialNewsArticleMultiple2.setAuthor("author2"); @@ -106,18 +121,18 @@ public void testAddNews() throws WxErrorException { wxMpMaterialNewsArticleMultiple2.setShowCoverPic(true); wxMpMaterialNewsArticleMultiple2.setDigest(""); - wxMpMaterialNewsMultiple.addArticle(wxMpMaterialNewsArticleMutiple1); + wxMpMaterialNewsMultiple.addArticle(wxMpMaterialNewsArticleMultiple1); wxMpMaterialNewsMultiple.addArticle(wxMpMaterialNewsArticleMultiple2); - WxMpMaterialUploadResult resSingle = wxService.materialNewsUpload(wxMpMaterialNewsSingle); + WxMpMaterialUploadResult resSingle = this.wxService.getMaterialService().materialNewsUpload(wxMpMaterialNewsSingle); singleNewsMediaId = resSingle.getMediaId(); - WxMpMaterialUploadResult resMulti = wxService.materialNewsUpload(wxMpMaterialNewsMultiple); + WxMpMaterialUploadResult resMulti = this.wxService.getMaterialService().materialNewsUpload(wxMpMaterialNewsMultiple); multiNewsMediaId = resMulti.getMediaId(); } @Test(dependsOnMethods = {"testAddNews"}) public void testMaterialCount() throws WxErrorException { - WxMpMaterialCountResult wxMaterialCountResult = wxService.materialCount(); + WxMpMaterialCountResult wxMaterialCountResult = this.wxService.getMaterialService().materialCount(); // 测试上传过程中添加了一个音频,一个视频,两个图片,两个图文消息 Assert.assertEquals(wxMaterialCountResultBeforeTest.getVoiceCount() + 1, wxMaterialCountResult.getVoiceCount()); Assert.assertEquals(wxMaterialCountResultBeforeTest.getVideoCount() + 1, wxMaterialCountResult.getVideoCount()); @@ -125,29 +140,18 @@ public void testMaterialCount() throws WxErrorException { Assert.assertEquals(wxMaterialCountResultBeforeTest.getNewsCount() + 2, wxMaterialCountResult.getNewsCount()); } - - @DataProvider - public Object[][] uploadMaterial() { - return new Object[][]{ - new Object[]{WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, "mm.jpeg"}, - new Object[]{WxConsts.MEDIA_VOICE, WxConsts.FILE_MP3, "mm.mp3"}, - new Object[]{WxConsts.MEDIA_VIDEO, WxConsts.FILE_MP4, "mm.mp4"}, - new Object[]{WxConsts.MEDIA_THUMB, WxConsts.FILE_JPG, "mm.jpeg"} - }; - } - @Test(dependsOnMethods = {"testMaterialCount"}, dataProvider = "downloadMaterial") public void testDownloadMaterial(String media_id) throws WxErrorException, IOException { Map materialInfo = media_ids.get(media_id); Assert.assertNotNull(materialInfo); String filename = materialInfo.get("filename").toString(); if (filename.endsWith(".mp3") || filename.endsWith(".jpeg")) { - InputStream inputStream = wxService.materialImageOrVoiceDownload(media_id); + InputStream inputStream = this.wxService.getMaterialService().materialImageOrVoiceDownload(media_id); Assert.assertNotNull(inputStream); IOUtils.closeQuietly(inputStream); } if (filename.endsWith("mp4")) { - WxMpMaterialVideoInfoResult wxMaterialVideoInfoResult = wxService.materialVideoInfo(media_id); + WxMpMaterialVideoInfoResult wxMaterialVideoInfoResult = this.wxService.getMaterialService().materialVideoInfo(media_id); Assert.assertNotNull(wxMaterialVideoInfoResult); Assert.assertNotNull(wxMaterialVideoInfoResult.getDownUrl()); } @@ -155,15 +159,15 @@ public void testDownloadMaterial(String media_id) throws WxErrorException, IOExc @Test(dependsOnMethods = {"testAddNews"}) public void testGetNewsInfo() throws WxErrorException { - WxMpMaterialNews wxMpMaterialNewsSingle = wxService.materialNewsInfo(singleNewsMediaId); - WxMpMaterialNews wxMpMaterialNewsMultiple = wxService.materialNewsInfo(multiNewsMediaId); + WxMpMaterialNews wxMpMaterialNewsSingle = this.wxService.getMaterialService().materialNewsInfo(singleNewsMediaId); + WxMpMaterialNews wxMpMaterialNewsMultiple = this.wxService.getMaterialService().materialNewsInfo(multiNewsMediaId); Assert.assertNotNull(wxMpMaterialNewsSingle); Assert.assertNotNull(wxMpMaterialNewsMultiple); } @Test(dependsOnMethods = {"testGetNewsInfo"}) public void testUpdateNewsInfo() throws WxErrorException { - WxMpMaterialNews wxMpMaterialNewsSingle = wxService.materialNewsInfo(singleNewsMediaId); + WxMpMaterialNews wxMpMaterialNewsSingle = this.wxService.getMaterialService().materialNewsInfo(singleNewsMediaId); Assert.assertNotNull(wxMpMaterialNewsSingle); WxMpMaterialArticleUpdate wxMpMaterialArticleUpdateSingle = new WxMpMaterialArticleUpdate(); WxMpMaterialNews.WxMpMaterialNewsArticle articleSingle = wxMpMaterialNewsSingle.getArticles().get(0); @@ -171,13 +175,13 @@ public void testUpdateNewsInfo() throws WxErrorException { wxMpMaterialArticleUpdateSingle.setMediaId(singleNewsMediaId); wxMpMaterialArticleUpdateSingle.setArticles(articleSingle); wxMpMaterialArticleUpdateSingle.setIndex(0); - boolean resultSingle = wxService.materialNewsUpdate(wxMpMaterialArticleUpdateSingle); + boolean resultSingle = this.wxService.getMaterialService().materialNewsUpdate(wxMpMaterialArticleUpdateSingle); Assert.assertTrue(resultSingle); - wxMpMaterialNewsSingle = wxService.materialNewsInfo(singleNewsMediaId); + wxMpMaterialNewsSingle = this.wxService.getMaterialService().materialNewsInfo(singleNewsMediaId); Assert.assertNotNull(wxMpMaterialNewsSingle); Assert.assertEquals("content single update", wxMpMaterialNewsSingle.getArticles().get(0).getContent()); - WxMpMaterialNews wxMpMaterialNewsMultiple = wxService.materialNewsInfo(multiNewsMediaId); + WxMpMaterialNews wxMpMaterialNewsMultiple = this.wxService.getMaterialService().materialNewsInfo(multiNewsMediaId); Assert.assertNotNull(wxMpMaterialNewsMultiple); WxMpMaterialArticleUpdate wxMpMaterialArticleUpdateMulti = new WxMpMaterialArticleUpdate(); WxMpMaterialNews.WxMpMaterialNewsArticle articleMulti = wxMpMaterialNewsMultiple.getArticles().get(1); @@ -185,31 +189,30 @@ public void testUpdateNewsInfo() throws WxErrorException { wxMpMaterialArticleUpdateMulti.setMediaId(multiNewsMediaId); wxMpMaterialArticleUpdateMulti.setArticles(articleMulti); wxMpMaterialArticleUpdateMulti.setIndex(1); - boolean resultMulti = wxService.materialNewsUpdate(wxMpMaterialArticleUpdateMulti); + boolean resultMulti = this.wxService.getMaterialService().materialNewsUpdate(wxMpMaterialArticleUpdateMulti); Assert.assertTrue(resultMulti); - wxMpMaterialNewsMultiple = wxService.materialNewsInfo(multiNewsMediaId); + wxMpMaterialNewsMultiple = this.wxService.getMaterialService().materialNewsInfo(multiNewsMediaId); Assert.assertNotNull(wxMpMaterialNewsMultiple); Assert.assertEquals("content 2 update", wxMpMaterialNewsMultiple.getArticles().get(1).getContent()); } - @Test(dependsOnMethods = {"testUpdateNewsInfo"}) public void testMaterialNewsList() throws WxErrorException { - WxMpMaterialNewsBatchGetResult wxMpMaterialNewsBatchGetResult = wxService.materialNewsBatchGet(0, 20); + WxMpMaterialNewsBatchGetResult wxMpMaterialNewsBatchGetResult = this.wxService.getMaterialService().materialNewsBatchGet(0, 20); return; } @Test(dependsOnMethods = {"testMaterialNewsList"}) public void testMaterialFileList() throws WxErrorException { - WxMpMaterialFileBatchGetResult wxMpMaterialVoiceBatchGetResult = wxService.materialFileBatchGet(WxConsts.MATERIAL_VOICE, 0, 20); - WxMpMaterialFileBatchGetResult wxMpMaterialVideoBatchGetResult = wxService.materialFileBatchGet(WxConsts.MATERIAL_VIDEO, 0, 20); - WxMpMaterialFileBatchGetResult wxMpMaterialImageBatchGetResult = wxService.materialFileBatchGet(WxConsts.MATERIAL_IMAGE, 0, 20); + WxMpMaterialFileBatchGetResult wxMpMaterialVoiceBatchGetResult = this.wxService.getMaterialService().materialFileBatchGet(WxConsts.MATERIAL_VOICE, 0, 20); + WxMpMaterialFileBatchGetResult wxMpMaterialVideoBatchGetResult = this.wxService.getMaterialService().materialFileBatchGet(WxConsts.MATERIAL_VIDEO, 0, 20); + WxMpMaterialFileBatchGetResult wxMpMaterialImageBatchGetResult = this.wxService.getMaterialService().materialFileBatchGet(WxConsts.MATERIAL_IMAGE, 0, 20); return; } @Test(dependsOnMethods = {"testMaterialFileList"}, dataProvider = "allTestMaterial") public void testDeleteMaterial(String mediaId) throws WxErrorException { - boolean result = wxService.materialDelete(mediaId); + boolean result = this.wxService.getMaterialService().materialDelete(mediaId); Assert.assertTrue(result); } @@ -234,4 +237,42 @@ public Iterator allTestMaterial() { params.add(new Object[]{this.multiNewsMediaId}); return params.iterator(); } + + // 以下为media接口的测试 + private List mediaIds = new ArrayList<>(); + @Test(dataProvider="uploadMedia") + public void testUploadMedia(String mediaType, String fileType, String fileName) throws WxErrorException, IOException { + try(InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName)){ + WxMediaUploadResult res = this.wxService.getMaterialService().mediaUpload(mediaType, fileType, inputStream); + Assert.assertNotNull(res.getType()); + Assert.assertNotNull(res.getCreatedAt()); + Assert.assertTrue(res.getMediaId() != null || res.getThumbMediaId() != null); + + if (res.getMediaId() != null) { + this.mediaIds.add(res.getMediaId()); + } + + if (res.getThumbMediaId() != null) { + this.mediaIds.add(res.getThumbMediaId()); + } + + System.out.println(res); + } + } + + @Test(dependsOnMethods = { "testUploadMedia" }, dataProvider="downloadMedia") + public void testDownloadMedia(String media_id) throws WxErrorException { + File file = this.wxService.getMaterialService().mediaDownload(media_id); + Assert.assertNotNull(file); + System.out.println(file.getAbsolutePath()); + } + + @DataProvider + public Object[][] downloadMedia() { + Object[][] params = new Object[this.mediaIds.size()][]; + for (int i = 0; i < this.mediaIds.size(); i++) { + params[i] = new Object[] { this.mediaIds.get(i) }; + } + return params; + } } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMenuAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImplTest.java similarity index 88% rename from weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMenuAPITest.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImplTest.java index 581c67eef7..0cbae4db1b 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMenuAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImplTest.java @@ -1,10 +1,11 @@ -package me.chanjar.weixin.mp.api; +package me.chanjar.weixin.mp.api.impl; import com.google.inject.Inject; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.bean.WxMenu; import me.chanjar.weixin.common.bean.WxMenu.WxMenuButton; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.api.ApiTestModule; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Guice; @@ -13,11 +14,12 @@ /** * 测试菜单 * @author chanjarster + * @author Binary Wang * */ -@Test(groups="menuAPI", dependsOnGroups="baseAPI") +@Test(groups="menuAPI") @Guice(modules = ApiTestModule.class) -public class WxMpMenuAPITest { +public class WxMpMenuServiceImplTest { @Inject protected WxMpServiceImpl wxService; @@ -25,7 +27,7 @@ public class WxMpMenuAPITest { @Test(dataProvider = "menu") public void testCreateMenu(WxMenu wxMenu) throws WxErrorException { System.out.println(wxMenu.toJson()); - wxService.menuCreate(wxMenu); + this.wxService.getMenuService().menuCreate(wxMenu); } @Test @@ -69,17 +71,19 @@ public void testCreateMenu2() throws WxErrorException { WxMenu menu = WxMenu.fromJson(a); System.out.println(menu.toJson()); - wxService.menuCreate(menu); + this.wxService.getMenuService().menuCreate(menu); } @Test(dependsOnMethods = { "testCreateMenu"}) public void testGetMenu() throws WxErrorException { - Assert.assertNotNull(wxService.menuGet()); + WxMenu wxMenu = this.wxService.getMenuService().menuGet(); + Assert.assertNotNull(wxMenu); + System.out.println(wxMenu.toJson()); } @Test(dependsOnMethods = { "testGetMenu"}) public void testDeleteMenu() throws WxErrorException { - wxService.menuDelete(); + this.wxService.getMenuService().menuDelete(); } @DataProvider(name="menu") diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpQrCodeAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpQrCodeServiceImplTest.java similarity index 56% rename from weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpQrCodeAPITest.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpQrCodeServiceImplTest.java index 7af300c9c3..d2ed01dad3 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpQrCodeAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpQrCodeServiceImplTest.java @@ -1,7 +1,8 @@ -package me.chanjar.weixin.mp.api; +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.bean.result.WxMpQrCodeTicket; import org.testng.Assert; import org.testng.annotations.Guice; @@ -14,37 +15,41 @@ * * @author chanjarster */ -@Test(groups = "qrCodeAPI", dependsOnGroups = { "baseAPI" }) +@Test(groups = "qrCodeAPI") @Guice(modules = ApiTestModule.class) -public class WxMpQrCodeAPITest { +public class WxMpQrCodeServiceImplTest { @Inject protected WxMpServiceImpl wxService; public void testQrCodeCreateTmpTicket() throws WxErrorException { - WxMpQrCodeTicket ticket = this.wxService.qrCodeCreateTmpTicket(1, null); + WxMpQrCodeTicket ticket = this.wxService.getQrcodeService().qrCodeCreateTmpTicket(1, null); Assert.assertNotNull(ticket.getUrl()); Assert.assertNotNull(ticket.getTicket()); Assert.assertTrue(ticket.getExpire_seconds() != -1); + System.out.println(ticket); } public void testQrCodeCreateLastTicket() throws WxErrorException { - WxMpQrCodeTicket ticket = this.wxService.qrCodeCreateLastTicket(1); + WxMpQrCodeTicket ticket = this.wxService.getQrcodeService().qrCodeCreateLastTicket(1); Assert.assertNotNull(ticket.getUrl()); Assert.assertNotNull(ticket.getTicket()); Assert.assertTrue(ticket.getExpire_seconds() == -1); + System.out.println(ticket); } public void testQrCodePicture() throws WxErrorException { - WxMpQrCodeTicket ticket = this.wxService.qrCodeCreateLastTicket(1); - File file = this.wxService.qrCodePicture(ticket); + WxMpQrCodeTicket ticket = this.wxService.getQrcodeService().qrCodeCreateLastTicket(1); + File file = this.wxService.getQrcodeService().qrCodePicture(ticket); Assert.assertNotNull(file); + System.out.println(file.getAbsolutePath()); } public void testQrCodePictureUrl() throws WxErrorException { - WxMpQrCodeTicket ticket = this.wxService.qrCodeCreateLastTicket(1); - String url = this.wxService.qrCodePictureUrl(ticket.getTicket()); + WxMpQrCodeTicket ticket = this.wxService.getQrcodeService().qrCodeCreateLastTicket(1); + String url = this.wxService.getQrcodeService().qrCodePictureUrl(ticket.getTicket()); Assert.assertNotNull(url); + System.out.println(url); } } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImplTest.java new file mode 100644 index 0000000000..af5289f0c1 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImplTest.java @@ -0,0 +1,84 @@ +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.bean.result.WxMpUser; +import me.chanjar.weixin.mp.bean.result.WxMpUserCumulate; +import me.chanjar.weixin.mp.bean.result.WxMpUserList; +import me.chanjar.weixin.mp.bean.result.WxMpUserSummary; +import org.testng.Assert; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +/** + * 测试用户相关的接口 + * + * @author chanjarster + * @author Binary Wang + */ +@Test(groups = "userAPI") +@Guice(modules = ApiTestModule.class) +public class WxMpUserServiceImplTest { + + @Inject + protected WxMpServiceImpl wxService; + + public void testUserUpdateRemark() throws WxErrorException { + ApiTestModule.WxXmlMpInMemoryConfigStorage configProvider = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.getWxMpConfigStorage(); + this.wxService.getUserService().userUpdateRemark(configProvider.getOpenId(), "测试备注名"); + } + + public void testUserInfo() throws WxErrorException { + ApiTestModule.WxXmlMpInMemoryConfigStorage configProvider = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.getWxMpConfigStorage(); + WxMpUser user = this.wxService.getUserService().userInfo(configProvider.getOpenId(), null); + Assert.assertNotNull(user); + System.out.println(user); + } + + public void testUserList() throws WxErrorException { + WxMpUserList wxMpUserList = this.wxService.getUserService().userList(null); + Assert.assertNotNull(wxMpUserList); + Assert.assertFalse(wxMpUserList.getCount() == -1); + Assert.assertFalse(wxMpUserList.getTotal() == -1); + Assert.assertFalse(wxMpUserList.getOpenIds().size() == -1); + System.out.println(wxMpUserList); + } + + public void testGroupQueryUserGroup() throws WxErrorException { + ApiTestModule.WxXmlMpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.getWxMpConfigStorage(); + long groupid = this.wxService.getGroupService().userGetGroup(configStorage.getOpenId()); + Assert.assertTrue(groupid != -1l); + } + + public void testGroupMoveUser() throws WxErrorException { + ApiTestModule.WxXmlMpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.getWxMpConfigStorage(); + this.wxService.getGroupService().userUpdateGroup(configStorage.getOpenId(), this.wxService.getGroupService().groupGet().get(3).getId()); + } + + @Test + public void testGetUserSummary() throws WxErrorException, ParseException { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + Date beginDate = simpleDateFormat.parse("2015-01-01"); + Date endDate = simpleDateFormat.parse("2015-01-02"); + List summaries = this.wxService.getUserService().dataCubeUserSummary(beginDate, endDate); + Assert.assertNotNull(summaries); + System.out.println(summaries); + } + + @Test + public void testGetUserCumulate() throws WxErrorException, ParseException { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + Date beginDate = simpleDateFormat.parse("2015-01-01"); + Date endDate = simpleDateFormat.parse("2015-01-02"); + List cumulates = this.wxService.getUserService().dataCubeUserCumulate(beginDate, endDate); + Assert.assertNotNull(cumulates); + System.out.println(cumulates); + } + +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/result/kefu/WxMpKfListTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/result/kefu/WxMpKfListTest.java new file mode 100644 index 0000000000..cc782250ff --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/result/kefu/WxMpKfListTest.java @@ -0,0 +1,41 @@ +package me.chanjar.weixin.mp.bean.result.kefu; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.testng.Assert; +import org.testng.annotations.Test; + +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfList; + +@Test +public class WxMpKfListTest { + + public void testFromJson() { + String json=" {\r\n" + + " \"kf_list\" : [\r\n" + + " {\r\n" + + " \"kf_account\" : \"test1@test\",\r\n" + + " \"kf_headimgurl\" : \"http://mmbiz.qpic.cn/mmbiz/4whpV1VZl2iccsvYbHvnphkyGtnvjfUS8Ym0GSaLic0FD3vN0V8PILcibEGb2fPfEOmw/0\",\r\n" + + " \"kf_id\" : \"1001\",\r\n" + + " \"kf_nick\" : \"ntest1\"\r\n" + + " },\r\n" + + " {\r\n" + + " \"kf_account\" : \"test2@test\",\r\n" + + " \"kf_headimgurl\" : \"http://mmbiz.qpic.cn/mmbiz/4whpV1VZl2iccsvYbHvnphkyGtnvjfUS8Ym0GSaLic0FD3vN0V8PILcibEGb2fPfEOmw/0\",\r\n" + + " \"kf_id\" : \"1002\",\r\n" + + " \"kf_nick\" : \"ntest2\"\r\n" + + " },\r\n" + + " {\r\n" + + " \"kf_account\" : \"test3@test\",\r\n" + + " \"kf_headimgurl\" : \"http://mmbiz.qpic.cn/mmbiz/4whpV1VZl2iccsvYbHvnphkyGtnvjfUS8Ym0GSaLic0FD3vN0V8PILcibEGb2fPfEOmw/0\",\r\n" + + " \"kf_id\" : \"1003\",\r\n" + + " \"kf_nick\" : \"ntest3\"\r\n" + + " }\r\n" + + " ]\r\n" + + " }"; + + WxMpKfList wxMpKfList = WxMpKfList.fromJson(json); + Assert.assertNotNull(wxMpKfList); + System.err.println(ToStringBuilder.reflectionToString(wxMpKfList)); + } + +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/result/kefu/WxMpKfOnlineListTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/result/kefu/WxMpKfOnlineListTest.java new file mode 100644 index 0000000000..ab04e8e00c --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/result/kefu/WxMpKfOnlineListTest.java @@ -0,0 +1,39 @@ +package me.chanjar.weixin.mp.bean.result.kefu; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.testng.Assert; +import org.testng.annotations.Test; + +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfOnlineList; + +@Test +public class WxMpKfOnlineListTest { + + @Test + public void testFromJson() { + String json = "{\r\n" + + " \"kf_online_list\": [\r\n" + + " {\r\n" + + " \"kf_account\": \"test1@test\", \r\n" + + " \"status\": 1, \r\n" + + " \"kf_id\": \"1001\", \r\n" + + " \"auto_accept\": 0, \r\n" + + " \"accepted_case\": 1\r\n" + + " },\r\n" + + " {\r\n" + + " \"kf_account\": \"test2@test\", \r\n" + + " \"status\": 1, \r\n" + + " \"kf_id\": \"1002\", \r\n" + + " \"auto_accept\": 0, \r\n" + + " \"accepted_case\": 2\r\n" + + " }\r\n" + + " ]\r\n" + + "}"; + + WxMpKfOnlineList wxMpKfOnlineList = WxMpKfOnlineList.fromJson(json); + Assert.assertNotNull(wxMpKfOnlineList); + System.err.println(ToStringBuilder.reflectionToString(wxMpKfOnlineList)); + + } + +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/DemoImageHandler.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/DemoImageHandler.java index 8cc505427c..a22f28d79d 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/DemoImageHandler.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/DemoImageHandler.java @@ -18,7 +18,7 @@ public class DemoImageHandler implements WxMpMessageHandler { public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, WxMpService wxMpService, WxSessionManager sessionManager) { try { - WxMediaUploadResult wxMediaUploadResult = wxMpService + WxMediaUploadResult wxMediaUploadResult = wxMpService.getMaterialService() .mediaUpload(WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, ClassLoader.getSystemResourceAsStream("mm.jpeg")); WxMpXmlOutImageMessage m = WxMpXmlOutMessage diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java index e92bd98655..b89b279610 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java @@ -2,6 +2,7 @@ import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.mp.api.*; +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHolder; diff --git a/weixin-java-mp/src/test/resources/test-config.sample.xml b/weixin-java-mp/src/test/resources/test-config.sample.xml index 6ec4825a99..1f79bea2cc 100644 --- a/weixin-java-mp/src/test/resources/test-config.sample.xml +++ b/weixin-java-mp/src/test/resources/test-config.sample.xml @@ -7,4 +7,5 @@ 可以不填写 某个加你公众号的用户的openId 网页授权获取用户信息回调地址 + 完整客服账号,格式为:账号前缀@公众号微信号 diff --git a/weixin-java-mp/src/test/resources/testng.xml b/weixin-java-mp/src/test/resources/testng.xml index cb1263d317..d821e398f6 100644 --- a/weixin-java-mp/src/test/resources/testng.xml +++ b/weixin-java-mp/src/test/resources/testng.xml @@ -3,19 +3,18 @@ - + - - + + - - - + + - - + +