1、微信支付java-sdk,倒包
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
2、用到包中的类
WXPay:统一支付、订单查询、关闭、退款等 WXPayConfig: 微信支付配置信息商户号、appid等 WXPayUtil:微信支付工具类,xml/map互转,签名等
3、继承WxPayConfig重写配置信息
@Data
@Component
@ConfigurationProperties(prefix = "wx")
public class WxConfig implements WXPayConfig {
// appid,在 微信开放平台 添加的应用上的appid,注意appid和appSecert是成对出现的
private String appID;
// appid,在 微信开放平台 添加的应用上的appSecret,
// 也可以是小程序、公众号,如果有多个用别名做区别
private String appSecret;
// 微信商户平台 账户中心的商户号
private String mchID;
// 回调路径,http://www.123.com等,配置多个获取的时候根据支付、退款等方式获取对应的路径
private String notify_url;
// appkey 微信商户平台 API安全中配置的APIv2、APIv3
private String appKey;
// *****cert.p12文件路径,该文件在 微信商户平台 API安全中配置,与APIv2、APIv3位置一致
private String keyPath;
// 服务器ip
private String spbill_create_ip;
// 通过交易类型获取不同的appid
public String getTradeAppId(String tradeType) {
if (tradeType.equals(CommonEnum.WechatPayType.JSAPI.getCode())) {
return wechatAppId;
} else if (tradeType.equals(CommonEnum.WechatPayType.APP.getCode())) {
return appID;
}
return null;
}
// 通过交易类型获取不同的appSecret
public String getTradeKey(String tradeType) {
if (tradeType.equals(CommonEnum.WechatPayType.JSAPI.getCode())) {
return wechatSecret;
} else if (tradeType.equals(CommonEnum.WechatPayType.APP.getCode())) {
return appSecret;
}
return null;
}
@Override
public String getMchID() {
return mchID;
}
@Override
public String getKey() {
return appKey;
}
// 获取证书数据
@Override
public InputStream getCertStream() {
try {
File file = ResourceUtils.getFile(keyPath);
return new FileInputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
@Override
public int getHttpConnectTimeoutMs() {
return 3000;
}
@Override
public int getHttpReadTimeoutMs() {
return 3000;
}
4、yml配置
wx:
#商户 ID
mchID: 123456789
# app的APP_ID
appID: afadfadsfqwr
# APP的 秘钥
appSecret: 1234123412341234123
appKey: 1341234123412341234134
# 支付后地址
notify_url: http://www.123.com/wx/pay/notify
keyPath: classpath: ****cert.p12
spbill_create_ip: 192.168.0.1
支付demo
public AnmoResult unifiedorder(String orderNo, String amount, String tradeType, String body, String openId) {
log.info("---------------微信统一下单预支付---------------------");
if (StringUtils.isEmpty(amount) || Integer.valueOf(amount) <= 0) {
return AnmoResult.error("支付金额格式不正确");
}
if (StringUtils.isEmpty(tradeType)) {
return AnmoResult.error("交易类型不能为空");
}
Map<String, String> map = new HashMap<>(20);
map.put("appid", wxConfig.getAppID());
map.put("mch_id", wxConfig.getMchID());
map.put("nonce_str", WXPayUtil.generateNonceStr());
map.put("body", body);
map.put("out_trade_no", orderNo);
map.put("total_fee", amount);
map.put("spbill_create_ip", wxConfig.getSpbill_create_ip());
map.put("notify_url", wxConfig.getNotify_url());
map.put("trade_type", tradeType);
try {
Map<String, String> resultMap = wxPay.unifiedOrder(map);
log.info("-------------orderNo:{}-----微信预支付同步返回结果:{}", orderNo, resultMap);
// 判断返回的结果
String returnMsg = "";
String returnCode = resultMap.get("return_code");
if (!returnCode.equals("SUCCESS")) {
returnMsg = resultMap.get("return_msg");
return AnmoResult.error(returnMsg);
}
String resultCode = resultMap.get("result_code");
if (returnCode.equals(resultCode) && returnCode.equals("SUCCESS")) {
if (resultMap.get("return_msg").equals("FAIL")) {
String s = resultMap.get("err_code_des");
return AnmoResult.error(s);
}
String prepayId = resultMap.get("prepay_id");
String nonce_str = resultMap.get("nonce_str");
Map<String, String> obj = appSecondSign(nonce_str, prepayId);
return AnmoResult.success(obj);
}
return AnmoResult.error();
} catch (Exception e) {
e.printStackTrace();
log.info("-------------orderNo:{}---预支付失败", orderNo);
redisService.del(orderNo);
return AnmoResult.error("预支付失败");
}
}
/**
* app支付签名构建
* @param noncestr
* @param prepayid
* @return
* @throws Exception
*/
private Map<String, String> appSecondSign(String noncestr, String prepayid) throws Exception {
//生成签名(官方给出来的签名方法)
Map<String, String> map = new HashMap<>(20);
map.put("appid", wxConfig.getAppID());
map.put("partnerid", wxConfig.getMchID());
map.put("prepayid", prepayid);
map.put("package", "Sign=WXPay");
map.put("noncestr", noncestr);
map.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
String sign = WXPayUtil.generateSignature(map, wxConfig.getAppKey());
System.out.println(JSONObject.toJSONString(map));
map.put("sign", sign);
return map;
}
/**
* 小程序支付签名构建
* @param noncestr
* @param prepayid
* @return
* @throws Exception
*/
private Map<String, String> wechatSecondSign(String noncestr, String prepayid) throws Exception {
//生成签名(官方给出来的签名方法)
Map<String, String> map = new HashMap<>(20);
map.put("appId", wxConfig.getWechatAppId());
map.put("package", "prepay_id=" + prepayid);
map.put("nonceStr", noncestr);
map.put("signType", "MD5");
map.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
String sign = WXPayUtil.generateSignature(map, wxConfig.getAppKey());
System.out.println(JSONObject.toJSONString(map));
map.put("paySign", sign);
return map;
}
/**
* 微信二次签名为前端拉起支付做参数处理,签名方式要按照对应的支付方式进行签名,
* 当前为:APP支付签名
* @param noncestr
* @param prepayid
* @return
* @throws Exception
*/
private Map<String, String> secondSign(String noncestr, String prepayid) throws Exception {
//生成签名(官方给出来的签名方法)
Map<String, String> map = new HashMap<>(20);
map.put("appid", wxConfig.getAppID());
map.put("partnerid", wxConfig.getMchID());
map.put("prepayid", prepayid);
map.put("package", "Sign=WXPay");
map.put("noncestr", noncestr);
map.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
String sign = WXPayUtil.generateSignature(map, wxConfig.getAppKey());
System.out.println(JSONObject.toJSONString(map));
map.put("sign", sign);
return map;
}
注意:
主要变更
统一下单接口会从新从配置中读取appid、mchid和随机字符,所以在出现签名异常的时候不要用自己的签名去在工具中做匹配,要在统一下单微信的源码中
这个reqBody是最终给微信上送的数据结果,如果在工具中校验签名成功,在业务中失败,那么就是appKey也就是API v2/v3配置的秘钥有问题,牢记的事这个秘钥最长是32位,更新秘钥即可