mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2025-04-05 17:38:05 +08:00
🆕 #3404 【小程序】增加同城配送相关接口,同时为WxMaService增加了API签名支持
This commit is contained in:
parent
f6e300b10a
commit
cff5616463
images/api-signature
weixin-java-miniapp
api-signature-readme.md
src
main/java/cn/binarywang/wx/miniapp
api
bean
WxMaApiResponse.java
intractiy
BasicWxMaOrder.javaBasicWxMaStoreChargeRefundRequest.javaPayMode.javaWxMaAddOrderRequest.javaWxMaAddOrderResponse.javaWxMaCancelOrderResponse.javaWxMaGetPayModeResponse.javaWxMaOrder.javaWxMaPreAddOrderRequest.javaWxMaQueryFlowRequest.javaWxMaStore.javaWxMaStoreBalance.javaWxMaStoreChargeRequest.javaWxMaStoreFlowResponse.javaWxMaStoreRefundRequest.javaWxMaTransCity.java
config
constant
executor
test
java/cn/binarywang/wx/miniapp/api/impl
resources
weixin-java-open/src/main/java/me/chanjar/weixin/open/api
BIN
images/api-signature/api-signature-1.png
Normal file
BIN
images/api-signature/api-signature-1.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 165 KiB |
BIN
images/api-signature/api-signature-2.png
Normal file
BIN
images/api-signature/api-signature-2.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 297 KiB |
46
weixin-java-miniapp/api-signature-readme.md
Normal file
46
weixin-java-miniapp/api-signature-readme.md
Normal file
@ -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安全处,可以看到如下图界面。
|
||||
|
||||

|
||||
|
||||
上图中A处对应 apiSignatureAesKeySn; B处对应apiSignatureAesKey; C处对应apiSignatureRsaPrivateKeySn
|
||||
|
||||
apiSignatureRsaPrivateKey 在上图中**无**对应,C处右侧是公钥,apiSignatureRsaPrivateKey 需要的是私钥。
|
||||
|
||||
可点击图上右上角的修改,打开如下图的设置页面
|
||||
|
||||

