0


JAVA SpringBoot整合 微信支付V3-JSAPI下单(支付/退款)

流程概要

1、小程序传递订单参数调用后端的支付订单接口
2、后端接口调用微信支付系统后生成6个必要参数返回给小程序
3、小程序调用wx.requestPayment拉起微信支付
4、用户支付后,微信支付系统调用后端回调接口
5、后端回调接口对具体的业务逻辑进行处理

官方接口文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml

添加Maven依赖

<dependency><groupId>com.github.javen205</groupId><artifactId>IJPay-All</artifactId><version>2.7.4</version></dependency>

平台证书的生成

平台证书是必须的,生成方法:
参考整理的另一篇笔记:https://blog.csdn.net/Yisermorn/article/details/127304729?spm=1001.2014.3001.5502

创建通用参数文件 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")publicclassWxPay{privateString keyPath;privateString certPath;privateString certP12Path;privateString platformCertPath;privateString mchId;privateString apiKey;privateString apiKey3;privateString domain;privateStringAppId;privateStringAppSecret;}

编写控制层代码

创建Controller类编写 获取微信支付唤起参数 接口

/**
     * 获取微信支付唤起参数
     * orderNumber: 订单号码
     */@GetMapping(value ="/jsapiPay")publicObjectjsapiPay(String orderNumber){try{return wxPayService.jsapiPay(orderNumber);}catch(Exception e){
            e.printStackTrace();}returnnull;}/**
     * 微信支付的回调接收接口
     */@RequestMapping("/payNotify")publicvoidpayNotify(HttpServletRequest request,HttpServletResponse response){
        wxPayService.payNotify(request,response);}

编写服务层代码

略过service层方法接口,展示的是方法的实现

@OverridepublicMap<String,String>jsapiPay(String orderNumber)throwsException{// 根据订单编号查询到订单记录,用户获取订单所需的金额之类的参数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(newDate(System.currentTimeMillis()+1000*60*5));UnifiedOrderModel unifiedOrderModel =newUnifiedOrderModel().setAppid( wxPay.getAppId()).setMchid( wxPay.getMchId()).setDescription("描述").setOut_trade_no( orderNumber ).setTime_expire(timeExpire).setAttach("附加数据").setNotify_url(wxPay.getDomain().concat("/weChatPay/payNotify"))//回调地址.setAmount(newAmount().setTotal(price)).setPayer(newPayer().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<String,String> map =WxPayKit.jsApiCreateSign(wxPay.getAppId(), prepayId, wxPay.getKeyPath());
                logger.info("唤起支付参数:{}", map);return map;}}returnnull;}@OverridepublicvoidpayNotify(HttpServletRequest request,HttpServletResponse response){
        logger.info("收到微信支付回调");Map<String,String> map =newHashMap<>(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();}}/**
     * 获取证书序列号
     */privateStringgetSerialNumber()throwsIOException{//这个是证书文件,后续要调整成读取证书文件的服务器存放地址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;}/**
     * 保存订单的支付通知明文
     */privatevoidsavePayPlainText(String plainText){JSONObject jsonObject =JSONUtil.parseObj(plainText);//这个就是发起订单时的那个订单号String outTradeNo = jsonObject.getStr("out_trade_no");//todo 把微信支付回调的明文消息存进数据库,方便后续校验查看//todo 把微信支付后需要处理的具体业务处理了}

退款接口的控制层代码

/**
     * 微信退款
     * 2个参数只传1个即可
     * transactionId: 原支付交易对应的微信订单号
     * outTradeNo: 原支付交易对应的商户订单号
     */@GetMapping(value ="/payRefund")publicStringpayRefund(String transactionId,String outTradeNo){return wxPayService.payRefund(transactionId, outTradeNo);}

退款接口的服务层代码

@OverridepublicStringpayRefund(String transactionId,String outTradeNo){
        logger.info("进入退款接口------>");
        logger.info("执行操作的 原支付交易对应的微信订单号:{}", transactionId);
        logger.info("执行操作的 原支付交易对应的商户订单号:{}", outTradeNo );try{String outRefundNo =PayKit.generateStr();
            logger.info("商户退款单号: {}", outRefundNo);List<RefundGoodsDetail> list =newArrayList<>();RefundGoodsDetail refundGoodsDetail =newRefundGoodsDetail().setMerchant_goods_id( outRefundNo ).setGoods_name("取消订单").setUnit_price(1)//金额,单位为分.setRefund_amount(1).setRefund_quantity(1);
            list.add(refundGoodsDetail);RefundModel refundModel =newRefundModel().setOut_refund_no(outRefundNo).setReason("取消订单")//.setNotify_url(wechatPayV3Bean.getDomain().concat("/wechat/operation/pay/refundNotify")) //退款异步回调通知.setAmount(newRefundAmount().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();}returnnull;}
标签: java spring boot 微信

本文转载自: https://blog.csdn.net/Yisermorn/article/details/127304598
版权归原作者 鱼笙安好 所有, 如有侵权,请联系我们删除。

“JAVA SpringBoot整合 微信支付V3-JSAPI下单(支付/退款)”的评论:

还没有评论