Java微信統一下單接口

PC網站NATIVE支付爲例

直接上代碼代碼片

主方法

  @RequestMapping("WeiXinPay")
    @ResponseBody
    public ResponseEntity WeiXinPay (String orderNum, String payInfo) {
        ResponseEntity entity = new ResponseEntity();
        entity.setFlag(false);
        HashMap<String, Object> maps = new HashMap<String, Object>();
        maps.put("orderNum",orderNum);
        Order  order = orderService.selectByPrimaryKey(maps);
        if (order == null) {
            entity.setMessage("訂單編號錯誤");
            return entity;
        }
        String appid = "wxd00000000000";
        String mch_id = "00000000000000000000000"; //商戶號
        String Key = "000000000000000000";// API 密鑰
        String notify_url = "http://00000000:0000000/notify";//測試環境使用IP地址
          //  String SIGNKEY = "你的商戶密鑰";
        String spbill_create_ip = "10000000000";//ip地址
        System.out.println("spbill_create_ip="+spbill_create_ip);
        //String spbill_create_ip = "";//測試地址,也就是本地真是ip,用於本地測試用
     //   String scene_info = "{\"h5_info\": {\"type\":\"Wap\",\"wap_url\": \"這裏寫在h5支付配置的那個域名\",\"wap_name\": \"信息認證\"}}";//我這裏是網頁入口,app入口參考文檔的安卓和ios寫法
        String tradeType = "NATIVE";//NATIVE支付標記
        String MD5 = "MD5";//雖然官方文檔不是必須參數,但是不送有時候會驗籤失敗
        String subject = "0000000-"+payInfo;//前端上送的支付描述
        String total_amount =String.valueOf(order.getPrice());//支付金額
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        //金額轉化爲分爲單位 微信支付以分爲單
        String finalmoney = WeiXinUtils.getMoney(total_amount);
        int randomNum  = (int) (Math.random() * 1999+5000);
        //String out_trade_no = DataUtil.getSysTime("yyyyMMddHHmmss") + randomNum;
        String out_trade_no = orderNum;

        //隨機數
        String nonce_str= WeiXinUtils.getMessageDigest(String.valueOf(new Random().nextInt(10000)).getBytes());
        //簽名數據
        Map<String, String> reqData = new HashMap();
        reqData.put("appid", appid);
        reqData.put("mch_id",mch_id);
        reqData.put("nonce_str",nonce_str);
        reqData.put("sign_type",MD5);
        reqData.put("body",subject);
        reqData.put("out_trade_no",out_trade_no );
        reqData.put("total_fee",finalmoney );
        reqData.put("spbill_create_ip",spbill_create_ip );
        reqData.put("notify_url",notify_url);
        reqData.put("trade_type",tradeType );
        reqData.put("product_id",orderNum);

        //簽名MD5加密
        String sign = null;
        try {
            logger.info("簽名數據:"+reqData);
            System.out.println("reqData="+reqData);

            sign = WeiXinUtils.generateSignature(reqData,Key, MD5);
        } catch (Exception e) {
            logger.error("微信簽名數據:"+e);
            entity.setMessage("微信簽名數據");
            return entity;

        }
        logger.info("簽名數據:"+sign);
        //封裝xml報文
        String xml="<xml>"+
                "<appid>"+ appid+"</appid>"+
                "<mch_id>"+ mch_id+"</mch_id>"+
                "<nonce_str>"+nonce_str+"</nonce_str>"+
                    "<sign>"+sign+"</sign>"+
                "<sign_type>MD5</sign_type>"+
                "<body>"+subject+"</body>"+
                "<out_trade_no>"+out_trade_no+"</out_trade_no>"+
                "<total_fee>"+finalmoney+"</total_fee>"+
                "<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"+
                "<notify_url>"+notify_url+"</notify_url>"+
                "<trade_type>"+tradeType+"</trade_type>"+
            //    "<scene_info>"+scene_info+"</scene_info>"+
                "<product_id>"+orderNum+"</product_id>"+
                "</xml>";

        String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信統一下單接口
        String code_url = "";
        Map map = new HashMap();
        try {
            //預下單 獲取接口地址
            map = WeiXinUtils.getMwebUrl(createOrderURL, xml);
            String return_code  = (String) map.get("return_code");
            String return_msg = (String) map.get("return_msg");
            if("SUCCESS".equals(return_code) && "OK".equals(return_msg)){
                code_url = (String) map.get("code_url");//調微信支付接口地址
                logger.info("map="+map);
                entity.setFlag(true);
                entity.setObject(code_url);
                entity.setMessage("success");
            }else{
                logger.error("統一支付接口獲取預支付訂單出錯"+map);
                entity.setMessage("支付錯誤");
                return entity;
            }
        } catch (Exception e) {
            logger.error("統一支付接口獲取預支付訂單出錯" + e);
            entity.setMessage("支付錯誤");
            return entity;
        }

        return entity;

    }

返回值例子:

<xml><return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[000000]]></appid>
<mch_id><![CDATA[000000000]]></mch_id>
<nonce_str><![CDATA[0000000]]></nonce_str>
<sign><![CDATA[0000000]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
<prepay_id><![CDATA[0000000000]]></prepay_id>
<trade_type><![CDATA[NATIVE]]></trade_type>
<code_url><![CDATA[weixin://wxpay/bizpayurl?pr=0000000000]]></code_url>
</xml>



工具類

package com.zd.exam.Unitl;

import com.zd.exam.Entity.WXPayConstants;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
import org.springframework.stereotype.Component;
import org.xml.sax.InputSource;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedInputStream;
import java.io.StringReader;
import java.security.MessageDigest;
import java.util.*;

@Component
public class WeiXinUtils {

    public static Map getMwebUrl(String url, String xmlParam){
        String jsonStr = null;
        HttpClient httpClient = new HttpClient();
        Map map = new HashMap();
        try {
            PostMethod method = null;
            RequestEntity reqEntity = new StringRequestEntity(xmlParam,"text/json","UTF-8");
            method = new PostMethod(url);
            method.setRequestEntity(reqEntity);
            method.addRequestHeader("Content-Type","application/json;charset=utf-8");
            httpClient.executeMethod(method);
            StringBuffer resBodyBuf = new StringBuffer();
            byte[] responseBody = new byte[1024];
            int readCount = 0;
            BufferedInputStream is = new BufferedInputStream(method.getResponseBodyAsStream());
            while((readCount = is.read(responseBody,0,responseBody.length))!=-1){
                resBodyBuf.append(new String(responseBody,0,readCount,"utf-8"));
            }
            jsonStr = resBodyBuf.toString();
            System.out.println(jsonStr);
            map = parseXmlToList(jsonStr);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }



    /**
     * description: 解析微信通知xml
     *
     * @param xml
     * @return
     * @author ex_yangxiaoyi
     * @see
     */
    @SuppressWarnings({ "unused", "rawtypes", "unchecked" })
    public static Map parseXmlToList(String xml) {
        Map retMap = new HashMap();
        try {
            StringReader read = new StringReader(xml);
            // 創建新的輸入源SAX 解析器將使用 InputSource 對象來確定如何讀取 XML 輸入
            InputSource source = new InputSource(read);
            // 創建一個新的SAXBuilder
            SAXBuilder sb = new SAXBuilder();
            // 通過輸入源構造一個Document
            Document doc = (Document) sb.build(source);
            Element root = doc.getRootElement();// 指向根節點
            List<Element> es = root.getChildren();
            if (es != null && es.size() != 0) {
                for (Element element : es) {
                    retMap.put(element.getName(), element.getValue());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return retMap;
    }

    /**
     * 元轉換成分
     * @param amount
     * @return
     */
    public static String getMoney(String amount) {
        if(amount==null){
            return "";
        }
        // 金額轉化爲分爲單位
        String currency =  amount.replaceAll("\\$|\\¥|\\,", "");  //處理包含, ¥ 或者$的金額
        int index = currency.indexOf(".");
        int length = currency.length();
        Long amLong = 0l;
        if(index == -1){
            amLong = Long.valueOf(currency+"00");
        }else if(length - index >= 3){
            amLong = Long.valueOf((currency.substring(0, index+3)).replace(".", ""));
        }else if(length - index == 2){
            amLong = Long.valueOf((currency.substring(0, index+2)).replace(".", "")+0);
        }else{
            amLong = Long.valueOf((currency.substring(0, index+1)).replace(".", "")+"00");
        }
        return amLong.toString();
    }


    public final static String getMessageDigest(byte[] buffer) {
        char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("MD5");
            mdTemp.update(buffer);
            byte[] md = mdTemp.digest();
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 生成簽名. 注意,若含有sign_type字段,必須和signType參數保持一致。
     *
     * @param data 待簽名數據
     * @param key API密鑰
     * @param signType 簽名方式
     * @return 簽名
     */
    public static String generateSignature(final Map<String, String> data, String key, String signType) throws Exception {
        Set<String> keySet = data.keySet();
        String[] keyArray = keySet.toArray(new String[keySet.size()]);
        Arrays.sort(keyArray);
        StringBuilder sb = new StringBuilder();
        for (String k : keyArray) {
            if (k.equals(WXPayConstants.FIELD_SIGN)) {
                continue;
            }
            if (data.get(k).trim().length() > 0) // 參數值爲空,則不參與簽名
                sb.append(k).append("=").append(data.get(k).trim()).append("&");
        }
        sb.append("key=").append(key);
        if (WXPayConstants.MD5.equals(signType)) {
            return MD5(sb.toString()).toUpperCase();
        }
        else if (WXPayConstants.HMACSHA256.equals(signType)) {
            return HMACSHA256(sb.toString(), key);
        }
        else {
            throw new Exception(String.format("Invalid sign_type: %s", signType));
        }
    }



    /**
     * 生成 MD5
     *
     * @param data 待處理數據
     * @return MD5結果
     */
    public static String MD5(String data) throws Exception {
        java.security.MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }

    /**
     * 生成 HMACSHA256
     * @param data 待處理數據
     * @param key 密鑰
     * @return 加密結果
     * @throws Exception
     */
    public static String HMACSHA256(String data, String key) throws Exception {
        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
        sha256_HMAC.init(secret_key);
        byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }
}



回調方法

    @RequestMapping(value = "/notify")
    public void weixinPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        BufferedReader reader = request.getReader();
        String line = "";
        Map map = new HashMap();
        String xml = "<xml><return_code><![CDATA[FAIL]]></xml>";
        ;
        JSONObject dataInfo = new JSONObject();
        StringBuffer inputString = new StringBuffer();
        while ((line = reader.readLine()) != null) {
            inputString.append(line);
        }
        request.getReader().close();
        logger.info("----接收到的報文---" + inputString.toString());
        if (inputString.toString().length() > 0) {
            map = WeiXinUtils.parseXmlToList(inputString.toString());
        } else {
            logger.info("接受微信報文爲空");
        }
        logger.info("map=" + map);
        if (map != null && "SUCCESS".equals(map.get("result_code"))) {
            //成功的業務。。。


            xml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
        } else {
            //失敗的業務。。。
        }
        //告訴微信端已經確認支付成功
        response.getWriter().write(xml);
    }

生成二維碼路徑需要 QRCode.js 生成二維碼 具體使用方法

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章