From 75c10cb035564134968c8a7c7662c40ab33e0a02 Mon Sep 17 00:00:00 2001 From: Sutra Zhou Date: Mon, 30 Apr 2018 15:56:39 +0800 Subject: [PATCH 1/5] Add WXBizDataCrypt for WeChat Mini Program. --- .gitignore | 8 +-- README.md | 6 +- pom.xml | 1 + weixin4j-wxa/pom.xml | 49 ++++++++++++++++ .../com/foxinmy/weixin4j/wxa/AESUtils.java | 58 +++++++++++++++++++ .../foxinmy/weixin4j/wxa/WXBizDataCrypt.java | 48 +++++++++++++++ .../foxinmy/weixin4j/wxa/package-info.java | 4 ++ .../weixin4j/wxa/WXBizDataCryptTest.java | 55 ++++++++++++++++++ 8 files changed, 224 insertions(+), 5 deletions(-) create mode 100644 weixin4j-wxa/pom.xml create mode 100644 weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/AESUtils.java create mode 100644 weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java create mode 100644 weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/package-info.java create mode 100644 weixin4j-wxa/src/test/java/com/foxinmy/weixin4j/wxa/WXBizDataCryptTest.java diff --git a/.gitignore b/.gitignore index 1d3be1be..dd217e55 100644 --- a/.gitignore +++ b/.gitignore @@ -12,9 +12,9 @@ hs_err_pid* *~ # eclipse ignore -*.settings/* -/.project -/.classpath +.settings/ +.project +.classpath /.tomcatplugin # idea ignore @@ -22,7 +22,7 @@ hs_err_pid* *.iml # maven ignore -target/* +target/ # other ignore *.log diff --git a/README.md b/README.md index a9347797..d47a3810 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,11 @@ weixin4j * **weixin4j-qy[1.7.8]** `企业号API封装` - + +* **weixin4j-wxa[1.7.9]** + + `小程序 API 封装` + * **weixin4j-server[1.1.8]** `netty服务器&消息分发` diff --git a/pom.xml b/pom.xml index a586f9e7..11cfda02 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,7 @@ weixin4j-base weixin4j-mp weixin4j-qy + weixin4j-wxa weixin4j-server weixin4j-example weixin4j-serverX diff --git a/weixin4j-wxa/pom.xml b/weixin4j-wxa/pom.xml new file mode 100644 index 00000000..1a552d0d --- /dev/null +++ b/weixin4j-wxa/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + com.foxinmy + weixin4j + 1.7.9 + + weixin4j-wxa + weixin4j-wxa + https://github.com/foxinmy/weixin4j/tree/master/weixin4j-wxa + 微信小程序 API 支持 + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.foxinmy + weixin4j-base + ${project.version} + + + commons-codec + commons-codec + 1.10 + + + org.bouncycastle + bcprov-jdk15on + 1.55 + + + junit + junit + + + ch.qos.logback + logback-core + 1.1.8 + test + + + \ No newline at end of file diff --git a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/AESUtils.java b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/AESUtils.java new file mode 100644 index 00000000..4b445b66 --- /dev/null +++ b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/AESUtils.java @@ -0,0 +1,58 @@ +package com.foxinmy.weixin4j.wxa; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.Key; +import java.security.NoSuchProviderException; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +final class AESUtils { + + private static boolean initialized = false; + + private AESUtils() { + } + + /** + * AES解密 + * + * @param content 密文 + * @return 明文 + * @throws InvalidAlgorithmParameterException + * @throws NoSuchProviderException + */ + static byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) + throws InvalidAlgorithmParameterException { + initialize(); + try { + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); + Key sKeySpec = new SecretKeySpec(keyByte, "AES"); + + cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte)); // 初始化 + byte[] result = cipher.doFinal(content); + return result; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static void initialize() { + if (initialized) + return; + Security.addProvider(new BouncyCastleProvider()); + initialized = true; + } + + private static AlgorithmParameters generateIV(byte[] iv) throws Exception { + AlgorithmParameters params = AlgorithmParameters.getInstance("AES"); + params.init(new IvParameterSpec(iv)); + return params; + } + +} diff --git a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java new file mode 100644 index 00000000..d65e4329 --- /dev/null +++ b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java @@ -0,0 +1,48 @@ +package com.foxinmy.weixin4j.wxa; + +import java.nio.charset.Charset; +import java.security.InvalidAlgorithmParameterException; + +import org.apache.commons.codec.binary.Base64; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; + +/** + * @see 加密数据解密算法 + */ +public class WXBizDataCrypt { + + private final String appid; + + private final String sessionKey; + + public WXBizDataCrypt(String appid, String sessionKey) { + this.appid = appid; + this.sessionKey = sessionKey; + } + + public JSONObject decryptData(final String encryptedData, final String iv) { + final byte[] aesKey = Base64.decodeBase64(sessionKey); + final byte[] aesCipher = Base64.decodeBase64(encryptedData); + final byte[] aesIV = Base64.decodeBase64(iv); + + final byte[] resultByte; + try { + resultByte = AESUtils.decrypt(aesCipher, aesKey, aesIV); + } catch (InvalidAlgorithmParameterException e) { + throw new RuntimeException(e); + } + + final String decryptedText = new String(resultByte, Charset.forName("UTF-8")); + final JSONObject decrypted = JSON.parseObject(decryptedText); + + final String appId = decrypted.getJSONObject("watermark").getString("appid"); + if (!appId.equals(this.appid)) { + throw new IllegalArgumentException("Invalid Buffer"); + } + + return decrypted; + } + +} diff --git a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/package-info.java b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/package-info.java new file mode 100644 index 00000000..6a4bfcc5 --- /dev/null +++ b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/package-info.java @@ -0,0 +1,4 @@ +/** + * WeChat Mini Program support library. + */ +package com.foxinmy.weixin4j.wxa; diff --git a/weixin4j-wxa/src/test/java/com/foxinmy/weixin4j/wxa/WXBizDataCryptTest.java b/weixin4j-wxa/src/test/java/com/foxinmy/weixin4j/wxa/WXBizDataCryptTest.java new file mode 100644 index 00000000..8743e9dc --- /dev/null +++ b/weixin4j-wxa/src/test/java/com/foxinmy/weixin4j/wxa/WXBizDataCryptTest.java @@ -0,0 +1,55 @@ +package com.foxinmy.weixin4j.wxa; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.alibaba.fastjson.JSONObject; + +public class WXBizDataCryptTest { + + @Test + public void testDecryptData() { + String appId = "wx4f4bc4dec97d474b"; + String sessionKey = "tiihtNczf5v6AKRyjwEUhQ=="; + + WXBizDataCrypt biz = new WXBizDataCrypt(appId, sessionKey); + + String encryptedData + = "CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZM" + + "QmRzooG2xrDcvSnxIMXFufNstNGTyaGS" + + "9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+" + + "3hVbJSRgv+4lGOETKUQz6OYStslQ142d" + + "NCuabNPGBzlooOmB231qMM85d2/fV6Ch" + + "evvXvQP8Hkue1poOFtnEtpyxVLW1zAo6" + + "/1Xx1COxFvrc2d7UL/lmHInNlxuacJXw" + + "u0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn" + + "/Hz7saL8xz+W//FRAUid1OksQaQx4CMs" + + "8LOddcQhULW4ucetDf96JcR3g0gfRK4P" + + "C7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB" + + "6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns" + + "/8wR2SiRS7MNACwTyrGvt9ts8p12PKFd" + + "lqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYV" + + "oKlaRv85IfVunYzO0IKXsyl7JCUjCpoG" + + "20f0a04COwfneQAGGwd5oa+T8yO5hzuy" + + "Db/XcxxmK01EpqOyuxINew=="; + String iv = "r7BXXKkLb8qrSNn05n0qiA=="; + + JSONObject data = biz.decryptData(encryptedData, iv); + + assertEquals("CN", data.getString("country")); + assertEquals("ocMvos6NjeKLIBqg5Mr9QjxrP1FA", data.getString("unionId")); + assertEquals(1, data.getIntValue("gender")); + assertEquals("Guangdong", data.getString("province")); + assertEquals("Guangzhou", data.getString("city")); + assertEquals("http://wx.qlogo.cn/mmopen/vi_32/aSKcBBPpibyKNicHNTMM0qJVh8Kjgiak2AHWr8MHM4WgMEm7GFhsf8OYrySdbvAMvTsw3mo8ibKicsnfN5pRjl1p8HQ/0", data.getString("avatarUrl")); + assertEquals("oGZUI0egBJY1zhBYw2KhdUfwVJJE", data.getString("openId")); + assertEquals("Band", data.getString("nickName")); + assertEquals("zh_CN", data.getString("language")); + + JSONObject watermark = data.getJSONObject("watermark"); + assertEquals("wx4f4bc4dec97d474b", watermark.getString("appid")); + assertEquals(1477314187L, watermark.getLongValue("timestamp")); + } + +} From 7a24532ab73ff35cf620c5271dec9e5f5f6adfe5 Mon Sep 17 00:00:00 2001 From: Sutra Zhou Date: Mon, 30 Apr 2018 16:07:31 +0800 Subject: [PATCH 2/5] Minor revision. --- weixin4j-wxa/pom.xml | 2 +- .../main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/weixin4j-wxa/pom.xml b/weixin4j-wxa/pom.xml index 1a552d0d..cec79627 100644 --- a/weixin4j-wxa/pom.xml +++ b/weixin4j-wxa/pom.xml @@ -46,4 +46,4 @@ test - \ No newline at end of file + diff --git a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java index d65e4329..97e3b0b9 100644 --- a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java +++ b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java @@ -27,14 +27,14 @@ public class WXBizDataCrypt { final byte[] aesCipher = Base64.decodeBase64(encryptedData); final byte[] aesIV = Base64.decodeBase64(iv); - final byte[] resultByte; + final byte[] decryptedBytes; try { - resultByte = AESUtils.decrypt(aesCipher, aesKey, aesIV); + decryptedBytes = AESUtils.decrypt(aesCipher, aesKey, aesIV); } catch (InvalidAlgorithmParameterException e) { throw new RuntimeException(e); } - final String decryptedText = new String(resultByte, Charset.forName("UTF-8")); + final String decryptedText = new String(decryptedBytes, Charset.forName("UTF-8")); final JSONObject decrypted = JSON.parseObject(decryptedText); final String appId = decrypted.getJSONObject("watermark").getString("appid"); From 2c1892a5e2629df03d87d85b169beba2a3c7f552 Mon Sep 17 00:00:00 2001 From: Sutra Zhou Date: Mon, 30 Apr 2018 21:25:09 +0800 Subject: [PATCH 3/5] Add javadoc. --- .../java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java index 97e3b0b9..b5af9b07 100644 --- a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java +++ b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java @@ -9,6 +9,8 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; /** + * 对微信小程序用户加密数据的解密. + * * @see 加密数据解密算法 */ public class WXBizDataCrypt { @@ -22,6 +24,13 @@ public class WXBizDataCrypt { this.sessionKey = sessionKey; } + /** + * 解密微信小程序用户加密数据. + * + * @param encryptedData 加密的用户数据. + * @param iv 与用户数据一同返回的初始向量. + * @return 解密后的原文. + */ public JSONObject decryptData(final String encryptedData, final String iv) { final byte[] aesKey = Base64.decodeBase64(sessionKey); final byte[] aesCipher = Base64.decodeBase64(encryptedData); From 1a2d9f26678c26d4a830e112c38c3808406bbda6 Mon Sep 17 00:00:00 2001 From: Sutra Zhou Date: Mon, 30 Apr 2018 22:33:16 +0800 Subject: [PATCH 4/5] Clean up exceptions, mark initialize as synchronized. --- .../java/com/foxinmy/weixin4j/wxa/AESUtils.java | 15 +++++++-------- .../com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java | 9 +-------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/AESUtils.java b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/AESUtils.java index 4b445b66..d424b587 100644 --- a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/AESUtils.java +++ b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/AESUtils.java @@ -1,9 +1,7 @@ package com.foxinmy.weixin4j.wxa; import java.security.AlgorithmParameters; -import java.security.InvalidAlgorithmParameterException; import java.security.Key; -import java.security.NoSuchProviderException; import java.security.Security; import javax.crypto.Cipher; @@ -23,12 +21,11 @@ final class AESUtils { * AES解密 * * @param content 密文 + * @param keyByte key + * @param ivByte 初始向量 * @return 明文 - * @throws InvalidAlgorithmParameterException - * @throws NoSuchProviderException */ - static byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) - throws InvalidAlgorithmParameterException { + static byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) { initialize(); try { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); @@ -42,9 +39,11 @@ final class AESUtils { } } - private static void initialize() { - if (initialized) + private static synchronized void initialize() { + if (initialized) { return; + } + Security.addProvider(new BouncyCastleProvider()); initialized = true; } diff --git a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java index b5af9b07..effcd87a 100644 --- a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java +++ b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java @@ -1,7 +1,6 @@ package com.foxinmy.weixin4j.wxa; import java.nio.charset.Charset; -import java.security.InvalidAlgorithmParameterException; import org.apache.commons.codec.binary.Base64; @@ -36,13 +35,7 @@ public class WXBizDataCrypt { final byte[] aesCipher = Base64.decodeBase64(encryptedData); final byte[] aesIV = Base64.decodeBase64(iv); - final byte[] decryptedBytes; - try { - decryptedBytes = AESUtils.decrypt(aesCipher, aesKey, aesIV); - } catch (InvalidAlgorithmParameterException e) { - throw new RuntimeException(e); - } - + final byte[] decryptedBytes = AESUtils.decrypt(aesCipher, aesKey, aesIV); final String decryptedText = new String(decryptedBytes, Charset.forName("UTF-8")); final JSONObject decrypted = JSON.parseObject(decryptedText); From a630bc2a795a01db85e87c66c60d67fe2ab2726a Mon Sep 17 00:00:00 2001 From: Sutra Zhou Date: Mon, 30 Apr 2018 23:32:39 +0800 Subject: [PATCH 5/5] Bump version number from 1.7.9 to 1.8.0-SNAPSHOT and mark new classes as since 1.8. --- README.md | 2 +- pom.xml | 2 +- weixin4j-base/pom.xml | 2 +- weixin4j-example/pom.xml | 6 +++--- weixin4j-mp/pom.xml | 2 +- weixin4j-qy/pom.xml | 2 +- weixin4j-server/pom.xml | 2 +- weixin4j-serverX/pom.xml | 2 +- weixin4j-wxa/pom.xml | 2 +- .../src/main/java/com/foxinmy/weixin4j/wxa/AESUtils.java | 3 +++ .../main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java | 1 + .../main/java/com/foxinmy/weixin4j/wxa/package-info.java | 5 ++++- 12 files changed, 19 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index d47a3810..957a1190 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ weixin4j `企业号API封装` -* **weixin4j-wxa[1.7.9]** +* **weixin4j-wxa[1.8.0]** `小程序 API 封装` diff --git a/pom.xml b/pom.xml index 11cfda02..7ebe0a6d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.foxinmy weixin4j - 1.7.9 + 1.8.0-SNAPSHOT pom weixin4j https://github.com/foxinmy/weixin4j diff --git a/weixin4j-base/pom.xml b/weixin4j-base/pom.xml index 9bf3d98a..08eb0a5e 100644 --- a/weixin4j-base/pom.xml +++ b/weixin4j-base/pom.xml @@ -5,7 +5,7 @@ com.foxinmy weixin4j - 1.7.9 + 1.8.0-SNAPSHOT weixin4j-base weixin4j-base diff --git a/weixin4j-example/pom.xml b/weixin4j-example/pom.xml index 986d9834..3b6eb45b 100644 --- a/weixin4j-example/pom.xml +++ b/weixin4j-example/pom.xml @@ -5,7 +5,7 @@ com.foxinmy weixin4j - 1.7.9 + 1.8.0-SNAPSHOT war weixin4j-example @@ -48,13 +48,13 @@ com.foxinmy weixin4j-mp - 1.7.9 + 1.8.0-SNAPSHOT com.foxinmy weixin4j-qy - 1.7.9 + 1.8.0-SNAPSHOT diff --git a/weixin4j-mp/pom.xml b/weixin4j-mp/pom.xml index 0e0ee994..4db3abed 100644 --- a/weixin4j-mp/pom.xml +++ b/weixin4j-mp/pom.xml @@ -5,7 +5,7 @@ com.foxinmy weixin4j - 1.7.9 + 1.8.0-SNAPSHOT weixin4j-mp weixin4j-mp diff --git a/weixin4j-qy/pom.xml b/weixin4j-qy/pom.xml index 798d274c..a69764c7 100644 --- a/weixin4j-qy/pom.xml +++ b/weixin4j-qy/pom.xml @@ -5,7 +5,7 @@ com.foxinmy weixin4j - 1.7.9 + 1.8.0-SNAPSHOT weixin4j-qy weixin4j-qy diff --git a/weixin4j-server/pom.xml b/weixin4j-server/pom.xml index d15af0e3..966436bb 100644 --- a/weixin4j-server/pom.xml +++ b/weixin4j-server/pom.xml @@ -5,7 +5,7 @@ com.foxinmy weixin4j - 1.7.9 + 1.8.0-SNAPSHOT weixin4j-server 1.1.9 diff --git a/weixin4j-serverX/pom.xml b/weixin4j-serverX/pom.xml index 2b9b7518..7a5d240f 100644 --- a/weixin4j-serverX/pom.xml +++ b/weixin4j-serverX/pom.xml @@ -6,7 +6,7 @@ com.foxinmy weixin4j - 1.7.9 + 1.8.0-SNAPSHOT weixin4j-serverX 0.0.1 diff --git a/weixin4j-wxa/pom.xml b/weixin4j-wxa/pom.xml index cec79627..81c827b4 100644 --- a/weixin4j-wxa/pom.xml +++ b/weixin4j-wxa/pom.xml @@ -5,7 +5,7 @@ com.foxinmy weixin4j - 1.7.9 + 1.8.0-SNAPSHOT weixin4j-wxa weixin4j-wxa diff --git a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/AESUtils.java b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/AESUtils.java index d424b587..748e9889 100644 --- a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/AESUtils.java +++ b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/AESUtils.java @@ -10,6 +10,9 @@ import javax.crypto.spec.SecretKeySpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; +/** + * @since 1.8 + */ final class AESUtils { private static boolean initialized = false; diff --git a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java index effcd87a..6c2ffe7d 100644 --- a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java +++ b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/WXBizDataCrypt.java @@ -10,6 +10,7 @@ import com.alibaba.fastjson.JSONObject; /** * 对微信小程序用户加密数据的解密. * + * @since 1.8 * @see 加密数据解密算法 */ public class WXBizDataCrypt { diff --git a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/package-info.java b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/package-info.java index 6a4bfcc5..c3fc0794 100644 --- a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/package-info.java +++ b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/package-info.java @@ -1,4 +1,7 @@ /** - * WeChat Mini Program support library. + * WeChat Mini + * Program support library. + * + * @since 1.8 */ package com.foxinmy.weixin4j.wxa;