java微信公众号支付

用最近在学习使用java开发微信公众号,在学习过程中踩了很多坑,确实费了不少劲,先来分享一下微信公众号的支付流程,已提供给朦朦胧胧的小伙伴们看看,顺便给自己整理了一下以便后续使用,这是博主第一次写博客,有毛病的地方还望指出来,谢谢!

本此开发使用的框架为springboot,开发分为三个步骤。
在开发前强烈推荐各位客官先看看开发文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1

一 定 要 看!!!


一、准备阶段

具备条件:已认证微信号,且通过微信支付认证,这个可以看微信文档,会有详细的解析,这里就不再重复了。

开发前,我们先登录自己的服务号,点击微信支付——>开发配置(目前开发配置已经迁移到商户平台了)

先进入商户平台—->产品中心—->开发配置
这里写图片描述

最下面有这个支付配置框,请配置好支付授权目录,这里的目录为 支付html页面所对应的url路径(文件路径)

配置API密匙,在商户平台中账户中心—->API安全
这里写图片描述

接下来要从公众号—->基本配置,拿到微信支付中所需要使用的参数AppId、AppSecret
这里写图片描述


二、前端页面

下面是我在做支付测试时使用的测试页面,为了方便,只做了一个支付按钮并且有点奇怪,直接上代码吧!

<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>

    <body>
        <a href="javascript:void(0);" onclick="pay();" class="button">支付</a>
    </body>
</html>
//这儿是相关的JS代码
<script type="text/javascript" src="../js/jquery-1.10.2.min.js"></script>
    <script type="application/javascript">
        var appid;
        var nonceStr;
        var myPackage = "prepay_id=";
        var tmp ;
        var sign;


        function pay() {
            $.ajax({
                url: "/web/wxpay/"+1000,
                async: false,
                dataType: "json",
                success: function(resp) {
                    appid=resp.appId;
                    nonceStr=resp.nonceStr;
                    tmp=resp.timeStamp;
                    myPackage=myPackage+resp.pg;
                    sign=resp.paySign;
                    alert(appid);
                    alert(nonceStr);
                    alert(tmp);
                    callpay();

                }
            });
        }
                function onBridgeReady() {
                    WeixinJSBridge.invoke(
                        'getBrandWCPayRequest', {
                            "appId": appid, //公众号名称,由商户传入     
                            "timeStamp": tmp, //时间戳,自1970年以来的秒数     
                            "nonceStr": nonceStr, //随机串     
                            "package": myPackage,
                            "signType": "MD5", //微信签名方式:     
                            "paySign": sign //微信签名 
                        },
                        function(res) {
                            if (res.err_msg == "get_brand_wcpay_request:ok") {
                                alert('支付成功');
                            } else if (res.err_msg == "get_brand_wcpay_request:cancel") {
                                alert('支付过程中用户取消');
                            } else if (res.err_msg == "get_brand_wcpay_request:fail") {
                                alert('支付失败');
                            } else {
                                alert('未知异常');
                            } // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回    ok,但并不保证它绝对可靠。 
                        }
                    );
                }

        function callpay() {
            if (typeof WeixinJSBridge == "undefined") {
                alert("WeixinJSBridge");
                if (document.addEventListener) {
                    alert("addEventListener");
                    document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
                } else if (document.attachEvent) {
                    document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
                    document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
                }
            } else {
                onBridgeReady();
            }
        }
    </script>

页面结果:
这里写图片描述

哈哈哈,当然不是这个按钮啦,这是项目中的按钮,别介意,作用还是差不多的!!


三、后端实现

首先,需要下载微信公众平台上提供的SDK,然后将SDK打成jar包,并在pom.xml添加依赖。
这里写图片描述

这是博主使用来统一下单的类

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import com.alibaba.fastjson.JSON;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import com.zt.dao.PrintDao;
import com.zt.dao.UserDao;
import com.zt.domain.User;

public class MyWXPay {

    public String strJson;
    public Map<String, String> resp = new HashMap<String, String>();
    public Map<String, String> payMap = new HashMap<String, String>();  
    public String str=getOutTradeNo();

