+ * 通过后台接口可以获取小程序任意页面的二维码,扫描该二维码可以直接进入小程序对应的页面。 + * 目前微信支持两种二维码,小程序码,小程序二维码。 + *
+ * + * @see 获取二维码 + * @since 1.8 + */ +public class QrCodeApi extends WxaApi { + + private final TokenManager tokenManager; + + public QrCodeApi(TokenManager tokenManager) { + this.tokenManager = tokenManager; + } + + /** + * 获取小程序码. + * + *接口A: 适用于需要的码数量较少的业务场景
+ *+ * 注意:通过该接口生成的小程序码,永久有效,数量限制见微信小程序文档文末说明,请谨慎使用。 + * 用户扫描该码进入小程序后,将直接进入 path 对应的页面。 + *
+ * @param path 不能为空,最大长度 128 字节 + * @param width 二维码的宽度,默认值 430 + * @param autoColor 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 + * @param lineColorauthColor 为 false 时生效
+ * @param hyaline 是否需要透明底色, 为true时,生成透明底色的小程序码
+ * @return image bytes of WXA code.
+ * @throws WeixinException indicates get access token failed or get WXA code failed.
+ *
+ * @see 获取小程序码
+ */
+ public byte[] getWxaCode(
+ String path,
+ Integer width,
+ Boolean autoColor,
+ Color lineColor,
+ Boolean hyaline
+ ) throws WeixinException {
+ final String accessToken = tokenManager.getAccessToken();
+ final String getWxaCodeUri = this.getRequestUri("wxa_getwxacode", accessToken);
+ final WxaCodeParameter param = new WxaCodeParameter(path, width, autoColor, lineColor, hyaline);
+ return this.postAsImageBytes(getWxaCodeUri, param);
+ }
+
+ /**
+ * 获取小程序码.
+ *
+ * 接口B:适用于需要的码数量极多的业务场景
+ *
+ * 注意:通过该接口生成的小程序码,永久有效,数量暂无限制。
+ * 用户扫描该码进入小程序后,开发者需在对应页面获取的码中 scene 字段的值,再做处理逻辑。
+ * 使用如下代码可以获取到二维码中的 scene 字段的值。
+ * 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,
+ * 开发工具模拟时的 scene 的参数值需要进行 urlencode
+ *
+ * // 这是首页的 js
+ * Page({
+ * onLoad: function(options) {
+ * // options 中的 scene 需要使用 decodeURIComponent 才能获取到生成二维码时传入的 scene
+ * var scene = decodeURIComponent(options.scene)
+ * }
+ * })
+ *
+ *
autoColor 为 false 时生效,使用 rgb 设置颜色
+ * @param hyaline 是否需要透明底色,为true时,生成透明底色的小程序码
+ * @return image bytes of WXA code.
+ * @throws WeixinException indicates get access token failed or get WXA code failed.
+ *
+ * @see 获取小程序码
+ */
+ public byte[] getWxaCodeUnlimit(
+ String scene,
+ String page,
+ Integer width,
+ Boolean autoColor,
+ Color lineColor,
+ Boolean hyaline
+ ) throws WeixinException {
+ final String accessToken = tokenManager.getAccessToken();
+ final String getWxaCodeUnlimitUri = this.getRequestUri("wxa_getwxacodeunlimit", accessToken);
+ final WxaCodeUnlimitParameter param = new WxaCodeUnlimitParameter(scene, page, width, autoColor, lineColor, hyaline);
+ return this.postAsImageBytes(getWxaCodeUnlimitUri, param);
+ }
+
+ /**
+ * 获取小程序二维码.
+ *
+ * 接口C:适用于需要的码数量较少的业务场景
+ *+ * 注意:通过该接口生成的小程序二维码,永久有效,数量限制见微信小程序文档文末说明,请谨慎使用。 + * 用户扫描该码进入小程序后,将直接进入 path 对应的页面。 + *
+ * @param path 不能为空,最大长度 128 字节 + * @param width 二维码的宽度,默认值 430 + * @return image bytes of WXA QR code. + * @throws WeixinException indicates get access token failed or get WXA QR code failed. + * + * @see 获取小程序二维码 + */ + public byte[] createWxaQrCode( + String path, + Integer width + ) throws WeixinException { + final String accessToken = tokenManager.getAccessToken(); + final String createWxaQrCode = this.getRequestUri("wxaapp_createwxaqrcode", accessToken); + final WxaQrCodeParameter param = new WxaQrCodeParameter(path, width); + return this.postAsImageBytes(createWxaQrCode, param); + } + + private byte[] postAsImageBytes(String uri, Object param) throws WeixinException { + final String body = JSON.toJSONString(param); + final WeixinResponse response = this.weixinExecutor.post(uri, body); + return toImageBytes(response); + } + + private byte[] toImageBytes(WeixinResponse response) throws WeixinException { + try { + return readImageBytes(response); + } catch (IOException e) { + throw new WeixinException(e); + } catch (WxaCodeError e) { + throw new WeixinException(Integer.toString(e.getErrcode()), e.getErrmsg()); + } + } + + private byte[] readImageBytes(WeixinResponse response) throws IOException, WxaCodeError { + final String contentType = response.getHeaders().getContentType(); + if (contentType != null && contentType.equals(ContentType.APPLICATION_JSON.getMimeType().getType())) { + WxaCodeError wxaCodeError = JSON.parseObject(response.getContent(), WxaCodeError.class); + throw wxaCodeError; + } else { + return response.getContent(); + } + } + +} diff --git a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/api/WxaCodeError.java b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/api/WxaCodeError.java new file mode 100644 index 00000000..ff31c025 --- /dev/null +++ b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/api/WxaCodeError.java @@ -0,0 +1,39 @@ +package com.foxinmy.weixin4j.wxa.api; + +class WxaCodeError extends Exception { + + private static final long serialVersionUID = 2018052201L; + + private int errcode; + private String errmsg; + + public WxaCodeError() { + } + + public WxaCodeError(int errcode, String errmsg) { + this.errcode = errcode; + this.errmsg = errmsg; + } + + public int getErrcode() { + return errcode; + } + + public void setErrcode(int errcode) { + this.errcode = errcode; + } + + public String getErrmsg() { + return errmsg; + } + + public void setErrmsg(String errmsg) { + this.errmsg = errmsg; + } + + @Override + public String getMessage() { + return errmsg; + } + +} diff --git a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/api/WxaCodeParameter.java b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/api/WxaCodeParameter.java new file mode 100644 index 00000000..1854e37b --- /dev/null +++ b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/api/WxaCodeParameter.java @@ -0,0 +1,76 @@ +package com.foxinmy.weixin4j.wxa.api; + +import java.io.Serializable; + +import com.alibaba.fastjson.annotation.JSONField; + +class WxaCodeParameter implements Serializable { + + private static final long serialVersionUID = 2018052201L; + + private String path; + private Integer width; + private Boolean autoColor; + private Color color; + private Boolean hyaline; + + public WxaCodeParameter( + String path, + Integer width, + Boolean autoColor, + java.awt.Color color, + Boolean hyaline + ) { + this.path = path; + this.width = width; + this.autoColor = autoColor; + if (color != null) { + this.color = new Color(color); + } + this.hyaline = hyaline; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public Integer getWidth() { + return width; + } + + public void setWidth(Integer width) { + this.width = width; + } + + @JSONField(name = "auto_color") + public Boolean getAutoColor() { + return autoColor; + } + + public void setAutoColor(Boolean autoColor) { + this.autoColor = autoColor; + } + + @JSONField(name = "line_color") + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + @JSONField(name = "is_hyaline") + public Boolean getHyaline() { + return hyaline; + } + + public void setHyaline(Boolean hyaline) { + this.hyaline = hyaline; + } + +} diff --git a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/api/WxaCodeUnlimitParameter.java b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/api/WxaCodeUnlimitParameter.java new file mode 100644 index 00000000..303175b4 --- /dev/null +++ b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/api/WxaCodeUnlimitParameter.java @@ -0,0 +1,87 @@ +package com.foxinmy.weixin4j.wxa.api; + +import java.io.Serializable; + +import com.alibaba.fastjson.annotation.JSONField; + +class WxaCodeUnlimitParameter implements Serializable { + + private static final long serialVersionUID = 2018052201L; + + private String scene; + private String page; + private Integer width; + private Boolean autoColor; + private Color color; + private Boolean hyaline; + + public WxaCodeUnlimitParameter( + String scene, + String page, + Integer width, + Boolean autoColor, + java.awt.Color color, + Boolean hyaline + ) { + this.scene = scene; + this.page = page; + this.width = width; + this.autoColor = autoColor; + if (color != null) { + this.color = new Color(color); + } + this.hyaline = hyaline; + } + + public String getScene() { + return scene; + } + + public void setScene(String scene) { + this.scene = scene; + } + + public String getPage() { + return page; + } + + public void setPage(String page) { + this.page = page; + } + + public Integer getWidth() { + return width; + } + + public void setWidth(Integer width) { + this.width = width; + } + + @JSONField(name = "auto_color") + public Boolean getAutoColor() { + return autoColor; + } + + public void setAutoColor(Boolean autoColor) { + this.autoColor = autoColor; + } + + @JSONField(name = "line_color") + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + @JSONField(name = "is_hyaline") + public Boolean getHyaline() { + return hyaline; + } + + public void setHyaline(Boolean hyaline) { + this.hyaline = hyaline; + } + +} diff --git a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/api/WxaQrCodeParameter.java b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/api/WxaQrCodeParameter.java new file mode 100644 index 00000000..0470faae --- /dev/null +++ b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/api/WxaQrCodeParameter.java @@ -0,0 +1,33 @@ +package com.foxinmy.weixin4j.wxa.api; + +import java.io.Serializable; + +class WxaQrCodeParameter implements Serializable { + + private static final long serialVersionUID = 2018052201L; + + private String path; + private Integer width; + + public WxaQrCodeParameter(String path, Integer width) { + this.path = path; + this.width = width; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public Integer getWidth() { + return width; + } + + public void setWidth(Integer width) { + this.width = width; + } + +} diff --git a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/api/weixin.properties b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/api/weixin.properties index e92081b2..72a3725c 100644 --- a/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/api/weixin.properties +++ b/weixin4j-wxa/src/main/java/com/foxinmy/weixin4j/wxa/api/weixin.properties @@ -6,3 +6,12 @@ api_base_url=https://api.weixin.qq.com # \u767b\u5f55\u51ed\u8bc1\u6821\u9a8c sns_jscode2session={api_base_url}/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=%s + +# \u83b7\u53d6\u5c0f\u7a0b\u5e8f\u7801 \u63a5\u53e3A: \u9002\u7528\u4e8e\u9700\u8981\u7684\u7801\u6570\u91cf\u8f83\u5c11\u7684\u4e1a\u52a1\u573a\u666f +wxa_getwxacode={api_base_url}/wxa/getwxacode?access_token=%s + +# \u83b7\u53d6\u5c0f\u7a0b\u5e8f\u7801 \u63a5\u53e3B\uff1a\u9002\u7528\u4e8e\u9700\u8981\u7684\u7801\u6570\u91cf\u6781\u591a\u7684\u4e1a\u52a1\u573a\u666f +wxa_getwxacodeunlimit={api_base_url}/wxa/getwxacodeunlimit?access_token=%s + +# \u83b7\u53d6\u5c0f\u7a0b\u5e8f\u4e8c\u7ef4\u7801 \u63a5\u53e3C\uff1a\u9002\u7528\u4e8e\u9700\u8981\u7684\u7801\u6570\u91cf\u8f83\u5c11\u7684\u4e1a\u52a1\u573a\u666f +wxaapp_createwxaqrcode={api_base_url}/cgi-bin/wxaapp/createwxaqrcode?access_token=%s diff --git a/weixin4j-wxa/src/test/java/com/foxinmy/weixin4j/wxa/api/WxaCodeParameterTest.java b/weixin4j-wxa/src/test/java/com/foxinmy/weixin4j/wxa/api/WxaCodeParameterTest.java new file mode 100644 index 00000000..3f2f39c9 --- /dev/null +++ b/weixin4j-wxa/src/test/java/com/foxinmy/weixin4j/wxa/api/WxaCodeParameterTest.java @@ -0,0 +1,21 @@ +package com.foxinmy.weixin4j.wxa.api; + +import static org.junit.Assert.assertTrue; + +import java.awt.Color; + +import org.junit.Test; + +import com.alibaba.fastjson.JSON; + +public class WxaCodeParameterTest { + + @Test + public void test() { + WxaCodeParameter param = new WxaCodeParameter("pages/index/index", 430, false, new Color(1, 2, 3), true); + String json = JSON.toJSONString(param); + assertTrue(json.contains("\"line_color\":")); + assertTrue(json.contains("\"is_hyaline\":true")); + } + +} diff --git a/weixin4j-wxa/src/test/java/com/foxinmy/weixin4j/wxa/api/WxaCodeUnlimitParameterTest.java b/weixin4j-wxa/src/test/java/com/foxinmy/weixin4j/wxa/api/WxaCodeUnlimitParameterTest.java new file mode 100644 index 00000000..54c2d1dd --- /dev/null +++ b/weixin4j-wxa/src/test/java/com/foxinmy/weixin4j/wxa/api/WxaCodeUnlimitParameterTest.java @@ -0,0 +1,21 @@ +package com.foxinmy.weixin4j.wxa.api; + +import static org.junit.Assert.assertTrue; + +import java.awt.Color; + +import org.junit.Test; + +import com.alibaba.fastjson.JSON; + +public class WxaCodeUnlimitParameterTest { + + @Test + public void test() { + WxaCodeUnlimitParameter param = new WxaCodeUnlimitParameter("myScene", "pages/index/index", 430, false, new Color(1, 2, 3), true); + String json = JSON.toJSONString(param); + assertTrue(json.contains("\"line_color\":")); + assertTrue(json.contains("\"is_hyaline\":true")); + } + +} diff --git a/weixin4j-wxa/src/test/java/com/foxinmy/weixin4j/wxa/api/WxaQrCodeParameterTest.java b/weixin4j-wxa/src/test/java/com/foxinmy/weixin4j/wxa/api/WxaQrCodeParameterTest.java new file mode 100644 index 00000000..5d0b677e --- /dev/null +++ b/weixin4j-wxa/src/test/java/com/foxinmy/weixin4j/wxa/api/WxaQrCodeParameterTest.java @@ -0,0 +1,19 @@ +package com.foxinmy.weixin4j.wxa.api; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import com.alibaba.fastjson.JSON; + +public class WxaQrCodeParameterTest { + + @Test + public void test() { + WxaQrCodeParameter param = new WxaQrCodeParameter("myPath", 100); + String json = JSON.toJSONString(param); + assertTrue(json.contains("\"path\":\"myPath\"")); + assertTrue(json.contains("\"width\":100")); + } + +}