微信扫码支付总结-PC端-Java(模式二)

前言

最近做的项目有对接微信支付的需求,于是开始了一个人的摸索。本文的前提是公司已经申请了商户号和appid,设置了商户号对应的key,即appId,mchId,key三个参数。以下为开发步骤:

1 阅读微信官方开发文档

微信官方文档链接:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1

这里选择流程更为简单的模式二,主要是看模式二的时序图:

åçæ¯ä»æ¨¡å¼äºæ¶åºå¾

作为开发者,此模式跟微信支付系统直接相关的是步骤2,步骤10,步骤11

(2)用户确认支付后调用微信支付【统一下单API】生成预支付交易;

(10)微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。

(11)未收到支付通知的情况,商户后台系统调用【查询订单API】。

2 导入相关依赖

2.1 添加pom.xml依赖

由于采用maven开发,故在pom.xml文件加上如下依赖:

<!-- wxpay -->
<dependency>
    <groupId>com.github.wxpay</groupId>
    <artifactId>wxpay-sdk</artifactId>
    <version>0.0.3</version>
</dependency>

也可以在官方开发文档网站下载sdk和demo

2.2 maven依赖的使用

只需新建一个Java配置类,实现WXPayConfig接口,配置appId,mchId,key三个主要参数

public class WxPayConfig implements WXPayConfig {
 
    @Override
    public String getAppID() {
        return "xxxxxxxxxxxxxxxxxx";
    }
 
    @Override
    public String getMchID() {
        return "xxxxxxxxxx";
    }
 
    @Override
    public String getKey() {
        return "xxxxxxxxxxxxxxxxxxxxx";
    }
 
    /*此证书是退款才需要配置*/
    @Override
    public InputStream getCertStream() {
        return this.getClass().getResourceAsStream("/cert/apiclient_cert.p12");
    }
 
    @Override
    public int getHttpConnectTimeoutMs() {
        return 6000;
    }
 
    @Override
    public int getHttpReadTimeoutMs() {
        return 8000;
    }
}

3 调用统一下单接口

3.1 接口地址

URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder

// new一个新建的配置类
WxPayConfig wxPayConfig = new WxPayConfig();
// WXPay即为maven依赖的jar包封装好的调用官方接口的
WXPay wxPay = new WXPay(wxPayConfig);
// 调用统一下单接口
Map<String, String> returnMap = wxPay.unifiedOrder(dataMap);

3.2 此处应注意参数传递notify_url这个参数(在第4节会细说)

3.3 接口的返回值

根据官方文档得知下单接口的返回值,可以判断returnMap的属性return_code和result_code都为SUCCESS时,返回二维码链接code_url

if(WXPayConstants.SUCCESS.equals(returnMap.get("return_code")) &&
                WXPayConstants.SUCCESS.equals(returnMap.get("result_code"))){
    return returnMap.get("code_url");
}

3.4 二维码插件

由于项目是前后端分离,这里使用前端插件生成qrcode,具体使用请参考http://code.ciaoca.com/javascript/qrcode/

<script type="text/javascript" src="qrcode.js"></script>
<script type="text/javascript">
// 设置参数方式
    var qrcode = new QRCode('qrcode', {
        // 只需替换这一串内容即可生成二维码
        text: 'weixin://wxpay/bizpayurl?pr=xxxxxx',
        width: 256,
        height: 256,
        colorDark : '#000000',
        colorLight : '#ffffff',
        correctLevel : QRCode.CorrectLevel.H
    });
</script>


ps:此处也可使用zxing的工具类直接在后端生成二维码图片返回给前端显示,暂不详细展开。

4 设置支付结果通知的notify_url

开发者在调用统一下单接口时,需要传递notify_url给微信支付系统。使得用户扫码付款成功后,微信会主动调用开发者设置的接口,对支付结果进行通知,开发者可对支付结果进行判断,并结合业务需求,实现项目业务。

4.1 使用内网穿透工具ngrok实现内网穿透

若是在本地测试开发,则需要使用内网穿透工具,方便测试

