微信支付二:微信公众号支付(jsapi支付)

SpringBoot 实现微信公众号支付(jsapi支付)

一、背景

在开发一个捐赠项目时须在pc端接入微信扫码支付(Native 扫码支付),在微信端接入微信公众号支付(Jsapi 支付)。后端使用的是Spring Boot框架,前台采用HTML+css+js 编写。
微信支付一:微信支付一

二、微信公众号支付流程

1、微信支付开发文档:微信支付开发文档
2、Jsapi 支付业务流程
在这里插入图片描述

三、配置

jsapi支付所需要的工具类与微信扫码支付的配置类相同,还可使用微信官方提供的sdk,本文以SDK为例。
1、Jsapi支付基本信息配置

 
public interface JsapiConfig {
    String APP_ID="";//微信公众号id
    String MCH_ID="";//商户id
    String API_KEY="";//API密钥
    String UFDOOER_URL="https://api.mch.weixin.qq.com/pay/unifiedorder";//微信统一下单地址
    String NOTIFY_URL="";//回调地址
    String CREATE_IP="";//发起ip
}
四、除SDK外的工具类

JsapiPayCommonUtil

/**
 * @author wxc
 * @date 2021年07月31日 16:02
 * @description JSAPI支付
 */
@Slf4j
public class JsapiPayCommonUtil implements JsapiConfig{


    /**
     *
     * @author wxc
     * @date 2021/7/31/031 16:33
     * @param order_price
     * @param body
     * @param out_trade_no
     * @param openid
     * @return java.lang.String
     * @description 获取prepay_id
     */
    public static String jsapiPay(String order_price,String body,String out_trade_no,Object openid){
        String appid=JsapiConfig.APP_ID; //账号信息
        String mch_id=JsapiConfig.MCH_ID; //商家号
        String key=JsapiConfig.API_KEY; //密钥

        String currTime=PayCommonUtil.getCurrTime();
        String strTime = currTime.substring(8, currTime.length());
        String strRandom = PayCommonUtil.buildRandom(4) + "";
        String nonce_str=strTime+strRandom; //随机字符串

        String spbill_create_ip=JsapiConfig.CREATE_IP;//获取发起电脑ip
        String notify_url=JsapiConfig.NOTIFY_URL;//回调接口
        String trade_type="JSAPI";

        SortedMap<Object,Object> packageParams=new TreeMap<>();
        packageParams.put("appid",appid);
        packageParams.put("mch_id",mch_id);
        packageParams.put("nonce_str",nonce_str);
        packageParams.put("body",body);
        packageParams.put("out_trade_no",out_trade_no);
        packageParams.put("total_fee",order_price);
        packageParams.put("spbill_create_ip",spbill_create_ip);
        packageParams.put("notify_url",notify_url);
        packageParams.put("trade_type",trade_type);
        packageParams.put("openid",openid);

        //根据前10个参数创建签名
        String sign = PayCommonUtil.createSign("UTF-8",packageParams,key);
        packageParams.put("sign",sign); //将第11个参数放入map中

        //请求前,将有11个参数的map转成XML格式
        String requestXML = PayCommonUtil.getRequestXml(packageParams);
        log.info(requestXML);

        //请求微信统一下单接口
        String resXml= WxHttpUtil.postData(JsapiConfig.UFDOOER_URL,requestXML);
        log.info(resXml);

        //解析微信返回的xml数据
        Map map = XMLUtil.doXMLParse(resXml);

        //取出prepay_id
        String prepayId=(String) map.get("prepay_id");
        return prepayId;

    }
}

五、具体实现

Controller层,具体需要的前台传的参数根据个人业务需要决定,但下面六个参数是必传的。

