微信支付示例代码,预支付接口和支付结果通知接口完整示例

对接微信支付功能,总结一下, 写一篇详细的博客,提供大家作为参考,示例代码获取

一、流程概述

这里是微信支付APP版的支付流程概述

APPæ¯ä»æ¶åºå¾

图片取自微信支付官方文档,

  1. 首先服务端需要调用统一下单接口,获取到prepay_id,然后按照指定格式对prepay_id进行封装,然后返回给客户端APP。
  2. 客户端APP获取参数后直接调取微信支付,输入密码支付,
  3. 微信支付调用服务端的通知接口, 告诉服务端支付结果

所以服务端需要些两个接口,就可以完成微信支付。

二、代码示例

创建预支付订单示例:

    /**
     *
     * @param map ,前段传的参数, 包含总金额,等信息
     * @return
     * @throws Exception
     */
    public String prepay(Map map) throws Exception {


        try {
            String totalFee = (String )map.get("totalFee");
            String AXZJXM_ID = (String) map.get("AXJZXM_ID");

            if(StringUtils.isAnyEmpty(totalFee,AXZJXM_ID)){
                return "{\"code\":\"error\"}";       //返回信息,根据业务自行完善
            }
            String moneyReg= "^\\d+(\\.\\d{1,2})?$";        //金额信息判断,这里只是最简单的判断,
            if(!Pattern.matches(moneyReg,totalFee)){
                return "{\"code\":\"error\"}";
            }
            String[] totals = totalFee.split("\\.");       //将金额信息转换成分为单位
            if(totals.length==1){
                totals[0]=totals[0]+"00";
            }else if(totals.length==2){
                totals[0]=totals[0]+(totals[1]+"00").substring(0,2);

            }
            int feeint = Integer.parseInt(totals[0]);
            if(feeint==0){
                return "{\"code\":\"error\"}";
            }

            WxPayApiConfig config = WxPayApiConfig.New();
            config.setAppId(MyPro.getPro("wx.appId")).setBody("微信支付示例").setOutTradeNo(UUID.randomUUID().toString().replace("-",""));
            config.setTotalFee(feeint+"");
            config.setMchId(MyPro.getPro("wx.mchId")).setSpbillCreateIp(getIP());//wx.mchId :微信商户号
            config.setTimeStart(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
            config.setTimeExpire(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date(System.currentTimeMillis()+1000*60*30)));
            config.setDeviceInfo("WEB");
            config.setTradeType(WxPayApi.TradeType.APP);
            config.setNotifyUrl(MyPro.getPro("wx.notifyUrl"));      //通知接口的地址
            config.setPaternerKey(MyPro.getPro("wx.partnerKey"));   //微信商户号的key
            String result = WxPayApi.doPost(MyPro.getPro("wx.payUrl")+"unifiedorder",config.build());
            Map returnMap  = PaymentKit.xmlToMap(result);
            String rc =(String) returnMap.get("return_code");
            if("SUCCESS".equals(rc)){
                String prepay_id = (String) returnMap.get("prepay_id");
                Map resMap = new TreeMap();
                resMap.put("appid",config.getAppId());
                resMap.put("prepayid",prepay_id);//TODO
                resMap.put("partnerid",config.getMchId());//TODO
                resMap.put("noncestr", HashKit.md5(System.currentTimeMillis()+"superBeyound").toUpperCase());
                Long mill =  System.currentTimeMillis();
                mill=mill/1000;         //时间搓, 以秒为最小单位
                resMap.put("timestamp",mill+"");
                resMap.put("package","Sign=WXPay");

                String sign = PaymentKit.createSign(resMap, MyPro.getPro("wx.partnerKey"));
                String nosignjson  = JSON.toJSONString(resMap);
                String json = nosignjson.substring(0,nosignjson.length()-1)+",\"sign\":\""+sign+"\"}";

                return json;
            }else{

                return "{\"code\":\"error\"}";
            }

        } catch (Exception e) {

        }
        return "{\"code\":\"error\"}";
    }
    private static String IP;
    public static String getIP(){
        if(IP==null||"".equals(IP)){
            String chinaz = "http://ip.chinaz.com";

            StringBuilder inputLine = new StringBuilder();
            String read = "";
            URL url = null;
            HttpURLConnection urlConnection = null;
            BufferedReader in = null;
            try {
                url = new URL(chinaz);
                urlConnection = (HttpURLConnection) url.openConnection();
                in = new BufferedReader( new InputStreamReader(urlConnection.getInputStream(),"UTF-8"));
                while((read=in.readLine())!=null){
                    inputLine.append(read+"\r\n");
                }
                //System.out.println(inputLine.toString());
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                if(in!=null){
                    try {
                        in.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
            Pattern p = Pattern.compile("\\<dd class\\=\"fz24\">(.*?)\\<\\/dd>");
            Matcher m = p.matcher(inputLine.toString());
            if(m.find()){
                String ipstr = m.group(1);
                IP =  ipstr;

            }
        }
        return IP;

    }

详细的注释都写在代码中了。

微信支付结果通知接口示例:(示例代码中,在修改订单状态时没有判断checkFlag, 需要修改一下,可以直接将这里贴出的代码替换到示例代码的相应方法中)



    /**
     * 返回成功xml
     */
    private String resSuccessXml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";

    /**
     * 返回失败xml
     */
    private String resFailXml = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[fail]]></return_msg></xml>";

    /**
     * 该链接是通过【统一下单API】中提交的参数notify_url设置,如果链接无法访问,商户将无法接收到微信通知。
     * 通知url必须为直接可访问的url,不能携带参数。示例:notify_url:“https://pay.weixin.qq.com/wxpay/pay.action”
     * <p>
     * 支付完成后,微信会把相关支付结果和用户信息发送给商户,商户需要接收处理,并返回应答。
     * 对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。
     * (通知频率为15/15/30/180/1800/1800/1800/1800/3600,单位:秒)
     * 注意:同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。
     * 推荐的做法是,当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。
     * 特别提醒:商户系统对于支付结果通知的内容一定要做签名验证,防止数据泄漏导致出现“假通知”,造成资金损失。

     */

    @RequestMapping("/wxnotify")
    @ResponseBody
    public Object wxnotify(HttpServletRequest request, HttpServletResponse response) {

        String resXml = resFailXml;
        InputStream inStream;
        try {

            inStream = request.getInputStream();
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }

            String result = new String(outSteam.toByteArray(), "utf-8");
            WXPayUtil.getLogger().debug("----result----=" + result);

            outSteam.close();
            inStream.close();

            Map<String, String> resultMap = WXPayUtil.xmlToMap(result);     //转换成Map
            Map dd = new HashMap() ;//TODO 查询数据库存储的订单信息,这个根据自己的业务逻辑,自行完善
            boolean isSuccess = false;
            String sign = (String) resultMap.remove("sign");        //验证签名是否正确
            String resultStr = PaymentKit.createSign(resultMap, MyPro.getPro("wx.partnerKey"));

            isSuccess = sign.equalsIgnoreCase(resultStr);
            WXPayUtil.getLogger().debug("veryfy result: "+isSuccess );
            String total_fee = resultMap.get("total_fee");
            boolean checkFlag= false;
            if (WXPayConstants.SUCCESS.equalsIgnoreCase(resultMap.get("return_code"))) {

                if (isSuccess) {
                    resXml = resSuccessXml;
                    if(total_fee.equals(dd.get("totalFee"))){
                        checkFlag = true;
                        System.out.println("check success!!! ");
                    }
                }
            } else {
                resXml = resFailXml;
            }
            if(checkFlag){    //TODO 示例代码中没有判断checkFlag,属于bug ,请读者自行修改一下
                String DDZT = (String) dd.get("DDZT");
                if(DDZT.equals("0")){
                    DDZT = checkFlag?"1":"2";
                    dd.put("DDZT",DDZT);
                    dd.put("ZF_ID",resultMap.get("openid"));
                    int updateResult =1;//TODO 更新订单状态,自行完善
                }
            }

        } catch (Exception e) {

        } finally {
            return resXml;
        }
    }

三、踩坑经历

微信支付对参数进行签名是需要制定签名方式,我这里没有指定,默认是MD5签名方式,而在微信开发者账号上面创建应用时填的包签名方式是SHA-3,导致对接的时候一直报错,

{"code":-100,"message":"[payment微信:-1]General errors"}

 试过好多种方法都不行,最后把应用的包签名改成了MD5签名之后成功掉通,所以这里推荐你直接用MD5作为微信开发者账号创建应用时的包签名,减少踩坑。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个使用Spring Boot实现企业级微信支付接口代码示例: 1. 配置文件(application.properties): ``` # 微信支付配置 wechat.pay.appId=your_appId wechat.pay.mchId=your_mchId wechat.pay.key=your_key wechat.pay.notifyUrl=your_notifyUrl wechat.pay.certPath=/path/to/your_cert.p12 ``` 2. 支付参数实体类(PayParams.java): ```java public class PayParams { private String body; // 商品描述 private String outTradeNo; // 商户订单号 private int totalFee; // 订单总金额(单位:分) // 其他参数... // getter和setter方法... } ``` 3. 支付回调实体类(PayCallback.java): ```java public class PayCallback { private String returnCode; // 返回状态码 private String returnMsg; // 返回信息 // 其他参数... // getter和setter方法... } ``` 4. 支付服务类(PayService.java): ```java @Service public class PayService { @Value("${wechat.pay.appId}") private String appId; @Value("${wechat.pay.mchId}") private String mchId; @Value("${wechat.pay.key}") private String key; @Value("${wechat.pay.notifyUrl}") private String notifyUrl; @Value("${wechat.pay.certPath}") private String certPath; public String unifiedOrder(PayParams payParams) throws Exception { // 构建统一下单请求参数 Map<String, String> data = new HashMap<>(); data.put("appid", appId); data.put("mch_id", mchId); data.put("nonce_str", WXPayUtil.generateNonceStr()); data.put("body", payParams.getBody()); data.put("out_trade_no", payParams.getOutTradeNo()); data.put("total_fee", String.valueOf(payParams.getTotalFee())); // 其他参数... // 生成签名 String sign = WXPayUtil.generateSignature(data, key); data.put("sign", sign); // 发起统一下单请求 WXPayRequest wxPayRequest = new WXPayRequest(); Map<String, String> result = wxPayRequest.requestWithCert("/pay/unifiedorder", data, certPath, mchId); // 处理返回结果 if ("SUCCESS".equals(result.get("return_code")) && "SUCCESS".equals(result.get("result_code"))) { return result.get("prepay_id"); } else { throw new Exception(result.get("return_msg")); } } public PayCallback parsePayCallback(String xmlData) throws Exception { // 解析支付回调数据 Map<String, String> map = WXPayUtil.xmlToMap(xmlData); // 验证签名 if (WXPayUtil.isSignatureValid(map, key)) { PayCallback payCallback = new PayCallback(); payCallback.setReturnCode(map.get("return_code")); payCallback.setReturnMsg(map.get("return_msg")); // 其他参数... return payCallback; } else { throw new Exception("Invalid signature"); } } } ``` 5. 支付控制器类(PayController.java): ```java @RestController @RequestMapping("/pay") public class PayController { @Autowired private PayService payService; @PostMapping("/unifiedOrder") public String unifiedOrder(@RequestBody PayParams payParams) throws Exception { return payService.unifiedOrder(payParams); } @PostMapping("/callback") public String callback(HttpServletRequest request) throws Exception { String xmlData = IOUtils.toString(request.getInputStream(), "UTF-8"); PayCallback payCallback = payService.parsePayCallback(xmlData); // 处理支付结果,更新订单状态等逻辑... return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>"; } } ``` 以上代码示例使用了微信支付的Java SDK:`com.github.wxpay.sdk`,你需要添加相应的依赖。 这只是一个简单的示例,实际开发中还需要根据业务需求进行适当的调整和扩展。同时,还需要保证支付过程的安全性和正确性,例如验证回调通知的有效性、处理支付结果等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值