接入前准备
对接支付
开发准备
- 下载对应的开发库wechatpay-apache-httpclient,或者到微信的官方文档点击链接下载
- appId(小程序中获取)
- appSecret(小程序中获取)
- openId(登录获取)
- mchId-商户号(商户平台中获取)
- mchSerialNo-商户证书序列号(商户平台中获取)
- gateway-预支付网关(微信的官方获取)
如下:https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi - apiV3Key-商户私钥(自己设置)
- 证书私钥
时序图
着手开发
- 从第四步开始,我们需要向微信服务器推送一个预支付订单,在生成订单之前,我们需要做三件事:加载商户私钥、加载平台证书、初始化httpClient,需要替换调其中的参数。
@Before
public void setup() throws IOException {
// 加载商户私钥(privateKey:私钥字符串)
PrivateKey merchantPrivateKey = PemUtil
.loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));
// 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3密钥)
AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)),apiV3Key.getBytes("utf-8"));
// 初始化httpClient
httpClient = WechatPayHttpClientBuilder.create()
.withMerchant(mchId, mchSerialNo, merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier)).build();
}
@After
public void after() throws IOException {
httpClient.close();
}
- 生成预支付订单,此时我们就拿到了prepay_id,务必要保证参数的正确性,否则会出现“验签失败”的错误
/**
* 创建预支付订单
*/
@Test
public void CreateOrder() throws Exception {
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode rootNode = objectMapper.createObjectNode();
rootNode.put("mchid", MerchantConstants.MCH_ID)
.put("appid", "wx-------------")
.put("description", "Tiger-test")
.put("notify_url", "https://www.weixin.qq.com/wxpay/pay.php")
.put("out_trade_no", IdUtils.simpleUUID());
rootNode.putObject("amount")
.put("total", 1);
rootNode.putObject("payer")
.put("openid", "-----------------");
objectMapper.writeValue(bos, rootNode);
httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
CloseableHttpResponse response = httpClient.execute(httpPost);
String bodyAsString = EntityUtils.toString(response.getEntity());
System.out.println(bodyAsString);
createSignature(bodyAsString);
}
- 生成带签名的支付信息,前端后端生成都可以,我选择后端生成,要注意signType = “RSA”,不要改成MD5
/**
* 生成带签名的支付信息
*
* @param prePayId 预支付ID
* @return
*/
public Map<String, String> createSignature(String prePayId) {
Map<String, String> prePayIdMap = JSON.parseObject(prePayId, new TypeReference<Map<String, String>>() {
});
String timestamp = System.currentTimeMillis() + "";
String randomString = IdUtils.simpleUUID();
StringBuilder paySign = new StringBuilder(); // 小程序签名
paySign.append(AppletConstants.APP_ID).append("\n");
paySign.append(timestamp).append("\n");
paySign.append(randomString).append("\n");
paySign.append(prePayIdMap.get("prepay_id")).append("\n");
HashMap<String, String> result = new HashMap<>();
result.put("appId", AppletConstants.APP_ID);
result.put("timeStamp", timestamp);
result.put("nonceStr", randomString);
result.put("package", prePayIdMap.get("prepay_id"));
result.put("signType", "RSA");
result.put("paySign", paySign.toString());
return result;
}
- 异步通知平台处理结果
@PostMapping("/applet/callback")
public synchronized Map callback(HttpServletRequest request) {
// 获取请求头
String wechatPayTimestamp = request.getHeader("Wechatpay-Timestamp"); // 时间戳
String wechatPayNonce = request.getHeader("Wechatpay-Nonce"); // 随机字符串
String wechatPaySignature = request.getHeader("Wechatpay-Signature"); // 应答签名
String wechatPaySerial = request.getHeader("Wechatpay-Serial"); // 序列号
// 给微信服务器返回的值
HashMap<String, String> result = new HashMap<>();
result.put("code", "FAIL");
try {
StringBuilder message = new StringBuilder(); // 请求报文
BufferedReader br = request.getReader();
String str = null;
StringBuilder builder = new StringBuilder();
while (true) {
if (!((str = br.readLine()) != null)) break;
builder.append(str);
}
// 构建报文
message.append(wechatPayTimestamp).append("\n");
message.append(wechatPayNonce).append("\n");
message.append(builder.toString()).append("\n");
// 验证签名
if (!new PayUtils().signVerify(wechatPaySerial, message.toString(), wechatPaySignature)) {
result.replace("code", "FAIL");
result.put("message", "签名错误");
return result;
}
// 解密
String decryptResult = PayUtils.decryptOrder(builder.toString());
if (StringUtils.isEmpty(decryptResult)) {
result.put("message", "解密失败");
return result;
}
// 验证订单,更新订单
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(decryptResult);
String orderId = jsonNode.get("out_trade_no").textValue();
Order order = new Order();
order.setId(orderId);
order.setOrderStatus("2"); // 配送中订单
orderService.updateOrder(order);
// 返回消息
result.replace("code", "SUCCESS");
result.put("message", "支付成功");
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
- 前端接收微信返回的支付信息,进行处理(跳转页面等)。
分享代付
同理,把这一系列过程放在支付接口
鸣谢
专治八阿哥的孟老师的微信支付V3版本视频,手把手教学,十分推荐