try{
            String prepayId = JsapiPayCommonUtil.jsapiPay(order_price,body,out_trade_no,openId);

            Map<String, String> payMap = new HashMap<String, String>();

            payMap.put("appId", JsapiConfig.APP_ID);
            payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");
            payMap.put("nonceStr", WXPayUtil.generateNonceStr());
            payMap.put("signType", "MD5");
            payMap.put("package", "prepay_id=" + prepayId);

            //根据前五个参数生成标签
            String paySign = WXPayUtil.generateSignature(payMap,JsapiConfig.API_KEY);

            payMap.put("paySign", paySign);

            return payMap;

        } catch(Exception e){
            e.printStackTrace();
        }

回调接口

@RequestMapping("notify")
    public void weixin_notify(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //读取参数
        InputStream inputStream;
        StringBuffer sb = new StringBuffer();
        inputStream=request.getInputStream();
        String s;
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
        while ((s=in.readLine())!=null){
            sb.append(s);
        }
        in.close();
        inputStream.close();

        //解析xml成map
        Map<String,String> m=new HashMap<String,String>();
        m= XMLUtil.doXMLParse(sb.toString());

        //过滤空 设置TreeMap
        SortedMap<Object,Object> packageParams=new TreeMap<Object,Object>();
        Iterator it=m.keySet().iterator();
        while (it.hasNext()){
            String paramter = (String)it.next();
            String parameterValue=m.get(paramter);

            String v="";
            if(null!=parameterValue){
                v=parameterValue.trim();
            }
            packageParams.put(paramter,v);
        }

        //账号信息
        String key= JsapiConfig.API_KEY;

        String out_trade_no=(String)packageParams.get("out_trade_no");
        //判断签名是否正确
        if(PayCommonUtil.isTenpaySign("UTF-8",packageParams,key)){
            //处理业务开始

            String resXml="";
            if("SUCCESS".equals((String)packageParams.get("result_code"))){
                //支付成功,下面执行自己的业务
                log.info("支付成功");
                log.info("========================================================================");
                resXml="<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";


            }else {
                log.info("订单"+out_trade_no+"支付失败");

                resXml="<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml>";

            }

            //业务处理完毕

            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            out.write(resXml.getBytes());
            out.flush();
            out.close();
        }else{
            log.info("通知签名验证失败");
        }

    }


前端js



var appId,timeStamp,nonceStr,package,signType,paySign;

function pay(){
    var url = "/wx/jsapi/wxJsapiPay";
    $.ajax({
        url:url,
        type: "get",
        data: {
            projectName:$("#projectNameH").val(),
            payMoney:$("#payMoneyH").val(),
            sysOrderId:$("#sysOrderIdH").val(),
            id:$("#id").val(),
            projectId:$("#projectId").val(),
        },success:function (data) {
            appId = data.appId;
            timeStamp = data.timeStamp;
            nonceStr = data.nonceStr;
            package = data.package;
            signType = data.signType;
            paySign = data.paySign;

            if (typeof WeixinJSBridge == "undefined") {
                if (document.addEventListener) {
                    document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
                } else if (document.attachEvent) {
                    document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
                    document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
                }
            } else {
                onBridgeReady();
            }
        }
    })
}



function onBridgeReady(){
    WeixinJSBridge.invoke( 'getBrandWCPayRequest', {
        "appId":appId, //公众号名称,由商户传入
        "timeStamp":timeStamp, //时间戳,自1970年以来的秒数
        "nonceStr":nonceStr, //随机串
        "package":package,
        "signType":signType, //微信签名方式:
        "paySign":paySign //微信签名

    }, function(res){
        if(res.err_msg == "get_brand_wcpay_request:ok" ) {
            console.log('支付成功');
            layer.msg("支付成功");
            //支付成功后跳转的页面
            window.location.href = "/wx/prePay/toWxMainHome";


        }else if(res.err_msg == "get_brand_wcpay_request:cancel"){
            console.log('支付取消');
            layer.msg("支付取消");
        }else if(res.err_msg == "get_brand_wcpay_request:fail"){
            console.log('支付失败');
            layer.msg("支付失败");
            WeixinJSBridge.call('closeWindow');

        } //使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
    });

}




$(function () {


    //确认支付
    $("#pay").on("click",function (){
            pay();
        });


})
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值