    public MyWXPay(HttpServletRequest request,String openid,BigDecimal money,long useIntegral) throws Exception {
//      WXPayUtil wxPayUtile=new WXPayUtil();
        MyConfig config = new MyConfig();
        WXPay wxpay = new WXPay(config);

        //这里生产预支付订单签名
        Map<String, String> data = new HashMap<String, String>();
        String theMoney =String.valueOf(money.multiply(new BigDecimal(100)).intValue()) ;//微信支付  total_fee不能出现小数   必须转换为分以整数形式传递数据
        String timeStampStr=String.valueOf(System.currentTimeMillis());
        String timeStamp=timeStampStr.substring(0, 10);
        data.put("appid","");//填写AppId
        data.put("mch_id","");//填写商户号
        data.put("body", "");//商品描述
        data.put("out_trade_no", str);//商户订单号,博主是用随机生成的方式生成
        data.put("device_info", "WEB");//设备号
        data.put("fee_type", "CNY");//人名币类型
        data.put("total_fee", theMoney);//支付金额
        data.put("openid", openid);//支付者的openId
        data.put("timeStamp", timeStamp);//时间戳
        data.put("spbill_create_ip", request.getRemoteAddr());//终端IP
        data.put("notify_url", "http://wechat.gdssn.top/web/notify");//通知地址
        data.put("nonce_str", str);//随机字符串
        data.put("trade_type", "JSAPI");  // 此处指定为公众号支付
        //这里生成支付订单
        try {
            resp = wxpay.unifiedOrder(data);
            String timeStampStr2=String.valueOf(System.currentTimeMillis());
            String timeStamp2=timeStampStr2.substring(0, 10);
            payMap.put("appId", config.getAppID());  
            payMap.put("timeStamp", timeStamp2);  
            payMap.put("nonceStr", getOutTradeNo());  
            payMap.put("signType", "MD5");  
            payMap.put("package", "prepay_id=" + resp.get("prepay_id")); 

            String paySign = WXPayUtil.generateSignature(payMap, config.getKey());    
            payMap.put("pg", resp.get("prepay_id"));  
            payMap.put("paySign", paySign); 
            strJson = JSON.toJSONString(payMap);  
            System.out.println("resp="+resp);
            System.out.println("strJson="+strJson);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    //生成随机的32位字符串,用于商户订单号,随机字符串
    public static String getOutTradeNo() { 
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";     
        Random random = new Random();     
        StringBuffer sb = new StringBuffer();     
        for (int i = 0; i < 32; i++) {     
            int number = random.nextInt(base.length());     
            sb.append(base.charAt(number));     
        }     
        return sb.toString();     
     }  
}

这是博主自己重写的配置参数的类,上面的类中的AppId、mchId等等参数是从这里获取的

import com.github.wxpay.sdk.WXPayConfig;
import java.io.*;

public class MyConfig implements WXPayConfig{

    public String keyPath ="";
    public String mchId="";
    public String ApiSecret="";
     public String appId="";

    private byte[] certData;

    public MyConfig() throws Exception {

        File file = new File(keyPath);
        InputStream certStream = new FileInputStream(file);
        this.certData = new byte[(int) file.length()];
        certStream.read(this.certData);
        certStream.close();
    }

    public String getAppID() {
        return appId;
    }

    public String getMchID() {
        return mchId;
    }

    public String getKey() {
        return ApiSecret;
    }

    public InputStream getCertStream() {
        ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
        return certBis;
    }

    public int getHttpConnectTimeoutMs() {
        return 8000;
    }

    public int getHttpReadTimeoutMs() {
        return 10000;
    }
}

最后是编写微信支付的接口

    String result;//返回给微信的回调数据
    MyWXPayRefund myWXPayRefund;
     @RequestMapping("/wxpay/{money:.+}")   //{money:.+}  这种写法可以接收小数点!
    public void WxPay(@PathVariable(name = "money", required = false)String money,HttpServletRequest request,HttpServletResponse response,ModelMap model){
        String openId=request.getSession().getAttribute("openid").toString();

        MyWXPay myWxPay;
        BigDecimal theMoneyBD=new BigDecimal(money); 
        BigDecimal theIntegral=new BigDecimal(0);
        theMoneyBD=theMoneyBD.setScale(2, BigDecimal.ROUND_UNNECESSARY );

        try {
            myWxPay = new MyWXPay(request,openId,theMoneyBD.subtract(theIntegral));
            CommonUtils.writeJson(myWxPay.payMap, response);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    @RequestMapping("/notify")
    public String notify(@RequestBody String notifyData) {
//           String notifyData = "...."; // 支付结果通知的xml格式数据
        try{
            MyConfig config = new MyConfig();
             WXPay wxpay = new WXPay(config);
             Map<String,String> resultData=new HashMap<>();

             Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData);  // 转换成map

             if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {
                 LOGGER.info("签名正确!");
                 // 签名正确
                 // 进行处理。
                 // 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功
             }
             else {
                 resultData.put("return_code", "FAIL");
                 resultData.put("return_msg", "签名失败");
                 result = WXPayUtil.mapToXml(resultData);
                 // 签名错误,如果数据里没有sign字段,也认为是签名错误
             }
             if(notifyMap.get("result_code").equals("SUCCESS")){

                 myWXPayRefund=new MyWXPayRefund(notifyMap);
                 if(myWXPayRefund.resp.get("isSuccess") != null&&myWXPayRefund.resp.get("isSuccess").equals("true")){
                     LOGGER.info("交易状态成功!return_code= "+notifyMap.get("result_code"));
                     resultData.put("return_code", "SUCCESS");
                     resultData.put("return_msg", "OK");
                     result = WXPayUtil.mapToXml(resultData);
                     return result;
                 }else{
                     LOGGER.info("交易状态失败!return_code= "+notifyMap.get("result_code"));
                     resultData.put("return_code", "fail");
                     resultData.put("return_msg", "交易失败");
                     result = WXPayUtil.mapToXml(resultData);
                 }


             }
             if(!notifyMap.get("result_code").equals("SUCCESS")){
                 LOGGER.info("交易状态失败!return_code= "+notifyMap.get("result_code"));
                 resultData.put("return_code", "fail");
                 resultData.put("return_msg", "参数格式校验错误");
                 result = WXPayUtil.mapToXml(resultData);
             }

             LOGGER.info("返回给微信后台的result= "+result);
        }catch(Exception e){
            e.printStackTrace();
        }
        return result;
    }

点击按钮结果:

这里写图片描述      这里写图片描述

到这里就结束啦,如有疑问或有不对的地方请留言,博主会进行解答与改正,谢谢!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值