|
||||
|
||||
首先确保对称密钥选中 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 字样,说明下载了公钥,重新生成密钥对,下载私钥
|
||||
|
||||
|
@ -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 <br>
|
||||
* *不是*即时配送接口,两个相近,容易混淆<br>
|
||||
* 微信相关接口 <br>
|
||||
* 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<WxMaStore> listAllStores() throws WxErrorException;
|
||||
|
||||
/** 根据wx_store_id查询门店 */
|
||||
WxMaStore queryStoreByWxStoreId(String wxStoreId) throws WxErrorException;
|
||||
|
||||
/** 根据 out_store_id 查询门店 */
|
||||
List<WxMaStore> queryStoreByOutStoreId(String outStoreId) throws WxErrorException;
|
||||
|
||||
/** 门店运费充值,返回充值URL */
|
||||
String storeCharge(WxMaStoreChargeRequest request) throws WxErrorException;
|
||||
|
||||
/** 门店运费退款,返回退款金额 */
|
||||
int storeRefund(WxMaStoreRefundRequest request) throws WxErrorException;
|
||||
|
||||
/** 门店运费流水查询 */
|
||||
WxMaStoreFlowResponse<? extends WxMaStoreFlowResponse.BasicFlowRecord> queryFlow(
|
||||
WxMaQueryFlowRequest request) throws WxErrorException;
|
||||
|
||||
/** 查询门店余额 */
|
||||
WxMaStoreBalance balanceQuery(String wxStoreId, String serviceTransId, PayMode payMode)
|
||||
throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 设置扣费主体 <br>
|
||||
* 接口调用成功后,小程序的管理员会收到模板消息,点击模板消息确认更改门店扣费主体后,修改生效。
|
||||
*/
|
||||
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<WxMaTransCity> getCity(String serviceTransId) throws WxErrorException;
|
||||
}
|
@ -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 <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
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 {
|
||||
|
||||
/**
|
||||
* 导入抽样数据
|
||||
*
|
||||
* <pre>
|
||||
* 第三方通过调用微信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 {
|
||||
* </pre>
|
||||
*
|
||||
* @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;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* 验证消息的确来自微信服务器.
|
||||
* 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319&token=&lang=zh_CN
|
||||
* </pre>
|
||||
*
|
||||
* @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;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* 获取access_token,本方法线程安全.
|
||||
* 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限
|
||||
@ -106,6 +107,8 @@ public interface WxMaService extends WxService {
|
||||
String getAccessToken(boolean forceRefresh) throws WxErrorException;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* 用户支付完成后,获取该用户的 UnionId,无需用户授权。本接口支持第三方平台代理查询。
|
||||
*
|
||||
@ -114,33 +117,45 @@ public interface WxMaService extends WxService {
|
||||
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api/getPaidUnionId.html
|
||||
* </pre>
|
||||
*
|
||||
* @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;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* Service没有实现某个API的时候,可以用这个,
|
||||
* 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
|
||||
* 可以参考,{@link MediaUploadRequestExecutor}的实现方法
|
||||
* </pre>
|
||||
*
|
||||
* @param <T> .
|
||||
* @param <E> .
|
||||
* @param <T> .
|
||||
* @param <E> .
|
||||
* @param executor 执行器
|
||||
* @param uri 接口请求地址
|
||||
* @param data 参数或请求数据
|
||||
* @param uri 接口请求地址
|
||||
* @param data 参数或请求数据
|
||||
* @return . t
|
||||
* @throws WxErrorException the wx error exception
|
||||
*/
|
||||
<T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException;
|
||||
|
||||
WxMaApiResponse execute(
|
||||
ApiSignaturePostRequestExecutor executor,
|
||||
String uri,
|
||||
Map<String, String> headers,
|
||||
String data)
|
||||
throws WxErrorException;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试.
|
||||
* 默认:1000ms
|
||||
@ -151,6 +166,8 @@ public interface WxMaService extends WxService {
|
||||
void setRetrySleepMillis(int retrySleepMillis);
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* 设置当微信系统响应系统繁忙时,最大重试次数.
|
||||
* 默认: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<String, WxMaConfig> 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();
|
||||
}
|
||||
|
@ -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 <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
* @see #doGetAccessTokenRequest
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestHttp<H, P> {
|
||||
/**
|
||||
* 开启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<H, P> 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<String, WxMaConfig> configMap = new HashMap<>();
|
||||
private int retrySleepMillis = 1000;
|
||||
@ -107,7 +172,7 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
|
||||
|
||||
@Override
|
||||
public String getPaidUnionId(String openid, String transactionId, String mchId, String outTradeNo)
|
||||
throws WxErrorException {
|
||||
throws WxErrorException {
|
||||
Map<String, String> params = new HashMap<>(8);
|
||||
params.put("openid", openid);
|
||||
|
||||
@ -123,7 +188,8 @@ public abstract class BaseWxMaServiceImpl<H, P> 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<H, P> 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<H, P> implements WxMaService, RequestH
|
||||
*/
|
||||
protected abstract String doGetAccessTokenRequest() throws IOException;
|
||||
|
||||
|
||||
/**
|
||||
* 通过网络请求获取稳定版接口调用凭据
|
||||
*
|
||||
@ -225,14 +292,33 @@ public abstract class BaseWxMaServiceImpl<H, P> 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<H, P> implements WxMaService, RequestH
|
||||
return this.post(url, obj.toJson());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String upload(String url, CommonUploadParam param) throws WxErrorException {
|
||||
RequestExecutor<String, CommonUploadParam> 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, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
|
||||
public String upload(String url, CommonUploadParam param) throws WxErrorException {
|
||||
RequestExecutor<String, CommonUploadParam> executor =
|
||||
CommonUploadRequestExecutor.create(getRequestHttp());
|
||||
return this.execute(executor, url, param);
|
||||
}
|
||||
|
||||
/** 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 */
|
||||
@Override
|
||||
public <R, T> R execute(RequestExecutor<R, T> 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<String, String> 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> {
|
||||
R execute(String urlWithAccessToken) throws IOException, WxErrorException;
|
||||
}
|
||||
|
||||
private <R, T> R excuteWithRetry(ExecutorAction<R> 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<H, P> implements WxMaService, RequestH
|
||||
throw new WxRuntimeException("微信服务端异常,超出重试次数");
|
||||
}
|
||||
|
||||
private <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data, boolean doNotAutoRefreshToken) throws WxErrorException {
|
||||
E dataForLog = DataUtils.handleDataWithSecret(data);
|
||||
private <R, T> R executeInternal(
|
||||
ExecutorAction<R> 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<H, P> 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<H, P> 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<H, P> 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<H, P> 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<String, String> 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;
|
||||
}
|
||||
}
|
||||
|
@ -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<String, String> 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<String, Object> 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<WxMaStore> listAllStores() throws WxErrorException {
|
||||
return queryStore(null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxMaStore queryStoreByWxStoreId(String wxStoreId) throws WxErrorException {
|
||||
List<WxMaStore> list = queryStore(wxStoreId, null);
|
||||
return list.isEmpty() ? null : list.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WxMaStore> queryStoreByOutStoreId(String outStoreId) throws WxErrorException {
|
||||
return queryStore(null, outStoreId);
|
||||
}
|
||||
|
||||
private List<WxMaStore> queryStore(String wxStoreId, String outStoreId) throws WxErrorException {
|
||||
Map<String, String> 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<List<WxMaStore>>() {}.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<? extends WxMaStoreFlowResponse.BasicFlowRecord> queryFlow(
|
||||
WxMaQueryFlowRequest request) throws WxErrorException {
|
||||
if (request == null || request.getWxStoreId() == null) {
|
||||
throw new IllegalArgumentException("查询请求 wxStoreId 不可为空");
|
||||
}
|
||||
WxMaStoreFlowResponse<? extends WxMaStoreFlowResponse.BasicFlowRecord> inst =
|
||||
getFlowInstanceByType(request.getFlowType());
|
||||
if (inst == null) {
|
||||
throw new IllegalArgumentException("查询请求 flowType 不正确,只能是1、2、3之一");
|
||||
}
|
||||
|
||||
String response = this.wxMaService.postWithSignature(Intracity.QUERY_FLOW, request);
|
||||
|
||||
WxMaStoreFlowResponse<? extends WxMaStoreFlowResponse.BasicFlowRecord> flowResponse;
|
||||
flowResponse =
|
||||
(WxMaStoreFlowResponse<? extends WxMaStoreFlowResponse.BasicFlowRecord>)
|
||||
gson.fromJson(response, inst.getClass());
|
||||
logger.debug("queryFlow: {}", flowResponse);
|
||||
return flowResponse;
|
||||
}
|
||||
|
||||
private WxMaStoreFlowResponse<? extends WxMaStoreFlowResponse.BasicFlowRecord>
|
||||
getFlowInstanceByType(int flowType) {
|
||||
WxMaStoreFlowResponse<? extends WxMaStoreFlowResponse.BasicFlowRecord> inst;
|
||||
if (flowType == 1) {
|
||||
inst = new WxMaStoreFlowResponse<WxMaStoreFlowResponse.ChargeFlowRecord>();
|
||||
} else if (flowType == 2) {
|
||||
inst = new WxMaStoreFlowResponse<WxMaStoreFlowResponse.RefundFlowRecord>();
|
||||
} else if (flowType == 3) {
|
||||
inst = new WxMaStoreFlowResponse<WxMaStoreFlowResponse.ConsumeFlowRecord>();
|
||||
} 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<WxMaTransCity> getCity(String serviceTransId) throws WxErrorException {
|
||||
Map<String, Object> 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<List<WxMaTransCity>>() {}.getType();
|
||||
return gson.fromJson(jsonObject.getAsJsonArray("support_list"), listType);
|
||||
}
|
||||
}
|
@ -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<String, String> headers;
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public Map<String, String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(Map<String, String> headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
/**
|
||||
* 充值/扣费主体 <br>
|
||||
* 门店: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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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<ItemDetail> itemList;
|
||||
|
||||
public List<ItemDetail> getItemList() {
|
||||
return itemList;
|
||||
}
|
||||
|
||||
public void setItemList(List<ItemDetail> 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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<Detail> 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<Detail> getBalanceDetail() {
|
||||
return balanceDetail;
|
||||
}
|
||||
|
||||
public void setBalanceDetail(List<Detail> 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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<T extends WxMaStoreFlowResponse.BasicFlowRecord> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(WxMaStoreFlowResponse.class);
|
||||
|
||||
/** 总支付金额 */
|
||||
private Long totalPayAmt;
|
||||
|
||||
/** 总退款金额 */
|
||||
private Long totalRefundAmt;
|
||||
|
||||
/** 总违约金 查询消费流水才返回 */
|
||||
private Long totalDeductAmt;
|
||||
|
||||
/** 流水 */
|
||||
private List<T> flowList;
|
||||
|
||||
public List<T> getFlowList() {
|
||||
return flowList;
|
||||
}
|
||||
|
||||
public void setFlowList(List<T> 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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<City> cityList;
|
||||
|
||||
public String getServiceTransId() {
|
||||
return serviceTransId;
|
||||
}
|
||||
|
||||
public void setServiceTransId(String serviceTransId) {
|
||||
this.serviceTransId = serviceTransId;
|
||||
}
|
||||
|
||||
public List<City> getCityList() {
|
||||
return cityList;
|
||||
}
|
||||
|
||||
public void setCityList(List<City> 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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<WxAccessTokenEntity> updateAccessTokenBefore) {
|
||||
|
||||
}
|
||||
default void setUpdateAccessTokenBefore(Consumer<WxAccessTokenEntity> 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 请求重试间隔
|
||||
*
|
||||
* <pre>
|
||||
* {@link cn.binarywang.wx.miniapp.api.impl.BaseWxMaServiceImpl#setRetrySleepMillis(int)}
|
||||
* </pre>
|
||||
@ -244,6 +233,7 @@ public interface WxMaConfig {
|
||||
|
||||
/**
|
||||
* http 请求最大重试次数
|
||||
*
|
||||
* <pre>
|
||||
* {@link cn.binarywang.wx.miniapp.api.impl.BaseWxMaServiceImpl#setMaxRetryTimes(int)}
|
||||
* </pre>
|
||||
@ -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();
|
||||
}
|
||||
|
@ -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<WxAccessTokenEntity> updateAccessTokenBefore;
|
||||
/** 自定义配置token的消费者 */
|
||||
@Setter private Consumer<WxAccessTokenEntity> 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;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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<CloseableHttpClient, HttpHost> {
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(ApacheApiSignaturePostRequestExecutor.class);
|
||||
|
||||
public ApacheApiSignaturePostRequestExecutor(RequestHttp<?, ?> requestHttp) {
|
||||
super(requestHttp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxMaApiResponse execute(
|
||||
String uri, Map<String, String> 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<String, String> 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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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<H, P>
|
||||
implements RequestExecutor<WxMaApiResponse, WxMaApiResponse> {
|
||||
|
||||
protected RequestHttp<H, P> 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<WxMaApiResponse> handler, WxType wxType)
|
||||
throws WxErrorException, IOException {
|
||||
throw new RemoteException("method not implemented yet.");
|
||||
}
|
||||
|
||||
public abstract WxMaApiResponse execute(
|
||||
String uri, Map<String, String> headers, String data, WxType wxType)
|
||||
throws WxErrorException, IOException;
|
||||
|
||||
@NotNull
|
||||
public WxMaApiResponse handleResponse(
|
||||
WxType wxType, String responseContent, Map<String, String> 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("非法请求参数");
|
||||
}
|
||||
}
|
||||
}
|
@ -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<HttpConnectionProvider, ProxyInfo> {
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(JoddApiSignaturePostRequestExecutor.class);
|
||||
|
||||
public JoddApiSignaturePostRequestExecutor(RequestHttp<?, ?> requestHttp) {
|
||||
super(requestHttp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxMaApiResponse execute(
|
||||
String uri, Map<String, String> 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<String, String> respHeaders = new HashMap<>();
|
||||
for (String n : response.headerNames()) {
|
||||
respHeaders.putIfAbsent(n, response.header(n));
|
||||
}
|
||||
return this.handleResponse(wxType, response.bodyText(), respHeaders);
|
||||
}
|
||||
}
|
@ -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<OkHttpClient, OkHttpProxyInfo> {
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(OkHttpApiSignaturePostRequestExecutor.class);
|
||||
|
||||
public OkHttpApiSignaturePostRequestExecutor(RequestHttp<?, ?> requestHttp) {
|
||||
super(requestHttp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxMaApiResponse execute(
|
||||
String uri, Map<String, String> 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<String, String> 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);
|
||||
}
|
||||
}
|
@ -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<WxMaStore> 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<WxMaStore> 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<WxMaStore> list =
|
||||
wxService.getIntracityService().queryStoreByOutStoreId(stores.get(0).getOutStoreId());
|
||||
logger.info("queryStoreByOutStoreId 查询到 {} 个门店 {}", list.size(), list);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoreChargeRelated() throws Exception {
|
||||
List<WxMaStore> 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<WxMaTransCity> list = wxService.getIntracityService().getCity(null);
|
||||
logger.debug("支持的城市 {}", list);
|
||||
List<WxMaTransCity> list2 = wxService.getIntracityService().getCity("SFTC");
|
||||
logger.debug("SFTC支持的城市有{}个", list2.get(0).getCityList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderRelatived() throws Exception {
|
||||
List<WxMaStore> 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<WxMaAddOrderRequest.ItemDetail> 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) {
|
||||
// 订单已经被取消了,重复取消会报错,这里才正常
|
||||
}
|
||||
}
|
||||
}
|
@ -9,4 +9,9 @@
|
||||
<expiresTime>可以不填写</expiresTime>
|
||||
<openid>某个用户的openId</openid>
|
||||
<templateId>模版消息的模版ID</templateId>
|
||||
<componentApiSignatureAesKey>API签名AES密钥【没有开启API签名不要这条】</componentApiSignatureAesKey>
|
||||
<componentApiSignatureAesKeySn>API签名AES密钥的序号【没有开启API签名不要这条】</componentApiSignatureAesKeySn>
|
||||
<componentApiSignatureRsaPrivateKey>API签名RSA私钥的【没有开启API签名不要这条】</componentApiSignatureRsaPrivateKey>
|
||||
<componentApiSignatureRsaPrivateKeySn>API签名RSA私钥的序【没有开启API签名不要这条】
|
||||
</componentApiSignatureRsaPrivateKeySn>
|
||||
</xml>
|
||||
|
@ -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 请求重试间隔
|
||||
*
|
||||
* <pre>
|
||||
* {@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 请求最大重试次数
|
||||
*
|
||||
* <pre>
|
||||
* {@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);
|
||||
}
|
||||
|
@ -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 请求重试间隔
|
||||
*
|
||||
* <pre>
|
||||
* {@link me.chanjar.weixin.mp.api.impl.BaseWxMpServiceImpl#setRetrySleepMillis(int)}
|
||||
* {@link cn.binarywang.wx.miniapp.api.impl.BaseWxMaServiceImpl#setRetrySleepMillis(int)}
|
||||
* </pre>
|
||||
*/
|
||||
private int retrySleepMillis = 1000;
|
||||
|
||||
/**
|
||||
* http 请求最大重试次数
|
||||
*
|
||||
* <pre>
|
||||
* {@link me.chanjar.weixin.mp.api.impl.BaseWxMpServiceImpl#setMaxRetryTimes(int)}
|
||||
* {@link cn.binarywang.wx.miniapp.api.impl.BaseWxMaServiceImpl#setMaxRetryTimes(int)}
|
||||
* </pre>
|
||||
*/
|
||||
private int maxRetryTimes = 5;
|
||||
|
||||
private ApacheHttpClientBuilder apacheHttpClientBuilder;
|
||||
|
||||
private Map<String, Token> 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<String, Token> 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<String, Token> map, String key, String tokenString, Integer expiresInSeconds) {
|
||||
private void updateToken(
|
||||
Map<String, Token> 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;
|
||||
|
Loading…
Reference in New Issue
Block a user