diff --git a/images/api-signature/api-signature-1.png b/images/api-signature/api-signature-1.png new file mode 100644 index 000000000..e4d4e1e27 Binary files /dev/null and b/images/api-signature/api-signature-1.png differ diff --git a/images/api-signature/api-signature-2.png b/images/api-signature/api-signature-2.png new file mode 100644 index 000000000..30982f498 Binary files /dev/null and b/images/api-signature/api-signature-2.png differ diff --git a/weixin-java-miniapp/api-signature-readme.md b/weixin-java-miniapp/api-signature-readme.md new file mode 100644 index 000000000..1ab8ab346 --- /dev/null +++ b/weixin-java-miniapp/api-signature-readme.md @@ -0,0 +1,46 @@ +# 使用API签名 + +如果对API签名不了解,可先阅读微信文档 [服务端API签名指南](https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/getting_started/api_signature.html) + +有API数据加密与签名两种功能,此处按照微信文档,简称为签名。 + +## 程序内设置 + +[WxMaConfig](src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java)类增加了几个属性,分别对应小程序内设置的签名密钥等。 + +* apiSignatureAesKey +* apiSignatureAesKeySn +* apiSignatureRsaPrivateKey +* apiSignatureRsaPrivateKeySn + +这4个属性需要按照小程序后台设置。 + +## 小程序后台设置/查看签名用密钥 + +在小程序后台,开发管理 -> 开发设置 -> API安全处,可以看到如下图界面。 + +![图一](../images/api-signature/api-signature-1.png) + +上图中A处对应 apiSignatureAesKeySn; B处对应apiSignatureAesKey; C处对应apiSignatureRsaPrivateKeySn + +apiSignatureRsaPrivateKey 在上图中**无**对应,C处右侧是公钥,apiSignatureRsaPrivateKey 需要的是私钥。 + +可点击图上右上角的修改,打开如下图的设置页面 + +![图二](../images/api-signature/api-signature-2.png) + +首先确保对称密钥选中 AES256,非对称密钥选中RSA。不要选SM4和SM2。 +(如果需要支持SM4/SM2,可修改BaseWxMaServiceImpl.java中postWithSignature方法中相应部分实现)。 + +在API非对称密钥中下方左侧有个「随机生成密钥对」,点击它,然后点它右侧的「下载私钥」,之后点击「确认」保存。 +下载得到的文件是PKCS1格式的私钥,用openssl可转成PKCS8格式。apiSignatureRsaPrivateKey 需要设置的是PKCS8格式的私钥。 + +注意: + +1. 如果不先点击「随机生成密钥对」,直接点击「下载私钥」得到的是公钥,公钥在这里没有用途。 +2. 打开下载的文件,第一行是「-----BEGIN RSA PRIVATE KEY-----」说明是PKCS1格式私钥。 +3. PKCS8格式第一行是「-----BEGIN PRIVATE KEY-----」 +4. 转换命令 `openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in PKCS1格式密钥文件名 -out 新的PKCS8格式密钥文件名` +5. 如果密钥文件有 PUBLIC KEY 字样,说明下载了公钥,重新生成密钥对,下载私钥 + + diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaIntracityService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaIntracityService.java new file mode 100644 index 000000000..80cd88b46 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaIntracityService.java @@ -0,0 +1,86 @@ +package cn.binarywang.wx.miniapp.api; + +import cn.binarywang.wx.miniapp.bean.intractiy.*; +import java.util.List; +import me.chanjar.weixin.common.error.WxErrorException; + +/** + * 微信小程序 物流服务 同城配送服务API
+ * *不是*即时配送接口,两个相近,容易混淆
+ * 微信相关接口
+ * https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/express/business/intracity_service.html + */ +public interface WxMaIntracityService { + + /** 申请开通门店权限 */ + void apply() throws WxErrorException; + + /** 创建门店 */ + String createStore(WxMaStore store) throws WxErrorException; + + /** + * 更新门店;只更新store中不为null的部分 wxStoreId和outStoreId至少要有一个不为null,根据这2个来更新。 仅支持更新 storeName orderPattern + * serviceTransPrefer addressInfo几个属性 + */ + void updateStore(WxMaStore store) throws WxErrorException; + + /** 查询门店(列出所有门店) */ + List listAllStores() throws WxErrorException; + + /** 根据wx_store_id查询门店 */ + WxMaStore queryStoreByWxStoreId(String wxStoreId) throws WxErrorException; + + /** 根据 out_store_id 查询门店 */ + List queryStoreByOutStoreId(String outStoreId) throws WxErrorException; + + /** 门店运费充值,返回充值URL */ + String storeCharge(WxMaStoreChargeRequest request) throws WxErrorException; + + /** 门店运费退款,返回退款金额 */ + int storeRefund(WxMaStoreRefundRequest request) throws WxErrorException; + + /** 门店运费流水查询 */ + WxMaStoreFlowResponse queryFlow( + WxMaQueryFlowRequest request) throws WxErrorException; + + /** 查询门店余额 */ + WxMaStoreBalance balanceQuery(String wxStoreId, String serviceTransId, PayMode payMode) + throws WxErrorException; + + /** + * 设置扣费主体
+ * 接口调用成功后,小程序的管理员会收到模板消息,点击模板消息确认更改门店扣费主体后,修改生效。 + */ + void setPayMode(PayMode payMode) throws WxErrorException; + + /** 查询扣费主体 */ + WxMaGetPayModeResponse getPayMode() throws WxErrorException; + + /** 查询运费 */ + WxMaAddOrderResponse preAddOrder(WxMaPreAddOrderRequest request) throws WxErrorException; + + /** 创建配送单 */ + WxMaAddOrderResponse addOrder(WxMaAddOrderRequest order) throws WxErrorException; + + /** 查询配送单 根据wxOrderId */ + WxMaOrder queryOrderByWxOrderId(String wxOrderId) throws WxErrorException; + + /** 依据商户订单号 查询配送单 */ + WxMaOrder queryOrderByStoreOrderId(String wxStoreId, String storeOrderId) throws WxErrorException; + + /** 依据微信订单号 查询配送单 */ + WxMaCancelOrderResponse cancelOrderByWxOrderId( + String wxOrderId, int cancelReasonId, String cancelReason) throws WxErrorException; + + /** 依据商户订单号 查询配送单 */ + WxMaCancelOrderResponse cancelOrderByStoreOrderId( + String wxStoreId, String storeOrderId, int cancelReasonId, String cancelReason) + throws WxErrorException; + + /** + * 查询支持同城配送的城市 + * + * @param serviceTransId 运力ID,传NULL则返回所有 + */ + List getCity(String serviceTransId) throws WxErrorException; +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java index 83cbf40a4..9d55df379 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java @@ -1,7 +1,11 @@ package cn.binarywang.wx.miniapp.api; +import cn.binarywang.wx.miniapp.bean.WxMaApiResponse; import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; import cn.binarywang.wx.miniapp.config.WxMaConfig; +import cn.binarywang.wx.miniapp.executor.ApiSignaturePostRequestExecutor; +import com.google.gson.JsonObject; +import java.util.Map; import java.util.function.Function; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.service.WxImgProcService; @@ -11,33 +15,25 @@ import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; -import java.util.Map; - /** * The interface Wx ma service. * * @author Binary Wang */ public interface WxMaService extends WxService { - /** - * 获取access_token. - */ - String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; + /** 获取access_token. */ + String GET_ACCESS_TOKEN_URL = + "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; + String GET_STABLE_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/stable_token"; - - /** - * The constant JSCODE_TO_SESSION_URL. - */ + /** The constant JSCODE_TO_SESSION_URL. */ String JSCODE_TO_SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session"; - /** - * getPaidUnionId - */ + + /** getPaidUnionId */ String GET_PAID_UNION_ID_URL = "https://api.weixin.qq.com/wxa/getpaidunionid"; - /** - * 导入抽样数据 - */ + /** 导入抽样数据 */ String SET_DYNAMIC_DATA_URL = "https://api.weixin.qq.com/wxa/setdynamicdata"; /** @@ -51,6 +47,7 @@ public interface WxMaService extends WxService { /** * 导入抽样数据 + * *
    * 第三方通过调用微信API,将数据写入到setdynamicdata这个API。每个Post数据包不超过5K,若数据过多可开多进(线)程并发导入数据(例如:数据量为十万量级可以开50个线程并行导数据)。
    * 文档地址:https://wsad.weixin.qq.com/wsad/zh_CN/htmledition/widget-docs-v3/html/custom/quickstart/implement/import/index.html
@@ -58,21 +55,23 @@ public interface WxMaService extends WxService {
    * 
* * @param lifespan 数据有效时间,秒为单位,一般为86400,一天一次导入的频率 - * @param type 用于标识数据所属的服务类目 - * @param scene 1代表用于搜索的数据 - * @param data 推送到微信后台的数据列表,该数据被微信用于流量分配,注意该字段为string类型而不是object + * @param type 用于标识数据所属的服务类目 + * @param scene 1代表用于搜索的数据 + * @param data 推送到微信后台的数据列表,该数据被微信用于流量分配,注意该字段为string类型而不是object * @throws WxErrorException . */ void setDynamicData(int lifespan, String type, int scene, String data) throws WxErrorException; /** + * + * *
    * 验证消息的确来自微信服务器.
    * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319&token=&lang=zh_CN
    * 
* * @param timestamp the timestamp - * @param nonce the nonce + * @param nonce the nonce * @param signature the signature * @return the boolean */ @@ -88,6 +87,8 @@ public interface WxMaService extends WxService { String getAccessToken() throws WxErrorException; /** + * + * *
    * 获取access_token,本方法线程安全.
    * 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限
@@ -106,6 +107,8 @@ public interface WxMaService extends WxService {
   String getAccessToken(boolean forceRefresh) throws WxErrorException;
 
   /**
+   *
+   *
    * 
    * 用户支付完成后,获取该用户的 UnionId,无需用户授权。本接口支持第三方平台代理查询。
    *
@@ -114,33 +117,45 @@ public interface WxMaService extends WxService {
    * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api/getPaidUnionId.html
    * 
* - * @param openid 必填 支付用户唯一标识 + * @param openid 必填 支付用户唯一标识 * @param transactionId 非必填 微信支付订单号 - * @param mchId 非必填 微信支付分配的商户号,和商户订单号配合使用 - * @param outTradeNo 非必填 微信支付商户订单号,和商户号配合使用 + * @param mchId 非必填 微信支付分配的商户号,和商户订单号配合使用 + * @param outTradeNo 非必填 微信支付商户订单号,和商户号配合使用 * @return UnionId. paid union id * @throws WxErrorException . */ - String getPaidUnionId(String openid, String transactionId, String mchId, String outTradeNo) throws WxErrorException; + String getPaidUnionId(String openid, String transactionId, String mchId, String outTradeNo) + throws WxErrorException; /** + * + * *
    * Service没有实现某个API的时候,可以用这个,
    * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
    * 可以参考,{@link MediaUploadRequestExecutor}的实现方法
    * 
* - * @param . - * @param . + * @param . + * @param . * @param executor 执行器 - * @param uri 接口请求地址 - * @param data 参数或请求数据 + * @param uri 接口请求地址 + * @param data 参数或请求数据 * @return . t * @throws WxErrorException the wx error exception */ T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; + WxMaApiResponse execute( + ApiSignaturePostRequestExecutor executor, + String uri, + Map headers, + String data) + throws WxErrorException; + /** + * + * *
    * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试.
    * 默认:1000ms
@@ -151,6 +166,8 @@ public interface WxMaService extends WxService {
   void setRetrySleepMillis(int retrySleepMillis);
 
   /**
+   *
+   *
    * 
    * 设置当微信系统响应系统繁忙时,最大重试次数.
    * 默认:5次
@@ -177,7 +194,7 @@ public interface WxMaService extends WxService {
   /**
    * Map里 加入新的 {@link WxMaConfig},适用于动态添加新的微信公众号配置.
    *
-   * @param miniappId     小程序标识
+   * @param miniappId 小程序标识
    * @param configStorage 新的微信配置
    */
   void addConfig(String miniappId, WxMaConfig configStorage);
@@ -190,8 +207,8 @@ public interface WxMaService extends WxService {
   void removeConfig(String miniappId);
 
   /**
-   * 注入多个 {@link WxMaConfig} 的实现. 并为每个 {@link WxMaConfig} 赋予不同的 {@link String mpId} 值
-   * 随机采用一个{@link String mpId}进行Http初始化操作
+   * 注入多个 {@link WxMaConfig} 的实现. 并为每个 {@link WxMaConfig} 赋予不同的 {@link String mpId} 值 随机采用一个{@link
+   * String mpId}进行Http初始化操作
    *
    * @param configs WxMaConfig map
    */
@@ -200,7 +217,7 @@ public interface WxMaService extends WxService {
   /**
    * 注入多个 {@link WxMaConfig} 的实现. 并为每个 {@link WxMaConfig} 赋予不同的 {@link String label} 值
    *
-   * @param configs          WxMaConfig map
+   * @param configs WxMaConfig map
    * @param defaultMiniappId 设置一个{@link WxMaConfig} 所对应的{@link String defaultMiniappId}进行Http初始化
    */
   void setMultiConfigs(Map configs, String defaultMiniappId);
@@ -328,9 +345,7 @@ public interface WxMaService extends WxService {
    */
   WxMaPluginService getPluginService();
 
-  /**
-   * 初始化http请求对象.
-   */
+  /** 初始化http请求对象. */
   void initHttp();
 
   /**
@@ -403,7 +418,6 @@ public interface WxMaService extends WxService {
    */
   WxMaShopAfterSaleService getShopAfterSaleService();
 
-
   /**
    * 返回小程序交易组件-物流服务接口
    *
@@ -411,7 +425,6 @@ public interface WxMaService extends WxService {
    */
   WxMaShopDeliveryService getShopDeliveryService();
 
-
   /**
    * 返回小程序交易组件-订单服务接口
    *
@@ -544,18 +557,21 @@ public interface WxMaService extends WxService {
    * @return getWxMaOpenApiService
    */
   WxMaOpenApiService getWxMaOpenApiService();
+
   /**
    * 小程序短剧管理
    *
    * @return getWxMaVodService
    */
   WxMaVodService getWxMaVodService();
+
   /**
    * 小程序虚拟支付
    *
    * @return getWxMaXPayService
    */
   WxMaXPayService getWxMaXPayService();
+
   WxMaExpressDeliveryReturnService getWxMaExpressDeliveryReturnService();
 
   /**
@@ -564,4 +580,14 @@ public interface WxMaService extends WxService {
    * @return WxMaPromotionService
    */
   WxMaPromotionService getWxMaPromotionService();
+
+  String postWithSignature(String url, Object obj) throws WxErrorException;
+
+  String postWithSignature(String url, JsonObject jsonObject) throws WxErrorException;
+
+  /**
+   * 微信物流服务 -- 同城配送
+   * https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/express/business/intracity_service.html
+   */
+  WxMaIntracityService getIntracityService();
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java
index 6b67b3c28..a9114465a 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java
@@ -1,16 +1,35 @@
 package cn.binarywang.wx.miniapp.api.impl;
 
 import cn.binarywang.wx.miniapp.api.*;
+import cn.binarywang.wx.miniapp.bean.WxMaApiResponse;
 import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
 import cn.binarywang.wx.miniapp.config.WxMaConfig;
+import cn.binarywang.wx.miniapp.executor.ApiSignaturePostRequestExecutor;
 import cn.binarywang.wx.miniapp.util.WxMaConfigHolder;
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
+import com.google.gson.FieldNamingPolicy;
 import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
 import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyFactory;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.PSSParameterSpec;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
 import java.util.function.Function;
+import javax.crypto.Cipher;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.api.WxConsts;
 import me.chanjar.weixin.common.bean.CommonUploadParam;
@@ -25,26 +44,65 @@ import me.chanjar.weixin.common.service.WxImgProcService;
 import me.chanjar.weixin.common.service.WxOcrService;
 import me.chanjar.weixin.common.util.DataUtils;
 import me.chanjar.weixin.common.util.crypto.SHA1;
-import me.chanjar.weixin.common.util.http.RequestExecutor;
-import me.chanjar.weixin.common.util.http.RequestHttp;
-import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
-import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
+import me.chanjar.weixin.common.util.http.*;
 import me.chanjar.weixin.common.util.json.GsonParser;
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 import org.apache.commons.lang3.StringUtils;
 
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
-
 /**
  * @author Binary Wang
  * @see #doGetAccessTokenRequest
  */
 @Slf4j
 public abstract class BaseWxMaServiceImpl implements WxMaService, RequestHttp {
+  /**
+   * 开启API签名验证后需要API签名的接口,根据 https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/
+   * 整理,uri包含下这些字符串且配置了api signature aes ras key 自动用签名接口
+   */
+  protected static final String[] urlPathSupportApiSignature =
+      new String[] {
+        "cgi-bin/clear_quota",
+        "cgi-bin/openapi/quota/get",
+        "cgi-bin/openapi/rid/get",
+        "wxa/getpluginopenpid",
+        "wxa/business/checkencryptedmsg",
+        "wxa/business/getuserencryptkey",
+        "wxa/business/getuserphonenumber",
+        "wxa/getwxacode",
+        "wxa/getwxacodeunlimit",
+        "cgi-bin/wxaapp/createwxaqrcode",
+        "cgi-bin/message/custom/send",
+        "cgi-bin/message/wxopen/updatablemsg/send",
+        "wxaapi/newtmpl/deltemplate",
+        "cgi-bin/message/subscribe/send",
+        "wxaapi/newtmpl/addtemplate",
+        "wxa/msg_sec_check",
+        "wxa/media_check_async",
+        "wxa/getuserriskrank",
+        "datacube/getweanalysisappidweeklyretaininfo",
+        "datacube/getweanalysisappidmonthlyretaininfo",
+        "datacube/getweanalysisappiddailyretaininfo",
+        "datacube/getweanalysisappidmonthlyvisittrend",
+        "datacube/getweanalysisappiddailyvisittrend",
+        "datacube/getweanalysisappidweeklyvisittrend",
+        "datacube/getweanalysisappiddailysummarytrend",
+        "datacube/getweanalysisappidvisitpage",
+        "datacube/getweanalysisappiduserportrait",
+        "wxa/business/performance/boot",
+        "datacube/getweanalysisappidvisitdistribution",
+        "wxa/getwxadevinfo",
+        "wxaapi/log/get_performance",
+        "wxaapi/log/jserr_detail",
+        "wxaapi/log/jserr_list",
+        "wxa/devplugin",
+        "wxa/plugin",
+        "cgi-bin/express/business/account/getall",
+        "cgi-bin/express/business/delivery/getall",
+        "cgi-bin/express/business/printer/getall",
+        "wxa/servicemarket",
+        "cgi-bin/soter/verify_signature"
+      };
+
   protected static final Gson GSON = new Gson();
   private final WxMaMsgService kefuService = new WxMaMsgServiceImpl(this);
   private final WxMaMediaService materialService = new WxMaMediaServiceImpl(this);
@@ -75,26 +133,33 @@ public abstract class BaseWxMaServiceImpl implements WxMaService, RequestH
   private final WxMaShopCatService shopCatService = new WxMaShopCatServiceImpl(this);
   private final WxMaShopImgService shopImgService = new WxMaShopImgServiceImpl(this);
   private final WxMaShopAuditService shopAuditService = new WxMaShopAuditServiceImpl(this);
-  private final WxMaShopAfterSaleService shopAfterSaleService = new WxMaShopAfterSaleServiceImpl(this);
+  private final WxMaShopAfterSaleService shopAfterSaleService =
+      new WxMaShopAfterSaleServiceImpl(this);
   private final WxMaShopDeliveryService shopDeliveryService = new WxMaShopDeliveryServiceImpl(this);
   private final WxMaLinkService linkService = new WxMaLinkServiceImpl(this);
-  private final WxMaReimburseInvoiceService reimburseInvoiceService = new WxMaReimburseInvoiceServiceImpl(this);
-  private final WxMaDeviceSubscribeService deviceSubscribeService = new WxMaDeviceSubscribeServiceImpl(this);
+  private final WxMaReimburseInvoiceService reimburseInvoiceService =
+      new WxMaReimburseInvoiceServiceImpl(this);
+  private final WxMaDeviceSubscribeService deviceSubscribeService =
+      new WxMaDeviceSubscribeServiceImpl(this);
   private final WxMaMarketingService marketingService = new WxMaMarketingServiceImpl(this);
-  private final WxMaImmediateDeliveryService immediateDeliveryService = new WxMaImmediateDeliveryServiceImpl(this);
+  private final WxMaImmediateDeliveryService immediateDeliveryService =
+      new WxMaImmediateDeliveryServiceImpl(this);
   private final WxMaShopSharerService shopSharerService = new WxMaShopSharerServiceImpl(this);
   private final WxMaProductService productService = new WxMaProductServiceImpl(this);
   private final WxMaProductOrderService productOrderService = new WxMaProductOrderServiceImpl(this);
   private final WxMaShopCouponService wxMaShopCouponService = new WxMaShopCouponServiceImpl(this);
   private final WxMaShopPayService wxMaShopPayService = new WxMaShopPayServiceImpl(this);
 
-  private final WxMaOrderShippingService wxMaOrderShippingService = new WxMaOrderShippingServiceImpl(this);
+  private final WxMaOrderShippingService wxMaOrderShippingService =
+      new WxMaOrderShippingServiceImpl(this);
 
   private final WxMaOpenApiService wxMaOpenApiService = new WxMaOpenApiServiceImpl(this);
   private final WxMaVodService wxMaVodService = new WxMaVodServiceImpl(this);
   private final WxMaXPayService wxMaXPayService = new WxMaXPayServiceImpl(this);
-  private final WxMaExpressDeliveryReturnService wxMaExpressDeliveryReturnService = new WxMaExpressDeliveryReturnServiceImpl(this);
+  private final WxMaExpressDeliveryReturnService wxMaExpressDeliveryReturnService =
+      new WxMaExpressDeliveryReturnServiceImpl(this);
   private final WxMaPromotionService wxMaPromotionService = new WxMaPromotionServiceImpl(this);
+  private final WxMaIntracityService intracityService = new WxMaIntracityServiceImpl(this);
 
   private Map configMap = new HashMap<>();
   private int retrySleepMillis = 1000;
@@ -107,7 +172,7 @@ public abstract class BaseWxMaServiceImpl implements WxMaService, RequestH
 
   @Override
   public String getPaidUnionId(String openid, String transactionId, String mchId, String outTradeNo)
-    throws WxErrorException {
+      throws WxErrorException {
     Map params = new HashMap<>(8);
     params.put("openid", openid);
 
@@ -123,7 +188,8 @@ public abstract class BaseWxMaServiceImpl implements WxMaService, RequestH
       params.put("out_trade_no", outTradeNo);
     }
 
-    String responseContent = this.get(GET_PAID_UNION_ID_URL, Joiner.on("&").withKeyValueSeparator("=").join(params));
+    String responseContent =
+        this.get(GET_PAID_UNION_ID_URL, Joiner.on("&").withKeyValueSeparator("=").join(params));
     WxError error = WxError.fromJson(responseContent, WxType.MiniApp);
     if (error.getErrorCode() != 0) {
       throw new WxErrorException(error);
@@ -141,12 +207,14 @@ public abstract class BaseWxMaServiceImpl implements WxMaService, RequestH
     params.put("js_code", jsCode);
     params.put("grant_type", "authorization_code");
 
-    String result = get(JSCODE_TO_SESSION_URL, Joiner.on("&").withKeyValueSeparator("=").join(params));
+    String result =
+        get(JSCODE_TO_SESSION_URL, Joiner.on("&").withKeyValueSeparator("=").join(params));
     return WxMaJscode2SessionResult.fromJson(result);
   }
 
   @Override
-  public void setDynamicData(int lifespan, String type, int scene, String data) throws WxErrorException {
+  public void setDynamicData(int lifespan, String type, int scene, String data)
+      throws WxErrorException {
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("lifespan", lifespan);
     jsonObject.addProperty("query", WxGsonBuilder.create().toJson(ImmutableMap.of("type", type)));
@@ -211,7 +279,6 @@ public abstract class BaseWxMaServiceImpl implements WxMaService, RequestH
    */
   protected abstract String doGetAccessTokenRequest() throws IOException;
 
-
   /**
    * 通过网络请求获取稳定版接口调用凭据
    *
@@ -225,14 +292,33 @@ public abstract class BaseWxMaServiceImpl implements WxMaService, RequestH
     return execute(SimpleGetRequestExecutor.create(this), url, queryParam);
   }
 
+  private boolean isApiSignatureRequired(String url) {
+    return this.getWxMaConfig().getApiSignatureAesKey() != null
+        && Arrays.stream(urlPathSupportApiSignature).anyMatch(part -> url.contains(part));
+  }
+
   @Override
   public String post(String url, String postData) throws WxErrorException {
-    return execute(SimplePostRequestExecutor.create(this), url, postData);
+    if (isApiSignatureRequired(url)) {
+      // 接口需要签名
+      log.debug("已经配置接口需要签名,接口{}将走加密访问路径", url);
+      JsonObject jsonObject = GSON.fromJson(postData, JsonObject.class);
+      return postWithSignature(url, jsonObject);
+    } else {
+      return execute(SimplePostRequestExecutor.create(this), url, postData);
+    }
   }
 
   @Override
   public String post(String url, Object obj) throws WxErrorException {
-    return this.execute(SimplePostRequestExecutor.create(this), url, WxGsonBuilder.create().toJson(obj));
+    if (isApiSignatureRequired(url)) {
+      // 接口需要签名
+      log.debug("已经配置接口需要签名,接口{}将走加密访问路径", url);
+      return postWithSignature(url, obj);
+    } else {
+      return this.execute(
+          SimplePostRequestExecutor.create(this), url, WxGsonBuilder.create().toJson(obj));
+    }
   }
 
   @Override
@@ -240,34 +326,67 @@ public abstract class BaseWxMaServiceImpl implements WxMaService, RequestH
     return this.post(url, obj.toJson());
   }
 
-  @Override
-  public String upload(String url, CommonUploadParam param) throws WxErrorException {
-    RequestExecutor executor = CommonUploadRequestExecutor.create(getRequestHttp());
-    return this.execute(executor, url, param);
-  }
-
   @Override
   public String post(String url, JsonObject jsonObject) throws WxErrorException {
     return this.post(url, jsonObject.toString());
   }
 
-  /**
-   * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求
-   */
   @Override
-  public  T execute(RequestExecutor executor, String uri, E data) throws WxErrorException {
+  public String upload(String url, CommonUploadParam param) throws WxErrorException {
+    RequestExecutor executor =
+        CommonUploadRequestExecutor.create(getRequestHttp());
+    return this.execute(executor, url, param);
+  }
+
+  /** 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 */
+  @Override
+  public  R execute(RequestExecutor executor, String uri, T data)
+      throws WxErrorException {
+    String dataForLog;
+    if (data instanceof String) {
+      dataForLog = DataUtils.handleDataWithSecret((String) data);
+    } else {
+      dataForLog = data.toString();
+    }
+    return excuteWithRetry(
+        (uriWithAccessToken) -> executor.execute(uriWithAccessToken, data, WxType.MiniApp),
+        uri,
+        dataForLog);
+  }
+
+  @Override
+  public WxMaApiResponse execute(
+      ApiSignaturePostRequestExecutor executor,
+      String uri,
+      Map headers,
+      String data)
+      throws WxErrorException {
+    String dataForLog = "Headers: " + headers.toString() + " Body: " + data;
+    return excuteWithRetry(
+        (uriWithAccessToken) -> executor.execute(uriWithAccessToken, headers, data, WxType.MiniApp),
+        uri,
+        dataForLog);
+  }
+
+  private static interface ExecutorAction {
+    R execute(String urlWithAccessToken) throws IOException, WxErrorException;
+  }
+
+  private  R excuteWithRetry(ExecutorAction executor, String uri, String dataForLog)
+      throws WxErrorException {
     int retryTimes = 0;
     do {
       try {
-        return this.executeInternal(executor, uri, data, false);
+        return this.executeInternal(executor, uri, dataForLog, false);
       } catch (WxErrorException e) {
         if (retryTimes + 1 > this.maxRetryTimes) {
           log.warn("重试达到最大次数【{}】", maxRetryTimes);
-          //最后一次重试失败后,直接抛出异常,不再等待
-          throw new WxErrorException(WxError.builder()
-            .errorCode(e.getError().getErrorCode())
-            .errorMsg("微信服务端异常,超出重试次数!")
-            .build());
+          // 最后一次重试失败后,直接抛出异常,不再等待
+          throw new WxErrorException(
+              WxError.builder()
+                  .errorCode(e.getError().getErrorCode())
+                  .errorMsg("微信服务端异常,超出重试次数!")
+                  .build());
         }
 
         WxError error = e.getError();
@@ -290,8 +409,9 @@ public abstract class BaseWxMaServiceImpl implements WxMaService, RequestH
     throw new WxRuntimeException("微信服务端异常,超出重试次数");
   }
 
-  private  T executeInternal(RequestExecutor executor, String uri, E data, boolean doNotAutoRefreshToken) throws WxErrorException {
-    E dataForLog = DataUtils.handleDataWithSecret(data);
+  private  R executeInternal(
+      ExecutorAction executor, String uri, String dataForLog, boolean doNotAutoRefreshToken)
+      throws WxErrorException {
 
     if (uri.contains("access_token=")) {
       throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri);
@@ -302,10 +422,10 @@ public abstract class BaseWxMaServiceImpl implements WxMaService, RequestH
       uri = uri.replace("https://api.weixin.qq.com", this.getWxMaConfig().getApiHostUrl());
     }
 
-    String uriWithAccessToken = uri + (uri.contains("?") ? "&" : "?") + "access_token=" + accessToken;
-
+    String uriWithAccessToken =
+        uri + (uri.contains("?") ? "&" : "?") + "access_token=" + accessToken;
     try {
-      T result = executor.execute(uriWithAccessToken, data, WxType.MiniApp);
+      R result = executor.execute(uriWithAccessToken);
       log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result);
       return result;
     } catch (WxErrorException e) {
@@ -324,10 +444,11 @@ public abstract class BaseWxMaServiceImpl implements WxMaService, RequestH
           lock.unlock();
         }
         if (this.getWxMaConfig().autoRefreshToken() && !doNotAutoRefreshToken) {
-          log.warn("即将重新获取新的access_token,错误代码:{},错误信息:{}", error.getErrorCode(), error.getErrorMsg());
-          //下一次不再自动重试
-          //当小程序误调用第三方平台专属接口时,第三方无法使用小程序的access token,如果可以继续自动获取token会导致无限循环重试,直到栈溢出
-          return this.executeInternal(executor, uri, data, true);
+          log.warn(
+              "即将重新获取新的access_token,错误代码:{},错误信息:{}", error.getErrorCode(), error.getErrorMsg());
+          // 下一次不再自动重试
+          // 当小程序误调用第三方平台专属接口时,第三方无法使用小程序的access token,如果可以继续自动获取token会导致无限循环重试,直到栈溢出
+          return this.executeInternal(executor, uri, dataForLog, true);
         }
       }
 
@@ -337,7 +458,8 @@ public abstract class BaseWxMaServiceImpl implements WxMaService, RequestH
       }
       return null;
     } catch (IOException e) {
-      log.warn("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
+      log.warn(
+          "\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
       throw new WxRuntimeException(e);
     }
   }
@@ -712,6 +834,164 @@ public abstract class BaseWxMaServiceImpl implements WxMaService, RequestH
 
   @Override
   public WxMaPromotionService getWxMaPromotionService() {
-      return this.wxMaPromotionService;
+    return this.wxMaPromotionService;
+  }
+
+  @Override
+  public String postWithSignature(String url, Object obj) throws WxErrorException {
+    Gson gson =
+        new GsonBuilder()
+            .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+            .create();
+    JsonObject jsonObject = gson.toJsonTree(obj).getAsJsonObject();
+    return this.postWithSignature(url, jsonObject);
+  }
+
+  private String generateNonce() {
+    byte[] nonce = generateRandomBytes(16);
+    return base64Encode(nonce).replace("=", "");
+  }
+
+  private byte[] generateRandomBytes(int length) {
+    byte[] bytes = new byte[length];
+    new SecureRandom().nextBytes(bytes);
+    return bytes;
+  }
+
+  private String base64Encode(byte[] data) {
+    return Base64.getEncoder().encodeToString(data);
+  }
+
+  @Override
+  public String postWithSignature(String url, JsonObject jsonObject) throws WxErrorException {
+    long timestamp = System.currentTimeMillis() / 1000;
+    String appId = this.getWxMaConfig().getWechatMpAppid();
+    String rndStr = UUID.randomUUID().toString().replace("-", "").substring(0, 30);
+    String aesKey = this.getWxMaConfig().getApiSignatureAesKey();
+    String aesKeySn = this.getWxMaConfig().getApiSignatureAesKeySn();
+
+    jsonObject.addProperty("_n", rndStr);
+    jsonObject.addProperty("_appid", appId);
+    jsonObject.addProperty("_timestamp", timestamp);
+
+    String plainText = jsonObject.toString();
+    String urlPath;
+    if (url.contains("?")) {
+      urlPath = url.substring(0, url.indexOf("?"));
+    } else {
+      urlPath = url;
+    }
+    String aad = urlPath + "|" + appId + "|" + timestamp + "|" + aesKeySn;
+    byte[] realKey;
+    try {
+      realKey = Base64.getDecoder().decode(aesKey);
+    } catch (Exception ex) {
+      log.error("解析AESKEY失败 {}", aesKey, ex);
+      throw new SecurityException("解析AES KEY失败,请检查ApiSignatureAesKey是否正确", ex);
+    }
+    byte[] realIv = generateRandomBytes(12);
+    byte[] realAad = aad.getBytes(StandardCharsets.UTF_8);
+    byte[] realPlainText = plainText.getBytes(StandardCharsets.UTF_8);
+
+    try {
+      // 加密内容 AES
+      Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+      SecretKeySpec aesKeySpec = new SecretKeySpec(realKey, "AES");
+      GCMParameterSpec parameterSpec = new GCMParameterSpec(128, realIv);
+      cipher.init(Cipher.ENCRYPT_MODE, aesKeySpec, parameterSpec);
+      cipher.updateAAD(realAad);
+
+      byte[] ciphertext = cipher.doFinal(realPlainText);
+      byte[] encryptedData = Arrays.copyOfRange(ciphertext, 0, ciphertext.length - 16);
+      byte[] authTag = Arrays.copyOfRange(ciphertext, ciphertext.length - 16, ciphertext.length);
+
+      JsonObject reqData = new JsonObject();
+      reqData.addProperty("iv", base64Encode(realIv));
+      reqData.addProperty("data", base64Encode(encryptedData));
+      reqData.addProperty("authtag", base64Encode(authTag));
+      String requestJson = reqData.toString();
+
+      // 计算签名 RSA
+      String payload = urlPath + "\n" + appId + "\n" + timestamp + "\n" + requestJson;
+      byte[] dataBuffer = payload.getBytes(StandardCharsets.UTF_8);
+      RSAPrivateKey priKey;
+      try {
+        String rsaPrivateKey = this.getWxMaConfig().getApiSignatureRsaPrivateKey();
+        rsaPrivateKey = rsaPrivateKey.replace("-----BEGIN PRIVATE KEY-----", "");
+        rsaPrivateKey = rsaPrivateKey.replace("-----END PRIVATE KEY-----", "");
+        rsaPrivateKey = rsaPrivateKey.replaceAll("\\s+", "");
+        byte[] decoded = Base64.getDecoder().decode(rsaPrivateKey.getBytes(StandardCharsets.UTF_8));
+        PKCS8EncodedKeySpec rsaKeySpec = new PKCS8EncodedKeySpec(decoded);
+        priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(rsaKeySpec);
+      } catch (Exception ex) {
+        log.error("解析RSA KEY失败 {}", aesKey, ex);
+        throw new SecurityException("解析RSA KEY失败,请检查ApiSignatureRsaPrivateKey是否正确,需要PKCS8格式私钥", ex);
+      }
+      Signature signature = Signature.getInstance("RSASSA-PSS");
+      // salt长度,需与SHA256结果长度(32)一致
+      PSSParameterSpec pssParameterSpec =
+          new PSSParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, 32, 1);
+      signature.setParameter(pssParameterSpec);
+      signature.initSign(priKey);
+      signature.update(dataBuffer);
+      byte[] sigBuffer = signature.sign();
+      String signatureString = base64Encode(sigBuffer);
+
+      Map header = new HashMap<>();
+      header.put("Wechatmp-Signature", signatureString);
+      header.put("Wechatmp-Appid", appId);
+      header.put("Wechatmp-TimeStamp", String.valueOf(timestamp));
+      log.debug("发送请求uri:{}, headers:{}, postData:{}", url, header, requestJson);
+      WxMaApiResponse response =
+          this.execute(ApiSignaturePostRequestExecutor.create(this), url, header, requestJson);
+      String respTs = response.getHeaders().get("Wechatmp-TimeStamp");
+      String respAad = urlPath + "|" + appId + "|" + respTs + "|" + aesKeySn;
+      if (!appId.equals(response.getHeaders().get("Wechatmp-Appid"))) {
+        throw new RuntimeException("响应的appId不符 " + response.getHeaders().get("Wechatmp-Appid"));
+      }
+      // 省略验证平台签名部分,直接解密内容,返回明文
+      String decryptedData = aesDecodeResponse(response, respAad, aesKeySpec);
+      log.debug("解密后的响应:{}", decryptedData);
+      WxError error = WxError.fromJson(decryptedData, WxType.MiniApp);
+      if (error.getErrorCode() != 0) {
+        log.debug("调用API出错, uri:{}, postData:{}, response:{}", url, plainText, error);
+        throw new WxErrorException(error);
+      }
+      return decryptedData;
+    } catch (WxErrorException | SecurityException ex) {
+      throw ex;
+    } catch (Exception e) {
+      log.error("postWithSignature", e);
+      throw new RuntimeException(e);
+    }
+  }
+
+  private String aesDecodeResponse(WxMaApiResponse response, String aad, SecretKeySpec aesKeySpec)
+      throws Exception {
+    Map map = GSON.fromJson(response.getContent(), Map.class);
+    String iv = (String) map.get("iv");
+    String data = (String) map.get("data");
+    String authTag = (String) map.get("authtag");
+
+    byte[] dataBytes = Base64.getDecoder().decode(data);
+    byte[] authTagBytes = Base64.getDecoder().decode(authTag);
+    byte[] newDataBytes = new byte[dataBytes.length + authTagBytes.length];
+    System.arraycopy(dataBytes, 0, newDataBytes, 0, dataBytes.length);
+    System.arraycopy(authTagBytes, 0, newDataBytes, dataBytes.length, authTagBytes.length);
+    byte[] aadBytes = aad.getBytes(StandardCharsets.UTF_8);
+    byte[] ivBytes = Base64.getDecoder().decode(iv);
+
+    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+    GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, ivBytes);
+    cipher.init(Cipher.DECRYPT_MODE, aesKeySpec, gcmParameterSpec);
+    cipher.updateAAD(aadBytes);
+    byte[] decryptedBytes = cipher.doFinal(newDataBytes);
+
+    return new String(decryptedBytes, StandardCharsets.UTF_8);
+  }
+
+  @Override
+  public WxMaIntracityService getIntracityService() {
+    return this.intracityService;
   }
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaIntracityServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaIntracityServiceImpl.java
new file mode 100644
index 000000000..46a728eca
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaIntracityServiceImpl.java
@@ -0,0 +1,276 @@
+package cn.binarywang.wx.miniapp.api.impl;
+
+import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Intracity;
+import static me.chanjar.weixin.common.api.WxConsts.ERR_CODE;
+
+import cn.binarywang.wx.miniapp.api.WxMaIntracityService;
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.intractiy.*;
+import com.google.gson.*;
+import com.google.gson.reflect.TypeToken;
+import java.lang.reflect.Type;
+import java.util.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.json.GsonParser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@RequiredArgsConstructor
+@Slf4j
+public class WxMaIntracityServiceImpl implements WxMaIntracityService {
+  private final WxMaService wxMaService;
+  private static final Logger logger = LoggerFactory.getLogger(WxMaIntracityServiceImpl.class);
+
+  private final Gson gson =
+      new GsonBuilder()
+          .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+          .create();
+
+  private void checkStringResponse(String response) throws WxErrorException {
+    JsonObject respObj = GsonParser.parse(response);
+    if (respObj.get(ERR_CODE).getAsInt() != 0) {
+      throw new WxErrorException(WxError.fromJson(response, WxType.MiniApp));
+    }
+  }
+
+  @Override
+  public void apply() throws WxErrorException {
+    String response = this.wxMaService.post(Intracity.APPLY_URL, "{}");
+    checkStringResponse(response);
+  }
+
+  @Override
+  public String createStore(WxMaStore store) throws WxErrorException {
+    if (store.getOutStoreId() == null) {
+      throw new IllegalArgumentException("创建门店时outStoreId不能为空");
+    }
+    if (store.getWxStoreId() != null) {
+      throw new IllegalArgumentException("创建门店时wxStoreId只能是null");
+    }
+    String response = this.wxMaService.postWithSignature(Intracity.CREATE_STORE_URL, store);
+    Map map = gson.fromJson(response, Map.class);
+    return (String) map.get("wx_store_id");
+  }
+
+  @Override
+  public void updateStore(WxMaStore store) throws WxErrorException {
+    if (store.getWxStoreId() == null && store.getOutStoreId() == null) {
+      throw new IllegalArgumentException("更新门店时wxStoreId 或 outStoreId 至少要有一个不为null");
+    }
+    JsonObject request = new JsonObject();
+    Map keys = new HashMap<>();
+    if (store.getWxStoreId() != null) {
+      keys.put("wx_store_id", store.getWxStoreId());
+    } else {
+      keys.put("out_store_id", store.getOutStoreId());
+    }
+    request.add("keys", gson.toJsonTree(keys));
+    Map updateContent = new HashMap<>();
+    if (store.getStoreName() != null) {
+      updateContent.put("store_name", store.getStoreName());
+    }
+    if (store.getOrderPattern() == 1 || store.getOrderPattern() == 2) {
+      updateContent.put("order_pattern", store.getOrderPattern());
+    }
+    if (store.getServiceTransPrefer() != null) {
+      updateContent.put("service_trans_prefer", store.getServiceTransPrefer());
+    }
+    if (store.getAddressInfo() != null) {
+      updateContent.put("address_info", store.getAddressInfo());
+    }
+    request.add("content", gson.toJsonTree(updateContent));
+    String response = this.wxMaService.postWithSignature(Intracity.UPDATE_STORE_URL, request);
+    checkStringResponse(response);
+  }
+
+  @Override
+  public List listAllStores() throws WxErrorException {
+    return queryStore(null, null);
+  }
+
+  @Override
+  public WxMaStore queryStoreByWxStoreId(String wxStoreId) throws WxErrorException {
+    List list = queryStore(wxStoreId, null);
+    return list.isEmpty() ? null : list.get(0);
+  }
+
+  @Override
+  public List queryStoreByOutStoreId(String outStoreId) throws WxErrorException {
+    return queryStore(null, outStoreId);
+  }
+
+  private List queryStore(String wxStoreId, String outStoreId) throws WxErrorException {
+    Map map = new HashMap<>();
+    if (wxStoreId != null) {
+      map.put("wx_store_id", wxStoreId);
+    } else if (outStoreId != null) {
+      map.put("out_store_id", outStoreId);
+    }
+    String response = this.wxMaService.postWithSignature(Intracity.QUERY_STORE_URL, map);
+    JsonObject jsonObject = gson.fromJson(response, JsonObject.class);
+    Type listType = new TypeToken>() {}.getType();
+    return gson.fromJson(jsonObject.getAsJsonArray("store_list"), listType);
+  }
+
+  @Override
+  public String storeCharge(WxMaStoreChargeRequest request) throws WxErrorException {
+    String response = this.wxMaService.postWithSignature(Intracity.STORE_CHARGE, request);
+    Map map = gson.fromJson(response, Map.class);
+    return (String) map.get("payurl");
+  }
+
+  @Override
+  public int storeRefund(WxMaStoreRefundRequest request) throws WxErrorException {
+    String response = this.wxMaService.postWithSignature(Intracity.STORE_REFUND, request);
+    Map map = gson.fromJson(response, Map.class);
+    return ((Number) map.get("refund_amount")).intValue();
+  }
+
+  @Override
+  public WxMaStoreFlowResponse queryFlow(
+      WxMaQueryFlowRequest request) throws WxErrorException {
+    if (request == null || request.getWxStoreId() == null) {
+      throw new IllegalArgumentException("查询请求 wxStoreId 不可为空");
+    }
+    WxMaStoreFlowResponse inst =
+        getFlowInstanceByType(request.getFlowType());
+    if (inst == null) {
+      throw new IllegalArgumentException("查询请求 flowType 不正确,只能是1、2、3之一");
+    }
+
+    String response = this.wxMaService.postWithSignature(Intracity.QUERY_FLOW, request);
+
+    WxMaStoreFlowResponse flowResponse;
+    flowResponse =
+        (WxMaStoreFlowResponse)
+            gson.fromJson(response, inst.getClass());
+    logger.debug("queryFlow: {}", flowResponse);
+    return flowResponse;
+  }
+
+  private WxMaStoreFlowResponse
+      getFlowInstanceByType(int flowType) {
+    WxMaStoreFlowResponse inst;
+    if (flowType == 1) {
+      inst = new WxMaStoreFlowResponse();
+    } else if (flowType == 2) {
+      inst = new WxMaStoreFlowResponse();
+    } else if (flowType == 3) {
+      inst = new WxMaStoreFlowResponse();
+    } else {
+      return null;
+    }
+    return inst;
+  }
+
+  @Override
+  public WxMaStoreBalance balanceQuery(String wxStoreId, String serviceTransId, PayMode payMode)
+      throws WxErrorException {
+    if (wxStoreId == null && (payMode != null && payMode != PayMode.STORE)) {
+      throw new IllegalArgumentException("payMode是PAY_MODE_STORE或null时,必须传递wxStoreId");
+    }
+    Map request = new HashMap<>();
+    if (wxStoreId != null) {
+      request.put("wx_store_id", wxStoreId);
+    }
+    if (serviceTransId != null) {
+      request.put("service_trans_id", serviceTransId);
+    }
+    if (payMode != null) {
+      request.put("pay_mode", payMode);
+    }
+    String response = this.wxMaService.postWithSignature(Intracity.BALANCE_QUERY, request);
+    WxMaStoreBalance balance = gson.fromJson(response, WxMaStoreBalance.class);
+    logger.debug("balance: {}", balance);
+    return balance;
+  }
+
+  public void setPayMode(PayMode payMode) throws WxErrorException {
+    Map request = new HashMap<>();
+    request.put("pay_mode", payMode);
+    request.put("appid", wxMaService.getWxMaConfig().getAppid());
+    String response = this.wxMaService.postWithSignature(Intracity.SET_PAY_MODE, request);
+    checkStringResponse(response);
+  }
+
+  public WxMaGetPayModeResponse getPayMode() throws WxErrorException {
+    Map request = new HashMap<>();
+    request.put("appid", wxMaService.getWxMaConfig().getAppid());
+    String response = this.wxMaService.postWithSignature(Intracity.GET_PAY_MODE, request);
+    return gson.fromJson(response, WxMaGetPayModeResponse.class);
+  }
+
+  @Override
+  public WxMaAddOrderResponse preAddOrder(WxMaPreAddOrderRequest request) throws WxErrorException {
+    String response = this.wxMaService.postWithSignature(Intracity.PRE_ADD_ORDER, request);
+    return gson.fromJson(response, WxMaAddOrderResponse.class);
+  }
+
+  @Override
+  public WxMaAddOrderResponse addOrder(WxMaAddOrderRequest request) throws WxErrorException {
+    String response = this.wxMaService.postWithSignature(Intracity.ADD_ORDER, request);
+    return gson.fromJson(response, WxMaAddOrderResponse.class);
+  }
+
+  @Override
+  public WxMaOrder queryOrderByWxOrderId(String wxOrderId) throws WxErrorException {
+    Map map = new HashMap<>();
+    map.put("wx_order_id", wxOrderId);
+    String response = this.wxMaService.postWithSignature(Intracity.QUERY_ORDER, map);
+    return gson.fromJson(response, WxMaOrder.class);
+  }
+
+  @Override
+  public WxMaOrder queryOrderByStoreOrderId(String wxStoreId, String storeOrderId)
+      throws WxErrorException {
+    Map map = new HashMap<>();
+    map.put("wx_store_id", wxStoreId);
+    map.put("store_order_id", storeOrderId);
+    String response = this.wxMaService.postWithSignature(Intracity.QUERY_ORDER, map);
+    return gson.fromJson(response, WxMaOrder.class);
+  }
+
+  @Override
+  public WxMaCancelOrderResponse cancelOrderByWxOrderId(
+      String wxOrderId, int cancelReasonId, String cancelReason) throws WxErrorException {
+    Map map = new HashMap<>();
+    map.put("wx_order_id", wxOrderId);
+    map.put("cancel_reason_id", cancelReasonId);
+    if (cancelReason != null) {
+      map.put("cancel_reason", cancelReason);
+    }
+    String response = this.wxMaService.postWithSignature(Intracity.CANCEL_ORDER, map);
+    return gson.fromJson(response, WxMaCancelOrderResponse.class);
+  }
+
+  @Override
+  public WxMaCancelOrderResponse cancelOrderByStoreOrderId(
+      String wxStoreId, String storeOrderId, int cancelReasonId, String cancelReason)
+      throws WxErrorException {
+    Map map = new HashMap<>();
+    map.put("wx_store_id", wxStoreId);
+    map.put("store_order_id", storeOrderId);
+    map.put("cancel_reason_id", cancelReasonId);
+    if (cancelReason != null) {
+      map.put("cancel_reason", cancelReason);
+    }
+    String response = this.wxMaService.postWithSignature(Intracity.CANCEL_ORDER, map);
+    return gson.fromJson(response, WxMaCancelOrderResponse.class);
+  }
+
+  @Override
+  public List getCity(String serviceTransId) throws WxErrorException {
+    Map map = new HashMap<>();
+    if (serviceTransId != null) {
+      map.put("service_trans_id", serviceTransId);
+    }
+    String response = this.wxMaService.postWithSignature(Intracity.GET_CITY, map);
+    JsonObject jsonObject = gson.fromJson(response, JsonObject.class);
+    Type listType = new TypeToken>() {}.getType();
+    return gson.fromJson(jsonObject.getAsJsonArray("support_list"), listType);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaApiResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaApiResponse.java
new file mode 100644
index 000000000..47345ba40
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaApiResponse.java
@@ -0,0 +1,34 @@
+package cn.binarywang.wx.miniapp.bean;
+
+import java.util.Map;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WxMaApiResponse {
+  private static final Logger logger = LoggerFactory.getLogger(WxMaApiResponse.class);
+
+  private String content;
+  private Map headers;
+
+  public String getContent() {
+    return content;
+  }
+
+  public void setContent(String content) {
+    this.content = content;
+  }
+
+  public Map getHeaders() {
+    return headers;
+  }
+
+  public void setHeaders(Map headers) {
+    this.headers = headers;
+  }
+
+  @Override
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/BasicWxMaOrder.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/BasicWxMaOrder.java
new file mode 100644
index 000000000..868cf5e5c
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/BasicWxMaOrder.java
@@ -0,0 +1,128 @@
+package cn.binarywang.wx.miniapp.bean.intractiy;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+
+class BasicWxMaOrder {
+
+  private String wxStoreId;
+  private String userName;
+  private String userPhone;
+  private double userLng;
+  private double userLat;
+  private String userAddress;
+  private int useSandbox;
+
+  public String getWxStoreId() {
+    return wxStoreId;
+  }
+
+  public void setWxStoreId(String wxStoreId) {
+    this.wxStoreId = wxStoreId;
+  }
+
+  public String getUserName() {
+    return userName;
+  }
+
+  public void setUserName(String userName) {
+    this.userName = userName;
+  }
+
+  public String getUserPhone() {
+    return userPhone;
+  }
+
+  public void setUserPhone(String userPhone) {
+    this.userPhone = userPhone;
+  }
+
+  public double getUserLng() {
+    return userLng;
+  }
+
+  public void setUserLng(double userLng) {
+    this.userLng = userLng;
+  }
+
+  public double getUserLat() {
+    return userLat;
+  }
+
+  public void setUserLat(double userLat) {
+    this.userLat = userLat;
+  }
+
+  public String getUserAddress() {
+    return userAddress;
+  }
+
+  public void setUserAddress(String userAddress) {
+    this.userAddress = userAddress;
+  }
+
+  public int isUseSandbox() {
+    return useSandbox;
+  }
+
+  public void setUseSandbox(int useSandbox) {
+    this.useSandbox = useSandbox;
+  }
+
+  @Override
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this);
+  }
+
+  static class Cargo {
+    private String cargoName;
+    private int cargoWeight;
+    private int cargoType;
+    private int cargoNum;
+    private int cargoPrice;
+
+    public String getCargoName() {
+      return cargoName;
+    }
+
+    public void setCargoName(String cargoName) {
+      this.cargoName = cargoName;
+    }
+
+    public int getCargoWeight() {
+      return cargoWeight;
+    }
+
+    public void setCargoWeight(int cargoWeight) {
+      this.cargoWeight = cargoWeight;
+    }
+
+    public int getCargoType() {
+      return cargoType;
+    }
+
+    public void setCargoType(int cargoType) {
+      this.cargoType = cargoType;
+    }
+
+    public int getCargoNum() {
+      return cargoNum;
+    }
+
+    public void setCargoNum(int cargoNum) {
+      this.cargoNum = cargoNum;
+    }
+
+    public int getCargoPrice() {
+      return cargoPrice;
+    }
+
+    public void setCargoPrice(int cargoPrice) {
+      this.cargoPrice = cargoPrice;
+    }
+
+    @Override
+    public String toString() {
+      return ToStringBuilder.reflectionToString(this);
+    }
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/BasicWxMaStoreChargeRefundRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/BasicWxMaStoreChargeRefundRequest.java
new file mode 100644
index 000000000..f9140ad57
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/BasicWxMaStoreChargeRefundRequest.java
@@ -0,0 +1,49 @@
+package cn.binarywang.wx.miniapp.bean.intractiy;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+
+class BasicWxMaStoreChargeRefundRequest {
+
+  /** 微信门店编号 pay_mode = PAY_MODE_STORE时必传,不传pay_mode时必传wx_store_id */
+  private String wxStoreId;
+
+  /**
+   * 充值/扣费主体 
+ * 门店:PAY_MODE_STORE;小程序:PAY_MODE_APP;服务商:PAY_MODE_COMPONENT,不传pay_mode默认pay_mode=PAY_MODE_STORE + */ + private PayMode payMode; + + /** + * 运力Id,必填。运力ID请参考:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/express/business/intracity_service.html#_6-%E8%BF%90%E5%8A%9B%E5%88%97%E8%A1%A8 + */ + private String serviceTransId; + + public String getWxStoreId() { + return wxStoreId; + } + + public void setWxStoreId(String wxStoreId) { + this.wxStoreId = wxStoreId; + } + + public PayMode getPayMode() { + return payMode; + } + + public void setPayMode(PayMode payMode) { + this.payMode = payMode; + } + + public String getServiceTransId() { + return serviceTransId; + } + + public void setServiceTransId(String serviceTransId) { + this.serviceTransId = serviceTransId; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/PayMode.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/PayMode.java new file mode 100644 index 000000000..bf779e21f --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/PayMode.java @@ -0,0 +1,16 @@ +package cn.binarywang.wx.miniapp.bean.intractiy; + +import com.google.gson.annotations.SerializedName; + +/** 充值、扣费主体 */ +public enum PayMode { + /** 门店 */ + @SerializedName("PAY_MODE_STORE") + STORE, + /** 小程序 */ + @SerializedName("PAY_MODE_APP") + APP, + /** 服务商 */ + @SerializedName("PAY_MODE_COMPONENT") + COMPONENT; +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaAddOrderRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaAddOrderRequest.java new file mode 100644 index 000000000..6e27c5780 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaAddOrderRequest.java @@ -0,0 +1,133 @@ +package cn.binarywang.wx.miniapp.bean.intractiy; + +import java.util.List; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WxMaAddOrderRequest extends BasicWxMaOrder { + private static final Logger logger = LoggerFactory.getLogger(WxMaAddOrderRequest.class); + private String storeOrderId; + private String userOpenid; + private String orderSeq; + + /** 验证码类型 0:不生成 1:生成取货码 2:生成收货码 3:两者都生成 */ + private int verifyCodeType; + + private String orderDetailPath; + private String callbackUrl; + private Cargo cargo; + + public String getStoreOrderId() { + return storeOrderId; + } + + public void setStoreOrderId(String storeOrderId) { + this.storeOrderId = storeOrderId; + } + + public String getUserOpenid() { + return userOpenid; + } + + public void setUserOpenid(String userOpenid) { + this.userOpenid = userOpenid; + } + + public String getOrderSeq() { + return orderSeq; + } + + public void setOrderSeq(String orderSeq) { + this.orderSeq = orderSeq; + } + + public int getVerifyCodeType() { + return verifyCodeType; + } + + public void setVerifyCodeType(int verifyCodeType) { + this.verifyCodeType = verifyCodeType; + } + + public String getOrderDetailPath() { + return orderDetailPath; + } + + public void setOrderDetailPath(String orderDetailPath) { + this.orderDetailPath = orderDetailPath; + } + + public String getCallbackUrl() { + return callbackUrl; + } + + public void setCallbackUrl(String callbackUrl) { + this.callbackUrl = callbackUrl; + } + + public Cargo getCargo() { + return cargo; + } + + public void setCargo(Cargo cargo) { + this.cargo = cargo; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + + public static class Cargo extends BasicWxMaOrder.Cargo { + private List itemList; + + public List getItemList() { + return itemList; + } + + public void setItemList(List itemList) { + this.itemList = itemList; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + } + + public static class ItemDetail { + private String itemName; + private String itemPicUrl; + private int count; + + public String getItemName() { + return itemName; + } + + public void setItemName(String itemName) { + this.itemName = itemName; + } + + public String getItemPicUrl() { + return itemPicUrl; + } + + public void setItemPicUrl(String itemPicUrl) { + this.itemPicUrl = itemPicUrl; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaAddOrderResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaAddOrderResponse.java new file mode 100644 index 000000000..7155c1153 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaAddOrderResponse.java @@ -0,0 +1,115 @@ +package cn.binarywang.wx.miniapp.bean.intractiy; + +import org.apache.commons.lang3.builder.ToStringBuilder; + +public class WxMaAddOrderResponse { + private String wxOrderId; + private String storeOrderId; + private String wxStoreId; + + /** 配送运力 */ + private String serviceTransId; + + /** 配送距离 单位:米 */ + private int distance; + + /** 运力订单号 */ + private String transOrderId; + + /** 运力配送单号 */ + private String waybillId; + + /** 配送费 */ + private int fee; + + /** 取货码 */ + private String fetchCode; + + /** 取货序号 */ + private String orderSeq; + + public String getWxOrderId() { + return wxOrderId; + } + + public void setWxOrderId(String wxOrderId) { + this.wxOrderId = wxOrderId; + } + + public String getStoreOrderId() { + return storeOrderId; + } + + public void setStoreOrderId(String storeOrderId) { + this.storeOrderId = storeOrderId; + } + + public String getWxStoreId() { + return wxStoreId; + } + + public void setWxStoreId(String wxStoreId) { + this.wxStoreId = wxStoreId; + } + + public String getServiceTransId() { + return serviceTransId; + } + + public void setServiceTransId(String serviceTransId) { + this.serviceTransId = serviceTransId; + } + + public int getDistance() { + return distance; + } + + public void setDistance(int distance) { + this.distance = distance; + } + + public String getTransOrderId() { + return transOrderId; + } + + public void setTransOrderId(String transOrderId) { + this.transOrderId = transOrderId; + } + + public String getWaybillId() { + return waybillId; + } + + public void setWaybillId(String waybillId) { + this.waybillId = waybillId; + } + + public int getFee() { + return fee; + } + + public void setFee(int fee) { + this.fee = fee; + } + + public String getFetchCode() { + return fetchCode; + } + + public void setFetchCode(String fetchCode) { + this.fetchCode = fetchCode; + } + + public String getOrderSeq() { + return orderSeq; + } + + public void setOrderSeq(String orderSeq) { + this.orderSeq = orderSeq; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaCancelOrderResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaCancelOrderResponse.java new file mode 100644 index 000000000..a2a21d7ff --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaCancelOrderResponse.java @@ -0,0 +1,67 @@ +package cn.binarywang.wx.miniapp.bean.intractiy; + +import org.apache.commons.lang3.builder.ToStringBuilder; + +public class WxMaCancelOrderResponse { + private String wxOrderId; + private String storeOrderId; + private String wxStoreId; + private String orderStatus; + private String appid; + + /** 违约金 */ + private int deductfee; + + public String getWxOrderId() { + return wxOrderId; + } + + public void setWxOrderId(String wxOrderId) { + this.wxOrderId = wxOrderId; + } + + public String getStoreOrderId() { + return storeOrderId; + } + + public void setStoreOrderId(String storeOrderId) { + this.storeOrderId = storeOrderId; + } + + public String getWxStoreId() { + return wxStoreId; + } + + public void setWxStoreId(String wxStoreId) { + this.wxStoreId = wxStoreId; + } + + public String getOrderStatus() { + return orderStatus; + } + + public void setOrderStatus(String orderStatus) { + this.orderStatus = orderStatus; + } + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + + public int getDeductfee() { + return deductfee; + } + + public void setDeductfee(int deductfee) { + this.deductfee = deductfee; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaGetPayModeResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaGetPayModeResponse.java new file mode 100644 index 000000000..8d49ce088 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaGetPayModeResponse.java @@ -0,0 +1,42 @@ +package cn.binarywang.wx.miniapp.bean.intractiy; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WxMaGetPayModeResponse { + private static final Logger logger = LoggerFactory.getLogger(WxMaGetPayModeResponse.class); + + private PayMode payMode; + private String payAppid; + private String componentAppid; + + public PayMode getPayMode() { + return payMode; + } + + public void setPayMode(PayMode payMode) { + this.payMode = payMode; + } + + public String getPayAppid() { + return payAppid; + } + + public void setPayAppid(String payAppid) { + this.payAppid = payAppid; + } + + public String getComponentAppid() { + return componentAppid; + } + + public void setComponentAppid(String componentAppid) { + this.componentAppid = componentAppid; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaOrder.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaOrder.java new file mode 100644 index 000000000..fbec5c8c6 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaOrder.java @@ -0,0 +1,344 @@ +package cn.binarywang.wx.miniapp.bean.intractiy; + +import java.util.Date; +import org.apache.commons.lang3.builder.ToStringBuilder; + +public class WxMaOrder extends WxMaAddOrderRequest { + private String wxOrderId; + private int orderStatus; + private String appid; + private String serviceTransId; + private String deliveryNo; + private int actualfee; + private int deductfee; + private long createTime; + private long acceptTime; + private long fetchTime; + private long finishTime; + private long cancelTime; + private long expectedFinishTime; + private String fetchCode; + private String recvCode; + private TransporterInfo transporterInfo; + private StoreInfo storeInfo; + private ReceiverInfo receiverInfo; + private Cargo cargoInfo; + + public String getWxOrderId() { + return wxOrderId; + } + + public void setWxOrderId(String wxOrderId) { + this.wxOrderId = wxOrderId; + } + + public int getOrderStatus() { + return orderStatus; + } + + public void setOrderStatus(int orderStatus) { + this.orderStatus = orderStatus; + } + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + + public String getServiceTransId() { + return serviceTransId; + } + + public void setServiceTransId(String serviceTransId) { + this.serviceTransId = serviceTransId; + } + + public String getDeliveryNo() { + return deliveryNo; + } + + public void setDeliveryNo(String deliveryNo) { + this.deliveryNo = deliveryNo; + } + + public int getActualfee() { + return actualfee; + } + + public void setActualfee(int actualfee) { + this.actualfee = actualfee; + } + + public int getDeductfee() { + return deductfee; + } + + public void setDeductfee(int deductfee) { + this.deductfee = deductfee; + } + + public long getCreateTime() { + return createTime; + } + + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + + public long getAcceptTime() { + return acceptTime; + } + + public void setAcceptTime(long acceptTime) { + this.acceptTime = acceptTime; + } + + public long getFetchTime() { + return fetchTime; + } + + public void setFetchTime(long fetchTime) { + this.fetchTime = fetchTime; + } + + public long getFinishTime() { + return finishTime; + } + + public void setFinishTime(long finishTime) { + this.finishTime = finishTime; + } + + public long getCancelTime() { + return cancelTime; + } + + public void setCancelTime(long cancelTime) { + this.cancelTime = cancelTime; + } + + public long getExpectedFinishTime() { + return expectedFinishTime; + } + + public void setExpectedFinishTime(long expectedFinishTime) { + this.expectedFinishTime = expectedFinishTime; + } + + public String getFetchCode() { + return fetchCode; + } + + public void setFetchCode(String fetchCode) { + this.fetchCode = fetchCode; + } + + public String getRecvCode() { + return recvCode; + } + + public void setRecvCode(String recvCode) { + this.recvCode = recvCode; + } + + public TransporterInfo getTransporterInfo() { + return transporterInfo; + } + + public void setTransporterInfo(TransporterInfo transporterInfo) { + this.transporterInfo = transporterInfo; + } + + public StoreInfo getStoreInfo() { + return storeInfo; + } + + public void setStoreInfo(StoreInfo storeInfo) { + this.storeInfo = storeInfo; + } + + public ReceiverInfo getReceiverInfo() { + return receiverInfo; + } + + public void setReceiverInfo(ReceiverInfo receiverInfo) { + this.receiverInfo = receiverInfo; + } + + public Cargo getCargoInfo() { + return cargoInfo; + } + + public void setCargoInfo(Cargo cargoInfo) { + this.cargoInfo = cargoInfo; + } + + public Date getCreateDate() { + return createTime == 0 ? null : new Date(createTime * 1000); + } + + public Date getAcceptDate() { + return acceptTime == 0 ? null : new Date(acceptTime * 1000); + } + + public Date getFetchDate() { + return fetchTime == 0 ? null : new Date(fetchTime * 1000); + } + + public Date getFinishDate() { + return finishTime == 0 ? null : new Date(finishTime * 1000); + } + + public Date getCancelDate() { + return cancelTime == 0 ? null : new Date(cancelTime * 1000); + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + + public static class TransporterInfo { + private String transporterName; + private String transporterPhone; + + public String getTransporterName() { + return transporterName; + } + + public void setTransporterName(String transporterName) { + this.transporterName = transporterName; + } + + public String getTransporterPhone() { + return transporterPhone; + } + + public void setTransporterPhone(String transporterPhone) { + this.transporterPhone = transporterPhone; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + } + + public static class StoreInfo { + private String storeName; + private String wxStoreId; + private String address; + private double lng; + private double lat; + private String phoneNum; + + public String getStoreName() { + return storeName; + } + + public void setStoreName(String storeName) { + this.storeName = storeName; + } + + public String getWxStoreId() { + return wxStoreId; + } + + public void setWxStoreId(String wxStoreId) { + this.wxStoreId = wxStoreId; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public double getLng() { + return lng; + } + + public void setLng(double lng) { + this.lng = lng; + } + + public double getLat() { + return lat; + } + + public void setLat(double lat) { + this.lat = lat; + } + + public String getPhoneNum() { + return phoneNum; + } + + public void setPhoneNum(String phoneNum) { + this.phoneNum = phoneNum; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + } + + public static class ReceiverInfo { + private String receiverName; + private String address; + private String phoneNum; + private double lng; + private double lat; + + public String getReceiverName() { + return receiverName; + } + + public void setReceiverName(String receiverName) { + this.receiverName = receiverName; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getPhoneNum() { + return phoneNum; + } + + public void setPhoneNum(String phoneNum) { + this.phoneNum = phoneNum; + } + + public double getLng() { + return lng; + } + + public void setLng(double lng) { + this.lng = lng; + } + + public double getLat() { + return lat; + } + + public void setLat(double lat) { + this.lat = lat; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaPreAddOrderRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaPreAddOrderRequest.java new file mode 100644 index 000000000..88c7fbd5a --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaPreAddOrderRequest.java @@ -0,0 +1,22 @@ +package cn.binarywang.wx.miniapp.bean.intractiy; + +import org.apache.commons.lang3.builder.ToStringBuilder; + +public class WxMaPreAddOrderRequest extends BasicWxMaOrder { + private Cargo cargo; + + public Cargo getCargo() { + return cargo; + } + + public void setCargo(Cargo cargo) { + this.cargo = cargo; + } + + public static class Cargo extends BasicWxMaOrder.Cargo {} + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaQueryFlowRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaQueryFlowRequest.java new file mode 100644 index 000000000..545be89ae --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaQueryFlowRequest.java @@ -0,0 +1,88 @@ +package cn.binarywang.wx.miniapp.bean.intractiy; + +import java.util.Date; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WxMaQueryFlowRequest { + private static final Logger logger = LoggerFactory.getLogger(WxMaQueryFlowRequest.class); + + private String wxStoreId; + + /** 流水类型: 1:充值流水, 2:消费流水,3:退款流水 */ + private int flowType = 1; + + /** 运力ID */ + private String serviceTransId; + + private transient Date beginDate; + private transient Date endDate; + private long beginTime; + private long endTime; + + public String getWxStoreId() { + return wxStoreId; + } + + public void setWxStoreId(String wxStoreId) { + this.wxStoreId = wxStoreId; + } + + public int getFlowType() { + return flowType; + } + + public void setFlowType(int flowType) { + this.flowType = flowType; + } + + public String getServiceTransId() { + return serviceTransId; + } + + public void setServiceTransId(String serviceTransId) { + this.serviceTransId = serviceTransId; + } + + public Date getBeginDate() { + return beginDate; + } + + public void setBeginDate(Date beginDate) { + this.beginDate = beginDate; + this.beginTime = beginDate.getTime() / 1000; + } + + public Date getEndDate() { + return endDate; + } + + public void setEndDate(Date endDate) { + this.endDate = endDate; + this.endTime = endDate.getTime() / 1000; + } + + public long getBeginTime() { + return beginTime; + } + + public void setBeginTime(long beginTime) { + this.beginTime = beginTime; + this.beginDate = new Date(beginTime * 1000); + } + + public long getEndTime() { + return endTime; + } + + public void setEndTime(long endTime) { + this.endTime = endTime; + this.endDate = new Date(endTime * 1000); + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaStore.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaStore.java new file mode 100644 index 000000000..958b078e5 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaStore.java @@ -0,0 +1,187 @@ +package cn.binarywang.wx.miniapp.bean.intractiy; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WxMaStore { + private static final Logger logger = LoggerFactory.getLogger(WxMaStore.class); + + /** 微信分配的ID,创建时不用填写,查询时返回,根据此ID下单等 */ + private String wxStoreId; + + /** 自己设置的门店ID,创建时填写,查询时返回,不可修改 */ + private String outStoreId; + + /** 门店名称,创建时需要,可修改;查询结果微信不返回此字段 */ + private String storeName; + + /** 创建时不用设置,查询时返回,微信自动设置 */ + private String cityId; + + /** 1:价格优先,2:运力优先 */ + private int orderPattern = 1; + + /** + * 运力优先时优先使用的运力。运力ID请参考:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/express/business/intracity_service.html#_6-%E8%BF%90%E5%8A%9B%E5%88%97%E8%A1%A8 + */ + private String ServiceTransPrefer; + + private AddressInfo addressInfo; + + public String getWxStoreId() { + return wxStoreId; + } + + public void setWxStoreId(String wxStoreId) { + this.wxStoreId = wxStoreId; + } + + public String getOutStoreId() { + return outStoreId; + } + + public void setOutStoreId(String outStoreId) { + this.outStoreId = outStoreId; + } + + public String getStoreName() { + return storeName; + } + + public void setStoreName(String storeName) { + this.storeName = storeName; + } + + public String getCityId() { + return cityId; + } + + public void setCityId(String cityId) { + this.cityId = cityId; + } + + public int getOrderPattern() { + return orderPattern; + } + + public void setOrderPattern(int orderPattern) { + this.orderPattern = orderPattern; + } + + public String getServiceTransPrefer() { + return ServiceTransPrefer; + } + + public void setServiceTransPrefer(String serviceTransPrefer) { + ServiceTransPrefer = serviceTransPrefer; + } + + public AddressInfo getAddressInfo() { + return addressInfo; + } + + public void setAddressInfo(AddressInfo addressInfo) { + this.addressInfo = addressInfo; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + + public static class AddressInfo { + /** 省、自治区、直辖市 必填 */ + private String province; + + /** 地级市 必填 */ + private String city; + + /** 区/县/县级市 必填 */ + private String area; + + /** 街道/镇 选填 */ + private String street; + + /** 路名和门牌号 必填 */ + private String house; + + /** 门店电话号码 必填 */ + private String phone; + + /** 纬度 必填 */ + private double lat; + + /** 经度 必填 */ + private double lng; + + public String getProvince() { + return province; + } + + public void setProvince(String province) { + this.province = province; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getArea() { + return area; + } + + public void setArea(String area) { + this.area = area; + } + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } + + public String getHouse() { + return house; + } + + public void setHouse(String house) { + this.house = house; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public double getLat() { + return lat; + } + + public void setLat(double lat) { + this.lat = lat; + } + + public double getLng() { + return lng; + } + + public void setLng(double lng) { + this.lng = lng; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaStoreBalance.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaStoreBalance.java new file mode 100644 index 000000000..783c76fcd --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaStoreBalance.java @@ -0,0 +1,115 @@ +package cn.binarywang.wx.miniapp.bean.intractiy; + +import java.util.Date; +import java.util.List; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WxMaStoreBalance { + private static final Logger logger = LoggerFactory.getLogger(WxMaStoreBalance.class); + + private String wxStoreId; + private String appid; + private int allBalance; + + private List balanceDetail; + + public String getWxStoreId() { + return wxStoreId; + } + + public void setWxStoreId(String wxStoreId) { + this.wxStoreId = wxStoreId; + } + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + + public int getAllBalance() { + return allBalance; + } + + public void setAllBalance(int allBalance) { + this.allBalance = allBalance; + } + + public List getBalanceDetail() { + return balanceDetail; + } + + public void setBalanceDetail(List balanceDetail) { + this.balanceDetail = balanceDetail; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + + public static class Detail { + private String payorderId; + private int chargeAmt; + private int unusedAmt; + private long beginTime; + private long endTime; + + public String getPayorderId() { + return payorderId; + } + + public void setPayorderId(String payorderId) { + this.payorderId = payorderId; + } + + public int getChargeAmt() { + return chargeAmt; + } + + public void setChargeAmt(int chargeAmt) { + this.chargeAmt = chargeAmt; + } + + public int getUnusedAmt() { + return unusedAmt; + } + + public void setUnusedAmt(int unusedAmt) { + this.unusedAmt = unusedAmt; + } + + public Date getBeginDate() { + return this.beginTime == 0 ? null : new Date(this.beginTime * 1000); + } + + public Date getEndDate() { + return this.endTime == 0 ? null : new Date(this.endTime * 1000); + } + + public long getBeginTime() { + return beginTime; + } + + public void setBeginTime(long beginTime) { + this.beginTime = beginTime; + } + + public long getEndTime() { + return endTime; + } + + public void setEndTime(long endTime) { + this.endTime = endTime; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaStoreChargeRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaStoreChargeRequest.java new file mode 100644 index 000000000..2f320995f --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaStoreChargeRequest.java @@ -0,0 +1,22 @@ +package cn.binarywang.wx.miniapp.bean.intractiy; + +import org.apache.commons.lang3.builder.ToStringBuilder; + +public class WxMaStoreChargeRequest extends BasicWxMaStoreChargeRefundRequest { + + /** 充值金额 单位:分, 50元起充 */ + private int amount; + + public int getAmount() { + return amount; + } + + public void setAmount(int amount) { + this.amount = amount; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaStoreFlowResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaStoreFlowResponse.java new file mode 100644 index 000000000..af5769aa5 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaStoreFlowResponse.java @@ -0,0 +1,318 @@ +package cn.binarywang.wx.miniapp.bean.intractiy; + +import java.util.Date; +import java.util.List; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WxMaStoreFlowResponse { + private static final Logger logger = LoggerFactory.getLogger(WxMaStoreFlowResponse.class); + + /** 总支付金额 */ + private Long totalPayAmt; + + /** 总退款金额 */ + private Long totalRefundAmt; + + /** 总违约金 查询消费流水才返回 */ + private Long totalDeductAmt; + + /** 流水 */ + private List flowList; + + public List getFlowList() { + return flowList; + } + + public void setFlowList(List flowList) { + this.flowList = flowList; + } + + public Long getTotalPayAmt() { + return totalPayAmt; + } + + public void setTotalPayAmt(Long totalPayAmt) { + this.totalPayAmt = totalPayAmt; + } + + public Long getTotalRefundAmt() { + return totalRefundAmt; + } + + public void setTotalRefundAmt(Long totalRefundAmt) { + this.totalRefundAmt = totalRefundAmt; + } + + public Long getTotalDeductAmt() { + return totalDeductAmt; + } + + public void setTotalDeductAmt(Long totalDeductAmt) { + this.totalDeductAmt = totalDeductAmt; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + + public static class BasicFlowRecord { + private int flowType; + private String appid; + private String wxStoreId; + private String payOrderId; + private String serviceTransId; + private int payAmount; + private long payTime; + private long createTime; + + public int getFlowType() { + return flowType; + } + + public void setFlowType(int flowType) { + this.flowType = flowType; + } + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + + public String getWxStoreId() { + return wxStoreId; + } + + public void setWxStoreId(String wxStoreId) { + this.wxStoreId = wxStoreId; + } + + public String getPayOrderId() { + return payOrderId; + } + + public void setPayOrderId(String payOrderId) { + this.payOrderId = payOrderId; + } + + public String getServiceTransId() { + return serviceTransId; + } + + public void setServiceTransId(String serviceTransId) { + this.serviceTransId = serviceTransId; + } + + public int getPayAmount() { + return payAmount; + } + + public void setPayAmount(int payAmount) { + this.payAmount = payAmount; + } + + public Date getPayDate() { + return this.payTime == 0 ? null : new Date(this.payTime * 1000); + } + + public long getPayTime() { + return payTime; + } + + public void setPayTime(long payTime) { + this.payTime = payTime; + } + + public Date getCreateDate() { + return this.createTime == 0 ? null : new Date(this.createTime * 1000); + } + + public long getCreateTime() { + return createTime; + } + + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + } + + /** 充值流水 */ + public static class ChargeFlowRecord extends BasicFlowRecord { + private String payStatus; + + private long consumeDeadline; + + public String getPayStatus() { + return payStatus; + } + + public void setPayStatus(String payStatus) { + this.payStatus = payStatus; + } + + public Date getConsumeDeadlineDate() { + return this.consumeDeadline == 0 ? null : new Date(this.consumeDeadline * 1000); + } + + public long getConsumeDeadline() { + return consumeDeadline; + } + + public void setConsumeDeadline(long consumeDeadline) { + this.consumeDeadline = consumeDeadline; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + } + + /** 退款流水 */ + public static class RefundFlowRecord extends BasicFlowRecord { + private int refundAmount; + private long refundTime; + private long consumeDeadline; + + public int getRefundAmount() { + return refundAmount; + } + + public void setRefundAmount(int refundAmount) { + this.refundAmount = refundAmount; + } + + public Date getRefundDate() { + return this.refundTime == 0 ? null : new Date(this.refundTime * 1000); + } + + public long getRefundTime() { + return refundTime; + } + + public void setRefundTime(long refundTime) { + this.refundTime = refundTime; + } + + public Date getConsumeDeadlineDate() { + return this.consumeDeadline == 0 ? null : new Date(this.consumeDeadline * 1000); + } + + public long getConsumeDeadline() { + return consumeDeadline; + } + + public void setConsumeDeadline(long consumeDeadline) { + this.consumeDeadline = consumeDeadline; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + } + + /** 消费流水 */ + public static class ConsumeFlowRecord extends BasicFlowRecord { + private String wxOrderId; + private String openid; + private String deliveryStatus; + private String payStatus; + private String refundStatus; + private int refundAmount; + private int deductAmount; + private String billId; + private long deliveryFinishedTime; + + public String getWxOrderId() { + return wxOrderId; + } + + public void setWxOrderId(String wxOrderId) { + this.wxOrderId = wxOrderId; + } + + public String getOpenid() { + return openid; + } + + public void setOpenid(String openid) { + this.openid = openid; + } + + public String getDeliveryStatus() { + return deliveryStatus; + } + + public void setDeliveryStatus(String deliveryStatus) { + this.deliveryStatus = deliveryStatus; + } + + public String getPayStatus() { + return payStatus; + } + + public void setPayStatus(String payStatus) { + this.payStatus = payStatus; + } + + public String getRefundStatus() { + return refundStatus; + } + + public void setRefundStatus(String refundStatus) { + this.refundStatus = refundStatus; + } + + public int getRefundAmount() { + return refundAmount; + } + + public void setRefundAmount(int refundAmount) { + this.refundAmount = refundAmount; + } + + public int getDeductAmount() { + return deductAmount; + } + + public void setDeductAmount(int deductAmount) { + this.deductAmount = deductAmount; + } + + public String getBillId() { + return billId; + } + + public void setBillId(String billId) { + this.billId = billId; + } + + public Date getDeliveryFinishedDate() { + return this.deliveryFinishedTime == 0 ? null : new Date(this.deliveryFinishedTime * 1000); + } + + public long getDeliveryFinishedTime() { + return deliveryFinishedTime; + } + + public void setDeliveryFinishedTime(long deliveryFinishedTime) { + this.deliveryFinishedTime = deliveryFinishedTime; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaStoreRefundRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaStoreRefundRequest.java new file mode 100644 index 000000000..cb4ebec3a --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaStoreRefundRequest.java @@ -0,0 +1,11 @@ +package cn.binarywang.wx.miniapp.bean.intractiy; + +import org.apache.commons.lang3.builder.ToStringBuilder; + +public class WxMaStoreRefundRequest extends BasicWxMaStoreChargeRefundRequest { + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaTransCity.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaTransCity.java new file mode 100644 index 000000000..ff125447f --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaTransCity.java @@ -0,0 +1,56 @@ +package cn.binarywang.wx.miniapp.bean.intractiy; + +import java.util.List; +import org.apache.commons.lang3.builder.ToStringBuilder; + +public class WxMaTransCity { + private String serviceTransId; + private List cityList; + + public String getServiceTransId() { + return serviceTransId; + } + + public void setServiceTransId(String serviceTransId) { + this.serviceTransId = serviceTransId; + } + + public List getCityList() { + return cityList; + } + + public void setCityList(List cityList) { + this.cityList = cityList; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + + public static class City { + private String cityName; + private String cityCode; + + public String getCityName() { + return cityName; + } + + public void setCityName(String cityName) { + this.cityName = cityName; + } + + public String getCityCode() { + return cityCode; + } + + public void setCityCode(String cityCode) { + this.cityCode = cityCode; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java index 12e1da07b..ba71b931c 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java @@ -1,11 +1,10 @@ package cn.binarywang.wx.miniapp.config; -import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.bean.WxAccessTokenEntity; -import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; - import java.util.concurrent.locks.Lock; import java.util.function.Consumer; +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.WxAccessTokenEntity; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; /** * 小程序配置 @@ -14,9 +13,7 @@ import java.util.function.Consumer; */ public interface WxMaConfig { - default void setUpdateAccessTokenBefore(Consumer updateAccessTokenBefore) { - - } + default void setUpdateAccessTokenBefore(Consumer updateAccessTokenBefore) {} /** * Gets access token. @@ -25,12 +22,12 @@ public interface WxMaConfig { */ String getAccessToken(); - //region 稳定版access token + // region 稳定版access token boolean isStableAccessToken(); void useStableAccessToken(boolean useStableAccessToken); - //endregion + // endregion /** * Gets access token lock. @@ -46,9 +43,7 @@ public interface WxMaConfig { */ boolean isAccessTokenExpired(); - /** - * 强制将access token过期掉 - */ + /** 强制将access token过期掉 */ void expireAccessToken(); /** @@ -63,7 +58,7 @@ public interface WxMaConfig { /** * 应该是线程安全的 * - * @param accessToken 新的accessToken值 + * @param accessToken 新的accessToken值 * @param expiresInSeconds 过期时间,以秒为单位 */ void updateAccessToken(String accessToken, int expiresInSeconds); @@ -77,10 +72,7 @@ public interface WxMaConfig { updateAccessToken(accessToken, expiresInSeconds); } - default void updateAccessTokenBefore(WxAccessTokenEntity wxAccessTokenEntity) { - - } - + default void updateAccessTokenBefore(WxAccessTokenEntity wxAccessTokenEntity) {} /** * Gets jsapi ticket. @@ -103,15 +95,13 @@ public interface WxMaConfig { */ boolean isJsapiTicketExpired(); - /** - * 强制将jsapi ticket过期掉 - */ + /** 强制将jsapi ticket过期掉 */ void expireJsapiTicket(); /** * 应该是线程安全的 * - * @param jsapiTicket 新的jsapi ticket值 + * @param jsapiTicket 新的jsapi ticket值 * @param expiresInSeconds 过期时间,以秒为单位 */ void updateJsapiTicket(String jsapiTicket, int expiresInSeconds); @@ -137,15 +127,13 @@ public interface WxMaConfig { */ boolean isCardApiTicketExpired(); - /** - * 强制将卡券api ticket过期掉. - */ + /** 强制将卡券api ticket过期掉. */ void expireCardApiTicket(); /** * 应该是线程安全的. * - * @param apiTicket 新的卡券api ticket值 + * @param apiTicket 新的卡券api ticket值 * @param expiresInSeconds 过期时间,以秒为单位 */ void updateCardApiTicket(String apiTicket, int expiresInSeconds); @@ -236,6 +224,7 @@ public interface WxMaConfig { /** * http 请求重试间隔 + * *
    *   {@link cn.binarywang.wx.miniapp.api.impl.BaseWxMaServiceImpl#setRetrySleepMillis(int)}
    * 
@@ -244,6 +233,7 @@ public interface WxMaConfig { /** * http 请求最大重试次数 + * *
    *   {@link cn.binarywang.wx.miniapp.api.impl.BaseWxMaServiceImpl#setMaxRetryTimes(int)}
    * 
@@ -288,10 +278,35 @@ public interface WxMaConfig { String getAccessTokenUrl(); /** - * 设置自定义的获取accessToken地址 - * 可用于设置获取accessToken的自定义服务 + * 设置自定义的获取accessToken地址 可用于设置获取accessToken的自定义服务 * * @param accessTokenUrl 自定义的获取accessToken地址 */ void setAccessTokenUrl(String accessTokenUrl); + + /** + * 服务端API签名用到的RSA私钥【pkcs8格式,会以 -----BEGIN PRIVATE KEY-----开头, 'BEGIN RSA PRIVATE + * KEY'的是pkcs1格式,需要转换(可用openssl转换)。 设置参考: + * https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/getting_started/api_signature.html + * + * @return rsa private key string + */ + String getApiSignatureRsaPrivateKey(); + + /** + * 服务端API签名用到的AES密钥 + * https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/getting_started/api_signature.html + * + * @return aes key string + */ + String getApiSignatureAesKey(); + + /** 密钥对应的序号 */ + String getApiSignatureAesKeySn(); + + /** 密钥对应的序号 */ + String getApiSignatureRsaPrivateKeySn(); + + /** 密钥对应的小程序ID (普通小程序同 appId, 托管第三方平台的是 componentAppId) */ + String getWechatMpAppid(); } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaDefaultConfigImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaDefaultConfigImpl.java index bd9a4e20b..ab82d6209 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaDefaultConfigImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaDefaultConfigImpl.java @@ -2,17 +2,16 @@ package cn.binarywang.wx.miniapp.config.impl; import cn.binarywang.wx.miniapp.config.WxMaConfig; import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +import java.io.File; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; import me.chanjar.weixin.common.bean.WxAccessTokenEntity; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; -import java.io.File; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Consumer; - /** * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 * @@ -23,30 +22,32 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { protected volatile String appid; protected volatile String token; - /** - * 是否使用稳定版获取accessToken接口 - */ + /** 是否使用稳定版获取accessToken接口 */ @Getter(value = AccessLevel.NONE) private boolean useStableAccessToken; - /** - * 小程序原始ID - */ + /** 小程序原始ID */ protected volatile String originalId; + protected Lock accessTokenLock = new ReentrantLock(); - /** - * 临时文件目录. - */ + + /** 临时文件目录. */ protected volatile File tmpDirFile; + private volatile String msgDataFormat; private volatile String secret; private volatile String accessToken; private volatile String aesKey; private volatile long expiresTime; - /** - * 云环境ID - */ + private volatile String apiSignatureRsaPrivateKey; + private volatile String apiSignatureAesKey; + private volatile String apiSignatureRsaPrivateKeySn; + private volatile String apiSignatureAesKeySn; + private volatile String wechatMpAppid; + + /** 云环境ID */ private volatile String cloudEnv; + private volatile String httpProxyHost; private volatile int httpProxyPort; private volatile String httpProxyUsername; @@ -57,10 +58,10 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { private volatile String jsapiTicket; private volatile long jsapiTicketExpiresTime; - /** - * 微信卡券的ticket单独缓存. - */ + + /** 微信卡券的ticket单独缓存. */ private volatile String cardApiTicket; + private volatile long cardApiTicketExpiresTime; protected volatile Lock jsapiTicketLock = new ReentrantLock(); protected volatile Lock cardApiTicketLock = new ReentrantLock(); @@ -68,35 +69,24 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { private String apiHostUrl; private String accessTokenUrl; - /** - * 自定义配置token的消费者 - */ - @Setter - private Consumer updateAccessTokenBefore; + /** 自定义配置token的消费者 */ + @Setter private Consumer updateAccessTokenBefore; - /** - * 开启回调 - */ + /** 开启回调 */ @Getter(AccessLevel.NONE) private boolean enableUpdateAccessTokenBefore = true; - /** - * 可临时关闭更新token回调,主要用于其他介质初始化数据时,可不进行回调 - */ + /** 可临时关闭更新token回调,主要用于其他介质初始化数据时,可不进行回调 */ public void enableUpdateAccessTokenBefore(boolean enableUpdateAccessTokenBefore) { this.enableUpdateAccessTokenBefore = enableUpdateAccessTokenBefore; } - /** - * 会过期的数据提前过期时间,默认预留200秒的时间 - */ + /** 会过期的数据提前过期时间,默认预留200秒的时间 */ protected long expiresAheadInMillis(int expiresInSeconds) { return System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; } - /** - * 判断 expiresTime 是否已经过期 - */ + /** 判断 expiresTime 是否已经过期 */ protected boolean isExpired(long expiresTime) { return System.currentTimeMillis() > expiresTime; } @@ -110,7 +100,7 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { this.accessToken = accessToken; } - //region 使用稳定版接口获取accessToken + // region 使用稳定版接口获取accessToken @Override public boolean isStableAccessToken() { return this.useStableAccessToken; @@ -120,8 +110,8 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { public void useStableAccessToken(boolean useStableAccessToken) { this.useStableAccessToken = useStableAccessToken; } - //endregion + // endregion @Override public Lock getAccessTokenLock() { @@ -137,10 +127,10 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { return isExpired(this.expiresTime); } -// @Override -// public synchronized void updateAccessToken(WxAccessToken accessToken) { -// updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); -// } + // @Override + // public synchronized void updateAccessToken(WxAccessToken accessToken) { + // updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + // } @Override public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { @@ -248,6 +238,46 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { this.aesKey = aesKey; } + public String getApiSignatureRsaPrivateKey() { + return apiSignatureRsaPrivateKey; + } + + public void setApiSignatureRsaPrivateKey(String apiSignatureRsaPrivateKey) { + this.apiSignatureRsaPrivateKey = apiSignatureRsaPrivateKey; + } + + public String getApiSignatureAesKey() { + return apiSignatureAesKey; + } + + public void setApiSignatureAesKey(String apiSignatureAesKey) { + this.apiSignatureAesKey = apiSignatureAesKey; + } + + public String getApiSignatureRsaPrivateKeySn() { + return apiSignatureRsaPrivateKeySn; + } + + public void setApiSignatureRsaPrivateKeySn(String apiSignatureRsaPrivateKeySn) { + this.apiSignatureRsaPrivateKeySn = apiSignatureRsaPrivateKeySn; + } + + public String getApiSignatureAesKeySn() { + return apiSignatureAesKeySn; + } + + public void setApiSignatureAesKeySn(String apiSignatureAesKeySn) { + this.apiSignatureAesKeySn = apiSignatureAesKeySn; + } + + public String getWechatMpAppid() { + return wechatMpAppid == null ? appid : wechatMpAppid; + } + + public void setWechatMpAppid(String wechatMpAppid) { + this.wechatMpAppid = wechatMpAppid; + } + @Override public String getOriginalId() { return originalId; diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java index f1bc84ad7..ab47d3e64 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java @@ -5,58 +5,62 @@ import lombok.experimental.UtilityClass; /** * 小程序接口地址常量. * - * @author Binary Wang - * created on 2021-01-28 + * @author Binary Wang created on 2021-01-28 */ @UtilityClass public class WxMaApiUrlConstants { - /** - * openApi管理 - */ + /** openApi管理 */ public interface OpenApi { - /** - * 重置API调用次数 - */ + /** 重置API调用次数 */ String CLEAR_QUOTA = "https://api.weixin.qq.com/cgi-bin/clear_quota"; - /** - * 查询API调用额度 - */ - String GET_API_QUOTA = "https://api.weixin.qq.com/cgi-bin/openapi/quota/get"; - /** - * 查询rid信息 - */ - String GET_RID_INFO = "https://api.weixin.qq.com/cgi-bin/openapi/rid/get"; - /** - * 使用AppSecret重置 API 调用次数 - */ - String CLEAR_QUOTA_BY_APP_SECRET = "https://api.weixin.qq.com/cgi-bin/clear_quota/v2?appid=%s&appsecret=%s"; + /** 查询API调用额度 */ + String GET_API_QUOTA = "https://api.weixin.qq.com/cgi-bin/openapi/quota/get"; + + /** 查询rid信息 */ + String GET_RID_INFO = "https://api.weixin.qq.com/cgi-bin/openapi/rid/get"; + + /** 使用AppSecret重置 API 调用次数 */ + String CLEAR_QUOTA_BY_APP_SECRET = + "https://api.weixin.qq.com/cgi-bin/clear_quota/v2?appid=%s&appsecret=%s"; } public interface Analysis { - String GET_DAILY_SUMMARY_TREND_URL = "https://api.weixin.qq.com/datacube/getweanalysisappiddailysummarytrend"; - String GET_DAILY_VISIT_TREND_URL = "https://api.weixin.qq.com/datacube/getweanalysisappiddailyvisittrend"; - String GET_WEEKLY_VISIT_TREND_URL = "https://api.weixin.qq.com/datacube/getweanalysisappidweeklyvisittrend"; - String GET_MONTHLY_VISIT_TREND_URL = "https://api.weixin.qq.com/datacube/getweanalysisappidmonthlyvisittrend"; - String GET_VISIT_DISTRIBUTION_URL = "https://api.weixin.qq.com/datacube/getweanalysisappidvisitdistribution"; - String GET_DAILY_RETAIN_INFO_URL = "https://api.weixin.qq.com/datacube/getweanalysisappiddailyretaininfo"; - String GET_WEEKLY_RETAIN_INFO_URL = "https://api.weixin.qq.com/datacube/getweanalysisappidweeklyretaininfo"; - String GET_MONTHLY_RETAIN_INFO_URL = "https://api.weixin.qq.com/datacube/getweanalysisappidmonthlyretaininfo"; + String GET_DAILY_SUMMARY_TREND_URL = + "https://api.weixin.qq.com/datacube/getweanalysisappiddailysummarytrend"; + String GET_DAILY_VISIT_TREND_URL = + "https://api.weixin.qq.com/datacube/getweanalysisappiddailyvisittrend"; + String GET_WEEKLY_VISIT_TREND_URL = + "https://api.weixin.qq.com/datacube/getweanalysisappidweeklyvisittrend"; + String GET_MONTHLY_VISIT_TREND_URL = + "https://api.weixin.qq.com/datacube/getweanalysisappidmonthlyvisittrend"; + String GET_VISIT_DISTRIBUTION_URL = + "https://api.weixin.qq.com/datacube/getweanalysisappidvisitdistribution"; + String GET_DAILY_RETAIN_INFO_URL = + "https://api.weixin.qq.com/datacube/getweanalysisappiddailyretaininfo"; + String GET_WEEKLY_RETAIN_INFO_URL = + "https://api.weixin.qq.com/datacube/getweanalysisappidweeklyretaininfo"; + String GET_MONTHLY_RETAIN_INFO_URL = + "https://api.weixin.qq.com/datacube/getweanalysisappidmonthlyretaininfo"; String GET_VISIT_PAGE_URL = "https://api.weixin.qq.com/datacube/getweanalysisappidvisitpage"; - String GET_USER_PORTRAIT_URL = "https://api.weixin.qq.com/datacube/getweanalysisappiduserportrait"; + String GET_USER_PORTRAIT_URL = + "https://api.weixin.qq.com/datacube/getweanalysisappiduserportrait"; } public interface Cloud { - String INVOKE_CLOUD_FUNCTION_URL = "https://api.weixin.qq.com/tcb/invokecloudfunction?env=%s&name=%s"; + String INVOKE_CLOUD_FUNCTION_URL = + "https://api.weixin.qq.com/tcb/invokecloudfunction?env=%s&name=%s"; String DATABASE_COLLECTION_GET_URL = "https://api.weixin.qq.com/tcb/databasecollectionget"; - String DATABASE_COLLECTION_DELETE_URL = "https://api.weixin.qq.com/tcb/databasecollectiondelete"; + String DATABASE_COLLECTION_DELETE_URL = + "https://api.weixin.qq.com/tcb/databasecollectiondelete"; String DATABASE_COLLECTION_ADD_URL = "https://api.weixin.qq.com/tcb/databasecollectionadd"; String GET_QCLOUD_TOKEN_URL = "https://api.weixin.qq.com/tcb/getqcloudtoken"; String BATCH_DELETE_FILE_URL = "https://api.weixin.qq.com/tcb/batchdeletefile"; String BATCH_DOWNLOAD_FILE_URL = "https://api.weixin.qq.com/tcb/batchdownloadfile"; String UPLOAD_FILE_URL = "https://api.weixin.qq.com/tcb/uploadfile"; - String DATABASE_MIGRATE_QUERY_INFO_URL = "https://api.weixin.qq.com/tcb/databasemigratequeryinfo"; + String DATABASE_MIGRATE_QUERY_INFO_URL = + "https://api.weixin.qq.com/tcb/databasemigratequeryinfo"; String DATABASE_MIGRATE_EXPORT_URL = "https://api.weixin.qq.com/tcb/databasemigrateexport"; String DATABASE_MIGRATE_IMPORT_URL = "https://api.weixin.qq.com/tcb/databasemigrateimport"; String UPDATE_INDEX_URL = "https://api.weixin.qq.com/tcb/updateindex"; @@ -73,16 +77,18 @@ public class WxMaApiUrlConstants { String KEFU_MESSAGE_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/custom/send"; String TEMPLATE_MSG_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send"; String SUBSCRIBE_MSG_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send"; - String UNIFORM_MSG_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send"; - String ACTIVITY_ID_CREATE_URL = "https://api.weixin.qq.com/cgi-bin/message/wxopen/activityid/create"; - String UPDATABLE_MSG_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/wxopen/updatablemsg/send"; + String UNIFORM_MSG_SEND_URL = + "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send"; + String ACTIVITY_ID_CREATE_URL = + "https://api.weixin.qq.com/cgi-bin/message/wxopen/activityid/create"; + String UPDATABLE_MSG_SEND_URL = + "https://api.weixin.qq.com/cgi-bin/message/wxopen/updatablemsg/send"; } public interface Code { - /** - * 为授权的小程序帐号上传小程序代码. - */ + /** 为授权的小程序帐号上传小程序代码. */ String COMMIT_URL = "https://api.weixin.qq.com/wxa/commit"; + String GET_QRCODE_URL = "https://api.weixin.qq.com/wxa/get_qrcode"; String GET_CATEGORY_URL = "https://api.weixin.qq.com/wxa/get_category"; String GET_PAGE_URL = "https://api.weixin.qq.com/wxa/get_page"; @@ -92,204 +98,158 @@ public class WxMaApiUrlConstants { String RELEASE_URL = "https://api.weixin.qq.com/wxa/release"; String CHANGE_VISIT_STATUS_URL = "https://api.weixin.qq.com/wxa/change_visitstatus"; String REVERT_CODE_RELEASE_URL = "https://api.weixin.qq.com/wxa/revertcoderelease"; - String GET_SUPPORT_VERSION_URL = "https://api.weixin.qq.com/cgi-bin/wxopen/getweappsupportversion"; - String SET_SUPPORT_VERSION_URL = "https://api.weixin.qq.com/cgi-bin/wxopen/setweappsupportversion"; + String GET_SUPPORT_VERSION_URL = + "https://api.weixin.qq.com/cgi-bin/wxopen/getweappsupportversion"; + String SET_SUPPORT_VERSION_URL = + "https://api.weixin.qq.com/cgi-bin/wxopen/setweappsupportversion"; String UNDO_CODE_AUDIT_URL = "https://api.weixin.qq.com/wxa/undocodeaudit"; String GET_VERSION_INFO_URL = "https://api.weixin.qq.com/wxa/getversioninfo"; } public interface Express { - /** - * 获取支持的快递公司列表 - */ + /** 获取支持的快递公司列表 */ String ALL_DELIVERY_URL = "https://api.weixin.qq.com/cgi-bin/express/business/delivery/getall"; - /** - * 获取所有绑定的物流账号 - */ + + /** 获取所有绑定的物流账号 */ String ALL_ACCOUNT_URL = "https://api.weixin.qq.com/cgi-bin/express/business/account/getall"; - /** - * 绑定、解绑物流账号 - */ + + /** 绑定、解绑物流账号 */ String BIND_ACCOUNT_URL = "https://api.weixin.qq.com/cgi-bin/express/business/account/bind"; - /** - * 获取电子面单余额 - */ + + /** 获取电子面单余额 */ String GET_QUOTA_URL = "https://api.weixin.qq.com/cgi-bin/express/business/quota/get"; - /** - * 配置面单打印员 - */ + + /** 配置面单打印员 */ String UPDATE_PRINTER_URL = "https://api.weixin.qq.com/cgi-bin/express/business/printer/update"; - /** - * 获取打印员 - */ + + /** 获取打印员 */ String GET_PRINTER_URL = "https://api.weixin.qq.com/cgi-bin/express/business/printer/getall"; - /** - * 生成运单 - */ + + /** 生成运单 */ String ADD_ORDER_URL = "https://api.weixin.qq.com/cgi-bin/express/business/order/add"; - /** - * 批量获取运单数据 - */ - String BATCH_GET_ORDER_URL = "https://api.weixin.qq.com/cgi-bin/express/business/order/batchget"; - /** - * 取消运单 - */ + + /** 批量获取运单数据 */ + String BATCH_GET_ORDER_URL = + "https://api.weixin.qq.com/cgi-bin/express/business/order/batchget"; + + /** 取消运单 */ String CANCEL_ORDER_URL = "https://api.weixin.qq.com/cgi-bin/express/business/order/cancel"; - /** - * 获取运单数据 - */ + + /** 获取运单数据 */ String GET_ORDER_URL = "https://api.weixin.qq.com/cgi-bin/express/business/order/get"; - /** - * 查询运单轨迹 - */ + + /** 查询运单轨迹 */ String GET_PATH_URL = "https://api.weixin.qq.com/cgi-bin/express/business/path/get"; - /** - * 模拟快递公司更新订单状态 - */ - String TEST_UPDATE_ORDER_URL = "https://api.weixin.qq.com/cgi-bin/express/business/test_update_order"; + + /** 模拟快递公司更新订单状态 */ + String TEST_UPDATE_ORDER_URL = + "https://api.weixin.qq.com/cgi-bin/express/business/test_update_order"; } public interface ImgProc { - /** - * 二维码/条码识别 - */ + /** 二维码/条码识别 */ String QRCODE = "https://api.weixin.qq.com/cv/img/qrcode?img_url=%s"; - /** - * 二维码/条码识别(文件) - */ + + /** 二维码/条码识别(文件) */ String FILE_QRCODE = "https://api.weixin.qq.com/cv/img/qrcode"; - /** - * 图片高清化 - */ + + /** 图片高清化 */ String SUPER_RESOLUTION = "https://api.weixin.qq.com/cv/img/superresolution?img_url=%s"; - /** - * 图片高清化(文件) - */ + + /** 图片高清化(文件) */ String FILE_SUPER_RESOLUTION = "https://api.weixin.qq.com/cv/img/superresolution"; - /** - * 图片智能裁剪 - */ + + /** 图片智能裁剪 */ String AI_CROP = "https://api.weixin.qq.com/cv/img/aicrop?img_url=%s&ratios=%s"; - /** - * 图片智能裁剪(文件) - */ + + /** 图片智能裁剪(文件) */ String FILE_AI_CROP = "https://api.weixin.qq.com/cv/img/aicrop?ratios=%s"; } public interface Jsapi { - /** - * 获得jsapi_ticket的url - */ + /** 获得jsapi_ticket的url */ String GET_JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket"; } public interface Broadcast { - /** - * 直播间管理相关接口 - */ + /** 直播间管理相关接口 */ interface Room { - /** - * 创建直播间 - */ + /** 创建直播间 */ String CREATE_ROOM = "https://api.weixin.qq.com/wxaapi/broadcast/room/create"; - /** - * 获取直播间列表 - * 获取直播间回放 - */ + + /** 获取直播间列表 获取直播间回放 */ String GET_LIVE_INFO = "https://api.weixin.qq.com/wxa/business/getliveinfo"; - /** - * 直播间导入商品 - */ + + /** 直播间导入商品 */ String ADD_GOODS = "https://api.weixin.qq.com/wxaapi/broadcast/room/addgoods"; - /** - * 删除直播间 - */ + + /** 删除直播间 */ String DELETE_ROOM = "https://api.weixin.qq.com/wxaapi/broadcast/room/deleteroom"; - /** - * 编辑直播间 - */ + + /** 编辑直播间 */ String EDIT_ROOM = "https://api.weixin.qq.com/wxaapi/broadcast/room/editroom"; - /** - * 获取直播间推流地址 - */ + + /** 获取直播间推流地址 */ String GET_PUSH_URL = "https://api.weixin.qq.com/wxaapi/broadcast/room/getpushurl"; - /** - * 获取直播间分享二维码 - */ + + /** 获取直播间分享二维码 */ String GET_SHARED_CODE = "https://api.weixin.qq.com/wxaapi/broadcast/room/getsharedcode"; - /** - * 添加管理直播间小助手 - */ + + /** 添加管理直播间小助手 */ String ADD_ASSISTANT = "https://api.weixin.qq.com/wxaapi/broadcast/room/addassistant"; - /** - * 修改管理直播间小助手 - */ + + /** 修改管理直播间小助手 */ String MODIFY_ASSISTANT = "https://api.weixin.qq.com/wxaapi/broadcast/room/modifyassistant"; - /** - * 删除管理直播间小助手 - */ + + /** 删除管理直播间小助手 */ String REMOVE_ASSISTANT = "https://api.weixin.qq.com/wxaapi/broadcast/room/removeassistant"; - /** - * 查询管理直播间小助手 - */ - String GET_ASSISTANT_LIST = "https://api.weixin.qq.com/wxaapi/broadcast/room/getassistantlist"; - /** - * 添加主播副号 - */ + + /** 查询管理直播间小助手 */ + String GET_ASSISTANT_LIST = + "https://api.weixin.qq.com/wxaapi/broadcast/room/getassistantlist"; + + /** 添加主播副号 */ String ADD_SUBANCHOR = "https://api.weixin.qq.com/wxaapi/broadcast/room/addsubanchor"; - /** - * 修改主播副号 - */ + + /** 修改主播副号 */ String MODIFY_SUBANCHOR = "https://api.weixin.qq.com/wxaapi/broadcast/room/modifysubanchor"; - /** - * 删除主播副号 - */ + + /** 删除主播副号 */ String DELETE_SUBANCHOR = "https://api.weixin.qq.com/wxaapi/broadcast/room/deletesubanchor"; - /** - * 获取主播副号 - */ + + /** 获取主播副号 */ String GET_SUBANCHOR = "https://api.weixin.qq.com/wxaapi/broadcast/room/getsubanchor"; - /** - * 开启/关闭直播间官方收录 - */ - String UPDATE_FEED_PUBLIC = "https://api.weixin.qq.com/wxaapi/broadcast/room/updatefeedpublic"; - /** - * 开启/关闭回放功能 - */ + + /** 开启/关闭直播间官方收录 */ + String UPDATE_FEED_PUBLIC = + "https://api.weixin.qq.com/wxaapi/broadcast/room/updatefeedpublic"; + + /** 开启/关闭回放功能 */ String UPDATE_REPLAY = "https://api.weixin.qq.com/wxaapi/broadcast/room/updatereplay"; - /** - * 开启/关闭客服功能 - */ + + /** 开启/关闭客服功能 */ String UPDATE_KF = "https://api.weixin.qq.com/wxaapi/broadcast/room/updatekf"; - /** - * 开启/关闭直播间全局禁言 - */ + + /** 开启/关闭直播间全局禁言 */ String UPDATE_COMMENT = "https://api.weixin.qq.com/wxaapi/broadcast/room/updatecomment"; - /** - * 上下架商品 - */ + + /** 上下架商品 */ String ONSALE = "https://api.weixin.qq.com/wxaapi/broadcast/goods/onsale"; - /** - * 删除商品 - */ + + /** 删除商品 */ String DELETE_IN_ROOM = "https://api.weixin.qq.com/wxaapi/broadcast/goods/deleteInRoom"; - /** - * 推送商品 - */ + + /** 推送商品 */ String PUSH = "https://api.weixin.qq.com/wxaapi/broadcast/goods/push"; - /** - * 商品排序 - */ + + /** 商品排序 */ String SORT = "https://api.weixin.qq.com/wxaapi/broadcast/goods/sort"; - /** - * 下载商品讲解视频 - */ + + /** 下载商品讲解视频 */ String GET_VIDEO = "https://api.weixin.qq.com/wxaapi/broadcast/goods/getVideo"; } - /** - * 直播商品管理相关接口 - */ + /** 直播商品管理相关接口 */ interface Goods { String ADD_GOODS = "https://api.weixin.qq.com/wxaapi/broadcast/goods/add"; String RESET_AUDIT_GOODS = "https://api.weixin.qq.com/wxaapi/broadcast/goods/resetaudit"; @@ -298,19 +258,15 @@ public class WxMaApiUrlConstants { String UPDATE_GOODS = "https://api.weixin.qq.com/wxaapi/broadcast/goods/update"; String GET_GOODS_WARE_HOUSE = "https://api.weixin.qq.com/wxa/business/getgoodswarehouse"; String GET_APPROVED_GOODS = "https://api.weixin.qq.com/wxaapi/broadcast/goods/getapproved"; - /** - * 直播挂件设置全局 Key - */ + + /** 直播挂件设置全局 Key */ String SET_KEY = "https://api.weixin.qq.com/wxaapi/broadcast/goods/setkey"; - /** - * 直播挂件获取全局 Key - */ + + /** 直播挂件获取全局 Key */ String GET_KEY = "https://api.weixin.qq.com/wxaapi/broadcast/goods/getkey"; } - /** - * 小程序直播成员管理接口 - */ + /** 小程序直播成员管理接口 */ interface Role { String ADD_ROLE = "https://api.weixin.qq.com/wxaapi/broadcast/role/addrole"; String DELETE_ROLE = "https://api.weixin.qq.com/wxaapi/broadcast/role/deleterole"; @@ -333,9 +289,7 @@ public class WxMaApiUrlConstants { String GET_WXACODE_UNLIMIT_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit"; } - public interface Run { - - } + public interface Run {} public interface Scheme { String GENERATE_SCHEME_URL = "https://api.weixin.qq.com/wxa/generatescheme"; @@ -351,17 +305,13 @@ public class WxMaApiUrlConstants { String GENERATE_SHORT_LINK_URL = "https://api.weixin.qq.com/wxa/genwxashortlink"; } - /** - * 小程序安全 - */ + /** 小程序安全 */ public interface SecCheck { String IMG_SEC_CHECK_URL = "https://api.weixin.qq.com/wxa/img_sec_check"; String MSG_SEC_CHECK_URL = "https://api.weixin.qq.com/wxa/msg_sec_check"; String MEDIA_CHECK_ASYNC_URL = "https://api.weixin.qq.com/wxa/media_check_async"; - /** - * 获取用户安全等级 - */ + /** 获取用户安全等级 */ String GET_USER_RISK_RANK = "https://api.weixin.qq.com/wxa/getuserriskrank"; } @@ -371,52 +321,48 @@ public class WxMaApiUrlConstants { * access_token 为 authorizer_access_token */ String MODIFY_DOMAIN_URL = "https://api.weixin.qq.com/wxa/modify_domain"; + String SET_WEB_VIEW_DOMAIN_URL = "https://api.weixin.qq.com/wxa/setwebviewdomain"; + /** * 小程序成员管理:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1489140588_nVUgx&token=&lang=zh_CN * access_token 为 authorizer_access_token */ String BIND_TESTER_URL = "https://api.weixin.qq.com/wxa/bind_tester"; + String UNBIND_TESTER_URL = "https://api.weixin.qq.com/wxa/unbind_tester"; } - public interface Share { - - } + public interface Share {} public interface Subscribe { - /** - * 获取模板标题下的关键词列表. - */ - String GET_PUB_TEMPLATE_TITLE_LIST_URL = "https://api.weixin.qq.com/wxaapi/newtmpl/getpubtemplatetitles"; - /** - * 获取模板标题下的关键词列表. - */ - String GET_PUB_TEMPLATE_KEY_WORDS_BY_ID_URL = "https://api.weixin.qq.com/wxaapi/newtmpl/getpubtemplatekeywords"; - /** - * 组合模板并添加至帐号下的个人模板库. - */ + /** 获取模板标题下的关键词列表. */ + String GET_PUB_TEMPLATE_TITLE_LIST_URL = + "https://api.weixin.qq.com/wxaapi/newtmpl/getpubtemplatetitles"; + + /** 获取模板标题下的关键词列表. */ + String GET_PUB_TEMPLATE_KEY_WORDS_BY_ID_URL = + "https://api.weixin.qq.com/wxaapi/newtmpl/getpubtemplatekeywords"; + + /** 组合模板并添加至帐号下的个人模板库. */ String TEMPLATE_ADD_URL = "https://api.weixin.qq.com/wxaapi/newtmpl/addtemplate"; - /** - * 获取当前帐号下的个人模板列表. - */ + + /** 获取当前帐号下的个人模板列表. */ String TEMPLATE_LIST_URL = "https://api.weixin.qq.com/wxaapi/newtmpl/gettemplate"; - /** - * 删除帐号下的某个模板. - */ + + /** 删除帐号下的某个模板. */ String TEMPLATE_DEL_URL = "https://api.weixin.qq.com/wxaapi/newtmpl/deltemplate"; - /** - * 获取小程序账号的类目 - */ + + /** 获取小程序账号的类目 */ String GET_CATEGORY_URL = "https://api.weixin.qq.com/wxaapi/newtmpl/getcategory"; - /** - * 发送订阅消息 - */ + + /** 发送订阅消息 */ String SUBSCRIBE_MSG_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send"; } public interface User { - String SET_USER_STORAGE = "https://api.weixin.qq.com/wxa/set_user_storage?appid=%s&signature=%s&openid=%s&sig_method=%s"; + String SET_USER_STORAGE = + "https://api.weixin.qq.com/wxa/set_user_storage?appid=%s&signature=%s&openid=%s&sig_method=%s"; String GET_PHONE_NUMBER_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber"; } @@ -459,12 +405,14 @@ public class WxMaApiUrlConstants { interface Order { String PRODUCT_ORDER_GET_LIST = "https://api.weixin.qq.com/product/order/get_list"; String PRODUCT_ORDER_DETAIL_URL = "https://api.weixin.qq.com/product/order/get"; - String PRODUCT_ORDER_CHANGE_MERCHANT_NOTES_URL = "https://api.weixin.qq.com/product/order/change_merchant_notes"; + String PRODUCT_ORDER_CHANGE_MERCHANT_NOTES_URL = + "https://api.weixin.qq.com/product/order/change_merchant_notes"; String PRODUCT_DELIVERY_SEND = "https://api.weixin.qq.com/product/delivery/send"; String GET_AFTER_SALE_ORDER = "https://api.weixin.qq.com/product/order/getaftersaleorder"; - String BATCH_GET_AFTER_SALE_ORDER = "https://api.weixin.qq.com/product/order/batchgetaftersaleorder"; + String BATCH_GET_AFTER_SALE_ORDER = + "https://api.weixin.qq.com/product/order/batchgetaftersaleorder"; String AFTER_SALE_ACCEPT_APPLY = "https://api.weixin.qq.com/product/order/acceptapply"; String AFTER_SALE_REJECT_APPLY = "https://api.weixin.qq.com/product/order/rejectrefund"; } @@ -472,7 +420,8 @@ public class WxMaApiUrlConstants { interface OTHER { String GET_CATEGORY = "https://api.weixin.qq.com/product/category/get"; String GET_BRAND = "https://api.weixin.qq.com/product/brand/get"; - String GET_FREIGHT_TEMPLATE = "https://api.weixin.qq.com/product/delivery/get_freight_template"; + String GET_FREIGHT_TEMPLATE = + "https://api.weixin.qq.com/product/delivery/get_freight_template"; String IMG_UPLOAD = "https://api.weixin.qq.com/product/img/upload"; } } @@ -502,7 +451,8 @@ public class WxMaApiUrlConstants { interface Register { String REGISTER_APPLY = "https://api.weixin.qq.com/shop/register/apply"; String REGISTER_CHECK = "https://api.weixin.qq.com/shop/register/check"; - String REGISTER_FINISH_ACCESS_INFO = "https://api.weixin.qq.com/shop/register/finish_access_info"; + String REGISTER_FINISH_ACCESS_INFO = + "https://api.weixin.qq.com/shop/register/finish_access_info"; String REGISTER_APPLY_SCENE = "https://api.weixin.qq.com/shop/register/apply_scene"; } @@ -525,7 +475,8 @@ public class WxMaApiUrlConstants { String AUDIT_BRAND = "https://api.weixin.qq.com/shop/audit/audit_brand"; String AUDIT_CATEGORY = "https://api.weixin.qq.com/shop/audit/audit_category"; String AUDIT_RESULT = "https://api.weixin.qq.com/shop/audit/result"; - String GET_MINIAPP_CERTIFICATE = "https://api.weixin.qq.com/shop/audit/get_miniapp_certificate"; + String GET_MINIAPP_CERTIFICATE = + "https://api.weixin.qq.com/shop/audit/get_miniapp_certificate"; } interface Delivery { @@ -539,11 +490,13 @@ public class WxMaApiUrlConstants { String AFTERSALE_CANCEL = "https://api.weixin.qq.com/shop/ecaftersale/cancel"; String AFTERSALE_UPDATE = "https://api.weixin.qq.com/shop/aftersale/update"; String EC_AFTERSALE_UPDATE = "https://api.weixin.qq.com/shop/ecaftersale/update"; - String AFTERSALE_UPLOAD_RETURN_INFO = "https://api.weixin.qq.com/shop/ecaftersale/uploadreturninfo"; + String AFTERSALE_UPLOAD_RETURN_INFO = + "https://api.weixin.qq.com/shop/ecaftersale/uploadreturninfo"; String AFTERSALE_ACCEPT_REFUND = "https://api.weixin.qq.com/shop/ecaftersale/acceptrefund"; String AFTERSALE_ACCEPT_RETURN = "https://api.weixin.qq.com/shop/ecaftersale/acceptreturn"; String AFTERSALE_REJECT = "https://api.weixin.qq.com/shop/ecaftersale/reject"; - String AFTERSALE_UPLOAD_CERTIFICATES = "https://api.weixin.qq.com/shop/ecaftersale/upload_certificates"; + String AFTERSALE_UPLOAD_CERTIFICATES = + "https://api.weixin.qq.com/shop/ecaftersale/upload_certificates"; String AFTERSALE_UPLOAD_DEADLINE = "https://api.weixin.qq.com/shop/aftersale/update_deadline"; String AFTERSALE_GET_LIST = "https://api.weixin.qq.com/shop/ecaftersale/get_list"; String AFTERSALE_GET = "https://api.weixin.qq.com/shop/aftersale/get"; @@ -552,10 +505,13 @@ public class WxMaApiUrlConstants { interface Sharer { String BIND = "https://api.weixin.qq.com/shop/sharer/bind"; - String GET_SHARER_DATA_SUMMARY = "https://api.weixin.qq.com/shop/sharer/get_sharer_data_summary"; + String GET_SHARER_DATA_SUMMARY = + "https://api.weixin.qq.com/shop/sharer/get_sharer_data_summary"; String GET_SHARER_LIST = "https://api.weixin.qq.com/shop/sharer/get_sharer_list"; - String GET_SHARER_LIVE_ORDER_LIST = "https://api.weixin.qq.com/shop/sharer/get_sharer_live_order_list"; - String GET_SHARER_LIVE_SUMMARY_LIST = "https://api.weixin.qq.com/shop/sharer/get_sharer_live_summary_list"; + String GET_SHARER_LIVE_ORDER_LIST = + "https://api.weixin.qq.com/shop/sharer/get_sharer_live_order_list"; + String GET_SHARER_LIVE_SUMMARY_LIST = + "https://api.weixin.qq.com/shop/sharer/get_sharer_live_summary_list"; String SEARCH_SHARER = "https://api.weixin.qq.com/shop/sharer/search_sharer"; String UNBIND = "https://api.weixin.qq.com/shop/sharer/unbind"; } @@ -570,7 +526,8 @@ public class WxMaApiUrlConstants { String ADD_USER_COUPON = "https://api.weixin.qq.com/shop/coupon/add_user_coupon"; String GET_USER_COUPON_LIST = "https://api.weixin.qq.com/shop/coupon/get_usercoupon_list"; String UPDATE_USER_COUPON = "https://api.weixin.qq.com/shop/coupon/update_user_coupon"; - String UPDATE_USER_COUPON_STATUS = "https://api.weixin.qq.com/shop/coupon/update_usercoupon_status"; + String UPDATE_USER_COUPON_STATUS = + "https://api.weixin.qq.com/shop/coupon/update_usercoupon_status"; } interface Pay { @@ -580,52 +537,41 @@ public class WxMaApiUrlConstants { } } - /** - * 电子发票报销方 - */ + /** 电子发票报销方 */ public interface Invoice { - /** - * 报销方查询报销发票信息 - */ + /** 报销方查询报销发票信息 */ String GET_INVOICE_INFO = "https://api.weixin.qq.com/card/invoice/reimburse/getinvoiceinfo"; - /** - * 报销方批量查询报销发票信息 - */ + /** 报销方批量查询报销发票信息 */ String GET_INVOICE_BATCH = "https://api.weixin.qq.com/card/invoice/reimburse/getinvoicebatch"; - /** - * 报销方更新发票状态 - */ - String UPDATE_INVOICE_STATUS = "https://api.weixin.qq.com/card/invoice/reimburse/updateinvoicestatus"; + /** 报销方更新发票状态 */ + String UPDATE_INVOICE_STATUS = + "https://api.weixin.qq.com/card/invoice/reimburse/updateinvoicestatus"; - /** - * 报销方批量更新发票状态 - */ - String UPDATE_STATUS_BATCH = "https://api.weixin.qq.com/card/invoice/reimburse/updatestatusbatch"; + /** 报销方批量更新发票状态 */ + String UPDATE_STATUS_BATCH = + "https://api.weixin.qq.com/card/invoice/reimburse/updatestatusbatch"; } public interface Internet { String GET_USER_ENCRYPT_KEY = "https://api.weixin.qq.com/wxa/business/getuserencryptkey"; } - /** - * 设备订阅消息 - */ + /** 设备订阅消息 */ public interface DeviceSubscribe { - /** - * 获取设备票据 - */ + /** 获取设备票据 */ String GET_SN_TICKET_URL = "https://api.weixin.qq.com/wxa/getsnticket"; - /** - * 发送设备订阅消息 - */ - String SEND_DEVICE_SUBSCRIBE_MSG_URL = "https://api.weixin.qq.com/cgi-bin/message/device/subscribe/send"; + + /** 发送设备订阅消息 */ + String SEND_DEVICE_SUBSCRIBE_MSG_URL = + "https://api.weixin.qq.com/cgi-bin/message/device/subscribe/send"; } /** * 即时配送相关接口. + * *
    * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/immediate-delivery/overview.html
    * 
@@ -634,6 +580,7 @@ public class WxMaApiUrlConstants { /** * 拉取已绑定账号. + * *
      * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/immediate-delivery/by-business/immediateDelivery.getBindAccount.html
      * 
@@ -642,6 +589,7 @@ public class WxMaApiUrlConstants { /** * 拉取配送单信息. + * *
      * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/immediate-delivery/by-business/immediateDelivery.getOrder.html
      * 
@@ -650,73 +598,64 @@ public class WxMaApiUrlConstants { /** * 模拟配送公司更新配送单状态. + * *
      * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/immediate-delivery/by-business/immediateDelivery.mockUpdateOrder.html
      * 
*/ - String MOCK_UPDATE_ORDER = "https://api.weixin.qq.com/cgi-bin/express/local/business/test_update_order"; + String MOCK_UPDATE_ORDER = + "https://api.weixin.qq.com/cgi-bin/express/local/business/test_update_order"; - /** - * 物流服务-查询组件-跟踪物流面单 - * 商户使用此接口向微信提供某交易单号对应的运单号。微信后台会跟踪运单的状态变化 - */ - String TRACE_WAYBILL_URL = "https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/trace_waybill"; + /** 物流服务-查询组件-跟踪物流面单 商户使用此接口向微信提供某交易单号对应的运单号。微信后台会跟踪运单的状态变化 */ + String TRACE_WAYBILL_URL = + "https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/trace_waybill"; + /** 物流服务-查询组件-查询运单接口 query_trace 商户在调用完trace_waybill接口后,可以使用本接口查询到对应运单的详情信息 */ + String QUERY_WAYBILL_TRACE_URL = + "https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/query_trace"; - /** - * 物流服务-查询组件-查询运单接口 query_trace - * 商户在调用完trace_waybill接口后,可以使用本接口查询到对应运单的详情信息 - */ - String QUERY_WAYBILL_TRACE_URL = "https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/query_trace"; + /** 物流服务-消息组件-传运单接口(订阅消息) follow_waybill 商户在调用完trace_waybill接口后,可以使用本接口查询到对应运单的详情信息 */ + String FOLLOW_WAYBILL_URL = + "https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/follow_waybill"; - /** - * 物流服务-消息组件-传运单接口(订阅消息) follow_waybill - * 商户在调用完trace_waybill接口后,可以使用本接口查询到对应运单的详情信息 - */ - String FOLLOW_WAYBILL_URL = "https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/follow_waybill"; + /** 物流服务-消息组件-查运单接口(订阅消息) query_follow_trace 商户在调用完trace_waybill接口后,可以使用本接口查询到对应运单的详情信息 */ + String QUERY_FOLLOW_TRACE_URL = + "https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/query_follow_trace"; - /** - * 物流服务-消息组件-查运单接口(订阅消息) query_follow_trace - * 商户在调用完trace_waybill接口后,可以使用本接口查询到对应运单的详情信息 - */ - String QUERY_FOLLOW_TRACE_URL = "https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/query_follow_trace"; + /** 获取运力id列表get_delivery_list 商户使用此接口获取所有运力id的列表 */ + String GET_DELIVERY_LIST_URL = + "https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/get_delivery_list"; - /** - * 获取运力id列表get_delivery_list - * 商户使用此接口获取所有运力id的列表 - */ - String GET_DELIVERY_LIST_URL = "https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/get_delivery_list"; + /** 获取运力id列表get_delivery_list 商户使用此接口获取所有运力id的列表 */ + String UPDATE_WAYBILL_GOODS_URL = + "https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/update_waybill_goods"; - /** - * 获取运力id列表get_delivery_list - * 商户使用此接口获取所有运力id的列表 - */ - String UPDATE_WAYBILL_GOODS_URL = "https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/update_waybill_goods"; - - - /** - * 下单接口. - */ + /** 下单接口. */ interface PlaceAnOrder { /** * 获取已支持的配送公司列表接口. + * *
        * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/immediate-delivery/by-business/immediateDelivery.getAllImmeDelivery.html
        * 
*/ - String GET_ALL_IMME_DELIVERY = "https://api.weixin.qq.com/cgi-bin/express/local/business/delivery/getall"; + String GET_ALL_IMME_DELIVERY = + "https://api.weixin.qq.com/cgi-bin/express/local/business/delivery/getall"; /** * 预下配送单接口. + * *
        * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/immediate-delivery/by-business/immediateDelivery.preAddOrder.html
        * 
*/ - String PRE_ADD_ORDER = "https://api.weixin.qq.com/cgi-bin/express/local/business/order/pre_add"; + String PRE_ADD_ORDER = + "https://api.weixin.qq.com/cgi-bin/express/local/business/order/pre_add"; /** * 下配送单接口. + * *
        * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/immediate-delivery/by-business/immediateDelivery.addOrder.html
        * 
@@ -725,6 +664,7 @@ public class WxMaApiUrlConstants { /** * 重新下单. + * *
        * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/immediate-delivery/by-business/immediateDelivery.reOrder.html
        * 
@@ -733,30 +673,31 @@ public class WxMaApiUrlConstants { /** * 增加小费. + * *
        * 可以对待接单状态的订单增加小费。需要注意:订单的小费,以最新一次加小费动作的金额为准,故下一次增加小费额必须大于上一次小费额.
        * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/immediate-delivery/by-business/immediateDelivery.addTip.html
        * 
*/ String ADD_TIP = "https://api.weixin.qq.com/cgi-bin/express/local/business/order/addtips"; - } - /** - * 取消接口. - */ + /** 取消接口. */ interface Cancel { /** * 预取消配送单接口. + * *
        * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/immediate-delivery/by-business/immediateDelivery.preCancelOrder.html
        * 
*/ - String PRE_CANCEL_ORDER = "https://api.weixin.qq.com/cgi-bin/express/local/business/order/precancel"; + String PRE_CANCEL_ORDER = + "https://api.weixin.qq.com/cgi-bin/express/local/business/order/precancel"; /** * 取消配送单接口. + * *
        * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/immediate-delivery/by-business/immediateDelivery.cancelOrder.html
        * 
@@ -765,18 +706,19 @@ public class WxMaApiUrlConstants { /** * 异常件退回商家商家确认收货接口. + * *
        * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/immediate-delivery/by-business/immediateDelivery.abnormalConfirm.html
        * 
*/ - String ABNORMAL_CONFIRM = "https://api.weixin.qq.com/cgi-bin/express/local/business/order/confirm_return"; - + String ABNORMAL_CONFIRM = + "https://api.weixin.qq.com/cgi-bin/express/local/business/order/confirm_return"; } - } /** * 发货信息管理服务相关接口 + * *
    * 文档地址: https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html#%E4%B8%80%E3%80%81%E5%8F%91%E8%B4%A7%E4%BF%A1%E6%81%AF%E5%BD%95%E5%85%A5%E6%8E%A5%E5%8F%A3
    * 
@@ -785,6 +727,7 @@ public class WxMaApiUrlConstants { /** * 查询小程序是否已开通发货信息管理服务. + * *
      * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html#%E4%B8%83%E3%80%81%E6%9F%A5%E8%AF%A2%E5%B0%8F%E7%A8%8B%E5%BA%8F%E6%98%AF%E5%90%A6%E5%B7%B2%E5%BC%80%E9%80%9A%E5%8F%91%E8%B4%A7%E4%BF%A1%E6%81%AF%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1
      * 
@@ -793,6 +736,7 @@ public class WxMaApiUrlConstants { /** * 发货信息录入接口. + * *
      * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html#%E4%B8%80%E3%80%81%E5%8F%91%E8%B4%A7%E4%BF%A1%E6%81%AF%E5%BD%95%E5%85%A5%E6%8E%A5%E5%8F%A3
      * 
@@ -801,14 +745,17 @@ public class WxMaApiUrlConstants { /** * 发货信息合单录入接口. + * *
      * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html#%E4%BA%8C%E3%80%81%E5%8F%91%E8%B4%A7%E4%BF%A1%E6%81%AF%E5%90%88%E5%8D%95%E5%BD%95%E5%85%A5%E6%8E%A5%E5%8F%A3
      * 
*/ - String UPLOAD_COMBINED_SHIPPING_INFO = "https://api.weixin.qq.com/wxa/sec/order/upload_combined_shipping_info"; + String UPLOAD_COMBINED_SHIPPING_INFO = + "https://api.weixin.qq.com/wxa/sec/order/upload_combined_shipping_info"; /** * 查询订单发货状态. + * *
      * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html#%E4%BA%8C%E3%80%81%E5%8F%91%E8%B4%A7%E4%BF%A1%E6%81%AF%E5%90%88%E5%8D%95%E5%BD%95%E5%85%A5%E6%8E%A5%E5%8F%A3
      * 
@@ -817,6 +764,7 @@ public class WxMaApiUrlConstants { /** * 查询订单发货状态列表. + * *
      * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html#%E5%9B%9B%E3%80%81%E6%9F%A5%E8%AF%A2%E8%AE%A2%E5%8D%95%E5%88%97%E8%A1%A8
      * 
@@ -825,20 +773,22 @@ public class WxMaApiUrlConstants { /** * 确认收货提醒接口. + * *
      * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html#%E4%BA%94%E3%80%81%E7%A1%AE%E8%AE%A4%E6%94%B6%E8%B4%A7%E6%8F%90%E9%86%92%E6%8E%A5%E5%8F%A3
      * 
*/ - String NOTIFY_CONFIRM_RECEIVE = "https://api.weixin.qq.com/wxa/sec/order/notify_confirm_receive"; + String NOTIFY_CONFIRM_RECEIVE = + "https://api.weixin.qq.com/wxa/sec/order/notify_confirm_receive"; /** * 消息跳转路径设置接口. + * *
      * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html#%E5%85%AD%E3%80%81%E6%B6%88%E6%81%AF%E8%B7%B3%E8%BD%AC%E8%B7%AF%E5%BE%84%E8%AE%BE%E7%BD%AE%E6%8E%A5%E5%8F%A3
      * 
*/ String SET_MSG_JUMP_PATH = "https://api.weixin.qq.com/wxa/sec/order/set_msg_jump_path"; - } public interface Vod { @@ -857,46 +807,58 @@ public class WxMaApiUrlConstants { String COMMIT_UPLOAD_URL = "https://api.weixin.qq.com/wxa/sec/vod/commitupload"; String GET_CDN_USAGE_DATA_URL = "https://api.weixin.qq.com/wxa/sec/vod/getcdnusagedata"; String GET_CDN_LOGS_URL = "https://api.weixin.qq.com/wxa/sec/vod/getcdnlogs"; - } /** * 小程序虚拟支付服务相关接口 + * *
    * 文档地址: https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/virtual-payment.html#_2-3-%E6%9C%8D%E5%8A%A1%E5%99%A8API
    * 
*/ public interface XPay { - String QUERY_USER_BALANCE_URL = "https://api.weixin.qq.com/xpay/query_user_balance?pay_sig=%s&signature=%s"; + String QUERY_USER_BALANCE_URL = + "https://api.weixin.qq.com/xpay/query_user_balance?pay_sig=%s&signature=%s"; String CURRENCY_PAY_URL = "https://api.weixin.qq.com/xpay/currency_pay?pay_sig=%s&signature=%s"; String QUERY_ORDER_URL = "https://api.weixin.qq.com/xpay/query_order?pay_sig=%s"; - String CANCEL_CURRENCY_PAY_URL = "https://api.weixin.qq.com/xpay/cancel_currency_pay?pay_sig=%s&signature=%s"; - String NOTIFY_PROVIDE_GOODS_URL = "https://api.weixin.qq.com/xpay/notify_provide_goods?pay_sig=%s"; + String CANCEL_CURRENCY_PAY_URL = + "https://api.weixin.qq.com/xpay/cancel_currency_pay?pay_sig=%s&signature=%s"; + String NOTIFY_PROVIDE_GOODS_URL = + "https://api.weixin.qq.com/xpay/notify_provide_goods?pay_sig=%s"; String PRESENT_CURRENCY_URL = "https://api.weixin.qq.com/xpay/present_currency?pay_sig=%s"; String DOWNLOAD_BILL_URL = "https://api.weixin.qq.com/xpay/download_bill?pay_sig=%s"; String REFUND_ORDER_URL = "https://api.weixin.qq.com/xpay/refund_order?pay_sig=%s"; - String CREATE_WITHDRAW_ORDER_URL = "https://api.weixin.qq.com/xpay/create_withdraw_order?pay_sig=%s"; - String QUERY_WITHDRAW_ORDER_URL = "https://api.weixin.qq.com/xpay/query_withdraw_order?pay_sig=%s"; + String CREATE_WITHDRAW_ORDER_URL = + "https://api.weixin.qq.com/xpay/create_withdraw_order?pay_sig=%s"; + String QUERY_WITHDRAW_ORDER_URL = + "https://api.weixin.qq.com/xpay/query_withdraw_order?pay_sig=%s"; String START_UPLOAD_GOODS_URL = "https://api.weixin.qq.com/xpay/start_upload_goods?pay_sig=%s"; String QUERY_UPLOAD_GOODS_URL = "https://api.weixin.qq.com/xpay/query_upload_goods?pay_sig=%s"; - String START_PUBLISH_GOODS_URL = "https://api.weixin.qq.com/xpay/start_publish_goods?pay_sig=%s"; - String QUERY_PUBLISH_GOODS_URL = "https://api.weixin.qq.com/xpay/query_publish_goods?pay_sig=%s"; - + String START_PUBLISH_GOODS_URL = + "https://api.weixin.qq.com/xpay/start_publish_goods?pay_sig=%s"; + String QUERY_PUBLISH_GOODS_URL = + "https://api.weixin.qq.com/xpay/query_publish_goods?pay_sig=%s"; } /** * 退货组件 + * *
    * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/express/business/express_sale_return.html
    * 
*/ public interface ExpressDeliveryReturn { - String ADD_DELIVERY_RETURN_URL = "https://api.weixin.qq.com/cgi-bin/express/delivery/return/add"; - String GET_DELIVERY_RETURN_URL = "https://api.weixin.qq.com/cgi-bin/express/delivery/return/get"; - String UNBIND_DELIVERY_RETURN_URL = "https://api.weixin.qq.com/cgi-bin/express/delivery/return/unbind"; + String ADD_DELIVERY_RETURN_URL = + "https://api.weixin.qq.com/cgi-bin/express/delivery/return/add"; + String GET_DELIVERY_RETURN_URL = + "https://api.weixin.qq.com/cgi-bin/express/delivery/return/get"; + String UNBIND_DELIVERY_RETURN_URL = + "https://api.weixin.qq.com/cgi-bin/express/delivery/return/unbind"; } /** + * + * *
 小程序推广员
    * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/promoter/instruction/instruction.html
    * 
@@ -908,7 +870,8 @@ public class WxMaApiUrlConstants { String PROMOTION_ADD_PROMOTER = "https://api.weixin.qq.com/promoter/addpromoter"; String PROMOTION_GET_PROMOTER = "https://api.weixin.qq.com/promoter/getpromoter"; String PROMOTION_UPDATE_PROMOTER = "https://api.weixin.qq.com/promoter/updatepromoter"; - String PROMOTION_GET_INVITATION_MATERIAL = "https://api.weixin.qq.com/promoter/getinvitationmaterial"; + String PROMOTION_GET_INVITATION_MATERIAL = + "https://api.weixin.qq.com/promoter/getinvitationmaterial"; String PROMOTION_SEND_MSG = "https://api.weixin.qq.com/promoter/sendmsg"; String PROMOTION_SINGLE_SEND_MSG = "https://api.weixin.qq.com/promoter/singlesendmsg"; String PROMOTION_GET_MSG = "https://api.weixin.qq.com/promoter/getmsg"; @@ -918,4 +881,24 @@ public class WxMaApiUrlConstants { String PROMOTION_GET_ORDER = "https://api.weixin.qq.com/promoter/getorder"; } + public interface Intracity { + String APPLY_URL = "https://api.weixin.qq.com/cgi-bin/express/intracity/apply"; + String CREATE_STORE_URL = "https://api.weixin.qq.com/cgi-bin/express/intracity/createstore"; + String QUERY_STORE_URL = "https://api.weixin.qq.com/cgi-bin/express/intracity/querystore"; + String UPDATE_STORE_URL = "https://api.weixin.qq.com/cgi-bin/express/intracity/updatestore"; + + String STORE_CHARGE = "https://api.weixin.qq.com/cgi-bin/express/intracity/storecharge"; + String STORE_REFUND = "https://api.weixin.qq.com/cgi-bin/express/intracity/storerefund"; + String QUERY_FLOW = "https://api.weixin.qq.com/cgi-bin/express/intracity/queryflow"; + String BALANCE_QUERY = "https://api.weixin.qq.com/cgi-bin/express/intracity/balancequery"; + String GET_PAY_MODE = "https://api.weixin.qq.com/cgi-bin/express/intracity/getpaymode"; + String SET_PAY_MODE = "https://api.weixin.qq.com/cgi-bin/express/intracity/setpaymode"; + + String PRE_ADD_ORDER = "https://api.weixin.qq.com/cgi-bin/express/intracity/preaddorder"; + String ADD_ORDER = "https://api.weixin.qq.com/cgi-bin/express/intracity/addorder"; + String QUERY_ORDER = "https://api.weixin.qq.com/cgi-bin/express/intracity/queryorder"; + String CANCEL_ORDER = "https://api.weixin.qq.com/cgi-bin/express/intracity/cancelorder"; + + String GET_CITY = "https://api.weixin.qq.com/cgi-bin/express/intracity/getcity"; + } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheApiSignaturePostRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheApiSignaturePostRequestExecutor.java new file mode 100644 index 000000000..3dcf22b10 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheApiSignaturePostRequestExecutor.java @@ -0,0 +1,71 @@ +package cn.binarywang.wx.miniapp.executor; + +import cn.binarywang.wx.miniapp.bean.WxMaApiResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import me.chanjar.weixin.common.enums.WxType; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import org.apache.http.Consts; +import org.apache.http.Header; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ApacheApiSignaturePostRequestExecutor + extends ApiSignaturePostRequestExecutor { + private static final Logger logger = + LoggerFactory.getLogger(ApacheApiSignaturePostRequestExecutor.class); + + public ApacheApiSignaturePostRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMaApiResponse execute( + String uri, Map headers, String postEntity, WxType wxType) + throws WxErrorException, IOException { + // logger.debug( + // "ApacheApiSignaturePostRequestExecutor.execute uri:{}, headers:{}, postData:{}", + // uri, + // headers, + // postEntity); + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = + RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + if (headers != null) { + headers.forEach(httpPost::addHeader); + } + + if (postEntity != null) { + StringEntity entity = new StringEntity(postEntity, Consts.UTF_8); + entity.setContentType("application/json; charset=utf-8"); + httpPost.setEntity(entity); + } + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + Map respHeaders = new HashMap<>(); + Header[] rHeaders = response.getAllHeaders(); + if (rHeaders != null) { + for (Header h : rHeaders) { + respHeaders.putIfAbsent(h.getName(), h.getValue()); + } + } + return this.handleResponse(wxType, responseContent, respHeaders); + } finally { + httpPost.releaseConnection(); + } + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApiSignaturePostRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApiSignaturePostRequestExecutor.java new file mode 100644 index 000000000..8e3ade961 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApiSignaturePostRequestExecutor.java @@ -0,0 +1,69 @@ +package cn.binarywang.wx.miniapp.executor; + +import cn.binarywang.wx.miniapp.bean.WxMaApiResponse; +import java.io.IOException; +import java.rmi.RemoteException; +import java.util.Map; +import me.chanjar.weixin.common.enums.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; +import org.jetbrains.annotations.NotNull; + +public abstract class ApiSignaturePostRequestExecutor + implements RequestExecutor { + + protected RequestHttp requestHttp; + + public ApiSignaturePostRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; + } + + @Override + public WxMaApiResponse execute(String uri, WxMaApiResponse data, WxType wxType) + throws WxErrorException, IOException { + throw new RemoteException("method not implemented yet."); + } + + @Override + public void execute( + String uri, WxMaApiResponse data, ResponseHandler handler, WxType wxType) + throws WxErrorException, IOException { + throw new RemoteException("method not implemented yet."); + } + + public abstract WxMaApiResponse execute( + String uri, Map headers, String data, WxType wxType) + throws WxErrorException, IOException; + + @NotNull + public WxMaApiResponse handleResponse( + WxType wxType, String responseContent, Map headers) throws WxErrorException { + if (responseContent.isEmpty()) { + throw new WxErrorException("无响应内容"); + } + WxError error = WxError.fromJson(responseContent, wxType); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + WxMaApiResponse response = new WxMaApiResponse(); + response.setContent(responseContent); + response.setHeaders(headers); + return response; + } + + public static ApiSignaturePostRequestExecutor create(RequestHttp requestHttp) { + switch (requestHttp.getRequestType()) { + case APACHE_HTTP: + return new ApacheApiSignaturePostRequestExecutor(requestHttp); + case JODD_HTTP: + return new JoddApiSignaturePostRequestExecutor(requestHttp); + case OK_HTTP: + return new OkHttpApiSignaturePostRequestExecutor(requestHttp); + default: + throw new IllegalArgumentException("非法请求参数"); + } + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddApiSignaturePostRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddApiSignaturePostRequestExecutor.java new file mode 100644 index 000000000..b7568bc21 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddApiSignaturePostRequestExecutor.java @@ -0,0 +1,59 @@ +package cn.binarywang.wx.miniapp.executor; + +import cn.binarywang.wx.miniapp.bean.WxMaApiResponse; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.enums.WxType; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JoddApiSignaturePostRequestExecutor + extends ApiSignaturePostRequestExecutor { + private static final Logger logger = + LoggerFactory.getLogger(JoddApiSignaturePostRequestExecutor.class); + + public JoddApiSignaturePostRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMaApiResponse execute( + String uri, Map headers, String postEntity, WxType wxType) + throws WxErrorException, IOException { + // logger.debug( + // "JoddApiSignaturePostRequestExecutor.execute uri:{}, headers:{}, postData:{}", + // uri, + // headers, + // postEntity); + HttpConnectionProvider provider = requestHttp.getRequestHttpClient(); + ProxyInfo proxyInfo = requestHttp.getRequestHttpProxy(); + + HttpRequest request = HttpRequest.post(uri); + if (proxyInfo != null) { + provider.useProxy(proxyInfo); + } + if (headers != null) { + headers.forEach(request::header); + } + request.withConnectionProvider(provider); + if (postEntity != null) { + request.contentType("application/json", "utf-8"); + request.bodyText(postEntity); + } + HttpResponse response = request.send(); + response.charset(StandardCharsets.UTF_8.name()); + Map respHeaders = new HashMap<>(); + for (String n : response.headerNames()) { + respHeaders.putIfAbsent(n, response.header(n)); + } + return this.handleResponse(wxType, response.bodyText(), respHeaders); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpApiSignaturePostRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpApiSignaturePostRequestExecutor.java new file mode 100644 index 000000000..10c75a26b --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpApiSignaturePostRequestExecutor.java @@ -0,0 +1,51 @@ +package cn.binarywang.wx.miniapp.executor; + +import cn.binarywang.wx.miniapp.bean.WxMaApiResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import me.chanjar.weixin.common.enums.WxType; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OkHttpApiSignaturePostRequestExecutor + extends ApiSignaturePostRequestExecutor { + private static final Logger logger = + LoggerFactory.getLogger(OkHttpApiSignaturePostRequestExecutor.class); + + public OkHttpApiSignaturePostRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMaApiResponse execute( + String uri, Map headers, String postEntity, WxType wxType) + throws WxErrorException, IOException { + // logger.debug( + // "OkHttpApiSignaturePostRequestExecutor.execute uri:{}, headers:{}, postData:{}", + // uri, + // headers, + // postEntity); + RequestBody body = + RequestBody.Companion.create( + postEntity, MediaType.parse("application/json; charset=utf-8")); + Request.Builder builder = new Request.Builder(); + if (headers != null) { + headers.forEach(builder::addHeader); + } + Request request = builder.url(uri).post(body).build(); + Response response = requestHttp.getRequestHttpClient().newCall(request).execute(); + Map respHeaders = new HashMap<>(); + Headers rHeaders = response.headers(); + for (String n : rHeaders.names()) { + respHeaders.put(n, rHeaders.get(n)); + } + return this.handleResponse( + wxType, Objects.requireNonNull(response.body()).string(), respHeaders); + } +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaIntracityServiceImpleTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaIntracityServiceImpleTest.java new file mode 100644 index 000000000..51ad846e9 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaIntracityServiceImpleTest.java @@ -0,0 +1,234 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import static org.testng.AssertJUnit.*; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.intractiy.*; +import cn.binarywang.wx.miniapp.bean.openapi.WxMiniGetApiQuotaResult; +import cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import cn.binarywang.wx.miniapp.test.TestConfig; +import com.google.inject.Inject; +import java.util.ArrayList; +import java.util.List; +import me.chanjar.weixin.common.error.WxErrorException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaIntracityServiceImpleTest { + private static final Logger logger = LoggerFactory.getLogger(WxMaIntracityServiceImpleTest.class); + + @Inject private WxMaService wxService; + + @Test + public void testApiSignature() throws Exception { + WxMiniGetApiQuotaResult result = + wxService + .getWxMaOpenApiService() + .getApiQuota( + WxMaApiUrlConstants.Intracity.APPLY_URL.substring( + "https://api.weixin.qq.com".length())); + logger.info("apply 额度剩余 :{}", result.getQuota()); + } + + @Test + public void testApply() throws Exception { + logger.debug("testApply"); + try { + wxService.getIntracityService().apply(); + } catch (WxErrorException wxEx) { + if (wxEx.getError().getErrorCode() == 45009) { + // 调用分钟频率受限 + } else { + throw wxEx; + } + } + } + + @Test + public void testStoreRelatedApis() throws Exception { + WxMaStore store = new WxMaStore(); + store.setStoreName("南京东路店"); + store.setOutStoreId("njdl-001"); + WxMaStore.AddressInfo addr = new WxMaStore.AddressInfo(); + addr.setProvince("上海市"); + addr.setCity("上海市"); + addr.setArea("黄浦区"); + addr.setStreet(""); + addr.setHouse("南京东路690号"); + addr.setLat(31.235318); + addr.setLng(121.477284); + addr.setPhone("021-23456789"); + store.setAddressInfo(addr); + String wxStoreId; + List result = + wxService.getIntracityService().queryStoreByOutStoreId(store.getOutStoreId()); + if (result.isEmpty()) { + wxStoreId = wxService.getIntracityService().createStore(store); + logger.debug("create store result:{}", wxStoreId); + } else { + wxStoreId = result.get(0).getWxStoreId(); + } + store.setWxStoreId(wxStoreId); + addr.setPhone("021-23450000"); + store.setStoreName(null); + wxService.getIntracityService().updateStore(store); + List stores = wxService.getIntracityService().listAllStores(); + logger.info("listAllStores 查询到 {} 个门店 {}", stores.size(), stores); + if (stores.size() > 0) { + WxMaStore s = + wxService.getIntracityService().queryStoreByWxStoreId(stores.get(0).getWxStoreId()); + assertNotNull(s); + List list = + wxService.getIntracityService().queryStoreByOutStoreId(stores.get(0).getOutStoreId()); + logger.info("queryStoreByOutStoreId 查询到 {} 个门店 {}", list.size(), list); + } + } + + @Test + public void testStoreChargeRelated() throws Exception { + List stores = wxService.getIntracityService().listAllStores(); + if (stores.isEmpty()) { + logger.warn("没有门店,无法测试"); + return; + } + WxMaStore store = stores.get(0); + + WxMaGetPayModeResponse resp = wxService.getIntracityService().getPayMode(); + logger.debug("查询付费主体 {}", resp); + PayMode currentPayMode = resp.getPayMode(); + // 只能用当前付费模式充值;否则微信接口会返回 错误代码:934025, 错误信息:pay_mode not match + WxMaStoreChargeRequest request = new WxMaStoreChargeRequest(); + request.setPayMode(currentPayMode); + request.setWxStoreId(store.getWxStoreId()); + request.setServiceTransId("DADA"); + request.setAmount(5000); + String payUrl = wxService.getIntracityService().storeCharge(request); + logger.debug("充值URL:{}", payUrl); + + // 查询余额 + WxMaStoreBalance balance = + wxService.getIntracityService().balanceQuery(store.getWxStoreId(), null, PayMode.STORE); + logger.debug("余额 {}", balance); + + // 退款 + WxMaStoreRefundRequest rr = new WxMaStoreRefundRequest(); + rr.setPayMode(PayMode.STORE); + rr.setWxStoreId(store.getWxStoreId()); + rr.setServiceTransId("DADA"); + int refundAmount = wxService.getIntracityService().storeRefund(rr); + logger.debug("退款:{}", refundAmount); + + // 查询流水 + WxMaQueryFlowRequest qfr = new WxMaQueryFlowRequest(); + qfr.setWxStoreId(store.getWxStoreId()); + WxMaStoreFlowResponse flowResponse = wxService.getIntracityService().queryFlow(qfr); + logger.debug("查询流水 {}", flowResponse); + } + + @Test + public void testPayMode() throws Exception { + WxMaGetPayModeResponse resp = wxService.getIntracityService().getPayMode(); + logger.debug("查询付费主体 {}", resp); + PayMode newMode = resp.getPayMode() == PayMode.APP ? PayMode.STORE : PayMode.APP; + logger.debug("set pay mode to {}", newMode); + wxService.getIntracityService().setPayMode(newMode); + WxMaGetPayModeResponse resp2 = wxService.getIntracityService().getPayMode(); + logger.debug("查询付费主体 {}", resp2); + } + + @Test + public void testGetCity() throws Exception { + List list = wxService.getIntracityService().getCity(null); + logger.debug("支持的城市 {}", list); + List list2 = wxService.getIntracityService().getCity("SFTC"); + logger.debug("SFTC支持的城市有{}个", list2.get(0).getCityList().size()); + } + + @Test + public void testOrderRelatived() throws Exception { + List stores = wxService.getIntracityService().listAllStores(); + if (stores.isEmpty()) { + logger.warn("没有门店,无法测试"); + return; + } + String wxStoreId = stores.get(0).getWxStoreId(); + { + WxMaPreAddOrderRequest request = new WxMaPreAddOrderRequest(); + request.setWxStoreId(wxStoreId); + request.setUseSandbox(1); + request.setUserName("顺丰同城"); + request.setUserPhone("13800000138"); + request.setUserAddress("北京市海淀区学清嘉创大厦A座15层"); + request.setUserLat(40.01496); + request.setUserLng(116.353093); + WxMaPreAddOrderRequest.Cargo cargo = new WxMaPreAddOrderRequest.Cargo(); + cargo.setCargoName("蛋糕"); + cargo.setCargoType(13); + cargo.setCargoNum(1); + cargo.setCargoPrice(10000); + cargo.setCargoWeight(1000); + request.setCargo(cargo); + WxMaAddOrderResponse response = wxService.getIntracityService().preAddOrder(request); + logger.debug("查询运费返回 {}, 预估运费{}元", response, response.getFee() / 100.0); + } + String wxOrderId = null; + { + TestConfig config = (TestConfig) this.wxService.getWxMaConfig(); + WxMaAddOrderRequest request = new WxMaAddOrderRequest(); + request.setWxStoreId(wxStoreId); + request.setStoreOrderId("store-order-" + System.currentTimeMillis()); + request.setOrderSeq("0001"); + request.setUserOpenid(config.getOpenid()); + request.setUseSandbox(1); + request.setUserName("顺丰同城"); + request.setUserPhone("13800000138"); + request.setUserAddress("北京市海淀区学清嘉创大厦A座15层"); + request.setUserLat(40.01496); + request.setUserLng(116.353093); + request.setOrderDetailPath("/pages/user-center/order/detail/detail?id=xxx"); + WxMaAddOrderRequest.Cargo cargo = new WxMaAddOrderRequest.Cargo(); + cargo.setCargoName("蛋糕"); + cargo.setCargoType(13); + cargo.setCargoNum(1); + cargo.setCargoPrice(10000); + cargo.setCargoWeight(1000); + WxMaAddOrderRequest.ItemDetail detail = new WxMaAddOrderRequest.ItemDetail(); + detail.setItemName("蛋糕A"); + detail.setItemPicUrl("https://www.somehost.com/aaa.jpg"); + detail.setCount(1); + List itemList = new ArrayList<>(); + itemList.add(detail); + cargo.setItemList(itemList); + request.setCargo(cargo); + WxMaAddOrderResponse response = wxService.getIntracityService().addOrder(request); + wxOrderId = response.getWxOrderId(); + logger.debug("创建订单返回 {}, wxOrderId:{}", response, wxOrderId); + } + WxMaOrder order = wxService.getIntracityService().queryOrderByWxOrderId(wxOrderId); + logger.debug("查询订单返回 {}, storeOrderId:{} ", order, order.getStoreOrderId()); + WxMaOrder order2 = + wxService + .getIntracityService() + .queryOrderByStoreOrderId(wxStoreId, order.getStoreOrderId()); + logger.debug("查询订单返回 {}, ", order); + assertEquals(order2.getWxOrderId(), wxOrderId); + + WxMaCancelOrderResponse cancelOrderResp = + wxService.getIntracityService().cancelOrderByWxOrderId(wxOrderId, 1, "不再需要"); + logger.debug("取消订单返回 {}, 扣费:{} ", cancelOrderResp, cancelOrderResp.getDeductfee()); + + try { + wxService + .getIntracityService() + .cancelOrderByStoreOrderId(wxStoreId, order.getStoreOrderId(), 1, "不再需要"); + fail("重复取消未抛异常,疑似第一次取消未成功"); + } catch (WxErrorException wxErrorException) { + // 订单已经被取消了,重复取消会报错,这里才正常 + } + } +} diff --git a/weixin-java-miniapp/src/test/resources/test-config-sample.xml b/weixin-java-miniapp/src/test/resources/test-config-sample.xml index 7812fc746..5a3272c0f 100644 --- a/weixin-java-miniapp/src/test/resources/test-config-sample.xml +++ b/weixin-java-miniapp/src/test/resources/test-config-sample.xml @@ -9,4 +9,9 @@ 可以不填写 某个用户的openId 模版消息的模版ID + API签名AES密钥【没有开启API签名不要这条】 + API签名AES密钥的序号【没有开启API签名不要这条】 + API签名RSA私钥的【没有开启API签名不要这条】 + API签名RSA私钥的序【没有开启API签名不要这条】 + diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenConfigStorage.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenConfigStorage.java index 60304604d..52f8f828c 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenConfigStorage.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenConfigStorage.java @@ -1,13 +1,12 @@ package me.chanjar.weixin.open.api; import cn.binarywang.wx.miniapp.config.WxMaConfig; +import java.util.concurrent.locks.Lock; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken; import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken; -import java.util.concurrent.locks.Lock; - /** * The interface Wx open config storage. * @@ -99,9 +98,7 @@ public interface WxOpenConfigStorage { */ boolean isComponentAccessTokenExpired(); - /** - * Expire component access token. - */ + /** Expire component access token. */ void expireComponentAccessToken(); /** @@ -141,6 +138,7 @@ public interface WxOpenConfigStorage { /** * http 请求重试间隔 + * *
    *   {@link me.chanjar.weixin.mp.api.impl.BaseWxMpServiceImpl#setRetrySleepMillis(int)}
    *   {@link cn.binarywang.wx.miniapp.api.impl.BaseWxMaServiceImpl#setRetrySleepMillis(int)}
@@ -150,6 +148,7 @@ public interface WxOpenConfigStorage {
 
   /**
    * http 请求最大重试次数
+   *
    * 
    *   {@link me.chanjar.weixin.mp.api.impl.BaseWxMpServiceImpl#setMaxRetryTimes(int)}
    *   {@link cn.binarywang.wx.miniapp.api.impl.BaseWxMaServiceImpl#setMaxRetryTimes(int)}
@@ -199,7 +198,7 @@ public interface WxOpenConfigStorage {
    * 应该是线程安全的
    *
    * @param componentAccessToken 新的accessToken值
-   * @param expiresInSeconds     过期时间,以秒为单位
+   * @param expiresInSeconds 过期时间,以秒为单位
    */
   void updateComponentAccessToken(String componentAccessToken, int expiresInSeconds);
 
@@ -221,7 +220,7 @@ public interface WxOpenConfigStorage {
   /**
    * Sets authorizer refresh token.
    *
-   * @param appId                  the app id
+   * @param appId the app id
    * @param authorizerRefreshToken the authorizer refresh token
    */
   void setAuthorizerRefreshToken(String appId, String authorizerRefreshToken);
@@ -229,7 +228,7 @@ public interface WxOpenConfigStorage {
   /**
    * setAuthorizerRefreshToken(String appId, String authorizerRefreshToken) 方法重载方法
    *
-   * @param appId                  the app id
+   * @param appId the app id
    * @param authorizerRefreshToken the authorizer refresh token
    */
   void updateAuthorizerRefreshToken(String appId, String authorizerRefreshToken);
@@ -260,7 +259,7 @@ public interface WxOpenConfigStorage {
   /**
    * 应该是线程安全的
    *
-   * @param appId                 the app id
+   * @param appId the app id
    * @param authorizerAccessToken 要更新的WxAccessToken对象
    */
   void updateAuthorizerAccessToken(String appId, WxOpenAuthorizerAccessToken authorizerAccessToken);
@@ -268,11 +267,12 @@ public interface WxOpenConfigStorage {
   /**
    * 应该是线程安全的
    *
-   * @param appId                 the app id
+   * @param appId the app id
    * @param authorizerAccessToken 新的accessToken值
-   * @param expiresInSeconds      过期时间,以秒为单位
+   * @param expiresInSeconds 过期时间,以秒为单位
    */
-  void updateAuthorizerAccessToken(String appId, String authorizerAccessToken, int expiresInSeconds);
+  void updateAuthorizerAccessToken(
+      String appId, String authorizerAccessToken, int expiresInSeconds);
 
   /**
    * Gets jsapi ticket.
@@ -300,8 +300,8 @@ public interface WxOpenConfigStorage {
   /**
    * 应该是线程安全的
    *
-   * @param appId            the app id
-   * @param jsapiTicket      新的jsapi ticket值
+   * @param appId the app id
+   * @param jsapiTicket 新的jsapi ticket值
    * @param expiresInSeconds 过期时间,以秒为单位
    */
   void updateJsapiTicket(String appId, String jsapiTicket, int expiresInSeconds);
@@ -314,7 +314,6 @@ public interface WxOpenConfigStorage {
    */
   String getCardApiTicket(String appId);
 
-
   /**
    * Is card api ticket expired boolean.
    *
@@ -333,8 +332,8 @@ public interface WxOpenConfigStorage {
   /**
    * 应该是线程安全的
    *
-   * @param appId            the app id
-   * @param cardApiTicket    新的cardApi ticket值
+   * @param appId the app id
+   * @param cardApiTicket 新的cardApi ticket值
    * @param expiresInSeconds 过期时间,以秒为单位
    */
   void updateCardApiTicket(String appId, String cardApiTicket, int expiresInSeconds);
@@ -342,10 +341,34 @@ public interface WxOpenConfigStorage {
   /**
    * 设置第三方平台基础信息
    *
-   * @param componentAppId     第三方平台 appid
+   * @param componentAppId 第三方平台 appid
    * @param componentAppSecret 第三方平台 appsecret
-   * @param componentToken     消息校验Token
-   * @param componentAesKey    消息加解密Key
+   * @param componentToken 消息校验Token
+   * @param componentAesKey 消息加解密Key
    */
-  void setWxOpenInfo(String componentAppId, String componentAppSecret, String componentToken, String componentAesKey);
+  void setWxOpenInfo(
+      String componentAppId,
+      String componentAppSecret,
+      String componentToken,
+      String componentAesKey);
+
+  /** 第三方平台设置API签名 RSA 私钥 */
+  String getComponentApiSignatureRsaPrivateKey();
+
+  void setComponentApiSignatureRsaPrivateKey(String apiSignatureRsaPrivateKey);
+
+  /** 第三方平台设置API签名 AES KEY */
+  String getComponentApiSignatureAesKey();
+
+  void setComponentApiSignatureAesKey(String apiSignatureAesKey);
+
+  /** 第三方平台设置API签名 RSA 私钥 序号 */
+  String getComponentApiSignatureRsaPrivateKeySn();
+
+  void setComponentApiSignatureRsaPrivateKeySn(String apiSignatureRsaPrivateKeySn);
+
+  /** 第三方平台设置API签名 AES key 序号 */
+  String getComponentApiSignatureAesKeySn();
+
+  void setComponentApiSignatureAesKeySn(String apiSignatureAesKeySn);
 }
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java
index 43a351100..a103315b5 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java
@@ -1,7 +1,11 @@
 package me.chanjar.weixin.open.api.impl;
 
-
 import cn.binarywang.wx.miniapp.config.WxMaConfig;
+import java.io.File;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 import lombok.AccessLevel;
 import lombok.Data;
 import lombok.Getter;
@@ -16,12 +20,6 @@ import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken;
 import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken;
 import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder;
 
-import java.io.File;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
 /**
  * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化
  *
@@ -37,26 +35,36 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage {
   private String componentAccessToken;
   private long componentExpiresTime;
 
+  private String componentApiSignatureRsaPrivateKey;
+  private String componentApiSignatureAesKey;
+  private String componentApiSignatureRsaPrivateKeySn;
+  private String componentApiSignatureAesKeySn;
+
   private String httpProxyHost;
   private int httpProxyPort;
   private String httpProxyUsername;
   private String httpProxyPassword;
+
   /**
    * http 请求重试间隔
+   *
    * 
    *   {@link me.chanjar.weixin.mp.api.impl.BaseWxMpServiceImpl#setRetrySleepMillis(int)}
    *   {@link cn.binarywang.wx.miniapp.api.impl.BaseWxMaServiceImpl#setRetrySleepMillis(int)}
    * 
*/ private int retrySleepMillis = 1000; + /** * http 请求最大重试次数 + * *
    *   {@link me.chanjar.weixin.mp.api.impl.BaseWxMpServiceImpl#setMaxRetryTimes(int)}
    *   {@link cn.binarywang.wx.miniapp.api.impl.BaseWxMaServiceImpl#setMaxRetryTimes(int)}
    * 
*/ private int maxRetryTimes = 5; + private ApacheHttpClientBuilder apacheHttpClientBuilder; private Map authorizerRefreshTokens = new ConcurrentHashMap<>(); @@ -77,7 +85,8 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { @Override public void updateComponentAccessToken(WxOpenComponentAccessToken componentAccessToken) { - updateComponentAccessToken(componentAccessToken.getComponentAccessToken(), componentAccessToken.getExpiresIn()); + updateComponentAccessToken( + componentAccessToken.getComponentAccessToken(), componentAccessToken.getExpiresIn()); } private Lock accessTokenLockInstance; @@ -126,8 +135,11 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { } @Override - public void setWxOpenInfo(String componentAppId, String componentAppSecret, String componentToken, - String componentAesKey) { + public void setWxOpenInfo( + String componentAppId, + String componentAppSecret, + String componentToken, + String componentAesKey) { setComponentAppId(componentAppId); setComponentAppSecret(componentAppSecret); setComponentToken(componentToken); @@ -141,7 +153,8 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { private String getTokenString(Map map, String key) { Token token = map.get(key); - if (token == null || (token.expiresTime != null && System.currentTimeMillis() > token.expiresTime)) { + if (token == null + || (token.expiresTime != null && System.currentTimeMillis() > token.expiresTime)) { return null; } return token.token; @@ -154,7 +167,8 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { } } - private void updateToken(Map map, String key, String tokenString, Integer expiresInSeconds) { + private void updateToken( + Map map, String key, String tokenString, Integer expiresInSeconds) { Token token = map.get(key); if (token == null) { token = new Token(); @@ -186,7 +200,6 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { return getTokenString(authorizerAccessTokens, appId); } - @Override public boolean isAuthorizerAccessTokenExpired(String appId) { return getTokenString(authorizerAccessTokens, appId) == null; @@ -198,13 +211,17 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { } @Override - public void updateAuthorizerAccessToken(String appId, WxOpenAuthorizerAccessToken authorizerAccessToken) { - updateAuthorizerAccessToken(appId, authorizerAccessToken.getAuthorizerAccessToken(), - authorizerAccessToken.getExpiresIn()); + public void updateAuthorizerAccessToken( + String appId, WxOpenAuthorizerAccessToken authorizerAccessToken) { + updateAuthorizerAccessToken( + appId, + authorizerAccessToken.getAuthorizerAccessToken(), + authorizerAccessToken.getExpiresIn()); } @Override - public void updateAuthorizerAccessToken(String appId, String authorizerAccessToken, int expiresInSeconds) { + public void updateAuthorizerAccessToken( + String appId, String authorizerAccessToken, int expiresInSeconds) { updateToken(authorizerAccessTokens, appId, authorizerAccessToken, expiresInSeconds); } @@ -261,21 +278,18 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { private WxMpHostConfig hostConfig; private String apiHostUrl; private String accessTokenUrl; - /** - * 是否使用稳定版获取accessToken接口 - */ + + /** 是否使用稳定版获取accessToken接口 */ @Getter(value = AccessLevel.NONE) @Setter(value = AccessLevel.NONE) private boolean useStableAccessToken; - /** - * 小程序原始ID - */ + /** 小程序原始ID */ private volatile String originalId; - /** - * 云环境ID - */ + + /** 云环境ID */ private volatile String cloudEnv; + private final Lock accessTokenLock; private final Lock jsapiTicketLock; private final Lock cardApiTicketLock; @@ -326,15 +340,18 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { @Override public String getTicket(TicketType type) { switch (type) { - case JSAPI: { - return wxOpenConfigStorage.getJsapiTicket(appId); - } - case WX_CARD: { - return wxOpenConfigStorage.getCardApiTicket(appId); - } - default: { - // do nothing - } + case JSAPI: + { + return wxOpenConfigStorage.getJsapiTicket(appId); + } + case WX_CARD: + { + return wxOpenConfigStorage.getCardApiTicket(appId); + } + default: + { + // do nothing + } } return null; } @@ -342,15 +359,18 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { @Override public Lock getTicketLock(TicketType type) { switch (type) { - case JSAPI: { - return this.jsapiTicketLock; - } - case WX_CARD: { - return this.cardApiTicketLock; - } - default: { - // do nothing - } + case JSAPI: + { + return this.jsapiTicketLock; + } + case WX_CARD: + { + return this.cardApiTicketLock; + } + default: + { + // do nothing + } } return null; } @@ -358,15 +378,18 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { @Override public boolean isTicketExpired(TicketType type) { switch (type) { - case JSAPI: { - return wxOpenConfigStorage.isJsapiTicketExpired(appId); - } - case WX_CARD: { - return wxOpenConfigStorage.isCardApiTicketExpired(appId); - } - default: { - // do nothing - } + case JSAPI: + { + return wxOpenConfigStorage.isJsapiTicketExpired(appId); + } + case WX_CARD: + { + return wxOpenConfigStorage.isCardApiTicketExpired(appId); + } + default: + { + // do nothing + } } return false; @@ -375,36 +398,41 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { @Override public void expireTicket(TicketType type) { switch (type) { - case JSAPI: { - wxOpenConfigStorage.expireJsapiTicket(appId); - break; - } - case WX_CARD: { - wxOpenConfigStorage.expireCardApiTicket(appId); - break; - } - default: { - // do nothing - } + case JSAPI: + { + wxOpenConfigStorage.expireJsapiTicket(appId); + break; + } + case WX_CARD: + { + wxOpenConfigStorage.expireCardApiTicket(appId); + break; + } + default: + { + // do nothing + } } } @Override public void updateTicket(TicketType type, String ticket, int expiresInSeconds) { switch (type) { - case JSAPI: { - wxOpenConfigStorage.updateJsapiTicket(appId, ticket, expiresInSeconds); - break; - } - case WX_CARD: { - wxOpenConfigStorage.updateCardApiTicket(appId, ticket, expiresInSeconds); - break; - } - default: { - // do nothing - } + case JSAPI: + { + wxOpenConfigStorage.updateJsapiTicket(appId, ticket, expiresInSeconds); + break; + } + case WX_CARD: + { + wxOpenConfigStorage.updateCardApiTicket(appId, ticket, expiresInSeconds); + break; + } + default: + { + // do nothing + } } - } @Override @@ -510,12 +538,35 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { return 0; } - @Override public String getAesKey() { return wxOpenConfigStorage.getComponentAesKey(); } + @Override + public String getApiSignatureRsaPrivateKey() { + return wxOpenConfigStorage.getComponentApiSignatureRsaPrivateKey(); + } + + @Override + public String getApiSignatureAesKey() { + return wxOpenConfigStorage.getComponentApiSignatureAesKey(); + } + + public String getApiSignatureRsaPrivateKeySn() { + return wxOpenConfigStorage.getComponentApiSignatureRsaPrivateKeySn(); + } + + @Override + public String getApiSignatureAesKeySn() { + return wxOpenConfigStorage.getComponentApiSignatureAesKeySn(); + } + + @Override + public String getWechatMpAppid() { + return wxOpenConfigStorage.getComponentAppId(); + } + @Override public String getMsgDataFormat() { return null;