微信扫码支付模式二小结

 

1.  准备工作


微信公众平台配置appid;


商户平台配置:MCH_ID   ,api_key,和notify_url(微信支付的支付结果   异步回调地址);


2.  生成订单,调用微信统一下单接口


//统一下单接口地址
public static String UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
/**


*这是统一下单参数
 * @param  公众账号ID    appid            String(32)
 * @param  商户号        mch_id              String(32)
 * @param  随机字符串    nonce_str         String(32)
 * @param 签名            sign             String(32)
 * @param  商品描述       body            String(128)
 * @param  商户订单号    out_trade_no       String(32)
 * @param  标价金额        total_fee      Int   88  单位 分
 * @param  终端IP        spbill_create_ip    String(16)
 * @param  通知地址        notify_url     String(256)
 * @param  交易类型        trade_type     String(16) NATIVE 扫码支付
 */


appid   已知;mchid   已知;notify_url  已知 ; trade_type  固定;


随机字符串   nonce_str  无要求 保证随机性即可


body (内容),out_trade_no(订单号) ,total_fee(总价格/分) 三个参数与业务相关,测试环境可设简单点


 以上八个参数放入map中(sign除外),对map进行遍历,去除非空参数生成一个 key1=value1& key2=value2…格式的字符串  sb.append("key=" + API_KEY);然后对此字符串MD5加密,统一编码,并转成大写  生成签名sign(字符串格式);


将sign添加至map中。
Map转为xml格式(工具类);
然后发起请求,调统一下单接口(参数:xml);
接收到的也是xml格式响应。
解析为map,取出xml中的code_url值(利用此链接可以生成二维码);
将code_url和业务结果(code,out_trade_no)一并存入json返回给前台。 
3.  用户支付完成后,微信异步通知notify_url,告诉我们支付结果。

 
 
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 m = new HashMap();
m = XMLUtil.doXMLParse(sb.toString());
拿到相应内容里面的签名。与之前签名进行匹配。如果匹配,进行业务逻辑操作。
4.前台收到链接生成二维码,并拿到订单号轮询调后台查询订单接口去查询支付结果。
5.后台重复调用订单查询接口:
   Appid,mchid,随机数,订单号,并进行签名,发送请求,接收到相应内容,转成xml,
获取里面的参数(trade_state,trade_state_desc)等,如果"SUCCESS".equalsIgnoreCase(trade_state),
代表查询到订单状态为成功,那么告诉前台,进行业务操作
@Service("wechatpayService")
public class WeChatPayServiceImpl extends SihealService {

    // 企业方公众号Id              
    private final static String APP_ID = "xxxxxxxxxxxxxxxxxx";
    //财付通平台的商户账号          
    private final static String MCH_ID = "xxxxxxxxxxxxxxxxxx";
    //财付通平台的商户密钥 
    private final static String API_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    //回调URL
    private final static String NOTIFY_URL = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    //查询订单URL
    private final static String ORDER_QUERY_URL = "https://api.mch.weixin.qq.com/pay/orderquery";

    private static final Logger LOG = Logger.getLogger(WeChatPayServiceImpl.class);

    @Autowired
    private OrderDaoImpl orderDao;

    /**
     * 微信支付调下单API,生成二维码链接
     *
     * @param order
     * @return String
     */
    public String payBySihealDynamicQrCode(TOrder order) throws AssertException {

        try {
            // (必填)商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|* 且在同一个商户号下唯一。
            String outTradeNo = order.getNo();

            String body = "xxxx";//商品名称
            String total_fee = (int) (order.getPayPrice() * 100) + "";//标价金额,以分为单位

            //构建请求参数
            Map param = new HashMap<>();
            param.put("appid", APP_ID);
            param.put("mch_id", MCH_ID);
            param.put("nonce_str", WXPayUtil.generateNonceStr());
            param.put("body", body);
            param.put("out_trade_no", outTradeNo);
            param.put("total_fee", total_fee);
            param.put("spbill_create_ip", "127.0.0.1");
            param.put("notify_url", NOTIFY_URL);
            param.put("trade_type", "NATIVE");
            //将map转换成xml
            String xml = WXPayUtil.generateSignedXml(param, API_KEY);
            System.out.println("发送给微信的参数" + xml);
            //发送请求调用统一下单接口
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
            client.setXmlParam(xml);
            client.setHttps(true);
            client.post();
            //返回结果
            String xmlResult = client.getContent();
            //将xml字符串转换成map集合
            Map result = WXPayUtil.xmlToMap(xmlResult);
            System.out.println("微信支付返回的参数" + result);
            if ("SUCCESS".equalsIgnoreCase((String) result.get("result_code"))) {
                LOG.error("微信扫码下单成功");
                //生成二维码
                ZxingUtils.getQRCodeImge(result.get("code_url").toString(), 256, "C:\\Users\\Administrator\\Desktop\\qrcode.png");
                return result.get("code_url").toString();
            } else {
                LOG.error("微信扫码下单失败");
                order.setOrderStatus(Constants.ORDER_STATUS_CREATE_FAILED);
                orderDao.SaveOrUpdate(order);
                throw new AssertException(Result.ERROR_WECHAT_ORDER_ERROR);
            }
        } catch (Exception ex) {
            LOG.error(ex.getMessage());
            order.setOrderStatus(Constants.ORDER_STATUS_CREATE_FAILED);
            orderDao.SaveOrUpdate(order);
            throw new AssertException(Result.ERROR_WECHAT_ORDER_ERROR);
        }
    }