这样微信访问马赛克的链接,就相当于访问了本地的8080端口的程序接口

4.2 配置notify_url

在项目配置文件application.properties文件或者自定义文件中配置notify_url

wechat.notify_url=http://xxxx.ngrok.xxxxx.cn/test/payNotify

4.3 新增payNotify接口,以便微信回调

controller层:提供微信回调接口

@PostMapping(value = "/payNotify")
public void payNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        request.setCharacterEncoding("UTF-8");
        String notify = payService.payNotify(request);
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.getWriter().println(notify);
}

service层:接收处理参数,并返回指定内容给微信支付系统   

        // 返回微信格式
        private static final String RESULT_SUCCESS = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
        private static final String RESULT_FAIL = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[参数为空]]></return_msg></xml>";
        // 异步接收到微信的支付结果
        String requestBody = getRequestBody(request);
        // 使用maven依赖工具类对结果进行转化
        Map<String, String> map = WXPayUtil.xmlToMap(requestBody);
        LOGGER.debug("微信支付结果通知:{}",requestBody);
        // 返回成功
        if(!WXPayConstants.SUCCESS.equals(map.get("return_code"))){
            LOGGER.error("支付失败");
            return RESULT_FAIL;
        }
        // 签名
        String sign = map.get("sign");
        // 业务结果
        String result_code = map.get("result_code");
        // 商户订单号
        String out_trade_no = map.get("out_trade_no");
        // 订单金额
        String total_fee = map.get("total_fee");
        // 微信支付订单号
        String transaction_id = map.get("transaction_id");
 
        // 1,验证签名是否正确
        WxPayConfig config = new WxPayConfig();
        String signature = WXPayUtil.generateSignature(map, config.getKey());
        LOGGER.info("重新生成的签名:{}",signature);
        if(!signature.equals(sign)){
            LOGGER.info("签名验证失败");
            return RESULT_FAIL;
        }
 
        LOGGER.info("验签成功");
        // 验证支付金额和订单金额是否一致,此处省略代码
        // ...
        // 验证通过,则返回成功结果
        return RESULT_SUCCESS;

获取request输入流,解析参数 

/**
     * 接收微信传过来的结果
     * @param request req
     * @return String格式
     * @throws IOException
     */
    private String getRequestBody(HttpServletRequest request) throws IOException {
        ServletInputStream inputStream = request.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        StringBuilder inputLine = new StringBuilder();
        String line;
        try {
            while ((line = reader.readLine())!=null){
                inputLine.append(line);
            }
        } catch (Exception e){
            LOGGER.debug(e.getMessage());
            e.printStackTrace();
        } finally {
            reader.close();
            inputStream.close();
        }
        return inputLine.toString();
    }

4.4 注意事项

微信回调此处有坑,微信回调是定时重试地调用,若因为网络原因或者其他因素,可能导致即使是返回成功了,也会不断调用回调接口,废话不多说,上代码:

        // 1获取订单号,查询该订单在商户系统中的订单状态
        Map<String, Object> order = orderInfoMapper.queryOrder(out_trade_no);
        // 2判断订单是否支付成功,成功则直接返回
        Integer statu = Integer.parseInt(order.get("statu") + "");
        // 1为已支付
        if(1 == statu){
            LOGGER.info("该订单已支付,订单号为:{}",out_trade_no);
            return RESULT_SUCCESS;
        }

5 查询订单状态接口调用

接口链接:https://api.mch.weixin.qq.com/pay/orderquery

参照api文档,传递参数直接调用:

/**
     * 查询订单
     * @param dataMap 数据参数
     * @return 返回结果集合
     * @throws Exception 异常
     */
    public static Map<String,String> queryOrder(Map<String,String> dataMap) throws Exception {
        WxPayConfig wxPayConfig = new WxPayConfig();
        WXPay wxPay = new WXPay(wxPayConfig);
        Map<String, String> orderQuery = wxPay.orderQuery(dataMap);
        return orderQuery;
    }

6 退款接口

退款接口需下载证书,并配置证书路径,未完待续...

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值