JAVA SpringBoot整合 微信支付V3-JSAPI下单(支付/退款)
创始人
2024-05-25 08:09:29
0

流程概要

1、小程序传递订单参数调用后端的支付订单接口

2、后端接口调用微信支付系统后生成6个必要参数返回给小程序

3、小程序调用wx.requestPayment拉起微信支付

4、用户支付后,微信支付系统调用后端回调接口

  1. 后端回调接口对具体的业务逻辑进行处理

添加Maven依赖

com.github.javen205IJPay-All2.7.4

创建通用参数文件 weChatPay.properties

文件存放路径: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=

创建通用参数类 WxPay

将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;}

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...