    /**
     * 微信支付查询订单状态
     *
     * @param order
     * @return TOrder
     */
    public TOrder getOrderStatus(TOrder order) throws Exception {
        //1.构建请求参数,
        String out_trade_no = order.getNo();
        LOG.warn("构建请求参数,查询订单,订单号为:" + out_trade_no);
        Map param = new HashMap<>();
        param.put("appid", APP_ID);
        param.put("mch_id", MCH_ID);
        // 随机数  nonce_str
        String nonce_str = WXPayUtil.generateNonceStr();
        param.put("nonce_str", nonce_str);
        //订单号
        param.put("out_trade_no", out_trade_no);
        //将map转换成xml
        String xml = WXPayUtil.generateSignedXml(param, API_KEY);
        LOG.info("查询订单的入参为:" + xml);
        //调用查询订单API
        HttpClient client = new HttpClient(ORDER_QUERY_URL);
        client.setXmlParam(xml);
        client.setHttps(true);
        client.post();
        //返回结果
        String xmlResult = client.getContent();
        //将xml字符串转换成map集合
        Map map = WXPayUtil.xmlToMap(xmlResult);
        System.out.println("查询订单返回参数:" + map);
        //return_code通信标识,非交易标识,交易是否成功需要查看trade_state来判断
        String return_code = (String) map.get("return_code");
        //交易状态,如trade_state不为 SUCCESS,则只返回out_trade_no(必传)和attach(选传)。
        String trade_state = (String) map.get("trade_state");
        LOG.info("交易状态为:" + trade_state);
        switch (trade_state) {
            case "SUCCESS":
                //支付成功
                String trade_state_desc = (String) map.get("trade_state_desc");
                LOG.info("trade_state_desc:" + trade_state_desc + ",查询返回该订单支付成功!");
                order.setPayStatus(Constants.PAYMENT_STATUS_PAID);
                orderDao.SaveOrUpdate(order);
                break;

            case "NOTPAY":
                //未支付
                LOG.info("查询返回该订单未支付");
                order.setPayStatus(Constants.PAYMENT_STATUS_UNPAY);
                orderDao.SaveOrUpdate(order);
                break;

            case "USERPAYING":
                //用户支付中
                LOG.info("查询返回该订单未支付");
                order.setPayStatus(Constants.PAYMENT_STATUS_UNPAY);
                orderDao.SaveOrUpdate(order);
                break;

            case "REFUND":
                //转入退款
                break;

            case "CLOSED":
                LOG.error("查询返回该订单被关闭!!!");
                order.setOrderStatus(Constants.ORDER_STATUS_CLOSED);
                orderDao.SaveOrUpdate(order);
                break;

            case "PAYERROR":
                //支付失败
                break;

            default:
                LOG.error("不支持的交易状态,交易返回异常!!!");
                break;

        }
        return order;
    }

    /**
     * 微信支付异步回调
     *
     * @param request
     * @param response
     */
    public void onPaymentStatusChanged(HttpServletRequest request, HttpServletResponse response) throws IOException, Exception {
        //读取参数
        LOG.info("微信异步通知商户后台,读取通知参数,获得xml字符串");
        System.out.println("微信异步通知商户后台,读取通知参数,获得xml字符串");
        InputStream inputStream;
        StringBuilder sb = new StringBuilder();
        //接收微信数据流,获得xml字符串
        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();
        LOG.info("接收到xml字符串为:" + sb.toString());
        //解析xml成map
        Map m = new HashMap<>();
        m = WXPayUtil.xmlToMap(sb.toString());
        //过滤空 设置 TreeMap
        SortedMap packageParams = new TreeMap<>();
        Iterator it = m.keySet().iterator();
        while (it.hasNext()) {
            String parameter = (String) it.next();
            String parameterValue = m.get(parameter);

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

        //判断签名是否正确
        if (WXPayUtil.isSignatureValid(m, API_KEY)) {
            //处理业务开始
            LOG.info("验签成功");
            String resXml = "";
            if (((String) packageParams.get("result_code")) != null && "SUCCESS".equals((String) packageParams.get("result_code"))) {
                LOG.info("result_code:" + (String) packageParams.get("result_code") + ",验证订单信息是否匹配");
                // 这里是支付成功,获取商户id,订单号,总金额等信息
                String mch_id = (String) packageParams.get("mch_id");
                String openid = (String) packageParams.get("openid");
                String is_subscribe = (String) packageParams.get("is_subscribe");
                String out_trade_no = (String) packageParams.get("out_trade_no");
                String total_fee = (String) packageParams.get("total_fee");
                //订单金额
                float totalAmount = Long.parseLong(total_fee) / 100.f;

                LOG.warn("商户的ID:  " + mch_id + "   openidID:  " + openid + "  is_subscribe:  :  " + is_subscribe + "    订单号: :" + out_trade_no);
                //执行自己的业务逻辑,根据微信通知的订单号去查询数据库中的订单,订单号和金额是否匹配
                TOrder order = orderDao.getOrder(out_trade_no);
                if (order != null && totalAmount == order.getPayPrice()) {
                    LOG.info("信息匹配,更新订单的支付状态,返回结果给微信");
                    System.out.println("信息匹配,更新订单的支付状态,返回结果给微信");
                    order.setPayStatus(Constants.PAYMENT_STATUS_PAID);
                    order.setRefundStatus(Constants.REFUND_STATUS_CAN);
                    orderDao.SaveOrUpdate(order);
                    //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
                    resXml = "" + ""
                            + "" + " ";
                } else {
                    LOG.error("返回信息与数据库信息不匹配");
                    resXml = "" + ""
                            + "" + " ";
                }

            } else {
                LOG.warn("result_code为fail");
                resXml = "" + ""
                        + "" + " ";
            }
            //------------------------------
            //处理业务完毕
            //------------------------------
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            out.write(resXml.getBytes());
            out.flush();
            out.close();
            System.out.println("回调结束");
        } else {
            LOG.error("通知签名验证失败");
        }
    }

 

你可能感兴趣的:(技术类)