Scan code of the micro-channel payment, APP, payment applet access Explanation

Electronic business platform to do a small partner know that payment services are an essential part of today we begin to talk about payment services and access to implementation. In China, nearly 90% of small and medium companies can not do without micro-payment system Alipay payment and letter. So we have to think, why micro-channel payment and Alipay can be used as the first choice for most companies access to it? Actually, this is mostly small partners should be very clear, that the white people have a huge user traffic, the current micro-channel in the domestic users has exceeded one billion, Alipay is also close to about 800 million, such a large user base, you will choose other third-party payment (microblogging wallet, money paid through, fast money, etc.) do, as an ordinary customer, we all want to be able to easily and quickly, who would buy something in order to download or open a platform for other services do, unless you give him there are benefits seductive. Today, access and implement micro-channel pay us first talk about.

 
image

Micro-channel pay access

We went to pay the preferred micro-channel official website, take a look at the development of the official documentation provided. Link Address: https://pay.weixin.qq.com/wiki/doc/api/index.html .

 
image

We take a look at micro-channel pay payment currently available (as shown above), this talk about native payment (scan code to pay), App payment and payment applet three. First, the preparatory work

Before development, you need to apply for a business version of the micro-channel micro-channel public number or a small program (currently micro-channel businesses pay only the public version number can be opened), then launched micro-channel payment functions, and do the appropriate configuration.

 
image

Subscribe to public micro-channel number and the opening of micro-channel payment (business) need to be reviewed and generally about 5 working days. After the opening of success, we need to get the configuration information:

wx.pay.appid=***
wx.pay.mchid=***
wx.pay.key=***
wx.pay.secret=***

注:appid是公众号ID,mchid是支付的商户ID,其中appid和secret可以在公众平台找着,mchid和key则在商户平台找到,特别是key(即API_KEY)要在商户平台设置好。本项目中这些配置通过properties文件放在-payment-service工程的resource根路径下。
在编码之前,还需要登录微信商户平台配置支付回调URL,此配置作为支付成功后回调接口的域名。如果配置的URL为:http://www.abc.com/, 你的支付回调路径则可设置为:http://www.abc.com/api/payment/notify。二,编码阶段
*在开始编码前,我们必须先了解清楚微信支付的对接及支付的业务流程。

  • 扫码支付的业务流程:
 
image
  • App支付的业务流程:
 
image
  • 小程序支付的业务流程:
 
image

从官方提供的业务流程图我们可以大致总结对接流程如下:

1,在发起支付前,先在自己的商户后台下单,生成商户订单信息;

2,根据对应支付方式的参数需求,封装对应所需参数,并调用微信官方提供的统一下单Api接口下单;

3,统一下单成功,微信后台返回对应的响应数据。返回数据类型如下:

  • 扫码支付统一下单后会返回生成二维码图片的链接code_url;
  • app和小程序支付统一下单后会返回预支付id,即:prepay_id;

4,如果扫码支付,你要用code_url生成一个二维码展示在前端页面供客户扫码付款;如果是app和小程序支付,后端只需将prepay_id及需要的参数传给app和小程序端。app会通过调用SDK、小程序会通过调用微信的JS发起支付。5,客户付款成功后,客户的微信端会展示付款结果信息,同时微信后台会异步调用商户后台的回调接口(回调的api接口在统一下单作为下单参数),更新商户系统的支付单状态。

看到这里,大家会发现这三种方式的基本业务流程都差不多,只是由于不同支付方式调起微信应用支付功能的方式不同,所以统一下单成功后返回的参数有所不同。

Controller接口层:


@RestController
@RequestMapping(value = "/api/payment/")
public class PaymentController { private static Logger logger = LoggerFactory.getLogger(PaymentController.class); @Autowired private PaymentService paymentService; /** * App支付接口 * 微信和支付宝统一下单入口 * * @param request * @return * @throws Exception */ @ResponseBody @RequestMapping(value="toPay", method=RequestMethod.POST, produces = {"application/json;charset=UTF-8"}) public JSONObject toPay(HttpServletRequest request) throws Exception { String requestStr = RequestStr.getRequestStr(request); if (StringUtils.isEmpty(requestStr)) { throw new ParamException(); } JSONObject jsonObj = JSONObject.parseObject(requestStr); if(StringUtils.isEmpty(jsonObj.getString("orderNo")) || StringUtils.isEmpty(jsonObj.getString("payAmount"))){ throw new ParamException(); } //验证订单是否存在 String orderNo = jsonObj.getString("orderNo"); double payAmount = jsonObj.getDouble("payAmount"); if(payAmount < 0.01){ return AjaxUtil.renderFailMsg("订单有误,请确认!"); } else { //微信支付 Map<String, String> resMap = paymentService.wxAppPayment(orderInfo.getOrderNo(),orderInfo.getPayPrice(),null); //判断微信统一下单是否成功 if("SUCCESS".equals(resMap.get("returnCode")) && "OK".equals(resMap.get("returnMsg"))){ //统一下单成功 resMap.remove("returnCode"); resMap.remove("returnMsg"); logger.info("【App支付服务】微信支付下单成功!"); return AjaxUtil.renderSuccessMsg(resMap); }else{ logger.info("【App支付服务】微信支付下单失败!原因:"+resMap.get("returnMsg")); return AjaxUtil.renderFailMsg(resMap.get("returnMsg")); } } } 

PaymentService接口方法:

 
image

PaymentService实现类部分代码(微信App支付):

@Service(value = "paymentService")
public class PaymentServiceImpl implements PaymentService { private static Logger LOGGER = LoggerFactory.getLogger(PaymentServiceImpl.class); @Value("${spring.profiles.active}") private String PROJECT_ENV; @Value("${hcc.pay.domain}") private String payDomain; @Autowired private PaymentRecordMapper paymentRecordMapper; @Override @Transactional(readOnly=false,rollbackFor={Exception.class}) public Map<String,String> wxAppPayment(String orderId, double money,Long customerId) throws Exception { LOGGER.info("【微信App支付】 统一下单开始, 订单编号="+orderId); SortedMap<String, String> resultMap = new TreeMap<String, String>(); //生成支付金额 double payAmount = PayUtils.getPayAmountByEnv(PROJECT_ENV, money); //TODO 操作数据库,添加或更新支付记录 //this.addOrUpdatePaymentRecord(......); //微信统一下单 Map<String,String> resMap = this.wxUnifieldOrder(orderId, PayConfig.TRADE_TYPE_APP, payAmount, null); if(PayConstant.SUCCESS.equals(resMap.get("return_code")) && PayConstant.OK.equals(resMap.get("return_msg"))){ //封装参数返回 resultMap.put("appid", PayConfig.WX_APP_ID); resultMap.put("partnerid", PayConfig.WX_MCH_ID); resultMap.put("prepayid", resMap.get("prepay_id")); resultMap.put("package", "Sign=WXPay"); resultMap.put("noncestr", PayUtils.makeUUID(32)); resultMap.put("timestamp", PayUtils.getCurrentTimeStamp()); resultMap.put("sign", PayUtils.createSign(resultMap,PayConfig.WX_KEY)); resultMap.put("returnCode", "SUCCESS"); resultMap.put("returnMsg", "OK"); LOGGER.info("【微信App支付】统一下单成功,返回参数:"+resultMap); }else{ resultMap.put("returnCode", resMap.get("return_code")); resultMap.put("returnMsg", resMap.get("return_msg")); LOGGER.info("【微信App支付】统一下单失败,失败原因:"+resMap.get("return_msg")); } return resultMap; } 

统一下单方法(在PaymentService实现类里):


/**
     * <p>微信支付统一下单</p>
     *
     * @param orderId 订单编号
     * @param tradeType 支付类型
     * @param payAmount 支付金额
     * @param openid
     * @return
     * @throws Exception
     */
    private Map<String,String> wxUnifieldOrder(String orderId, String tradeType, double payAmount, String openid) throws Exception{ //封装参数 SortedMap<String,String> paramMap = new TreeMap<String,String>(); String appid = PayConfig.WX_APP_ID; String mchid = PayConfig.WX_MCH_ID; if(PayConstant.WX_TRADE_TYPE_JSAPI.equals(tradeType)){ appid = PayConfig.XCX_APP_ID; mchid = PayConfig.XCX_MCH_ID; } paramMap.put("appid", appid); paramMap.put("mch_id", mchid); paramMap.put("nonce_str", PayUtils.makeUUID(32)); paramMap.put("body", BaseConstants.PLATFORM_COMPANY_NAME); paramMap.put("out_trade_no", orderId); paramMap.put("total_fee", PayUtils.moneyToIntegerStr(payAmount)); paramMap.put("spbill_create_ip", PayUtils.getLocalIp()); paramMap.put("notify_url", this.getNotifyUrl(PayConstant.PAY_TYPE_WX)); paramMap.put("trade_type", tradeType); if(PayConstant.WX_TRADE_TYPE_JSAPI.equals(tradeType)){ paramMap.put("openid",openid); } paramMap.put("sign", PayUtils.createSign(paramMap,PayConfig.WX_KEY)); //转换为xml String xmlData = PayUtils.mapToXml(paramMap); //请求微信后台 String resXml = HttpUtils.postData(PayConfig.WX_PAY_UNIFIED_ORDER, xmlData); LOGGER.info("【微信支付】 统一下单响应:\n"+resXml); return PayUtils.xmlStrToMap(resXml); } 

统一下单完成,微信后台将相应的参数以xml的形式返回,统一下单成功后返回xml示例:

<xml>
   <return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg> <appid><![CDATA[wx2421b1c4370ec43b]]></appid> <mch_id><![CDATA[10000100]]></mch_id> <nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str> <sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign> <result_code><![CDATA[SUCCESS]]></result_code> <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id> <trade_type><![CDATA[APP]]></trade_type> </xml> 

因此我们需要将统一下单后的xml解析成map(上面的统一下单方法里已经转换成map),并判断下单状态。如果返回的return_code为SUCCESS并return_msg为OK,那么表示统一下单成功,然后封装对应的参数返回给前端。前端根据下单成功后Java后端返回的参数,进行相应的处理并唤起微信应用的支付服务。注意,扫码支付是用统一下单成功后微信后台返回的code_url生成二维码展示给客户。二维码的生成可以前端也可Java后端生成然后以输出流的形式输出到网页上(坚决不建议Java端生成二维码图片保存到文件服务器然后再展示)。

客户在手机调起微信支付服务并输入密码成功付款后,客户手机的微信里会收到支付成功的付款信息,同时微信后台也在异步调用商户的后台接口。这个回调地址就是在统一下单方法里我们传的notify_url字段的参数值。

下面是回调接口代码:

/**
   * 微信支付完成回调Api
   * 
   * @param request
   * @param response
   * @throws Exception
   */
    @RequestMapping(value="notify")
  public void wxNotify(HttpServletRequest request,HttpServletResponse response) throws Exception {
     InputStream inputStream =  request.getInputStream();
     //获取请求输入流
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len=inputStream.read(buffer))!=-1){
            outputStream.write(buffer,0,len);
        }
        outputStream.close();
        inputStream.close();
        Map<String,Object> map = BeanToMap.getMapFromXML(new String(outputStream.toByteArray(),"utf-8"));
        logger.info("【微信支付回调】 回调数据:\n"+map);
        String resXml = "";
        String returnCode = (String) map.get("return_code");
        if ("SUCCESS".equalsIgnoreCase(returnCode)) {
            String returnmsg = (String) map.get("result_code");
            if("SUCCESS".equals(returnmsg)){
              //更新支付单状态信息
              int result = paymentService.wxNotify(map);
              if(result > 0){
                //支付成功
                  resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>"+"</xml>"; } }else{ resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]></return_msg>" + "</xml>"; logger.info("支付失败:"+resXml); } }else{ resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]></return_msg>" + "</xml>"; logger.info("【订单支付失败】"); } logger.info("【微信支付回调响应】 响应内容:\n"+resXml); //做出响应 response.getWriter().print(resXml); } 

到此为止,所有的编码工作已完成。

三,测试(用扫码支付)

选择要购买的商品,然后下单,再去发起支付。

 
image

单击“去支付”按钮,跳转到二维码支付页面:

 
image

扫码支付完成后,显示二维码的页面会跳转到支付成功页面(带微信支付成功logo),并有3s的倒计时,然后跳转到“订单详情”页。

 
image

本文章只是给大家讲解原理和接入思路及实现,所以文章里只放了核心业务代码。还有好多工具类及配置等代码,全放到这里来肯定也不现实,如果有需要完整代码的可关注公众号获取。

获取方式

扫码关注公众号;找到“关于我”>>>"联系我" ;添加我个人微信获取;

 
 

Guess you like

Origin www.cnblogs.com/lyn20141231/p/11465124.html