1. 程式人生 > >支付寶支付介面之非同步回撥

支付寶支付介面之非同步回撥

近期寫了一個微信支付的非同步回撥,現在就把支付寶的也寫了吧。

@Before(Tx.class)
	public void asynchronous_notify() throws UnsupportedEncodingException {
		try {
			Uransaction Uransaction = common_notify();
		
			renderText("success");
		} catch (ServiceException ex) {
			logger.error(ex.getMessage());
			if (ex.getCode() == 33) {
				renderText("success");
			} else {
				renderText("fail");
			}
			
		}
	}

	private Transaction common_notify() throws UnsupportedEncodingException {
		// 獲取支付寶POST過來反饋資訊
		Map<String, String> params = new HashMap<String, String>();
		Map<String, String[]> requestParams = getRequest().getParameterMap();
		for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
			String name = iter.next();
			String[] values = requestParams.get(name);
			String valueStr = "";
			for (int i = 0; i < values.length; i++) {
				valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
			}
			params.put(name, valueStr);
		}
		logger.info("收到支付寶非同步回撥:");
		logger.info(getRequest().getParameterMap().toString());

		// 交易狀態
		String trade_status = new String(getRequest().getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");

		// 獲取支付寶的通知返回引數
		if (!AlipayNotify.verify(params)) {
			throw new ServiceException(30, "不是支付寶發出的合法訊息");
		}

		if (!"TRADE_FINISHED".equals(trade_status) && !"TRADE_SUCCESS".equals(trade_status)) {
			throw new ServiceException(31, "支付寶返回的交易狀態不正確(trade_status=" + trade_status + ")");
		}

		return "Ok" ;
	}
package com.alipay.util;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

import com.alipay.config.AlipayConfig;
import com.alipay.sign.RSA;

/* *
 *類名:AlipayNotify
 *功能:支付寶通知處理類
 *詳細:處理支付寶各介面通知返回
 *版本:3.3
 *日期:2012-08-17
 *說明:
 *以下程式碼只是為了方便商戶測試而提供的樣例程式碼,商戶可以根據自己網站的需要,按照技術文件編寫,並非一定要使用該程式碼。
 *該程式碼僅供學習和研究支付寶介面使用,只是提供一個參考

 *************************注意*************************
 *除錯通知返回時,可檢視或改寫log日誌的寫入TXT裡的資料,來檢查通知返回是否正常
 */
public class AlipayNotify {

    /**
     * 支付寶訊息驗證地址
     */
    private static final String HTTPS_VERIFY_URL = "https://mapi.alipay.com/gateway.do?service=notify_verify&";

    /**
     * 驗證訊息是否是支付寶發出的合法訊息
     * @param params 通知返回來的引數陣列
     * @return 驗證結果
     */
    public static boolean verify(Map<String, String> params) {

        //判斷responsetTxt是否為true,isSign是否為true
        //responsetTxt的結果不是true,與伺服器設定問題、合作身份者ID、notify_id一分鐘失效有關
        //isSign不是true,與安全校驗碼、請求時的引數格式(如:帶自定義引數等)、編碼格式有關
    	String responseTxt = "false";
		if(params.get("notify_id") != null) {
			String notify_id = params.get("notify_id");
			responseTxt = verifyResponse(notify_id);
		}
	    String sign = "";
	    if(params.get("sign") != null) {sign = params.get("sign");}
	    boolean isSign = getSignVeryfy(params, sign);

        //寫日誌記錄(若要除錯,請取消下面兩行註釋)
        //String sWord = "responseTxt=" + responseTxt + "\n isSign=" + isSign + "\n 返回回來的引數:" + AlipayCore.createLinkString(params);
	    //AlipayCore.logResult(sWord);

        if (isSign && responseTxt.equals("true")) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 根據反饋回來的資訊,生成簽名結果
     * @param Params 通知返回來的引數陣列
     * @param sign 比對的簽名結果
     * @return 生成的簽名結果
     */
	private static boolean getSignVeryfy(Map<String, String> Params, String sign) {
    	//過濾空值、sign與sign_type引數
    	Map<String, String> sParaNew = AlipayCore.paraFilter(Params);
        //獲取待簽名字串
        String preSignStr = AlipayCore.createLinkString(sParaNew);
        //獲得簽名驗證結果
        boolean isSign = false;
        if(AlipayConfig.sign_type.equals("RSA")){
        	isSign = RSA.verify(preSignStr, sign, AlipayConfig.ali_public_key, AlipayConfig.input_charset);
        }
        return isSign;
    }

    /**
    * 獲取遠端伺服器ATN結果,驗證返回URL
    * @param notify_id 通知校驗ID
    * @return 伺服器ATN結果
    * 驗證結果集:
    * invalid命令引數不對 出現這個錯誤,請檢測返回處理中partner和key是否為空 
    * true 返回正確資訊
    * false 請檢查防火牆或者是伺服器阻止埠問題以及驗證時間是否超過一分鐘
    */
    private static String verifyResponse(String notify_id) {
        //獲取遠端伺服器ATN結果,驗證是否是支付寶伺服器發來的請求

        String partner = AlipayConfig.partner;
        String veryfy_url = HTTPS_VERIFY_URL + "partner=" + partner + "¬ify_id=" + notify_id;

        return checkUrl(veryfy_url);
    }

    /**
    * 獲取遠端伺服器ATN結果
    * @param urlvalue 指定URL路徑地址
    * @return 伺服器ATN結果
    * 驗證結果集:
    * invalid命令引數不對 出現這個錯誤,請檢測返回處理中partner和key是否為空 
    * true 返回正確資訊
    * false 請檢查防火牆或者是伺服器阻止埠問題以及驗證時間是否超過一分鐘
    */
    private static String checkUrl(String urlvalue) {
        String inputLine = "";

        try {
            URL url = new URL(urlvalue);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection
                .getInputStream()));
            inputLine = in.readLine().toString();
        } catch (Exception e) {
            e.printStackTrace();
            inputLine = "";
        }

        return inputLine;
    }
}