1
0
mirror of synced 2026-10-13 10:36:46 +08:00

🆕 #4040 【小程序】新增 URL Link 二维码快速跳转规则管理服务

This commit is contained in:
Copilot
2026-06-01 21:57:09 +08:00
committed by GitHub
parent abc9a971b5
commit 9de8759f0b
9 changed files with 375 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
package cn.binarywang.wx.miniapp.api;
import cn.binarywang.wx.miniapp.bean.qrcode.WxMaQrcodeJumpRule;
import me.chanjar.weixin.common.error.WxErrorException;
import java.util.List;
/**
* 小程序 URL Link 二维码快速跳转规则管理服务。
*/
public interface WxMaQrcodeJumpService {
/**
* 添加二维码快速跳转规则。
*
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/url-link/qr-code-quickly-jump.html
*
* @param rule 规则
* @return 结果(errmsg/errcode)
*/
String addRule(WxMaQrcodeJumpRule rule) throws WxErrorException;
/**
* 获取二维码快速跳转规则。
*
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/url-link/get-qr-code-jump-rule.html
*
* @param isDefault 是否查询默认规则
* @param prefix 路径前缀(最长 32 个字符)
* @return 二维码规则列表
*/
List<WxMaQrcodeJumpRule> getRules(Boolean isDefault, String prefix) throws WxErrorException;
/**
* 分页获取二维码快速跳转规则列表。
*
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/url-link/get-qr-code-jump-rule-list.html
*
* @param getType 1:查询前缀匹配的规则;2:查询默认规则
* @param pageNum 页码,从 1 开始
* @param pageSize 每页条数,最多 20
* @return 二维码规则列表
*/
List<WxMaQrcodeJumpRule> getRuleList(Integer getType, Integer pageNum, Integer pageSize) throws WxErrorException;
/**
* 删除二维码快速跳转规则。
*
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/url-link/delete-qr-code-jump-rule.html
*
* @param prefix 路径前缀
* @return 结果(errmsg/errcode)
*/
String deleteRule(String prefix) throws WxErrorException;
}

View File

@@ -472,6 +472,15 @@ public interface WxMaService extends WxService {
*/
WxMaLinkService getLinkService();
/**
* 获取 URL Link 二维码快速跳转规则管理服务对象。
*
* 文档:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/url-link/qr-code-quickly-jump.html
*
* @return 二维码快速跳转规则管理服务对象WxMaQrcodeJumpService
*/
WxMaQrcodeJumpService getQrcodeJumpService();
/**
* 获取电子发票报销方服务接口服务对象。
*

View File

@@ -140,6 +140,7 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
new WxMaShopAfterSaleServiceImpl(this);
private final WxMaShopDeliveryService shopDeliveryService = new WxMaShopDeliveryServiceImpl(this);
private final WxMaLinkService linkService = new WxMaLinkServiceImpl(this);
private final WxMaQrcodeJumpService qrcodeJumpService = new WxMaQrcodeJumpServiceImpl(this);
private final WxMaReimburseInvoiceService reimburseInvoiceService =
new WxMaReimburseInvoiceServiceImpl(this);
private final WxMaDeviceSubscribeService deviceSubscribeService =
@@ -788,6 +789,11 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
return this.linkService;
}
@Override
public WxMaQrcodeJumpService getQrcodeJumpService() {
return this.qrcodeJumpService;
}
@Override
public WxMaReimburseInvoiceService getReimburseInvoiceService() {
return this.reimburseInvoiceService;

View File

@@ -0,0 +1,76 @@
package cn.binarywang.wx.miniapp.api.impl;
import cn.binarywang.wx.miniapp.api.WxMaQrcodeJumpService;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.qrcode.WxMaQrcodeJumpRule;
import cn.binarywang.wx.miniapp.bean.qrcode.WxMaQrcodeJumpRuleListResponse;
import com.google.gson.JsonObject;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.common.error.WxErrorException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.QrcodeJump.*;
import static me.chanjar.weixin.common.util.json.WxGsonBuilder.create;
/**
* {@link WxMaQrcodeJumpService} 实现。
*/
@RequiredArgsConstructor
public class WxMaQrcodeJumpServiceImpl implements WxMaQrcodeJumpService {
private final WxMaService wxMaService;
@Override
public String addRule(WxMaQrcodeJumpRule rule) throws WxErrorException {
return this.wxMaService.post(QRCODE_JUMP_ADD, create().toJson(rule));
}
@Override
public List<WxMaQrcodeJumpRule> getRules(Boolean isDefault, String prefix) throws WxErrorException {
final JsonObject request = new JsonObject();
if (isDefault != null) {
request.addProperty("is_default", isDefault);
}
if (prefix != null) {
request.addProperty("prefix", prefix);
}
String response = this.wxMaService.post(QRCODE_JUMP_GET, request.toString());
WxMaQrcodeJumpRuleListResponse result = create().fromJson(response, WxMaQrcodeJumpRuleListResponse.class);
if (result == null || result.getRuleList() == null || result.getRuleList().isEmpty()) {
return Collections.emptyList();
}
return result.getRuleList();
}
@Override
public List<WxMaQrcodeJumpRule> getRuleList(Integer getType, Integer pageNum, Integer pageSize) throws WxErrorException {
final JsonObject request = new JsonObject();
if (getType != null) {
request.addProperty("get_type", getType);
}
if (pageNum != null) {
request.addProperty("page_num", pageNum);
}
if (pageSize != null) {
request.addProperty("page_size", pageSize);
}
String response = this.wxMaService.post(QRCODE_JUMP_GET_LIST, request.toString());
WxMaQrcodeJumpRuleListResponse result = create().fromJson(response, WxMaQrcodeJumpRuleListResponse.class);
if (result == null || result.getRuleList() == null || result.getRuleList().isEmpty()) {
return Collections.emptyList();
}
return result.getRuleList();
}
@Override
public String deleteRule(String prefix) throws WxErrorException {
final Map<String, String> request = new HashMap<>(1);
request.put("prefix", prefix);
return this.wxMaService.post(QRCODE_JUMP_DELETE, create().toJson(request));
}
}

View File

@@ -0,0 +1,58 @@
package cn.binarywang.wx.miniapp.bean.qrcode;
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
/**
* URL Link 二维码快速跳转规则。
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class WxMaQrcodeJumpRule implements Serializable {
private static final long serialVersionUID = -3450269467817402123L;
/**
* 跳转链接规则前缀,最多 32 个字符。
*/
@SerializedName("prefix")
private String prefix;
/**
* 是否支持子路径匹配。
*/
@SerializedName("permit_sub_rule")
private Boolean permitSubRule;
/**
* 跳转版本,1:正式版;2:测试版;3:体验版。
*/
@SerializedName("open_version")
private Integer openVersion;
/**
* 正式版跳转页面。
*/
@SerializedName("path")
private String path;
/**
* 测试版/体验版可跳转小程序信息。
*/
@SerializedName("debug_wxa_info")
private List<WxMaQrcodeJumpWxaItem> debugWxaInfo;
/**
* 二维码规则是否失效。
*/
@SerializedName("is_expire")
private Boolean isExpire;
}

View File

@@ -0,0 +1,28 @@
package cn.binarywang.wx.miniapp.bean.qrcode;
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
/**
* URL Link 二维码快速跳转规则列表返回值。
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class WxMaQrcodeJumpRuleListResponse implements Serializable {
private static final long serialVersionUID = 6706970228943946110L;
/**
* 规则列表。
*/
@SerializedName("rule_list")
private List<WxMaQrcodeJumpRule> ruleList;
}

View File

@@ -0,0 +1,33 @@
package cn.binarywang.wx.miniapp.bean.qrcode;
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* URL Link 跳转规则中的小程序信息。
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class WxMaQrcodeJumpWxaItem implements Serializable {
private static final long serialVersionUID = -675341413130655505L;
/**
* 小程序 appid。
*/
@SerializedName("appid")
private String appId;
/**
* 跳转页面路径。
*/
@SerializedName("path")
private String path;
}

View File

@@ -301,6 +301,16 @@ public class WxMaApiUrlConstants {
String QUERY_URLLINK_URL = "https://api.weixin.qq.com/wxa/query_urllink";
}
/**
* URL Link 二维码快速跳转规则管理.
*/
public interface QrcodeJump {
String QRCODE_JUMP_ADD = "https://api.weixin.qq.com/wxaapi/wxaqrcodefast/addcategoryrule";
String QRCODE_JUMP_GET = "https://api.weixin.qq.com/wxaapi/wxaqrcodefast/getcategory";
String QRCODE_JUMP_GET_LIST = "https://api.weixin.qq.com/wxaapi/wxaqrcodefast/getcategorybypage";
String QRCODE_JUMP_DELETE = "https://api.weixin.qq.com/wxaapi/wxaqrcodefast/deletecategoryrule";
}
public interface ShortLink {
String GENERATE_SHORT_LINK_URL = "https://api.weixin.qq.com/wxa/genwxashortlink";
}

View File

@@ -0,0 +1,99 @@
package cn.binarywang.wx.miniapp.api.impl;
import cn.binarywang.wx.miniapp.api.WxMaQrcodeJumpService;
import cn.binarywang.wx.miniapp.bean.qrcode.WxMaQrcodeJumpRule;
import me.chanjar.weixin.common.error.WxErrorException;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.List;
import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.QrcodeJump.*;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
/**
* {@link WxMaQrcodeJumpServiceImpl} 单元测试。
*/
public class WxMaQrcodeJumpServiceImplTest {
private cn.binarywang.wx.miniapp.api.WxMaService wxMaService;
private WxMaQrcodeJumpService qrcodeJumpService;
@BeforeMethod
public void setUp() {
this.wxMaService = mock(cn.binarywang.wx.miniapp.api.WxMaService.class);
this.qrcodeJumpService = new WxMaQrcodeJumpServiceImpl(this.wxMaService);
}
@Test
public void testAddRule() throws WxErrorException {
when(this.wxMaService.post(anyString(), anyString())).thenReturn("{\"errcode\":0,\"errmsg\":\"ok\"}");
WxMaQrcodeJumpRule rule = WxMaQrcodeJumpRule.builder()
.prefix("/pages/index")
.permitSubRule(true)
.openVersion(1)
.path("pages/index")
.build();
String result = this.qrcodeJumpService.addRule(rule);
assertTrue(result.contains("\"errcode\":0"));
verify(this.wxMaService).post(eq(QRCODE_JUMP_ADD), anyString());
}
@Test
public void testGetRules() throws WxErrorException {
when(this.wxMaService.post(anyString(), anyString()))
.thenReturn("{\"rule_list\":[{\"prefix\":\"/pages/index\",\"path\":\"pages/index\"}]}");
List<WxMaQrcodeJumpRule> rules = this.qrcodeJumpService.getRules(false, "/pages");
assertNotNull(rules);
assertEquals(rules.size(), 1);
assertEquals(rules.get(0).getPrefix(), "/pages/index");
assertEquals(rules.get(0).getPath(), "pages/index");
verify(this.wxMaService).post(eq(QRCODE_JUMP_GET), eq("{\"is_default\":false,\"prefix\":\"/pages\"}"));
}
@Test
public void testGetRuleList() throws WxErrorException {
when(this.wxMaService.post(anyString(), anyString()))
.thenReturn("{\"rule_list\":[{\"prefix\":\"/pages/index\",\"path\":\"pages/index\"}]}");
List<WxMaQrcodeJumpRule> rules = this.qrcodeJumpService.getRuleList(1, 1, 20);
assertNotNull(rules);
assertEquals(rules.size(), 1);
assertEquals(rules.get(0).getPrefix(), "/pages/index");
verify(this.wxMaService).post(eq(QRCODE_JUMP_GET_LIST), eq("{\"get_type\":1,\"page_num\":1,\"page_size\":20}"));
}
@Test
public void testGetRuleListWhenNoRules() throws WxErrorException {
when(this.wxMaService.post(anyString(), anyString())).thenReturn("{\"errcode\":0,\"errmsg\":\"ok\"}");
List<WxMaQrcodeJumpRule> rules = this.qrcodeJumpService.getRuleList(null, null, null);
assertNotNull(rules);
assertTrue(rules.isEmpty());
verify(this.wxMaService).post(eq(QRCODE_JUMP_GET_LIST), eq("{}"));
}
@Test
public void testDeleteRule() throws WxErrorException {
when(this.wxMaService.post(anyString(), anyString())).thenReturn("{\"errcode\":0,\"errmsg\":\"ok\"}");
String result = this.qrcodeJumpService.deleteRule("/pages/index");
assertTrue(result.contains("\"errcode\":0"));
verify(this.wxMaService).post(eq(QRCODE_JUMP_DELETE), eq("{\"prefix\":\"/pages/index\"}"));
}
}