更新支付方法,更新readme,调整结构

master
yclimb 2018-11-01 17:23:17 +08:00
parent ea20c2a105
commit 91fe2b7400
11 changed files with 1881 additions and 194 deletions

164
README.md
View File

@ -1,29 +1,153 @@
微信支付 Java SDK
------
对[微信支付开发者文档](https://pay.weixin.qq.com/wiki/doc/api/index.html)中给出的API进行了封装
本项目依托于 [微信支付开发者文档](https://pay.weixin.qq.com/wiki/doc/api/index.html),对文档中的接口进行二次封装,从而为小伙伴们提供一个`拿来即用`的支付sdk工具
com.weixin.pay.WXPay类下提供了对应的方法
## 项目结构
首先需要简单说明整个 `wxpay-sdk` 的项目结构,主体结构如下所示:
|方法名 | 说明 |
|--------|--------|
|microPay| 刷卡支付 |
|unifiedOrder | 统一下单|
|orderQuery | 查询订单 |
|reverse | 撤销订单 |
|closeOrder|关闭订单|
|refund|申请退款|
|refundQuery|查询退款|
|downloadBill|下载对账单|
|report|交易保障|
|shortUrl|转换短链接|
|authCodeToOpenid|授权码查询openid|
- wxpay-sdk
- src
- main
- java
- com.weixin.pay
- card // 微信卡券
- constants // 常量文件
- redis // redis工具类
- util // 支付工具类(支付、签名、加密解密)
- xxx class // 支付实体类,基础配置信息
- test
- controller
- xxx class // 测试的相关类
- .gitignore
- pom.xml // 引用包
- README.md
提供微信支付的基础功能脱胎于微信官方Java-SDK进行二次封装后提供一系列的方法
基础方法主要在 `com.weixin.pay.WXPay` 类下,此项目包含的微信支付功能主要分为以下几个部分:
### 1. 基础支付功能
`com.weixin.pay.WXPay`
|方法名 | 说明 |
|--------|--------|
|microPay| 刷卡支付 |
|unifiedOrder | 统一下单|
|chooseWXPayMap | 微信支付二次签名|
|orderQuery | 查询订单 |
|reverse | 撤销订单 |
|closeOrder|关闭订单|
|refund|申请退款|
|refundQuery|查询退款|
|downloadBill|下载对账单|
|report|交易保障|
|shortUrl|转换短链接|
|authCodeToOpenid|授权码查询openid|
### 2. 验收用例
支付验收指引:`https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=23_1`
`controller.TestWXPay`
|方法名 | 说明 |
|--------|--------|
|unifiedOrder | 统一下单|
|orderQuery | 查询订单 |
|reverse | 撤销订单 |
|closeOrder|关闭订单|
|refund|申请退款|
|refundQuery|查询退款|
### 3. 商户平台-现金红包
`com.weixin.pay.WXPay`
|方法名 | 说明 |
|--------|--------|
|sendRedPack| 企业向指定微信用户的openid发放指定金额红包 |
|getRedPackInfo| 查询红包记录 |
### 4. 商户平台-代金券或立减优惠
`com.weixin.pay.WXPay`
|方法名 | 说明 |
|--------|--------|
|sendCoupon| 发放代金券 |
|queryCouponsInfo| 查询代金券信息 |
|queryCouponStock| 查询代金券批次 |
### 5. 公众平台-微信卡券
`com.weixin.pay.util.WXUtils`
|方法名 | 说明 |
|--------|--------|
|getAccessToken| 获取微信全局accessToken |
|getMiniBaseUserInfo| 获取小程序静默登录返回信息 |
|getJsapiAccessTokenByCode| 网页授权获取用户信息时用于获取access_token以及openid |
|getJsapiUserinfo| 通过access_token和openid请求获取用户信息 |
|getWxMiniQRImg| 生成带参数的小程序二维码[] |
|getWxCardApiTicket| 获取卡券 api_ticket 的 api |
|getWxApiTicket| 获取卡券 api_ticket 的 api |
### 6. 公众平台-社交立减金活动
`com.weixin.pay.util.WXUtils`
|方法名 | 说明 |
|--------|--------|
|getCardList| 根据代金券批次ID得到组合的cardList |
|createCardActivity| 创建支付后领取立减金活动接口 |
## 微信支付调用示例
```$xslt
public Map<String, String> saveWxPayUnifiedOrder(Payment payment, User user) throws Exception {
if (payment == null) {
return null;
}
if (user == null) {
return null;
}
// 1.调用微信统一下单接口
WXPay wxPay = new WXPay(WXPayConfigImpl.getInstance());
Map<String, String> resultMap = wxPay.unifiedOrder(...);
// 1.1.记录付款流水
...
// 下单失败,进行处理
if (WXPayConstants.FAIL.equals(resultMap.get(WXPayConstants.RETURN_CODE)) ||
WXPayConstants.FAIL.equals(resultMap.get(WXPayConstants.RESULT_CODE))) {
// 处理结果返回,无需继续执行
resultMap.put(WXPayConstants.RESULT_CODE, WXPayConstants.FAIL);
resultMap.put(WXPayConstants.ERR_CODE_DES, resultMap.get(WXPayConstants.RETURN_MSG));
return resultMap;
}
// 1.2.获取prepay_id、nonce_str
String prepay_id = resultMap.get("prepay_id");
String nonce_str = resultMap.get("nonce_str");
// 2.根据微信统一下单接口返回数据组装微信支付参数,返回结果
return wxPay.chooseWXPayMap(prepay_id, nonce_str);
}
```
基础调用方式如上所述,统一返回值为 `Map<String, String>`,详细信息见实体类,文档会实时更新,尽情期待!!!
* 参数为`Map<String, String>`对象,返回类型也是`Map<String, String>`。
* 方法内部会将参数会转换成含有`appid`、`mch_id`、`nonce_str`、`sign\_type`和`sign`的XML
* 可选HMAC-SHA256算法和MD5算法签名
* 通过HTTPS请求得到返回数据后会对其做必要的处理例如验证签名签名错误则抛出异常
* 对于downloadBill无论是否成功都返回Map且都含有`return_code`和`return_msg`。若成功,其中`return_code`为`SUCCESS`,另外`data`对应对账单数据。

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,91 @@
package com.weixin.pay.card;
/**
*
*
* @author yclimb
* @date 2018/9/18
*/
public enum CardBgColorEnum {
/**
* 绿
*/
COLOR_010("Color010", "#63b359"),
/**
* 绿
*/
COLOR_020("Color020", "#2c9f67"),
/**
*
*/
COLOR_030("Color030", "#509fc9"),
/**
*
*/
COLOR_040("Color040", "#5885cf"),
/**
*
*/
COLOR_050("Color050", "#9062c0"),
/**
*
*/
COLOR_060("Color060", "#d09a45"),
/**
*
*/
COLOR_070("Color070", "#e4b138"),
/**
*
*/
COLOR_080("Color080", "#ee903c"),
/**
* plus
*/
COLOR_081("Color081", "#f08500"),
/**
*
*/
COLOR_082("Color082", "#a9d92d"),
/**
*
*/
COLOR_090("Color090", "#dd6549"),
/**
*
*/
COLOR_100("Color100", "#cc463d"),
/**
*
*/
COLOR_101("Color101", "#cf3e36"),
/**
*
*/
COLOR_102("Color102", "#5E6671")
;
/**
*
*/
private String bgName;
/**
*
*/
private String bgVal;
CardBgColorEnum(String bgName, String bgVal) {
this.bgName = bgName;
this.bgVal = bgVal;
}
public String getBgName() {
return bgName;
}
public String getBgVal() {
return bgVal;
}
}

View File

@ -29,6 +29,11 @@ public class WXConstants {
*/
public static final String OAUTH_STATE = "xxx";
/**
* access token code
*/
public static final String WX_MINI_PROGRAM_CODE = "xxxx";
/**
* accessToken
*/

View File

@ -4,9 +4,6 @@ import org.apache.http.client.HttpClient;
/**
* SDK
*
* @author yclimb
* @date 2018/8/17
*/
public class WXPayConstants {
@ -24,7 +21,7 @@ public class WXPayConstants {
*
*/
public enum SignType {
MD5, HMACSHA256
MD5, HMACSHA256, SHA1
}
/**
@ -64,9 +61,9 @@ public class WXPayConstants {
* JSAPI--NATIVE--APP--apptrade_type
* MICROPAY--
*/
public static String TRADE_TYPE = "JSAPI";
public static String TRADE_TYPE_APP = "APP";
public static String TRADE_TYPE_NATIVE = "NATIVE";
public static final String TRADE_TYPE = "JSAPI";
public static final String TRADE_TYPE_APP = "APP";
public static final String TRADE_TYPE_NATIVE = "NATIVE";
/**
* - API
@ -133,6 +130,29 @@ public class WXPayConstants {
*
*/
public static final String SENDREDPACK_URL_SUFFIX = "/mmpaymkttransfers/sendredpack";
/**
* --<br>
*
*
*/
public static final String GETHBINFO_URL_SUFFIX = "/mmpaymkttransfers/gethbinfo";
/**
* --<br>
*
*
*
*/
public static final String SEND_COUPON_URL_SUFFIX = "/mmpaymkttransfers/send_coupon";
/**
* --<br>
*
*/
public static final String QUERYCOUPONSINFO_URL_SUFFIX = "/mmpaymkttransfers/querycouponsinfo";
/**
* --<br>
*
*/
public static final String QUERY_COUPON_STOCK_URL_SUFFIX = "/mmpaymkttransfers/query_coupon_stock";
/**
* <br>
*
@ -210,7 +230,7 @@ public class WXPayConstants {
public static final String SANDBOX_ORDERQUERY_URL_SUFFIX = "/sandboxnew/pay/orderquery";
public static final String SANDBOX_REVERSE_URL_SUFFIX = "/sandboxnew/secapi/pay/reverse";
public static final String SANDBOX_CLOSEORDER_URL_SUFFIX = "/sandboxnew/pay/closeorder";
public static final String SANDBOX_REFUND_URL_SUFFIX = "/sandboxnew/secapi/pay/refund";
public static final String SANDBOX_REFUND_URL_SUFFIX = "/sandboxnew/pay/refund";
public static final String SANDBOX_REFUNDQUERY_URL_SUFFIX = "/sandboxnew/pay/refundquery";
public static final String SANDBOX_DOWNLOADBILL_URL_SUFFIX = "/sandboxnew/pay/downloadbill";
public static final String SANDBOX_REPORT_URL_SUFFIX = "/sandboxnew/payitil/report";
@ -218,6 +238,11 @@ public class WXPayConstants {
public static final String SANDBOX_AUTHCODETOOPENID_URL_SUFFIX = "/sandboxnew/tools/authcodetoopenid";
public static final String SANDBOX_SENDREDPACK_URL_SUFFIX = "/sandboxnew/mmpaymkttransfers/sendredpack";
public static final String SANDBOX_TRANSFERS_URL_SUFFIX = "/sandboxnew/mmpaymkttransfers/promotion/transfers";
public static final String SANDBOX_GETHBINFO_URL_SUFFIX = "/sandboxnew/mmpaymkttransfers/promotion/gethbinfo";
public static final String SANDBOX_SEND_COUPON_URL_SUFFIX = "/sandboxnew/mmpaymkttransfers/send_coupon";
public static final String SANDBOX_QUERYCOUPONSINFO_URL_SUFFIX = "/sandboxnew/mmpaymkttransfers/querycouponsinfo";
public static final String SANDBOX_QUERY_COUPON_STOCK_URL_SUFFIX = "/sandboxnew/mmpaymkttransfers/query_coupon_stock";
}

View File

@ -0,0 +1,109 @@
package com.weixin.pay.constants;
/**
*
*
* @author yclimb
* @date 2018/11/1
*/
public interface WeChatURL {
/**
* URLjsapi_ticket
*/
String PAGE_URL_SIGN = "jsapi_ticket={0}&noncestr={1}&timestamp={2}&url={3}";
/**
* URLaccess_token
*/
String BASE_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";
/**
* URLjsapi_ticket
*/
String BASE_JSAPI_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi";
/**
* URL
*/
String MENU_CREATE = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token={0}";
/**
* URL
*/
String MENU_QUERY = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token={0}";
/**
* URL
*/
String MENU_DELETE = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token={0}";
/**
* code
*/
String OAUTH_CODE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=" + WXConstants.OAUTH_STATE + "#wechat_redirect";
/**
* codeaccess_token
*/
String OAUTH_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code";
/**
*
*/
String OAUTH_GET_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token={0}&openid={1}&lang=zh_CN";
/**
* access_token
*/
String GET_USERINFO_URL = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
/**
*
*/
String WX_TEMPLATE_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={0}";
/**
*
*/
String WX_CUSTMOER_SERVICE_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={}";
/***
* ticket
*/
String WX_TICKET_CREATE = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={0}";
/**
*
*/
String WX_MINI_LOGIN = "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code";
/**
*
*/
String WX_MINI_TEMPLATE_MSG = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token={ACCESS_TOKEN}";
/**
*
*/
String WX_MINI_QR_CODE_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={0}";
/**
*
*
* cardidappidid
* https://mp.weixin.qq.com/wiki?t=resource/res_main&id=21515658940X5pIn
*
* https
* http: POST
* URLhttps://api.weixin.qq.com/card/mkt/activity/create?access_token=ACCESS_TOKEN
* POSTJSON
*/
String WX_CARD_ACTIVITY_CREATE_URL = "https://api.weixin.qq.com/card/mkt/activity/create?access_token={0}";
/**
* JSSDK
* JSSDK使JS
*
* JSJSSDKJSAPIappsecret/api_ticket
* api_ticket 7200 access_token jsapi_ticket
* api_ticket api api_ticket api api_ticket
*/
String BASE_API_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=wx_card";
}

View File

@ -11,7 +11,15 @@ public enum RedisKeyEnum {
/**
* KEY
*/
XXX_MINI_WX_CODE(RedisKeyUtil.KEY_PREFIX, "mini", "getwxacodeunlimit", "生成永久无限制微信二维码")
XXX_MINI_WX_CODE(RedisKeyUtil.KEY_PREFIX, "mini", "getwxacodeunlimit", "生成永久无限制微信二维码"),
/**
* api_ticket
*/
IMALL_WXCARD_APITICKET(RedisKeyUtil.KEY_PREFIX, "jsapi", "getWxCardApiTicket", "获取卡券api_ticket的api"),
/**
* api_ticket
*/
IMALL_WX_APITICKET(RedisKeyUtil.KEY_PREFIX, "jsapi", "getWxApiTicket", "获取api_ticket的api")
;

View File

@ -0,0 +1,159 @@
package com.weixin.pay.util;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*
*
* @author yclimb
* @date 2018/11/1
*/
public class DateTimeUtil {
public static final String TIME_FORMAT_SHORT = "yyyyMMddHHmmss";
public static final String TIME_FORMAT_SHORT_HOUR = "yyyyMMddHH";
public static final String TIME_FORMAT_YMD = "yyyy/MM/dd HH:mm:ss";
public static final String TIME_FORMAT_NORMAL = "yyyy-MM-dd HH:mm:ss";
public static final String TIME_FORMAT_ENGLISH = "MM/dd/yyyy HH:mm:ss";
public static final String TIME_FORMAT_CHINA = "yyyy年MM月dd日 HH时mm分ss秒";
public static final String TIME_FORMAT_CHINA_M = "yyyy年MM月dd日 HH时mm分";
public static final String TIME_FORMAT_CHINA_S = "yyyy年M月d日 H时m分s秒";
public static final String TIME_FORMAT_SHORT_S = "HH:mm:ss";
public static final String DATE_FORMAT_SHORT = "yyyyMMdd";
public static final String DATE_FORMAT_NORMAL = "yyyy-MM-dd";
public static final String DATE_FORMAT_ENGLISH = "MM/dd/yyyy";
public static final String DATE_FORMAT_CHINA = "yyyy年MM月dd日";
public static final String DATE_FORMAT_CHINA_YEAR_MONTH = "yyyy年MM月";
public static final String MONTH_FORMAT = "yyyyMM";
public static final String YEAR_MONTH_FORMAT = "yyyy-MM";
public static final String DATE_FORMAT_MINUTE = "yyyyMMddHHmm";
public static final String MONTH_DAY_FORMAT = "MM-dd";
public static final String YEAR_FORMAT = "yyyy";
public static final String TIME_FORMAT_TIME = "yyyy/MM/dd HH:mm";
private static final SimpleDateFormat sdf = new SimpleDateFormat(
DATE_FORMAT_NORMAL);
private static final SimpleDateFormat sdfTime = new SimpleDateFormat(
TIME_FORMAT_NORMAL);
private static final SimpleDateFormat sdfTimes = new SimpleDateFormat(
"yyyyMMddHHmmssSSS");
private static final SimpleDateFormat sdfTChina = new SimpleDateFormat(
TIME_FORMAT_CHINA);
/**
*
*
* @param dateStr
* @return
* @since 0.1
*/
public static Date convertAsDate(String dateStr) {
if (dateStr == null || "".equals(dateStr)) {
return null;
}
DateFormat fmt = null;
if (dateStr.matches("\\d{14}")) {
fmt = new SimpleDateFormat(TIME_FORMAT_SHORT);
} else if (dateStr
.matches("\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}")) {
fmt = new SimpleDateFormat(TIME_FORMAT_NORMAL);
} else if (dateStr
.matches("\\d{1,2}/\\d{1,2}/\\d{4} \\d{1,2}:\\d{1,2}:\\d{1,2}")) {
fmt = new SimpleDateFormat(TIME_FORMAT_ENGLISH);
} else if (dateStr
.matches("\\d{4}年\\d{1,2}月\\d{1,2}日 \\d{1,2}时\\d{1,2}分\\d{1,2}秒")) {
fmt = new SimpleDateFormat(TIME_FORMAT_CHINA);
} else if (dateStr.matches("\\d{8}")) {
fmt = new SimpleDateFormat(DATE_FORMAT_SHORT);
} else if (dateStr.matches("\\d{4}-\\d{1,2}-\\d{1,2}")) {
fmt = new SimpleDateFormat(DATE_FORMAT_NORMAL);
} else if (dateStr.matches("\\d{1,2}/\\d{1,2}/\\d{4}")) {
fmt = new SimpleDateFormat(DATE_FORMAT_ENGLISH);
} else if (dateStr.matches("\\d{4}年\\d{1,2}月\\d{1,2}日")) {
fmt = new SimpleDateFormat(DATE_FORMAT_CHINA);
} else if (dateStr.matches("\\d{4}\\d{1,2}\\d{1,2}\\d{1,2}\\d{1,2}")) {
fmt = new SimpleDateFormat(DATE_FORMAT_MINUTE);
} else if (dateStr.matches("\\d{1,2}:\\d{1,2}:\\d{1,2}")) {
fmt = new SimpleDateFormat(TIME_FORMAT_SHORT_S);
}
try {
return fmt.parse(dateStr);
} catch (ParseException e) {
throw new IllegalArgumentException(
"Date or Time String is invalid.");
}
}
/**
* , yyyyMMddHHmmss
* @return
*
* @author yclimb
* @date 2018/11/1
*/
public static String getTimeShortString(Date date) {
return new SimpleDateFormat(TIME_FORMAT_SHORT).format(date);
}
/**
*
* @param date
* @return long
*
* @author yclimb
* @date 2018/9/18
*/
public static long getTenTimeByDate(Date date) {
return date.getTime() / 1000;
}
/**
*
* @param dateStr
* @return long
*
* @author yclimb
* @date 2018/9/18
*/
public static long getTenTimeByDate(String dateStr) {
return convertAsDate(dateStr).getTime() / 1000;
}
/**
* Description: <br/>
* true,false
*
* @param strFirst
* @param strSecond
* @param strFormat eg:"yyyy-MM-dd HH:mm:ss"," yyyy-MM-dd"
* @return true-,false-
*
* @author yclimb
* @date 2018/11/1
*/
public static boolean latterThan(String strFirst, String strSecond,
String strFormat) {
SimpleDateFormat ft = new SimpleDateFormat(strFormat);
try {
Date date1 = ft.parse(strFirst);
Date date2 = ft.parse(strSecond);
long quot = date2.getTime() - date1.getTime();
if (0 < quot) {
return true;
} else {
return false;
}
} catch (ParseException e) {
e.printStackTrace();
}
return false;
}
}

View File

@ -116,7 +116,7 @@ public class WXPayUtil {
* @return signXML
*/
public static String generateSignedXml(final Map<String, String> data, String key) throws Exception {
return generateSignedXml(data, key, SignType.MD5);
return generateSignedXml(data, key, WXPayConstants.SignType.MD5);
}
/**
@ -238,6 +238,44 @@ public class WXPayUtil {
return new String(nonceChars);
}
/**
*
* @param type 1:key;2:value
* @param data d
* @return sb
*/
public static String dictionaryOrder(final Map<String, String> data, int type) {
Set<String> keySet = data.keySet();
String[] keyArray = keySet.toArray(new String[keySet.size()]);
StringBuilder sb = new StringBuilder();
if (type == 2) {
String[] valArray = new String[keySet.size()];
for (int i = 0; i < keySet.size(); i++) {
valArray[i] = data.get(keyArray[i]);
}
Arrays.sort(valArray);
for (String v : valArray) {
// 参数值为空,则不参与签名
if (v.trim().length() > 0) {
sb.append(v);
}
}
} else {
Arrays.sort(keyArray);
for (int i = 0; i < keyArray.length; i++) {
// 参数值为空,则不参与签名
if (data.get(keyArray[i]).trim().length() > 0) {
if (i == keyArray.length - 1) {
sb.append(keyArray[i]).append("=").append(data.get(keyArray[i]).trim());
} else {
sb.append(keyArray[i]).append("=").append(data.get(keyArray[i]).trim()).append("&");
}
}
}
}
return sb.toString();
}
/**
* MD5
@ -260,7 +298,7 @@ public class WXPayUtil {
* @param data
* @param key
* @return
* @throws Exception
* @throws Exception e
*/
public static String HMACSHA256(String data, String key) throws Exception {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
@ -274,9 +312,35 @@ public class WXPayUtil {
return sb.toString().toUpperCase();
}
/**
* SHA1
* @param data
* @return str
* @throws Exception e
*/
public static String SHA1(String data) throws Exception {
//指定sha1算法
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.update(data.getBytes("UTF-8"));
//获取字节数组
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuilder hexString = new StringBuilder();
// 字节数组转换为 十六进制 数
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexString.append(0);
}
hexString.append(shaHex);
}
return hexString.toString();
}
/**
*
* @return
* @return log
*/
public static Logger getLogger() {
return LoggerFactory.getLogger("wxpay java sdk");
@ -284,15 +348,15 @@ public class WXPayUtil {
/**
*
* @return
* @return long
*/
public static long getCurrentTimestamp() {
return System.currentTimeMillis()/1000;
return System.currentTimeMillis() / 1000;
}
/**
*
* @return
* @return long
*/
public static long getCurrentTimestampMs() {
return System.currentTimeMillis();
@ -300,10 +364,22 @@ public class WXPayUtil {
/**
* uuid nonce_str
* @return
* @return str
*/
public static String generateUUID() {
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
}
/**
* 28
* mch_id+yyyyMMddHHmmss+4
*
* @author yclimb
* @date 2018/9/18
*/
public static String getPayNo() {
String yyyyMMddHHmmss = DateTimeUtil.getTimeShortString(new Date());
int str4 = (int) (Math.random() * 9000) + 1000;
return WXPayConstants.MCH_ID + yyyyMMddHHmmss + str4;
}
}

View File

@ -1,10 +1,13 @@
package com.weixin.pay.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.weixin.pay.card.CardBgColorEnum;
import com.weixin.pay.constants.WXConstants;
import com.weixin.pay.constants.WXPayConstants;
import com.weixin.pay.constants.WXURL;
import com.weixin.pay.constants.WeChatURL;
import com.weixin.pay.redis.RedisKeyEnum;
import com.weixin.pay.redis.RedisKeyUtil;
import lombok.extern.slf4j.Slf4j;
@ -21,6 +24,7 @@ import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
@ -274,4 +278,346 @@ public class WXUtils {
return null;
}
/**
*
*
* cardidappidid
* https://mp.weixin.qq.com/wiki?t=resource/res_main&id=21515658940X5pIn
*
* @param begin_time
* @param end_time
* @param gift_num 3-15
* @param max_partic_times_act ,501
* @param max_partic_times_one_day ,501
* @param card_id ID
* @param min_amt
* @param membership_appid appidappidappid
* @param new_tinyapp_user membership_appidnew_tinyapp_userfalse
* @return json
* @author yclimb
* @date 2018/9/18
*/
public JSONObject createCardActivity(String begin_time, String end_time, int gift_num, int max_partic_times_act,
int max_partic_times_one_day, String card_id, String min_amt,
String membership_appid, boolean new_tinyapp_user) {
try {
// 创建活动接口之前的验证
String msg = checkCardActivity(begin_time, end_time, gift_num, max_partic_times_act, max_partic_times_one_day, min_amt);
if (null != msg) {
JSONObject resultJson = new JSONObject(2);
resultJson.put("errcode", "1");
resultJson.put("errmsg", msg);
return resultJson;
}
// 获取[爱上悦店]公众号的 access_token
String accessToken = this.getAccessToken(WXConstants.WX_MINI_PROGRAM_CODE);
// 调用接口传入参数
JSONObject paramJson = new JSONObject(1);
// info 包含 basic_info、card_info_list、custom_info
JSONObject info = new JSONObject(3);
// 基础信息对象
JSONObject basic_info = new JSONObject(8);
// activity_bg_color 是 活动封面的背景颜色,可参考:选取卡券背景颜色
basic_info.put("activity_bg_color", CardBgColorEnum.COLOR_090.getBgName());
// activity_tinyappid 是 用户点击链接后可静默添加到列表的小程序appid
basic_info.put("activity_tinyappid", WXPayConstants.APP_ID);
// mch_code 是 支付商户号
basic_info.put("mch_code", WXPayConstants.MCH_ID);
// begin_time 是 活动开始时间精确到秒unix时间戳
basic_info.put("begin_time", DateTimeUtil.getTenTimeByDate(begin_time));
// end_time 是 活动结束时间精确到秒unix时间戳
basic_info.put("end_time", DateTimeUtil.getTenTimeByDate(end_time));
// gift_num 是 单个礼包社交立减金数量3-15个
basic_info.put("gift_num", gift_num);
// max_partic_times_act 否 每个用户活动期间最大领取次数,最大为50不填默认为1
basic_info.put("max_partic_times_act", max_partic_times_act);
// max_partic_times_one_day 否 每个用户活动期间单日最大领取次数,最大为50不填默认为1
basic_info.put("max_partic_times_one_day", max_partic_times_one_day);
// card_info_list 是 可以配置两种发放规则:小程序新老用户、新老会员
JSONArray card_info_list = new JSONArray(1);
JSONObject card_info = new JSONObject(3);
// card_id 是 卡券ID
card_info.put("card_id", card_id);
// min_amt 是 最少支付金额,单位是分
card_info.put("min_amt", String.valueOf(new BigDecimal(min_amt).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue()));
/*
* membership_appid appidappidappid
* new_tinyapp_user
* total_user
* membership_appidnew_tinyapp_usertotal_user31false
*/
if (StringUtils.isNotBlank(membership_appid)) {
card_info.put("membership_appid", membership_appid);
} else {
if (new_tinyapp_user) {
card_info.put("new_tinyapp_user", true);
} else {
card_info.put("total_user", true);
}
}
card_info_list.add(card_info);
// 自定义字段,表示支付后领券
JSONObject custom_info = new JSONObject(1);
custom_info.put("type", "AFTER_PAY_PACKAGE");
// 拼装json对象
info.put("basic_info", basic_info);
info.put("card_info_list", card_info_list);
info.put("custom_info", custom_info);
paramJson.put("info", info);
// 请求微信接口,得到返回结果[json]
HttpEntity<JSONObject> entity = new HttpEntity<>(paramJson, this.getHttpHeadersUTF8JSON());
JSONObject resultJson = restTemplate.postForObject(WeChatURL.WX_CARD_ACTIVITY_CREATE_URL, entity, JSONObject.class, accessToken);
// {"errcode":0,"errmsg":"ok","activity_id":"4728935"}
System.out.println(resultJson.toJSONString());
return resultJson;
} catch (Exception e) {
WXPayUtil.getLogger().error(e.getMessage(), e);
}
return null;
}
/**
*
*
* @param begin_time
* @param end_time
* @param gift_num 3-15
* @param max_partic_times_act ,501
* @param max_partic_times_one_day ,501
* @param min_amt
* @return msg str
* @author yclimb
* @date 2018/9/18
*/
public String checkCardActivity(String begin_time, String end_time, int gift_num, int max_partic_times_act,
int max_partic_times_one_day, String min_amt) {
// 开始时间不能小于结束时间
if (DateTimeUtil.latterThan(end_time, begin_time, DateTimeUtil.TIME_FORMAT_NORMAL)) {
return "活动开始时间不能小于活动结束时间";
}
// 单个礼包社交立减金数量3-15个
if (gift_num < 3 || gift_num > 15) {
return "单个礼包社交立减金数量3-15个";
}
// 每个用户活动期间最大领取次数,最大为50默认为1
if (max_partic_times_act <= 0 || max_partic_times_act > 50) {
return "每个用户活动期间最大领取次数,最大为50默认为1";
}
// 每个用户活动期间单日最大领取次数,最大为50默认为1
if (max_partic_times_one_day <= 0 || max_partic_times_one_day > 50) {
return "每个用户活动期间单日最大领取次数,最大为50默认为1";
}
// 最少支付金额,单位是元
if (BigDecimal.ONE.compareTo(new BigDecimal(min_amt)) > 0) {
return "最少支付金额必须大于1元";
}
return null;
}
/**
* api_ticket api
* https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=wx_card
*
* @param access_token token
* @return api_ticket json obj
* @author yclimb
* @date 2018/9/21
*/
public String getWxCardApiTicket(String access_token) {
if (StringUtils.isBlank(access_token)) {
return null;
}
try {
// redis key
String redisKey = RedisKeyUtil.keyBuilder(RedisKeyEnum.IMALL_WXCARD_APITICKET, access_token);
// 从redis中获取缓存
Object obj = redisTemplate.opsForValue().get(redisKey);
if (obj != null) {
return obj.toString();
}
// 获取卡券 api_ticket
String api_ticket = restTemplate.getForObject(WeChatURL.BASE_API_TICKET, String.class, access_token);
WXPayUtil.getLogger().info("getWxCardApiTicket:api_ticket:{}", api_ticket);
if (StringUtils.isBlank(api_ticket)) {
return null;
}
JSONObject jsonObject = JSON.parseObject(api_ticket);
if (0 != jsonObject.getIntValue("errcode")) {
return null;
}
// 设置到redis中下次取直接拿缓存即可防止多次生成
String ticket = jsonObject.getString("ticket");
redisTemplate.opsForValue().set(redisKey, ticket, jsonObject.getIntValue("expires_in"), TimeUnit.SECONDS);
return ticket;
} catch (Exception e) {
WXPayUtil.getLogger().error(e.getMessage(), e);
}
return null;
}
/**
* api_ticket api
* https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi
*
* @param access_token token
* @return api_ticket json obj
* @author yclimb
* @date 2018/9/25
*/
public String getWxApiTicket(String access_token) {
if (StringUtils.isBlank(access_token)) {
return null;
}
try {
// redis key
String redisKey = RedisKeyUtil.keyBuilder(RedisKeyEnum.IMALL_WX_APITICKET, access_token);
// 从redis中获取缓存
Object obj = redisTemplate.opsForValue().get(redisKey);
if (obj != null) {
return obj.toString();
}
// 获取 api_ticket
String api_ticket = restTemplate.getForObject(WeChatURL.BASE_JSAPI_TICKET, String.class, access_token);
WXPayUtil.getLogger().info("getWxApiTicket:api_ticket:{}", api_ticket);
if (StringUtils.isBlank(api_ticket)) {
return null;
}
JSONObject jsonObject = JSON.parseObject(api_ticket);
if (0 != jsonObject.getIntValue("errcode")) {
return null;
}
// 设置到redis中下次取直接拿缓存即可防止多次生成
String ticket = jsonObject.getString("ticket");
redisTemplate.opsForValue().set(redisKey, ticket, jsonObject.getIntValue("expires_in"), TimeUnit.SECONDS);
return ticket;
} catch (Exception e) {
WXPayUtil.getLogger().error(e.getMessage(), e);
}
return null;
}
/**
* IDcardList
*
* @param cardId ID
* @return cardList
* @author yclimb
* @date 2018/9/21
*/
public JSONArray getCardList(String cardId) {
if (StringUtils.isBlank(cardId)) {
return null;
}
try {
// 获取[爱上悦店]公众号的 access_token
String accessToken = this.getAccessToken(WXConstants.WX_MINI_PROGRAM_CODE);
String timestamp = String.valueOf(WXPayUtil.getCurrentTimestamp());
String nonce_str = WXPayUtil.generateNonceStr();
// 卡券的扩展参数。需进行 JSON 序列化为字符串传入
JSONObject cardExt = new JSONObject();
//cardExt.put("code", "");
//cardExt.put("openid", "");
//cardExt.put("fixed_begintimestamp", "");
//cardExt.put("outer_str", "");
cardExt.put("timestamp", timestamp);
cardExt.put("nonce_str", nonce_str);
/**
* 1. api_tickettimestampcard_idcodeopenidnonce_strvalue
* 2.sha1signature
* 3.signaturetimestampnoncecard_exttimestampnonce_str
*/
Map<String, String> map = new HashMap<>(8);
//map.put("code", "");
//map.put("openid", "");
map.put("api_ticket", this.getWxCardApiTicket(accessToken));
map.put("timestamp", timestamp);
map.put("card_id", cardId);
map.put("nonce_str", nonce_str);
cardExt.put("signature", WXPayUtil.SHA1(WXPayUtil.dictionaryOrder(map, 2)));
// 卡券对象
JSONObject cardInfo = new JSONObject();
cardInfo.put("cardId", cardId);
cardInfo.put("cardExt", cardExt.toJSONString());
// 需要添加的卡券列表
JSONArray cardList = new JSONArray(1);
cardList.add(cardInfo);
return cardList;
} catch (Exception e) {
WXPayUtil.getLogger().error(e.getMessage(), e);
}
return null;
}
/**
*
*
* @param requestUrl
* @param appid appid
* @param code code
* @return mapnoncestr:timestampappid;Id;signature:
* @author yclimb
* @date 2018/9/25
*/
public Map<String, Object> getSignature(String requestUrl, String appid, String code) {
Map<String, Object> map = new HashMap<>();
try {
// 获取公众号的 access_token、jsapi_ticket
String accessToken = this.getAccessToken(code);
String jsapi_ticket = this.getWxApiTicket(accessToken);
String nonce_str = WXPayUtil.generateNonceStr();
String timestamp = Long.toString(WXPayUtil.getCurrentTimestamp());
// 注意这里参数名必须全部小写,且必须有序
String dataStr = "jsapi_ticket=" + jsapi_ticket +
"&noncestr=" + nonce_str +
"&timestamp=" + timestamp +
"&url=" + requestUrl;
WXPayUtil.getLogger().info(dataStr);
String signature = WXPayUtil.SHA1(dataStr);
map.put("noncestr", nonce_str);
map.put("timestamp", timestamp);
map.put("appid", appid);
map.put("signature", signature);
} catch (Exception e) {
WXPayUtil.getLogger().error(e.getMessage(), e);
}
return map;
}
}

View File

@ -0,0 +1,389 @@
package controller;
import com.weixin.pay.WXPay;
import com.weixin.pay.WXPayConfigImpl;
import com.weixin.pay.XxxWXPayConfigImpl;
import com.weixin.pay.util.WXPayUtil;
import com.weixin.pay.util.WXUtils;
import java.util.HashMap;
import java.util.Map;
/**
*
*/
public class TestWXPay {
private WXPay wxpay;
private WXPayConfigImpl config;
private String out_trade_no;
private String total_fee;
public TestWXPay() throws Exception {
config = WXPayConfigImpl.getInstance();
// wxpay = new WXPay(config);
wxpay = new WXPay(config, true, true);
total_fee = "1.01";
// out_trade_no = "201701017496748980290321";
out_trade_no = "20180912004";
}
/**
*
* @param url
*/
private void getWeixinMap(String url) {
/*Map<String, Object> map = new HashMap<>();
try {
map = WXSignatureUtil.getSignature(request, url);
} catch (IOException | CloneNotSupportedException e) {
e.printStackTrace();
System.out.println("获取微信签名信息异常!" + e.getMessage());
}
model.addAttribute("noncestr", map.get("noncestr"));
model.addAttribute("timestamp", map.get("timestamp"));
model.addAttribute("appid", map.get("appid"));
model.addAttribute("signature", map.get("signature"));*/
}
/**
*
*/
private void getWeixinMap() {
getWeixinMap(getRequestURL());
}
private String getRequestURL() {
String url = null;
/*if (null == request.getQueryString()) {
url = request.getRequestURL().toString();
} else {
url = request.getRequestURL() + "?" + request.getQueryString();
}*/
return url;
}
/**
*
*/
private void doUnifiedOrder() throws Exception {
WXPay wxPay = new WXPay(WXPayConfigImpl.getInstance());
Map<String, String> resultMap = wxPay.unifiedOrder("https://api.uat.iyuedian.com/iyd-imall-manage/imall/v1/weixin/pay/wxnotify",
"oPR7T5PFjcfgugIu2abQG6ijQGV4", "悦店-测试商品", WXPayUtil.getPayNo(), "10.01", "127.0.0.1",
"vip", "",null,null);
String prepay_id = resultMap.get("prepay_id");
String nonce_str = resultMap.get("nonce_str");
Map<String, String> map = wxPay.chooseWXPayMap(prepay_id, nonce_str);
System.out.println("map:" + map);
}
private void doOrderClose() {
System.out.println("关闭订单");
HashMap<String, String> data = new HashMap<String, String>();
data.put("out_trade_no", out_trade_no);
try {
Map<String, String> r = wxpay.closeOrder(data);
System.out.println(r);
} catch (Exception e) {
e.printStackTrace();
}
}
private void doOrderQuery() {
System.out.println("查询订单");
HashMap<String, String> data = new HashMap<String, String>();
data.put("out_trade_no", out_trade_no);
// data.put("transaction_id", "4008852001201608221962061594");
try {
Map<String, String> r = wxpay.orderQuery(data);
System.out.println(r);
} catch (Exception e) {
e.printStackTrace();
}
}
private void doOrderReverse() {
System.out.println("撤销");
HashMap<String, String> data = new HashMap<String, String>();
data.put("out_trade_no", out_trade_no);
// data.put("transaction_id", "4008852001201608221962061594");
try {
Map<String, String> r = wxpay.reverse(data);
System.out.println(r);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
*
*/
private void doShortUrl() {
String long_url = "weixin://wxpay/bizpayurl?pr=etxB4DY";
HashMap<String, String> data = new HashMap<String, String>();
data.put("long_url", long_url);
try {
Map<String, String> r = wxpay.shortUrl(data);
System.out.println(r);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 退
*
*/
private void doRefund() {
HashMap<String, String> data = new HashMap<String, String>();
data.put("out_trade_no", out_trade_no);
data.put("out_refund_no", out_trade_no);
data.put("total_fee", total_fee);
data.put("refund_fee", total_fee);
data.put("refund_fee_type", "CNY");
data.put("op_user_id", config.getMchID());
try {
Map<String, String> r = wxpay.refund(data);
System.out.println(r);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 退
*
*/
private void doRefundQuery() {
HashMap<String, String> data = new HashMap<String, String>();
data.put("out_trade_no", out_trade_no);
//data.put("transactionId", out_trade_no);
data.put("out_refund_no", out_trade_no);
//data.put("refund_id", out_trade_no);
try {
Map<String, String> r = wxpay.refundQuery(data);
System.out.println(r);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
*
*/
private void doDownloadBill() {
HashMap<String, String> data = new HashMap<String, String>();
data.put("bill_date", "20161102");
data.put("bill_type", "ALL");
try {
Map<String, String> r = wxpay.downloadBill(data);
System.out.println(r);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* sandbox_signkey
*
* @author yclimb
* @date 2018/9/18
*/
private void doGetSandboxSignKey() throws Exception {
WXPayConfigImpl config = WXPayConfigImpl.getInstance();
HashMap<String, String> data = new HashMap<String, String>();
data.put("mch_id", config.getMchID());
data.put("nonce_str", WXPayUtil.generateNonceStr());
String sign = WXPayUtil.generateSignature(data, config.getKey());
data.put("sign", sign);
WXPay wxPay = new WXPay(config);
// String result = wxPay.requestWithoutCert("https://api.mch.weixin.qq.com/sandbox/pay/getsignkey", data, 10000, 10000);
String result = wxPay.requestWithoutCert("/sandboxnew/pay/getsignkey", data, 10000, 10000);
System.out.println(result);
}
private void doReport() {
HashMap<String, String> data = new HashMap<String, String>();
data.put("interface_url", "20160822");
data.put("bill_type", "ALL");
}
/**
*
*/
private void test001() {
String xmlStr="<xml><return_code><![CDATA[SUCCESS]]></return_code>\n" +
"<return_msg><![CDATA[OK]]></return_msg>\n" +
"<appid><![CDATA[wx273fe72f2db863ed]]></appid>\n" +
"<mch_id><![CDATA[1228845802]]></mch_id>\n" +
"<nonce_str><![CDATA[lCXjx3wNx45HfTV2]]></nonce_str>\n" +
"<sign><![CDATA[68D7573E006F0661FD2A77BA59124E87]]></sign>\n" +
"<result_code><![CDATA[SUCCESS]]></result_code>\n" +
"<openid><![CDATA[oZyc_uPx_oed7b4q1yKmj_3M2fTU]]></openid>\n" +
"<is_subscribe><![CDATA[N]]></is_subscribe>\n" +
"<trade_type><![CDATA[NATIVE]]></trade_type>\n" +
"<bank_type><![CDATA[CFT]]></bank_type>\n" +
"<total_fee>1</total_fee>\n" +
"<fee_type><![CDATA[CNY]]></fee_type>\n" +
"<transaction_id><![CDATA[4008852001201608221983528929]]></transaction_id>\n" +
"<out_trade_no><![CDATA[20160822162018]]></out_trade_no>\n" +
"<attach><![CDATA[]]></attach>\n" +
"<time_end><![CDATA[20160822202556]]></time_end>\n" +
"<trade_state><![CDATA[SUCCESS]]></trade_state>\n" +
"<cash_fee>1</cash_fee>\n" +
"</xml>";
try {
System.out.println(xmlStr);
System.out.println("+++++++++++++++++");
System.out.println(WXPayUtil.isSignatureValid(xmlStr, config.getKey()));
Map<String, String> hm = WXPayUtil.xmlToMap(xmlStr);
System.out.println("+++++++++++++++++");
System.out.println(hm);
System.out.println(hm.get("attach").length());
} catch (Exception e) {
e.printStackTrace();
}
}
private void testUnifiedOrderSpeed() throws Exception {
TestWXPay dodo = new TestWXPay();
for (int i=0; i<100; ++i) {
long startTs = System.currentTimeMillis();
out_trade_no = out_trade_no+i;
dodo.doUnifiedOrder();
long endTs = System.currentTimeMillis();
System.out.println(endTs-startTs);
Thread.sleep(1000);
}
}
/**
*
*
* @author yclimb
* @date 2018/9/18
*/
public void doTranster() throws Exception {
// 微信调用接口
WXPay wxPay = new WXPay(WXPayConfigImpl.getInstance());
Map<String, String> resultMap = wxPay.transfers("1507928321201809301504246520",
"oPR7T5DWvXuhfKfyqNdi6MTQGaxo", "1.9", "测试退款", "127.0.0.1");
System.out.println("wxPay.transfers:" + resultMap);
}
/**
*
*
* @author yclimb
* @date 2018/9/18
*/
private void sendRedPack() throws Exception {
WXPay wxPay = new WXPay(WXPayConfigImpl.getInstance());
wxPay.sendRedPack(WXPayUtil.getPayNo(), "obX_c0YRpT47zKcvq-ZYpjU6GFuA", "1",
"活动名称", "红包祝福语", "备注", "127.0.0.1");
}
/**
*
*
* @author yclimb
* @date 2018/9/18
*/
private void getRedPackInfo() throws Exception {
WXPay wxPay = new WXPay(WXPayConfigImpl.getInstance());
wxPay.getRedPackInfo("1507928321201809171554055254");
}
/**
*
*
* @author yclimb
* @date 2018/9/18
*/
private void sendCoupon() throws Exception {
WXPay wxPay = new WXPay(WXPayConfigImpl.getInstance());
wxPay.sendCoupon("9248266", WXPayUtil.getPayNo(), "obX_c0YRpT47zKcvq-ZYpjU6GFuA");
}
/**
*
*
* @author yclimb
* @date 2018/9/18
*/
private void queryCouponsInfo() throws Exception {
WXPay wxPay = new WXPay(XxxWXPayConfigImpl.getInstance());
wxPay.queryCouponsInfo("3983069127", "9248266", "obX_c0YRpT47zKcvq-ZYpjU6GFuA");
}
/**
*
*
* @author yclimb
* @date 2018/9/18
*/
private void queryCouponStock() throws Exception {
WXPay wxPay = new WXPay(XxxWXPayConfigImpl.getInstance());
wxPay.queryCouponStock("9248266");
}
/**
*
*
* @author yclimb
* @date 2018/9/18
*/
private void createCardActivity() {
WXUtils wxUtils = new WXUtils();
wxUtils.createCardActivity("2018-09-18 18:00:00", "2018-09-18 19:59:59", 3, 1,
1, "pX2-vjpU_MT1gFDsP8lNl15PdaZE", "100",
null, false);
}
public static void main(String[] args) throws Exception {
System.out.println("--------------->");
TestWXPay dodo = new TestWXPay();
//dodo.doGetSandboxSignKey();
//dodo.doOrderQuery();
//dodo.doRefundQuery();
//dodo.doDownloadBill();
//dodo.sendRedPack();
//dodo.getRedPackInfo();
//dodo.sendCoupon();
//dodo.queryCouponsInfo();
//dodo.queryCouponStock();
//dodo.createCardActivity();
//dodo.doUnifiedOrder();
dodo.doTranster();
// 沙箱环境测试
//WXPay wxPay = new WXPay(WXPayConfigImpl.getInstance(), true, true);
//WXPay wxPay = new WXPay(ChunboWXPayConfigImpl.getInstance());
/*Map<String, String> resultMap = wxPay.refund("http://127.0.0.1:11000/weixin/pay/wxnotify", null,
"20180912004", "20180912004", "5.52", "5.52", "测试退款");*/
//System.out.println(resultMap);
/*Map<String, String> resultMap = wxPay.refund(null, "10000", "10001", "1.01", "0.01", "测试微信退款");
System.out.println(WXPayUtil.isSignatureValid(resultMap, WXPayConstants.API_KEY));*/
System.out.println("<---------------");
}
}