官方文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_1.shtml
- 小程序开通微信支付
微信小程序集成参考最新先程序集成文档
yml配置:
x-pay:
v3:
#微信关联的小程序的appid
appId: wx281xxxxxxxxxxx
#微信支付商户号
mchId: 16480333333333
#微信支付证书序列号 在配置api证书的界面可以找到
serialnumber: 43442BF
#微信支付apiv3的密钥
apiKey3: D321123456789
#微信支付证书
certKeyPath: /home/key/apiclient_key.pem
#微信支付回调商户线上地址api
notifyUrl: https://cc/api/wxPay/notify
#微信支付关闭订单api
closeOrderUrl: https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}/close
#微信支付小程序预下单api
jsApiUrl: https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
#微信支付订单查询api
queryOrder: https://api.mch.weixin.qq.com/v3/pay/transactions/id/
配置类xie
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix="wx-pay.v3")
public class WxPayConfig {
//appId
private String appId;
//商户id
private String mchId;
//证书序列号
private String serialnumber;
//商户秘钥
private String apiKey3;
//商户的key【API密匙】存放路径
private String certKeyPath;
//回调通知地址
private String notifyUrl;
//jsapi预支付url
private String jsApiUrl;
//关闭订单接口
private String closeOrderUrl;
//查询订单地址
private String queryOrder;
}
servieImp实现
public class PayOrderServiceImpl extends ServiceImpl<PayOrderMapper, PayOrder> implements IPayOrderService {
@Autowired
private WxPayConfig wxPayConfig;
//生成签名用
private static Sign sign;
//证书管理器
private static CertificatesManager certificatesManager;
private static CloseableHttpClient httpClient;
//商户证书私钥
private PrivateKey merchantPrivateKey;
//证书
private Verifier verifier;
//初始化微信支付的参数
@PostConstruct
public void init() throws Exception {
logger.info("微信支付获取支付二维码path:{} input:{}", wxPayConfig.getCertKeyPath(), new FileInputStream(wxPayConfig.getCertKeyPath()));
//获取商户私钥
merchantPrivateKey = PemUtil.loadPrivateKey(new FileInputStream(wxPayConfig.getCertKeyPath()));
// 获取证书管理器实例
certificatesManager = CertificatesManager.getInstance();
sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, merchantPrivateKey.getEncoded(), null);
// 向证书管理器增加需要自动更新平台证书的商户信息
certificatesManager.putMerchant(wxPayConfig.getMchId(), new WechatPay2Credentials(wxPayConfig.getMchId(),
new PrivateKeySigner(wxPayConfig.getSerialnumber(), merchantPrivateKey)), wxPayConfig.getApiKey3().getBytes(StandardCharsets.UTF_8));
// 从证书管理器中获取verifier
verifier = certificatesManager.getVerifier(wxPayConfig.getMchId());
//用于构造HttpClient
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(wxPayConfig.getMchId(), wxPayConfig.getSerialnumber(), merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier));
httpClient = builder.build();
}
@Override
public AjaxResult prePay(PayOrder payOrder) {
logger.info("微信小程序支付JSAPI预下单开始------");
AjaxResult ajaxResult = AjaxResult.success();
JSONObject obj = new JSONObject();
//应用ID
obj.put("appid", wxPayConfig.getAppId());
//直连商户号
obj.put("mchid", wxPayConfig.getMchId());
//商品描述
obj.put("description", payOrder.getOrderRemark());
//商户订单号
obj.put("out_trade_no", payOrder.getTradeNo());
//通知地址
obj.put("notify_url", wxPayConfig.getNotifyUrl());
//附加数据 查询API和支付通知中原样返回,可作为自定义参数使用,实际情况下只有支付完成状态才会返回该字段。
Map<String, String> attach = new HashMap<>();
attach.put("orderCode", payOrder.getOrderName());
obj.put("attach", JSON.toJSONString(attach));
//订单金额
JSONObject amount = new JSONObject();
amount.put("total", payOrder.getOrderAmount().intValue());
obj.put("amount", amount);
//支付者
JSONObject payer = new JSONObject();
payer.put("openid", payOrder.getOpenId());
obj.put("payer", payer);
logger.info("微信小程序支付JSAPI预下单请求参数:{}" + obj.toJSONString());
HttpPost httpPost = new HttpPost(wxPayConfig.getJsApiUrl());
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
httpPost.setEntity(new StringEntity(obj.toJSONString(), "UTF-8"));
String bodyAsString;
try {
if (httpClient == null) {
logger.info("微信小程序支付JSAPI预下单请求失败");
return AjaxResult.error("预下单失败,请重试,无法连接微信支付服务器!");
}
//执行请求
CloseableHttpResponse response = httpClient.execute(httpPost);
bodyAsString = EntityUtils.toString(response.getEntity());
} catch (IOException e) {
logger.info("微信小程序支付JSAPI预下单请求失败{}", e.getMessage());
return AjaxResult.error("预下单失败,请重试!" + e.getMessage());
}
String prePayId = JSONObject.parseObject(bodyAsString).getString("prepay_id");
if (prePayId == null) {
String message = JSONObject.parseObject(bodyAsString).getString("message");
logger.info("微信小程序支付JSAPI预下单请求失败{}", message);
return AjaxResult.error("预下单失败,请重试!" + message);
}
//准备小程序端的请求参数
ajaxResult.put("appId", wxPayConfig.getAppId());
String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
ajaxResult.put("timeStamp", timeStamp);
String nonceStr = IdUtil.fastSimpleUUID();
ajaxResult.put("nonceStr", nonceStr);
String packageStr = "prepay_id=" + prePayId;
ajaxResult.put("package", packageStr);
ajaxResult.put("signType", "MD5");
String signString = wxPayConfig.getAppId() + "\n" + timeStamp + "\n" + nonceStr + "\n" + packageStr + "\n";
//ajaxResult.put("paySign", (sign.sign(signString.getBytes())));
// 公共参数
Map<String, Object> resMap = new HashMap<>();
resMap.put("nonceStr", nonceStr);
resMap.put("timeStamp", timeStamp);
resMap.put("appId", wxPayConfig.getAppId());
resMap.put("package", packageStr);
// 使用字段appId、timeStamp、nonceStr、package进行签名
String paySign = signRSA(signString);
ajaxResult.put("paySign", paySign);
return ajaxResult;
}
/**
* 微信支付v3签名 RSA签名
*
* @param message 要签名的字符串
* @return
*/
public String signRSA(String message) {
try {
Signer signer = new PrivateKeySigner(wxPayConfig.getSerialnumber(), merchantPrivateKey);
Signer.SignatureResult signature = signer.sign(message.getBytes(StandardCharsets.UTF_8));
return signature.getSign();
} catch (Exception e) {
e.printStackTrace();
logger.error("签名出错:{}", e);
return "";
}
}
}
controler代码:
/**
* 微信支付统一下单接口
*/
@Log(title = "统一下单", businessType = BusinessType.INSERT)
@PostMapping("/unifiedOrder")
public AjaxResult unifiedOrder(@RequestBody PayOrder payOrder,
HttpServletRequest request) {
logger.info("payOrder:{} request:{}", payOrder, request);
String openId = payOrder.getOpenId();
if (StringUtils.isEmpty(openId)) {
return AjaxResult.error("openId不能为空");
}
String redisKey = "h5_order_add" + openId;
String redisValue = openId + "_" + System.currentTimeMillis();
try {
redisCache.lock(redisKey, redisValue, 60);
// 1、验证订单是否存在
//根据订单号查询出订单信息
QueryWrapper<PayOrder> wrapper = new QueryWrapper<>();
wrapper.eq("trade_no", payOrder.getTradeNo());
wrapper.eq("order_status", OrderStatusEnum.PENDING_PAYMENT.getStatus());
PayOrder payOrder1 = iPayOrderService.getOne(wrapper);
if (payOrder1 == null) {
String orderNo = TenpayUtil.getTradeNoByPhone();
payOrder.setTradeNo(orderNo);
//更新创建人和时间
//payOrder.setCreateBy(LoginHelper.getUserId());
payOrder.setCreateTime(new Date());
payOrder.setOrderAmount(payOrder.getOrderAmount());
//payOrder.setOrderUid(LoginHelper.getUserId());
}
payOrder.setOrderUserName(payOrder.getOpenId());
payOrder.setPayWay(1L);
//支付品牌为余额
payOrder.setPayBrand(1L);
//消费类型为通话
payOrder.setConsumeType(2L);
//套餐操作类型 1为购买
payOrder.setOperateType(1L);
//状态为未付款
payOrder.setOrderStatus(OrderStatusEnum.PENDING_PAYMENT.getStatus());
iPayOrderService.saveOrUpdate(payOrder);
// 2、开始微信支付统一下单
//ResultMap resultMap = wxPayService.unifiedOrder(orderNo, orderNo, body);
return iPayOrderService.prePay(payOrder);
//return iPayOrderService.unifiedOrder(payOrder.getOpenId(),payOrder.getTradeNo(), payOrder.getOrderAmount(), payOrder.getOrderName(), request);
} catch (Exception e) {
logger.error("unifiedOrder error:{}", e);
return AjaxResult.error("运行异常,请联系管理员");
} finally {
try {
redisCache.unLock(redisKey, redisValue);
} catch (Exception e) {
e.printStackTrace();
}
}
}