1. 程式人生 > >微信:微信掃碼支付、呼叫統一下單介面、網站支付 + springmvc

微信:微信掃碼支付、呼叫統一下單介面、網站支付 + springmvc

  1. 準備:根據統一下單介面API我先定義了三個物件:UnifiedOrderRequest(統一下單請求引數(必填))、UnifiedOrderRequestExt(統一下單請求引數(非必填))、UnifiedOrderRespose(統一下單返回引數);具體如下程式碼,get、set方法可自行生產,太佔篇幅。

    UnifiedOrderRequest.class [javascript] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
    1. /** 
    2.  * 統一下單請求引數(必填) 
    3.  * @author Y 
    4.  * 
    5.  */
    6. publicclass UnifiedOrderRequest {  
    7.     private
       String appid;               //公眾賬號ID
    8.     private String mch_id;              //商戶號
    9.     private String nonce_str;           //隨機字串
    10.     private String sign;                //簽名
    11.     private String body;                //商品描述
    12.     private String out_trade_no;        <span style="white-space:pre">    </span>
      //商戶訂單號
    13.     private String total_fee;           //總金額
    14.     private String spbill_create_ip;    <span style="white-space:pre">    </span>//終端IP
    15.     private String notify_url;          //通知地址
    16.     private String trade_type;          //交易型別
    17. }  
    /**
     * 統一下單請求引數(必填)
     * @author Y
     *
     */
    public class UnifiedOrderRequest {
    	private String appid;				//公眾賬號ID
    	private String mch_id;				//商戶號
    	private String nonce_str;			//隨機字串
    	private String sign;				//簽名
    	private String body;				//商品描述
    	private String out_trade_no;		<span style="white-space:pre">	</span>//商戶訂單號
    	private String total_fee;			//總金額
    	private String spbill_create_ip;	<span style="white-space:pre">	</span>//終端IP
    	private String notify_url;			//通知地址
    	private String trade_type;			//交易型別
    }
    UnifiedOrderRequestExt.class [javascript] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
    1. /** 
    2.  * 統一下單請求引數(非必填) 
    3.  * @author Y 
    4.  * 
    5.  */
    6. publicclass UnifiedOrderRequestExt extends UnifiedOrderRequest{  
    7.     private String device_info;         //裝置號
    8.     private String detail;              //商品詳情
    9.     private String attach;              //附加資料
    10.     private String fee_type;            //貨幣型別
    11.     private String time_start;          //交易起始時間
    12.     private String time_expire;         //交易結束時間
    13.     private String goods_tag;           //商品標記
    14.     private String product_id;          //商品ID
    15.     private String limit_pay;           //指定支付方式
    16.     private String openid;              //使用者標識
    17. }  
    /**
     * 統一下單請求引數(非必填)
     * @author Y
     *
     */
    public class UnifiedOrderRequestExt extends UnifiedOrderRequest{
    	
    	private String device_info;			//裝置號
    	private String detail;				//商品詳情
    	private String attach;				//附加資料
    	private String fee_type;			//貨幣型別
    	private String time_start;			//交易起始時間
    	private String time_expire;			//交易結束時間
    	private String goods_tag;			//商品標記
    	private String product_id;			//商品ID
    	private String limit_pay;			//指定支付方式
    	private String openid;				//使用者標識
    }
    UnifiedOrderRespose.class [javascript] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
    1. /** 
    2.  * 統一下單返回引數 
    3.  * @author Y 
    4.  * 
    5.  */
    6. publicclass UnifiedOrderRespose {  
    7.     private String return_code;             //返回狀態碼
    8.     private String return_msg;              //返回資訊
    9.     private String appid;                   //公眾賬號ID
    10.     private String mch_id;                  //商戶號
    11.     private String device_info;             //裝置號
    12.     private String nonce_str;               //隨機字串
    13.     private String sign;                    //簽名
    14.     private String result_code;             //業務結果
    15.     private String err_code;                //錯誤程式碼
    16.     private String err_code_des;            <span style="white-space:pre">    </span>//錯誤程式碼描述
    17.     private String trade_type;              //交易型別
    18.     private String prepay_id;               //預支付交易會話標識
    19.     private String code_url;                //二維碼連結
    20. }  
    /**
     * 統一下單返回引數
     * @author Y
     *
     */
    public class UnifiedOrderRespose {
    	private String return_code;				//返回狀態碼
    	private String return_msg;				//返回資訊
    	private String appid;					//公眾賬號ID
    	private String mch_id;					//商戶號
    	private String device_info;				//裝置號
    	private String nonce_str;				//隨機字串
    	private String sign;					//簽名
    	private String result_code;				//業務結果
    	private String err_code;				//錯誤程式碼
    	private String err_code_des;			<span style="white-space:pre">	</span>//錯誤程式碼描述
    	private String trade_type;				//交易型別
    	private String prepay_id;				//預支付交易會話標識
    	private String code_url;				//二維碼連結
    }
  2. Controller主入口: [javascript] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
    1. /** 
    2.  * 建立二維碼 
    3.  */
    4. @RequestMapping("createQRCode")  
    5. publicvoid createQRCode(String orderId, HttpServletResponse response) {  
    6.     //生成訂單
    7.     String orderInfo = createOrderInfo(orderId);  
    8.     //調統一下單API
    9.     String code_url = httpOrder(orderInfo);  
    10.     //將返回預支付交易連結(code_url)生成二維碼圖片
    11.     //這裡使用的是zxing   <span style="color:#ff0000;"><strong>說明1(見文末)</strong></span>
    12.     try {  
    13.         int width = 200;  
    14.         int height = 200;  
    15.         String format = "png";  
    16.         Hashtable hints = new Hashtable();  
    17.         hints.put(EncodeHintType.CHARACTER_SET, "utf-8");  
    18.         BitMatrix bitMatrix = new MultiFormatWriter().encode(code_url, BarcodeFormat.QR_CODE, width, height, hints);  
    19.         OutputStream out = null;  
    20.         out = response.getOutputStream();  
    21.         MatrixToImageWriter.writeToStream(bitMatrix, format, out);  
    22.         out.flush();  
    23.         out.close();  
    24.     } catch (Exception e) {  
    25.     }  
    26. }  
    	/**
    	 * 建立二維碼
    	 */
    	@RequestMapping("createQRCode")
    	public void createQRCode(String orderId, HttpServletResponse response) {
    		
    		//生成訂單
    		String orderInfo = createOrderInfo(orderId);
    		//調統一下單API
    		String code_url = httpOrder(orderInfo);
    		//將返回預支付交易連結(code_url)生成二維碼圖片
    		//這裡使用的是zxing   <span style="color:#ff0000;"><strong>說明1(見文末)</strong></span>
    		try {
    			int width = 200;
    			int height = 200;
    			String format = "png";
    			Hashtable hints = new Hashtable();
    			hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
    			BitMatrix bitMatrix = new MultiFormatWriter().encode(code_url, BarcodeFormat.QR_CODE, width, height, hints);
    			OutputStream out = null;
    			out = response.getOutputStream();
    			MatrixToImageWriter.writeToStream(bitMatrix, format, out);
    			out.flush();
    			out.close();
    		} catch (Exception e) {
    		}
    
    	}

  3. 生成訂單:分兩部分:一部分是業務需求的訂單資訊,就是發起支付前的訂單資訊,業務系統自行建立儲存;另一部分是滿足統一下單API要求的訂單資訊(也是我們這裡要講的)。“xxxxxx”:是你需要自己填寫的對應資訊: [javascript] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
    1. /** 
    2.  * 生成訂單 
    3.  * @param orderId 
    4.  * @return 
    5.  */
    6. private String createOrderInfo(String orderId) {  
    7.     //生成訂單物件
    8.     UnifiedOrderRequest unifiedOrderRequest = new UnifiedOrderRequest();  
    9.     unifiedOrderRequest.setAppid("xxxxxxxxxxxxx");//公眾賬號ID
    10.     unifiedOrderRequest.setMch_id("xxxxxxxxx");//商戶號
    11.     unifiedOrderRequest.setNonce_str(StringUtil.makeUUID());//隨機字串       <span style="color:#ff0000;"><strong>說明2(見文末)</strong></span>
    12.     unifiedOrderRequest.setBody("xxxxxx");//商品描述
    13.     unifiedOrderRequest.setOut_trade_no(orderId);//商戶訂單號
    14.     unifiedOrderRequest.setTotal_fee("x");  //金額需要擴大100倍:1代表支付時是0.01
    15.     unifiedOrderRequest.setSpbill_create_ip("xxxxxxxxxxxxx");//終端IP
    16.     unifiedOrderRequest.setNotify_url("xxxxxxxxxxxxxx");//通知地址
    17.     unifiedOrderRequest.setTrade_type("NATIVE");//JSAPI--公眾號支付、NATIVE--原生掃碼支付、APP--app支付
    18.     unifiedOrderRequest.setSign(createSign(unifiedOrderRequest));//簽名<span style="color:#ff0000;"><strong>說明5(見文末,簽名方法一併給出)</strong></span>
    19.     //將訂單物件轉為xml格式
    20.     XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-""_"))); //<span style="color:#ff0000;"><strong>說明3(見文末)</strong></span>
    21.     xStream.alias("xml", UnifiedOrderRequest.class);//根元素名需要是xml
    22.     return xStream.toXML(unifiedOrderRequest);  
    23. }  
    	/**
    	 * 生成訂單
    	 * @param orderId
    	 * @return
    	 */
    	private String createOrderInfo(String orderId) {
    		//生成訂單物件
    		UnifiedOrderRequest unifiedOrderRequest = new UnifiedOrderRequest();
    		unifiedOrderRequest.setAppid("xxxxxxxxxxxxx");//公眾賬號ID
    		unifiedOrderRequest.setMch_id("xxxxxxxxx");//商戶號
    		unifiedOrderRequest.setNonce_str(StringUtil.makeUUID());//隨機字串       <span style="color:#ff0000;"><strong>說明2(見文末)</strong></span>
    		unifiedOrderRequest.setBody("xxxxxx");//商品描述
    		unifiedOrderRequest.setOut_trade_no(orderId);//商戶訂單號
    		unifiedOrderRequest.setTotal_fee("x");	//金額需要擴大100倍:1代表支付時是0.01
    		unifiedOrderRequest.setSpbill_create_ip("xxxxxxxxxxxxx");//終端IP
    		unifiedOrderRequest.setNotify_url("xxxxxxxxxxxxxx");//通知地址
    		unifiedOrderRequest.setTrade_type("NATIVE");//JSAPI--公眾號支付、NATIVE--原生掃碼支付、APP--app支付
    		unifiedOrderRequest.setSign(createSign(unifiedOrderRequest));//簽名<span style="color:#ff0000;"><strong>說明5(見文末,簽名方法一併給出)</strong></span>
    		//將訂單物件轉為xml格式
    		XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_"))); //<span style="color:#ff0000;"><strong>說明3(見文末)</strong></span>
    		xStream.alias("xml", UnifiedOrderRequest.class);//根元素名需要是xml
    		return xStream.toXML(unifiedOrderRequest);
    	}

  4. 調統一下單API:根據要求將生成訂單中返回的xml向微信給定的統一下單URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder,傳送請求,成功並獲得二維碼。 [javascript] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
    1. /** 
    2.  * 調統一下單API 
    3.  * @param orderInfo 
    4.  * @return 
    5.  */
    6. private String httpOrder(String orderInfo) {  
    7.     String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";  
    8.     try {  
    9.         HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();  
    10.         //加入資料  
    11.            conn.setRequestMethod("POST");    
    12.            conn.setDoOutput(true);    
    13.            BufferedOutputStream buffOutStr = new BufferedOutputStream(conn.getOutputStream());    
    14.            buffOutStr.write(orderInfo.getBytes());  
    15.            buffOutStr.flush();    
    16.            buffOutStr.close();    
    17.            //獲取輸入流  
    18.            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));    
    19.            String line = null;    
    20.            StringBuffer sb = new StringBuffer();    
    21.            while((line = reader.readLine())!= null){    
    22.                sb.append(line);    
    23.            }    
    24.            XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-""_")));//說明3(見文末)
    25.            //將請求返回的內容通過xStream轉換為UnifiedOrderRespose物件
    26.            xStream.alias("xml", UnifiedOrderRespose.class);  
    27.            UnifiedOrderRespose unifiedOrderRespose = (UnifiedOrderRespose) xStream.fromXML(sb.toString());  
    28.            //根據微信文件return_code 和result_code都為SUCCESS的時候才會返回code_url
    29.            //<span style="color:#ff0000;"><strong>說明4(見文末)</strong></span>
    30.            if(null!=unifiedOrderRespose   
    31.                 && "SUCCESS".equals(unifiedOrderRespose.getReturn_code())   
    32.                 && "SUCCESS".equals(unifiedOrderRespose.getResult_code())){  
    33.             return unifiedOrderRespose.getCode_url();  
    34.            }else{  
    35.             returnnull;  
    36.            }  
    37.     } catch (Exception e) {  
    38.         e.printStackTrace();  
    39.     }  
    40.     returnnull;  
    41. }  
    	/**
    	 * 調統一下單API
    	 * @param orderInfo
    	 * @return
    	 */
    	private String httpOrder(String orderInfo) {
    		String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    		try {
    			HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
    			//加入資料  
                conn.setRequestMethod("POST");  
                conn.setDoOutput(true);  
                  
                BufferedOutputStream buffOutStr = new BufferedOutputStream(conn.getOutputStream());  
                buffOutStr.write(orderInfo.getBytes());
                buffOutStr.flush();  
                buffOutStr.close();  
                  
                //獲取輸入流  
                BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));  
                  
                String line = null;  
                StringBuffer sb = new StringBuffer();  
                while((line = reader.readLine())!= null){  
                    sb.append(line);  
                }  
                
                XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_")));//說明3(見文末)
                //將請求返回的內容通過xStream轉換為UnifiedOrderRespose物件
                xStream.alias("xml", UnifiedOrderRespose.class);
                UnifiedOrderRespose unifiedOrderRespose = (UnifiedOrderRespose) xStream.fromXML(sb.toString());
                
                //根據微信文件return_code 和result_code都為SUCCESS的時候才會返回code_url
                //<span style="color:#ff0000;"><strong>說明4(見文末)</strong></span>
                if(null!=unifiedOrderRespose 
                		&& "SUCCESS".equals(unifiedOrderRespose.getReturn_code()) 
                		&& "SUCCESS".equals(unifiedOrderRespose.getResult_code())){
                	return unifiedOrderRespose.getCode_url();
                }else{
                	return null;
                }
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return null;
    	}

  5. 將返回的支付交易連結生成二維碼展示:沒有異常的情況下,在頁面中使用<img>標籤接收就行。實際使用時,結合前端和業務的需求放置二維碼。可以在掃碼支付/案例及規範中找到部分素材和介面規範來設計微信風格的支付頁面。 [javascript] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
    1. <img src="${ctx}/wxPay/createQRCode?orderId=1111" width="174px">  
    <img src="${ctx}/wxPay/createQRCode?orderId=1111" width="174px">

  6. 使用者可以通過維繫客戶端進行掃碼支付。支付完成後回撥我們notify_url設定的url,通過成功的回撥來更改業務系統中的訂單狀態或者一些業務需求。這裡回撥沒有寫出可以參考支付寶:web頁面掃碼支付、網站支付、支付寶即時到賬 + springmvc中的回撥。