1、小程序传递订单参数调用后端的支付订单接口
2、后端接口调用微信支付系统后生成6个必要参数返回给小程序
3、小程序调用wx.requestPayment拉起微信支付
4、用户支付后,微信支付系统调用后端回调接口
后端回调接口对具体的业务逻辑进行处理
com.github.javen205 IJPay-All 2.7.4
文件存放路径:src\main\resources\
#秘钥
v3.keyPath=opt/.../apiclient_key.pem
#CA证书 格式.pem
v3.certPath=opt/.../apiclient_cert.pem
#CA证书 格式.p12
v3.certP12Path=opt/.../apiclient_cert.p12
#平台证书路径
v3.platformCertPath=opy/.../wx_cert.pem#服务商id/商户id
v3.mchId=
#自定义 api 秘钥
v3.apiKey=
#自定义 apiv3 秘钥
v3.apiKey3=
#项目域名
v3.domain=#服务商/直连商户平台 关联的 公众号appid
v3.AppId=
#服务商/直连商户平台 关联的 公众号secret
v3.AppSecret=
将properties文件中属性的值赋值到WxPay类中
@Data
@Component
@PropertySource("classpath:weChatPay.properties")
@ConfigurationProperties(prefix = "v3")
public class WxPay {private String keyPath;private String certPath;private String certP12Path;private String platformCertPath;private String mchId;private String apiKey;private String apiKey3;private String domain;private String AppId;private String AppSecret;}
创建Controller类编写 获取微信支付唤起参数 接口
/*** 获取微信支付唤起参数* orderNumber: 订单号码*/@GetMapping(value = "/jsapiPay")public Object jsapiPay(String orderNumber){try {return wxPayService.jsapiPay(orderNumber);} catch (Exception e) {e.printStackTrace();}return null;}/*** 微信支付的回调接收接口*/@RequestMapping("/payNotify")public void payNotify(HttpServletRequest request, HttpServletResponse response) {wxPayService.payNotify(request,response);}
略过service层方法接口,展示的是方法的实现
@Overridepublic Map jsapiPay(String orderNumber) throws Exception{// 根据订单编号查询到订单记录,用户获取订单所需的金额之类的参数Order order = orderMapper.selectOneByOrderNumber(orderNumber);// OpenIdString openId = ;// 设置订单金额 单位为分且最小为1Integer price = 1;//price = Integer.parseInt( order.getAmountMoney().multiply(new BigDecimal("100")).stripTrailingZeros().toString() );// 设置支付超时时间 时间格式:yyyy-MM-dd'T'HH:mm:ssXXXString timeExpire = Utils.rfc3339.format( new Date(System.currentTimeMillis()+1000*60*5) );UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel().setAppid( wxPay.getAppId() ).setMchid( wxPay.getMchId() ).setDescription( "描述" ).setOut_trade_no( orderNumber ).setTime_expire(timeExpire).setAttach( "附加数据" ).setNotify_url(wxPay.getDomain().concat("/weChatPay/payNotify")) //回调地址.setAmount(new Amount().setTotal(price)).setPayer(new Payer().setOpenid(openId));logger.info("订单创建参数:"+ JSONUtil.toJsonStr(unifiedOrderModel));IJPayHttpResponse response = WxPayApi.v3(RequestMethod.POST,WxDomain.CHINA.toString(),WxApiType.JS_API_PAY.toString(),wxPay.getMchId(),getSerialNumber(),null,wxPay.getKeyPath(),JSONUtil.toJsonStr(unifiedOrderModel));logger.info("统一下单响应:{}", response.toString());if ( response.getStatus()==200 ) {// 根据证书序列号查询对应的证书来验证签名结果boolean verifySignature = WxPayKit.verifySignature(response, wxPay.getPlatformCertPath());logger.info("verifySignature: {}", verifySignature);if (verifySignature) {String body = response.getBody();JSONObject jsonObject = JSONUtil.parseObj(body);String prepayId = jsonObject.getStr("prepay_id");Map map = WxPayKit.jsApiCreateSign(wxPay.getAppId(), prepayId, wxPay.getKeyPath());logger.info("唤起支付参数:{}", map);return map;}}return null;}@Overridepublic void payNotify(HttpServletRequest request, HttpServletResponse response) {logger.info("收到微信支付回调");Map map = new HashMap<>(12);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");logger.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);String result = HttpKit.readData(request);logger.info("支付通知密文: {}", result);// 需要通过证书序列号查找对应的证书,verifyNotify 中有验证证书的序列号String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,wxPay.getApiKey3(), wxPay.getPlatformCertPath());logger.info("支付通知明文 {}", plainText);//具体的业务情况savePayPlainText(plainText);//回复微信if (StrUtil.isNotEmpty(plainText)) {response.setStatus(200);map.put("code", "SUCCESS");map.put("message", "SUCCESS");} else {response.setStatus(500);map.put("code", "ERROR");map.put("message", "签名错误");}response.setHeader("Content-type", ContentType.JSON.toString());response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));response.flushBuffer();} catch (Exception e) {e.printStackTrace();}}/*** 获取证书序列号*/private String getSerialNumber() throws IOException {//这个是证书文件,后续要调整成读取证书文件的服务器存放地址String certPath = wxPay.getCertPath();logger.info("path:{}", certPath);// 获取证书序列号X509Certificate certificate = PayKit.getCertificate(FileUtil.getInputStream(certPath));String serialNo = certificate.getSerialNumber().toString(16).toUpperCase();logger.info("获取证书序列号:{},", serialNo);return serialNo;}/*** 保存订单的支付通知明文*/private void savePayPlainText(String plainText) {JSONObject jsonObject = JSONUtil.parseObj(plainText);//这个就是发起订单时的那个订单号String outTradeNo = jsonObject.getStr("out_trade_no");//todo 把微信支付回调的明文消息存进数据库,方便后续校验查看//todo 把微信支付后需要处理的具体业务处理了}
/*** 微信退款* 2个参数只传1个即可* transactionId: 原支付交易对应的微信订单号* outTradeNo: 原支付交易对应的商户订单号*/@GetMapping(value = "/payRefund")public String payRefund(String transactionId, String outTradeNo) {return wxPayService.payRefund(transactionId, outTradeNo);}
@Overridepublic String payRefund(String transactionId, String outTradeNo) {logger.info("进入退款接口------>" );logger.info("执行操作的 原支付交易对应的微信订单号:{}", transactionId);logger.info("执行操作的 原支付交易对应的商户订单号:{}", outTradeNo );try {String outRefundNo = PayKit.generateStr();logger.info("商户退款单号: {}", outRefundNo);List list = new ArrayList<>();RefundGoodsDetail refundGoodsDetail = new RefundGoodsDetail().setMerchant_goods_id( outRefundNo ).setGoods_name( "取消订单" ).setUnit_price( 1 ) //金额,单位为分.setRefund_amount( 1 ).setRefund_quantity(1);list.add(refundGoodsDetail);RefundModel refundModel = new RefundModel().setOut_refund_no(outRefundNo).setReason("取消订单")//.setNotify_url(wechatPayV3Bean.getDomain().concat("/wechat/operation/pay/refundNotify")) //退款异步回调通知.setAmount(new RefundAmount().setRefund(1).setTotal(1).setCurrency("CNY")).setGoods_detail(list);if (transactionId!=null && !transactionId.equals("")) {refundModel.setTransaction_id(transactionId);}if (outTradeNo!=null && !outTradeNo.equals("")) {refundModel.setOut_trade_no( outTradeNo );}logger.info("退款参数: {}", JSONUtil.toJsonStr(refundModel));IJPayHttpResponse response = WxPayApi.v3(RequestMethod.POST,WxDomain.CHINA.toString(),WxApiType.DOMESTIC_REFUNDS.toString(),wxPay.getMchId(),getSerialNumber(),null,wxPay.getKeyPath(),JSONUtil.toJsonStr(refundModel));logger.info("退款响应 {}", response);// 根据证书序列号查询对应的证书来验证签名结果boolean verifySignature = WxPayKit.verifySignature(response, wxPay.getPlatformCertPath());logger.info("verifySignature: {}", verifySignature);String body = response.getBody();JSONObject jsonObject = JSONUtil.parseObj(body); //转换为JSONif(response.getStatus()==200){ //退款成功,处理业务逻辑}if (verifySignature) {return response.getBody();}} catch (Exception e) {e.printStackTrace();return e.getMessage();}return null;}