1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > JSAPI微信公众号apiV3文档支付

JSAPI微信公众号apiV3文档支付

时间:2020-11-20 05:38:44

相关推荐

JSAPI微信公众号apiV3文档支付

文章目录

一.所需参数及maven依赖二.前端vue部分三.后端java部分

一.所需参数及maven依赖

官方文档

1.公众号id appid

2.商户号 mchid

3.APIv3秘钥 secret

4.商户api私钥 apiclient_key.pem

5.证书序列号

maven依赖

<!-- 微信支付V3版sdk --><dependency><groupId>com.github.wechatpay-apiv3</groupId><artifactId>wechatpay-apache-httpclient</artifactId><version>0.2.1</version></dependency>


二.前端vue部分

// 确认支付onSubmit() {// 手机端校验if (!navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)) {this.$dialog.alert({message: '请在手机端微信关注公众号"跃迁赋能中心"进行购买' })return}// TODO 购买商品参数拼接、非空校验let that = thisthis.$api.request({url: '/wxpay/pay',method: 'post',params: params}).then(response => {// 拉起微信支付参数赋值that.payMap = response.dataif (typeof WeixinJSBridge === 'undefined') {if (document.addEventListener) {document.addEventListener('WeixinJSBridgeReady', this.onBridgeReady, false)} else if (document.attachEvent) {document.attachEvent('WeixinJSBridgeReady', this.onBridgeReady)document.attachEvent('onWeixinJSBridgeReady', this.onBridgeReady)}} else {this.onBridgeReady()}})},// 拉起微信支付onBridgeReady() {let payMap = this.payMaplet that = thisWeixinJSBridge.invoke('getBrandWCPayRequest', {'appId': payMap.appId, // 公众号名称,由商户传入'timeStamp': payMap.timeStamp, // 时间戳,自1970年以来的秒数'nonceStr': payMap.nonceStr, // 随机串'package': payMap.package,'signType': payMap.signType, // 微信签名方式:'paySign': payMap.paySign // 微信签名},function(res) {if (res.err_msg == 'get_brand_wcpay_request:ok') {// 付款成功处理that.$router.replace({path: '/' })}})},

三.后端java部分

3.1 获取前端拉起微信支付参数

Controller

@ApiOperation("微信公众号支付")@PostMapping("/pay")public AjaxResult pay(HttpServletRequest request, @RequestParam(required = false) String miniIdStr,@RequestParam Double payAmount, @RequestParam String couponIdStr,@RequestParam(required = false) Long courseId) {Long personId = tokenService.getPersonId(request);// TODO 购买课程参数校验try {JSONObject result = officeOrderService.wxPay(personId, miniIdStr, payAmount, couponIdStr, courseId);Integer status = result.getInteger("status");if (status != null && status == 0) {// 支付失败不反回前端拉起微信支付参数return AjaxResult.error("支付失败,请稍后再试");}return AjaxResult.success(result);} catch (Exception e) {log.error("微信支付下单接口失败,personId:{},miniIdStr:{},payAmount:{},couponIdStr:{},courseId:{}", personId,miniIdStr, payAmount, couponIdStr, courseId, e);return AjaxResult.error("支付失败,请稍后再试");}}

Service

@Overridepublic JSONObject wxPay(Long personId, String miniIdStr, Double payAmount, String couponIdStr, Long courseId) {// 根据personId获取公众号openIdString openId = wxLoginMapper.selectOpenIdByPersonId(personId);// 生成商品订单号String orderNumber = UUID.randomUUID().toString().replace("-", "");// TODO 查询购买课程信息// 返回前端数据集合JSONObject payMap = new JSONObject();// TODO 校验优惠券与购买课程是否相符(不符返回支付失败)// TODO 查询优惠券信息BigDecimal totalVal = BigDecimal.ZERO;// TODO 计算订单金额 填充生成本地订单数据(存入本地数据库的订单)Double total = totalVal.doubleValue();// 校验订单金额if (!total.equals(payAmount)) {log.error("订单金额不符,personId:{},miniIdStr:{},payAmount:{},couponIdStr:{},total:{}", personId, miniIdStr,payAmount, couponIdStr, total);payMap.put("status", 0);return payMap;}// 支付金额大于0时调用微信支付if (total > 0) {// 拼接统一下单参数JSONObject params = new JSONObject();params.put("appid", WxConstants.OFFICIAL_APPID);params.put("mchid", WxConstants.PAY_MCH_ID);params.put("description", "课程购买");params.put("notify_url", "/office/wxpay/payNotify");params.put("out_trade_no", orderNumber);// 商品金额JSONObject amount = new JSONObject();amount.put("total", totalVal.multiply(new BigDecimal(100)).intValue());log.info("订单金额:" + amount.get("total"));params.put("amount", amount);// 支付者JSONObject payer = new JSONObject();payer.put("openid", openId);params.put("payer", payer);// 发送微信预支付订单请求String prepayId = WxPayUtils.sendPay(params);if (StringUtils.isBlank(prepayId)) {// 生成预支付订单id失败(发送微信下单请求)log.error("生成预支付订单id失败,params:{}", params);payMap.put("status", 0);return payMap;}// 填充返回前端数据 注:返回前端的timeStamp与nonceStr字段必须与生成签名的一致 否则前端验签失败payMap.put("appId", WxConstants.OFFICIAL_APPID);long timestamp = System.currentTimeMillis() / 1000;payMap.put("timeStamp", timestamp + "");String nonceStr = WxPayUtils.generateNonceStr();payMap.put("nonceStr", nonceStr);payMap.put("package", "prepay_id=" + prepayId);payMap.put("signType", "RSA");// 生成请求签名String paySign = WxPayUtils.getPaySign(nonceStr, timestamp, payMap.getString("package"));payMap.put("paySign", paySign);} else {// 订单金额为0时返回status为1(按支付成功处理)payMap.put("status", 1);}// TODO 添加本地数据库订单信息return payMap;}

WxPayUtils工具类

package mon.utils.wxpay;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.UnsupportedEncodingException;import java.nio.charset.StandardCharsets;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.security.PrivateKey;import java.security.PublicKey;import java.security.SecureRandom;import java.security.Signature;import java.security.SignatureException;import java.security.cert.X509Certificate;import java.util.Base64;import java.util.Random;import javax.servlet.http.HttpServletRequest;import org.apache.http.HttpResponse;import org.apache.http.client.HttpClient;import org.apache.http.client.methods.HttpPost;import org.apache.http.entity.StringEntity;import org.apache.http.util.EntityUtils;import org.springframework.core.io.ClassPathResource;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;import mon.constant.WxConstants;import lombok.extern.slf4j.Slf4j;/*** 微信支付工具类* * @author suihao* @create -10-22 16:51*/@Slf4jpublic class WxPayUtils {/*** 发送微信预支付订单请求* * @param params* @return* @throws IOException*/public static String sendPay(JSONObject params) {try {// 读取证书私钥PrivateKey privateKey = PemUtil.loadPrivateKey(new ClassPathResource("apiclient_key.pem").getInputStream());// 不需要传入微信支付证书,将会自动更新AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(new WechatPay2Credentials(WxConstants.PAY_MCH_ID,new PrivateKeySigner(WxConstants.PAY_SERIAL_NO, privateKey)),WxConstants.PAY_SECRET_V3.getBytes(StandardCharsets.UTF_8.name()));// 创建http请求HttpClient client = WechatPayHttpClientBuilder.create().withMerchant(WxConstants.PAY_MCH_ID, WxConstants.PAY_SERIAL_NO, privateKey).withValidator(new WechatPay2Validator(verifier)).build();// 配置http请求参数HttpPost post = new HttpPost("https://api.mch./v3/pay/transactions/jsapi");post.setHeader("Content-Type", "application/json");post.setHeader("Accept", "application/json");post.setEntity(new StringEntity(params.toJSONString(), "utf-8"));// 获取请求结果HttpResponse response = client.execute(post);// System.out.println("响应码:" + response.getStatusLine());// System.out.println("响应body体:" + EntityUtils.toString(response.getEntity()));JSONObject jo = JSON.parseObject(EntityUtils.toString(response.getEntity()));// 预支付订单生成失败(微信端订单)if (response.getStatusLine().getStatusCode() != 200) {log.error("发送微信预支付订单请求失败:" + jo.getString("message") + ",params:{}", params);return null;}// 获取预支付订单idreturn jo.getString("prepay_id");} catch (IOException e) {log.error("发送微信预支付订单请求失败,params:{}", params, e);return null;}}/*** 获取调起微信支付签名* * @param nonceStr* @param timestamp* @param prepayId* @return*/public static String getPaySign(String nonceStr, long timestamp, String prepayId) {String message = WxConstants.OFFICIAL_APPID + "\n" + timestamp + "\n" + nonceStr + "\n" + prepayId + "\n";String signature = null;try {signature = sign(message.getBytes(StandardCharsets.UTF_8.name()), "apiclient_key.pem");} catch (UnsupportedEncodingException e) {log.error("生成微信支付签名失败,message:{}", message, e);}return signature;}/*** 读取请求体中数据* * @param request* @return*/public static String readData(HttpServletRequest request) {BufferedReader br = null;try {StringBuilder result = new StringBuilder();String line;for (br = request.getReader(); (line = br.readLine()) != null; result.append(line)) {if (result.length() > 0) {result.append("\n");}}line = result.toString();return line;} catch (IOException e) {throw new RuntimeException(e);} finally {if (br != null) {try {br.close();} catch (IOException e) {log.error("关闭字符输入流失败", e);}}}}/*** 微信支付回调签名验证并对加密请求参数解密** @param serialNo* @param result* @param signatureStr* @param nonce* @param timestamp* @param paySecretV3* @return*/public static String verifyNotify(String serialNo, String result, String signatureStr, String nonce,String timestamp, String paySecretV3) throws Exception {// 读取证书私钥PrivateKey privateKey = PemUtil.loadPrivateKey(new ClassPathResource("apiclient_key.pem").getInputStream());// 获取平台证书AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(new WechatPay2Credentials(WxConstants.PAY_MCH_ID,new PrivateKeySigner(WxConstants.PAY_SERIAL_NO, privateKey)),WxConstants.PAY_SECRET_V3.getBytes(StandardCharsets.UTF_8.name()));X509Certificate certificate = verifier.getValidCertificate();// 证书序列号String serialNumber = certificate.getSerialNumber().toString(16).toUpperCase();// 证书验证if (serialNumber.equals(serialNo)) {// 构造验签名串String buildSignMessage = timestamp + "\n" + nonce + "\n" + result + "\n";// 获取平台公钥PublicKey publicKey = certificate.getPublicKey();Signature signature = Signature.getInstance("SHA256WithRSA");signature.initVerify(publicKey);signature.update(buildSignMessage.getBytes(StandardCharsets.UTF_8));boolean verifySignature =signature.verify(Base64.getDecoder().decode(signatureStr.getBytes(StandardCharsets.UTF_8)));if (verifySignature) {JSONObject resultObject = JSON.parseObject(result);JSONObject resource = resultObject.getJSONObject("resource");String cipherText = resource.getString("ciphertext");String nonceStr = resource.getString("nonce");String associatedData = resource.getString("associated_data");AesUtil aesUtil = new AesUtil(paySecretV3.getBytes(StandardCharsets.UTF_8));return aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8),nonceStr.getBytes(StandardCharsets.UTF_8), cipherText);}}return null;}/** 对字节数据进行私钥签名(加密) */private static String sign(byte[] message, String serialPath) {try {// 签名方式(固定SHA256withRSA)Signature sign = Signature.getInstance("SHA256withRSA");// 使用私钥进行初始化签名(私钥需要从私钥文件【证书】中读取)InputStream inputStream = new ClassPathResource(serialPath).getInputStream();sign.initSign(PemUtil.loadPrivateKey(inputStream));// 签名更新sign.update(message);// 对签名结果进行Base64编码return Base64.getEncoder().encodeToString(sign.sign());} catch (SignatureException | InvalidKeyException | NoSuchAlgorithmException | IOException e) {log.error("微信支付进行私钥签名失败,message:{}", message, e);}return null;}/*** 获取随机字符串 Nonce Str* 随机字符从symbols获取* SecureRandom真随机数* * @return String 随机字符串*/public static String generateNonceStr() {String symbols = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";Random random = new SecureRandom();char[] nonceChars = new char[32];for (int index = 0; index < nonceChars.length; ++index) {nonceChars[index] = symbols.charAt(random.nextInt(symbols.length()));}return new String(nonceChars);}}

3.2 用户支付成功回调

@ApiOperation("微信公众号支付回调")@RequestMapping("/payNotify")public void payNotify(HttpServletRequest request, HttpServletResponse response) {JSONObject resObj = new JSONObject();String plainText = null;try {// 获取回调请求头String timestamp = request.getHeader("Wechatpay-Timestamp");String nonce = request.getHeader("Wechatpay-Nonce");String serialNo = request.getHeader("Wechatpay-Serial");String signature = request.getHeader("Wechatpay-Signature");// 获取回调支付密文String result = WxPayUtils.readData(request);// 验证签名并对请求参数解密plainText =WxPayUtils.verifyNotify(serialNo, result, signature, nonce, timestamp, WxConstants.PAY_SECRET_V3);if (StringUtils.isNotBlank(plainText)) {JSONObject payResult = JSON.parseObject(plainText);// TODO 用户支付成功业务处理(更改本地订单支付状态、添加购买记录、删除购物车内对应商品)// 注: 业务处理应先查本地数据库订单支付状态 未处理时再进行后面业务处理 微信支付可能会多次调用回调接口response.setStatus(200);resObj.put("code", "SUCCESS");resObj.put("message", "SUCCESS");} else {log.warn("签名校验失败");response.setStatus(500);resObj.put("code", "ERROR");resObj.put("message", "签名错误");}// 响应请求结果response.setHeader("Content-type", "application/json");response.getOutputStream().write(resObj.toJSONString().getBytes(StandardCharsets.UTF_8));response.flushBuffer();} catch (Exception e) {log.error("微信支付回调接口处理失败,plainText:{}", plainText, e);}}

第一次写博文,去掉了业务处理部分,尽量使其简化,写的不好多见谅。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。