[支付]微信NATIVE掃碼支付JAVA實現


步驟:

  1.預訂單

  2.接受微信返回的url

  3.將url轉為二維碼顯示到頁面上

  4.掃碼支付

  5.接收微信的異步通知,在這步修改訂單的狀態

  6.收到異步通知的同時給微信返回指定數據,告知對方已成功處理異步通知

難點:

  1.根據傳遞的參數生成簽名

  2.將數據轉為xml格式發送給微信預訂單接口

常見錯誤:

  1.簽名錯誤(推薦用微信的驗簽工具檢驗)

  2.xml格式錯誤(很有可能是發送數據的方式出現了問題)

具體實現:

  1.預訂單

public String getImageUrl(String body,String out_trade_no,String product_id,String total_fee) throws Exception{
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("appid", data.getAppid()); //appid:每個公眾號都有一個appid 
        paramMap.put("body", body); //商品描述 
        paramMap.put("mch_id", data.getMch_id()); //商戶號:開通微信支付后分配 
        paramMap.put("nonce_str", RandomStringGenerator.getRandomStringByLength(32));  // 隨機字符串
        paramMap.put("notify_url", data.getNotify_url()); //支付成功后,回調地址
        paramMap.put("out_trade_no",  out_trade_no);  //商戶訂單號
        paramMap.put("product_id", product_id); // 商戶根據自己業務傳遞的參數 當trade_type=NATIVE時必填
        paramMap.put("spbill_create_ip", this.localIp()); //本機的Ip
        paramMap.put("total_fee", total_fee); //金額必須為整數  單位為分
        paramMap.put("trade_type", data.getTrade_type()); //交易類型
        paramMap.put("sign", WxzfUtil.getSign(paramMap, WXPayAction.KEY));//根據微信簽名規則,生成簽名。隨機參數可以在商戶后台管理系統中進行設置。
       
        String xmlData = XmlUtils.map2xmlBody(paramMap,"xml");//把參數轉換成XML數據格式
        String codeUrl = getCodeUrl(xmlData);   //獲取二維碼鏈接
        return codeUrl;
    }
public static String getSign(Map map, String key) throws Exception {
        String signTemp = "appid=" + map.get("appid") + "&body="
                + map.get("body") + "&mch_id=" + map.get("mch_id")
                + "&nonce_str=" + map.get("nonce_str") + "&notify_url="
                + map.get("notify_url") + "&out_trade_no="
                + map.get("out_trade_no") + "&product_id="
                + map.get("product_id") + "&spbill_create_ip="
                + map.get("spbill_create_ip") + "&total_fee="
                + map.get("total_fee") + "&trade_type=" + map.get("trade_type")
                + "&key=" + key; 
        String sign = MD5.MD5Encode(signTemp).toUpperCase();//MD5微信接口中提供,直接調用即可
        return sign;
    }
public static String map2xmlBody(Map<String, Object> vo, String rootElement) {
        org.dom4j.Document doc = DocumentHelper.createDocument();
        Element body = DocumentHelper.createElement(rootElement);
        doc.add(body);
        __buildMap2xmlBody(body, vo);
        return doc.asXML();
    }
    
    @SuppressWarnings("unchecked")
    private static void __buildMap2xmlBody(Element body, Map<String, Object> vo) {
        if (vo != null) {
            Iterator<String> it = vo.keySet().iterator();
            while (it.hasNext()) {
                String key = (String) it.next();
                if (StringUtil.isNotEmpty(key)) {
                    Object obj = vo.get(key);
                    Element element = DocumentHelper.createElement(key);
                    if (obj != null) {
                        if (obj instanceof java.lang.String) {
                            element.setText((String) obj);
                        } else {
                            if (obj instanceof java.lang.Character || obj instanceof java.lang.Boolean || obj instanceof java.lang.Number
                                    || obj instanceof java.math.BigInteger || obj instanceof java.math.BigDecimal) {
                                org.dom4j.Attribute attr = DocumentHelper.createAttribute(element, "type", obj.getClass().getCanonicalName());
                                element.add(attr);
                                element.setText(String.valueOf(obj));
                            } else if (obj instanceof java.util.Map) {
                                org.dom4j.Attribute attr = DocumentHelper.createAttribute(element, "type", java.util.Map.class.getCanonicalName());
                                element.add(attr);
                                __buildMap2xmlBody(element, (Map<String, Object>) obj);
                            } else {
                            }
                        }
                    }
                    body.add(element);
                }
            }
        }
    }
/**
     * 獲取一定長度的隨機字符串
     * @param length 指定字符串長度
     * @return 一定長度的字符串
     */
    public static String getRandomStringByLength(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }
//獲取本機ip地址
@SuppressWarnings("rawtypes")
    private String localIp(){
         String ip = null;
         Enumeration allNetInterfaces;
         try {
             allNetInterfaces = NetworkInterface.getNetworkInterfaces();            
             while (allNetInterfaces.hasMoreElements()) {
                 NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
                 List<InterfaceAddress> InterfaceAddress = netInterface.getInterfaceAddresses();
                 for (InterfaceAddress add : InterfaceAddress) {
                     InetAddress Ip = add.getAddress();
                     if (Ip != null && Ip instanceof Inet4Address) {
                         ip = Ip.getHostAddress();
                     }
                 }
             }
         } catch (SocketException e) {
             log.warn("獲取本機Ip失敗:異常信息:"+e.getMessage());
         }
         return ip;
     }

  2.接受微信返回的url

/**
     * 獲取二維碼鏈接
     * @param xmlData
     * @return
     */
    private String getCodeUrl(String xmlData) {
        String resXml = null;
        try {
            resXml = WxzfUtil.sendPost(WXPayAction.WX_CREATE_ORDER_URL, xmlData);
        } catch (UnrecoverableKeyException e1) {
            log.error(e1.getMessage());
        } catch (KeyManagementException e1) {
            log.error(e1.getMessage());
        } catch (KeyStoreException e1) {
            log.error(e1.getMessage());
        } catch (NoSuchAlgorithmException e1) {
            log.error(e1.getMessage());
        } catch (IOException e1) {
            log.error(e1.getMessage());
        }
        
        String code_url = "";
        Map<String, String> map;
        try {
            map = WxzfUtil.parseXml(resXml);
            Object returnCode = map.get("return_code");
            if("SUCCESS".equals(returnCode)) {
                Object resultCode = map.get("result_code");
                if("SUCCESS".equals(resultCode)) {
                    code_url = map.get("code_url").toString();
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            return "";
        }
        return code_url;
    }
//將xml數據發送給微信
@SuppressWarnings({ "resource" })
    public static String sendPost(String url, String postDataXML)
            throws IOException, KeyStoreException, UnrecoverableKeyException,
            NoSuchAlgorithmException, KeyManagementException {

        String result = null;

        HttpPost httpPost = new HttpPost(url);
        HttpClient client = new DefaultHttpClient();

        // 得指明使用UTF-8編碼,否則到API服務器XML的中文不能被成功識別

        StringEntity postEntity = new StringEntity(postDataXML, "UTF-8");

        httpPost.addHeader("Content-Type", "text/xml");

        httpPost.setEntity(postEntity);

        try {

            HttpResponse response = client.execute(httpPost);

            HttpEntity entity = response.getEntity();

            result = EntityUtils.toString(entity, "UTF-8");

        } catch (ConnectionPoolTimeoutException e) {

            // LOG.debug("http get throw ConnectionPoolTimeoutException(wait time out)");

        } catch (ConnectTimeoutException e) {

            // LOG.debug("http get throw ConnectTimeoutException");

        } catch (SocketTimeoutException e) {

            // LOG.debug("http get throw SocketTimeoutException");

        } catch (Exception e) {

            e.printStackTrace();

            // LOG.debug("http get throw Exception" );

        } finally {
            httpPost.abort();
        }

        System.out.println(result);

        return result;

    }

  3.將url轉為二維碼顯示到頁面上

public String payWeChat(String ids,String content,HttpServletResponse response,HttpServletRequest request, ModelMap model){
        WebErrors errors = WebErrors.create(request);
        try {
            OmShopOrder order = orderService.findById(Long.parseLong(ids));
            content = this.getImageUrl(order.getSoProductname(), order.getSoId().toString(), order.getSoId().toString(), (int)(order.getSoTotal()*10*10)+"");
            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            Hashtable hints = new Hashtable();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, 400, 400,hints);
            response.setContentType("image/jpeg");
            MatrixToImageWriter.writeToStream(bitMatrix, "jpg", response.getOutputStream());
         } catch (Exception e) {
            e.printStackTrace();
            log.warn("訂單已支付,請勿重新支付");
         }
        return null;
    }

  4.掃碼支付

  5.接收微信的異步通知,在這步修改訂單的狀態

if ("SUCCESS".equals(returnMap.get("return_code"))&&"SUCCESS".equals(returnMap.get("result_code"))) {
//處理你的業務邏輯代碼(修改訂單支付狀態)
            }

  6.收到異步通知的同時給微信返回指定數據,告知對方已成功處理異步通知

response.setContentType("text/plain;charset=UTF-8");
                PrintWriter writer;
                try {
                    writer = response.getWriter();
                    writer.write("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
                    writer.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM