天天看點

支付寶APP支付——支付流程說明及示例支付寶APP支付——支付流程說明及示例

支付寶APP支付——支付流程說明及示例

官方示例圖

螞蟻金服開放平台文檔:位址

官方流程圖:位址

支付寶APP支付——支付流程說明及示例支付寶APP支付——支付流程說明及示例
如圖,以Android平台為例:

第步:調用支付接口:此消息就是本接口所描述的支付寶用戶端SDK提供的支付對象PayTask,将商戶簽名後的訂單資訊傳進payv2方法喚起支付寶收銀台,交易資料格式具體參見請求參數說明。

第步:支付請求:支付寶用戶端SDK将會按照商戶用戶端提供的請求參數發送支付請求。

第步:接口傳回支付結果:商戶用戶端在第步中調用的支付接口,會傳回最終的支付結果(即同步通知),參見用戶端同步傳回。

第步:使用者在支付寶APP或H5收銀台完成支付後,會根據商戶在手機網站支付API中傳入的前台回跳位址return_url自動跳轉回商戶頁面,同時在URL請求中附帶上支付結果參數。同時,支付寶還會根據原始支付API中傳入的異步通知位址notify_url,通過POST請求的形式将支付結果作為參數通知到商戶系統,詳情見支付結果異步通知。



除了正向支付流程外,支付寶也提供交易查詢、關閉、退款、退款查詢以及對賬等配套API。

特别注意:

    構造交易資料并簽名必須在商戶服務端完成,商戶的應用私鑰絕對不能儲存在商戶APP用戶端中,也不能從服務端下發。

    同步傳回的資料,隻是一個簡單的結果通知,商戶确定該筆交易付款是否成功需要依賴服務端收到支付寶異步通知的結果進行判斷。

    商戶系統接收到通知以後,必須通過驗簽(驗證通知中的sign參數)來確定支付通知是由支付寶發送的。建議使用支付寶提供的SDK來完成,詳細驗簽規則參考異步通知驗簽。
           

個人實際應用後的了解及實作

  1. 生成訂單資訊
  2. app調用支付寶支付接口,服務端會傳回支付資訊
  3. 支付寶服務端調用異步通知接口,根據傳回資訊處理自己的業務邏輯,比如記入本地台賬,修改訂單狀态等

生成訂單資訊

1. 建立本地訂單并儲存, 商品,價格,訂單号

/**

 * 添加一條支付寶的訂單

 * @param user

 * @param vipPrice

 * @return

 */

private VipOrder addVipOrder(User user, VipPrice vipPrice) {

    //根據業務設定訂單參數

    VipOrder vo = new VipOrder();

    vo.setCostPrice(vipPrice.getCostPrice());//原價

    vo.setCurrentPrice(vipPrice.getCurrentPrice());//現價

    vo.setGoodsId(Integer.parseInt(vipPrice.getId()));//商品id

    vo.setGoodsName(vipPrice.getTypeName()+vipPrice.getName());//商品名稱

    vo.setPayMode(VipOrder.PAYMODE_ALIPAY);//支付寶

    vo.setPayState(VipOrder.PAYSTATE_CREATE);//支付狀态

    vo.setVipId(String.valueOf(vipPrice.getVipId()));//vipId

    vo.setVipName(vipPrice.getTypeName());//vip名稱

    vo.setTimesNum(vipPrice.getTimesNum());//時長

    vo.setUserId(user.getUid());//使用者id

    vo.setUserName(user.getUsername());//使用者名稱

    vo.setOrderNum(OrderInfoUtil2_0.getOutTradeNo(user.getUid()))//訂單号,自定義随機碼就可以建議位;

    vo.setComId(String.valueOf(user.getCom_id()));//公司id

    vo.setComName(user.getCom_name());//公司名稱

    vo.setIsClaim();//初始化賬單為未索取

    vipOrderMapper.add(vo);//新增一條資料

    return vo;

}
           

訂單實體

/**

 * vip_order 實體類

 * 

 * @author pzr

 */

public class VipOrder implements Serializable {



    /**

     * 支付方式 支付寶

     */

    public static final String PAYMODE_ALIPAY = "alipay";

    /**

     * 支付方式 微信

     */

    public static final String PAYMODE_WX = "wx";

    /**

     * 支付狀态 建立待付款

     */

    public static final String PAYSTATE_CREATE = "create";

    /**

     * 支付狀态 支付成功

     */

    public static final String PAYSTATE_SUCCESS = "success";

    /**

     * 支付狀态 支付完成,完成後不可退款

     */

    public static final String PAYSTATE_FINISHED = "finished";

    /**

     * 支付狀态 支付失敗

     */

    public static final String PAYSTATE_FAILURE = "failure";



    private static final long serialVersionUID = -L;

    /**

     * 套餐id

     */

    private Integer goodsId = -;

    /**

     * 原價

     */

    private String costPrice;

    /**

     * 備注

     */

    private String remark;

    /**

     * 商品時長 機關(月)

     */

    private Integer timesNum = -;

    /**

     * vip編号

     */

    private String orderNum;

    /**

     * 現價

     */

    private String currentPrice;

    /**

     * 

     */

    private String id;

    /**

     * 訂單建立時間

     */

    private String createtime;

    /**

     * 支付狀态

     */

    private String payState;

    /**

     * 處理對象,包含【處理時間】【處理類型】

     */

    private Integer handId = -;

    /**

     * 支付方式

     */

    private String payMode;

    /**

     * 使用者id

     */

    private Integer userId = -;

    /**

     * 使用者名稱

     */

    private String userName;

    /**

     * 商品名稱

     */

    private String goodsName;



    /**

     * 企業id

     */

    private String comId;



    /**

     * 企業名稱

     */

    private String comName;



    /**

     * 會員名稱

     */

    private String vipName;



    /**

     * 會員id

     */

    private String vipId;



    /**

     * 是否索取發票,【1、已索取,2、未索取,3、索取中】

     */

    private Integer isClaim = -;



    /**

     * 是否郵寄發票,【1、是,2、否】

     */

    private Integer isMail = -;



    public String getVipId() {

        return vipId;

    }



    public void setVipId(String vipId) {

        this.vipId = vipId;

    }



    public String getVipName() {

        return vipName;

    }



    public void setVipName(String vipName) {

        this.vipName = vipName;

    }



    public String getComId() {

        return comId;

    }



    public void setComId(String comId) {

        this.comId = comId;

    }



    public String getComName() {

        return comName;

    }



    public void setComName(String comName) {

        this.comName = comName;

    }



    public void setGoodsId(Integer goodsId) {

        this.goodsId = goodsId;

    }



    public Integer getGoodsId() {

        return goodsId;

    }



    public void setCostPrice(String costPrice) {

        this.costPrice = costPrice;

    }



    public String getCostPrice() {

        return costPrice;

    }



    public void setRemark(String remark) {

        this.remark = remark;

    }



    public String getRemark() {

        return remark;

    }



    public void setTimesNum(Integer timesNum) {

        this.timesNum = timesNum;

    }



    public Integer getTimesNum() {

        return timesNum;

    }



    public void setOrderNum(String orderNum) {

        this.orderNum = orderNum;

    }



    public String getOrderNum() {

        return orderNum;

    }



    public void setCurrentPrice(String currentPrice) {

        this.currentPrice = currentPrice;

    }



    public String getCurrentPrice() {

        return currentPrice;

    }



    public void setId(String id) {

        this.id = id;

    }



    public String getId() {

        return id;

    }



    public void setCreatetime(String createtime) {

        this.createtime = createtime;

    }



    public String getCreatetime() {

        return createtime;

    }



    public void setPayState(String payState) {

        this.payState = payState;

    }



    public String getPayState() {

        return payState;

    }



    public void setHandId(Integer handId) {

        this.handId = handId;

    }



    public Integer getHandId() {

        return handId;

    }



    public void setPayMode(String payMode) {

        this.payMode = payMode;

    }



    public String getPayMode() {

        return payMode;

    }



    public void setUserId(Integer userId) {

        this.userId = userId;

    }



    public Integer getUserId() {

        return userId;

    }



    public void setUserName(String userName) {

        this.userName = userName;

    }



    public String getUserName() {

        return userName;

    }



    public void setGoodsName(String goodsName) {

        this.goodsName = goodsName;

    }



    public String getGoodsName() {

        return goodsName;

    }



    public Integer getIsClaim() {

        return isClaim;

    }



    public void setIsClaim(Integer isClaim) {

        this.isClaim = isClaim;

    }



    public Integer getIsMail() {

        return isMail;

    }



    public void setIsMail(Integer isMail) {

        this.isMail = isMail;

    }



    // 重寫Object對象的equals方法

    @Override

    public boolean equals(Object obj) {

        if (this == obj) {

            return true;

        } else {

            if (obj == null) {

                return false;

            }

            final VipOrder vipOrder = (VipOrder) obj;

            if (this.getId().equals(vipOrder.getId())) {

                return true;

            } else {

                return false;

            }

        }

    }

}
           

2. 根據訂單,結合支付寶業務對象,生成訂單資訊字元串,并傳回

/**

 * 支付寶生成訂單資訊

 * @param vipPrice

 * @param vo

 * @return

 */

private String aliPayHandle(VipPrice vipPrice, VipOrder vo) {

    String subject = vo.getGoodsName(); //商品标題

    String out_trade_no = vo.getOrderNum(); //商品網站唯一訂單号 32位

    String total_amount = vo.getCurrentPrice(); //支付價格

    //拼裝業務對象,可以設定個性化内容

    WorkParameter wp = new WorkParameter(subject, out_trade_no, total_amount);

    wp.setTimeout_express("30m");//收款時間

    wp.setBody(vipPrice.getName());

    String passback_params = vo.getId();

    try {

        passback_params = URLEncoder.encode(passback_params, "UTF-8");

    } catch (UnsupportedEncodingException e) {

        e.printStackTrace();

    }//URL編碼,支付寶需要以這樣的方式傳遞參數

    wp.setPassback_params(passback_params);//公用回傳參數

    String orderInfo = OrderInfoUtil2_0.getOrderInfo(wp);//生成傳回字元串

    return orderInfo;

}
           

OrderInfoUtil2_0工具類

import java.io.IOException;

import java.io.InputStream;

import java.io.UnsupportedEncodingException;

import java.net.URLEncoder;

import java.text.SimpleDateFormat;

import java.util.ArrayList;

import java.util.Collections;

import java.util.Date;

import java.util.HashMap;

import java.util.List;

import java.util.Locale;

import java.util.Map;

import java.util.Properties;

import java.util.Random;



import com.fasterxml.jackson.annotation.JsonInclude.Include;

import com.fasterxml.jackson.core.JsonProcessingException;

import com.fasterxml.jackson.databind.ObjectMapper;



public class OrderInfoUtil2_0 {



    /**

     * 構造授權參數清單

     * 

     * @param pid

     * @param app_id

     * @param target_id

     * @return

     */

    public static Map<String, String> buildAuthInfoMap(String pid,

            String app_id, String target_id) {

        Map<String, String> keyValues = new HashMap<String, String>();



        // 商戶簽約拿到的app_id,如:2013081700024223

        keyValues.put("app_id", app_id);



        // 商戶簽約拿到的pid,如:2088102123816631

        keyValues.put("pid", pid);



        // 服務接口名稱, 固定值

        keyValues.put("apiname", "com.alipay.account.auth");



        // 商戶類型辨別, 固定值

        keyValues.put("app_name", "mc");



        // 業務類型, 固定值

        keyValues.put("biz_type", "openservice");



        // 産品碼, 固定值

        keyValues.put("product_id", "APP_FAST_LOGIN");



        // 授權範圍, 固定值

        keyValues.put("scope", "kuaijie");



        // 商戶唯一辨別,如:kkkkk091125

        keyValues.put("target_id", target_id);



        // 授權類型, 固定值

        keyValues.put("auth_type", "AUTHACCOUNT");



        // 簽名類型

        keyValues.put("sign_type", "RSA");



        return keyValues;

    }



    /**

     * 構造支付訂單參數清單

     * 

     * @param pid

     * @param app_id

     * @param target_id

     * @return

     */

    public static Map<String, String> buildOrderParamMap(String app_id,

            WorkParameter wp) {



        InputStream in = Object.class.getResourceAsStream("/test.properties");



        Map<String, String> keyValues = new HashMap<String, String>();



        ObjectMapper objectMapper = new ObjectMapper();

        objectMapper.setSerializationInclusion(Include.NON_EMPTY);

        String biz_contentStr = "";

        try {

            biz_contentStr = objectMapper.writeValueAsString(wp);

        } catch (JsonProcessingException e) {

            e.printStackTrace();

        }

        System.out.println(biz_contentStr);

        keyValues.put("app_id", app_id);

        keyValues.put("biz_content", biz_contentStr);

        keyValues.put("charset", "utf-8");

        keyValues.put("method", "alipay.trade.app.pay");

        keyValues.put("sign_type", "RSA");

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:s");

        keyValues.put("timestamp", sdf.format(new Date()));

        keyValues.put("notify_url", AlipayConfig.notify_url);



        keyValues.put("version", "1.0");



        return keyValues;

    }



    /**

     * 構造支付訂單參數資訊

     * 

     * @param map

     *            支付訂單參數

     * @return

     */

    public static String buildOrderParam(Map<String, String> map) {

        List<String> keys = new ArrayList<String>(map.keySet());



        StringBuilder sb = new StringBuilder();

        for (int i = ; i < keys.size() - ; i++) {

            String key = keys.get(i);

            String value = map.get(key);

            sb.append(buildKeyValue(key, value, true));

            sb.append("&");

        }



        String tailKey = keys.get(keys.size() - );

        String tailValue = map.get(tailKey);

        sb.append(buildKeyValue(tailKey, tailValue, true));



        return sb.toString();

    }



    /**

     * 拼接鍵值對

     * 

     * @param key

     * @param value

     * @param isEncode

     * @return

     */

    private static String buildKeyValue(String key, String value,

            boolean isEncode) {

        StringBuilder sb = new StringBuilder();

        sb.append(key);

        sb.append("=");

        if (isEncode) {

            try {

                sb.append(URLEncoder.encode(value, "UTF-8"));

            } catch (UnsupportedEncodingException e) {

                sb.append(value);

            }

        } else {

            sb.append(value);

        }

        return sb.toString();

    }



    /**

     * 對支付參數資訊進行簽名

     * 

     * @param map

     *            待簽名授權資訊

     * 

     * @return

     */

    public static String getSign(Map<String, String> map, String rsaKey) {

        List<String> keys = new ArrayList<String>(map.keySet());

        // key排序

        Collections.sort(keys);



        StringBuilder authInfo = new StringBuilder();

        for (int i = ; i < keys.size() - ; i++) {

            String key = keys.get(i);

            String value = map.get(key);

            authInfo.append(buildKeyValue(key, value, false));

            authInfo.append("&");

        }



        String tailKey = keys.get(keys.size() - );

        String tailValue = map.get(tailKey);

        authInfo.append(buildKeyValue(tailKey, tailValue, false));



        String oriSign = SignUtils.sign(authInfo.toString(), rsaKey);

        String encodedSign = "";



        try {

            encodedSign = URLEncoder.encode(oriSign, "UTF-8");

        } catch (UnsupportedEncodingException e) {

            e.printStackTrace();

        }

        return "sign=" + encodedSign;

    }



    /**

     * 要求外部訂單号必須唯一。

     * 

     * @return

     */

    public static String getOutTradeNo(int id) {

        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmssS",

                Locale.getDefault());

        Date date = new Date();

        String key = format.format(date);



        Random r = new Random();

        // 5位随機碼

        int i = r.nextInt() % ( -  + ) + ;

        // id補0

        String idStr = getIdStr(id);

        key = idStr + key + i;

        key = key.substring(, );

        return key;

    }



    /**

     * id補0 字元串長度12位 id不夠的補0

     * 

     * @param id

     * @return

     */

    private static String getIdStr(int id) {

        String str = "";

        if ( < id && id < ) {

            str = "00000000000" + id;

        }

        if ( <= id && id < ) {

            str = "0000000000" + id;

        }

        if ( <= id && id < ) {

            str = "000000000" + id;

        }

        if ( <= id && id < ) {

            str = "00000000" + id;

        }

        if ( <= id && id < ) {

            str = "0000000" + id;

        }

        if ( <= id && id < ) {

            str = "000000" + id;

        }

        if ( <= id && id < ) {

            str = "00000" + id;

        }

        return str;

    }



    /**

     * 擷取訂單資訊

     * 

     * @param wp

     *            訂單基礎資訊對象

     * @return

     */

    public static String getOrderInfo(WorkParameter wp) {

        Properties prop = new Properties();

        String appid = "";

        String private_key = "";

        InputStream in = OrderInfoUtil2_0.class

                .getResourceAsStream("zfbinfo.properties");



        try {

            prop.load(in);

            appid = prop.getProperty("appid").trim();

            private_key = prop.getProperty("private_key").trim();

        } catch (IOException e) {

            e.printStackTrace();

        }

        Map<String, String> params = OrderInfoUtil2_0.buildOrderParamMap(appid,

                wp);

        String orderParam = OrderInfoUtil2_0.buildOrderParam(params);

        // 添加簽名

        String sign = OrderInfoUtil2_0.getSign(params, private_key);

        // 組裝參數

        String orderInfo = orderParam + "&" + sign;

        return orderInfo;

    }



}
           

zfbinfo.properties配置檔案(支付寶參數配置檔案)

可下載下傳支付寶官方密鑰生成工具

位址:https://doc.open.alipay.com/docs/doc.htm?treeId=291&articleId=105971&docType=1

open_api_domain =   https://openapi.alipaydev.com/gateway.do

mcloud_api_domain = http://mcloudmonitor.com/gateway.do

pid = pid

appid =  appid



private_key = 私鑰

public_key = 公鑰

alipay_public_key = 公鑰
           

業務對象

/**

 * 業務參數對象

 * @author pzr

 *

 */

public class WorkParameter {

    /**

     * 【非必填】

     * 對一筆交易的具體描述資訊。如果是多種商品,請将商品描述字元串累加傳給body。

     */

    private String body;

    /**

     * 【必填】

     * 商品的标題/交易标題/訂單标題/訂單關鍵字等。

     */

    private String subject;

    /**

     * 【必填】

     * 商戶網站唯一訂單号

     */

    private String out_trade_no;

    /**

     * 【非必填】

     * 該筆訂單允許的最晚付款時間,逾期将關閉交易。

     * 取值範圍:1m~15d。m-分鐘,h-小時,d-天,1c-當天(1c-當天的情況下,無論交易何時建立,都在0點關閉)。

     *  該參數數值不接受小數點, 如 1.5h,可轉換為 90m。

     */

    private String timeout_express;

    /**

     * 【必填】

     * 訂單總金額,機關為元,精确到小數點後兩位,取值範圍[0.01,100000000]

     */

    private String total_amount;

    /**

     * 【非必填】

     * 收款支付寶使用者ID。 如果該值為空,則預設為商戶簽約賬号對應的支付寶使用者ID

     */

    private String seller_id;

    /**

     * 【必填】

     * 銷售産品碼,商家和支付寶簽約的産品碼,為固定值QUICK_MSECURITY_PAY

     */

    private String product_code = "QUICK_MSECURITY_PAY";

    /**

     * 【非必填】

     * 商品主類型:0—虛拟類商品,1—實物類商品

     * 注:虛拟類商品不支援使用花呗管道

     */

    private String goods_type;

    /**

     * 【非必填】

     * 公用回傳參數,如果請求時傳遞了該參數,則傳回給商戶時會回傳該參數。

     * 支付寶會在異步通知時将該參數原樣傳回。本參數必須進行UrlEncode之後才可以發送給支付寶

     */

    private String passback_params;

    /**

     * 【非必填】

     * 優惠參數

     * 注:僅與支付寶協商後可用

     */

    private String promo_params;

    /**

     * 【非必填】

     * 業務擴充參數,詳見下面的“業務擴充參數說明”

     */

    private String extend_params;

    /**

     * 【非必填】

     * 可用管道,使用者隻能在指定管道範圍内支付

     * 當有多個管道時用“,”分隔

     * 注:與disable_pay_channels互斥

     */

    private String enable_pay_channels;

    /**

     * 【非必填】

     * 禁用管道,使用者不可用指定管道支付

     * 當有多個管道時用“,”分隔

     * 注:與enable_pay_channels互斥

     */

    private String disable_pay_channels;



    public WorkParameter(){



    }



    /**

     * 必填項構造方法

     * @param subject  商品的标題/交易标題/訂單标題/訂單關鍵字等。

     * @param out_trade_no 商戶網站唯一訂單号

     * @param total_amount 訂單總金額,機關為元,精确到小數點後兩位,取值範圍[0.01,100000000]

     */

    public WorkParameter(String subject,String out_trade_no,String total_amount){

        this.subject = subject;

        this.out_trade_no = out_trade_no;

        this.total_amount = total_amount;

    }



    public String getBody() {

        return body;

    }

    public void setBody(String body) {

        this.body = body;

    }

    public String getSubject() {

        return subject;

    }

    public void setSubject(String subject) {

        this.subject = subject;

    }

    public String getOut_trade_no() {

        return out_trade_no;

    }

    public void setOut_trade_no(String out_trade_no) {

        this.out_trade_no = out_trade_no;

    }

    public String getTimeout_express() {

        return timeout_express;

    }

    public void setTimeout_express(String timeout_express) {

        this.timeout_express = timeout_express;

    }

    public String getTotal_amount() {

        return total_amount;

    }

    public void setTotal_amount(String total_amount) {

        this.total_amount = total_amount;

    }

    public String getSeller_id() {

        return seller_id;

    }

    public void setSeller_id(String seller_id) {

        this.seller_id = seller_id;

    }

    public String getProduct_code() {

        return product_code;

    }

    public void setProduct_code(String product_code) {

        this.product_code = product_code;

    }

    public String getGoods_type() {

        return goods_type;

    }

    public void setGoods_type(String goods_type) {

        this.goods_type = goods_type;

    }

    public String getPassback_params() {

        return passback_params;

    }

    public void setPassback_params(String passback_params) {

        this.passback_params = passback_params;

    }

    public String getPromo_params() {

        return promo_params;

    }

    public void setPromo_params(String promo_params) {

        this.promo_params = promo_params;

    }

    public String getExtend_params() {

        return extend_params;

    }

    public void setExtend_params(String extend_params) {

        this.extend_params = extend_params;

    }

    public String getEnable_pay_channels() {

        return enable_pay_channels;

    }

    public void setEnable_pay_channels(String enable_pay_channels) {

        this.enable_pay_channels = enable_pay_channels;

    }

    public String getDisable_pay_channels() {

        return disable_pay_channels;

    }

    public void setDisable_pay_channels(String disable_pay_channels) {

        this.disable_pay_channels = disable_pay_channels;

    }

}
           

app調用支付寶支付接口,服務端會傳回支付資訊

參考:https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.DO5i9o&treeId=204&articleId=105296&docType=1

關鍵代碼:其中orderInfo就是服務端傳回的訂單資訊

final String orderInfo = info;   // 訂單資訊

Runnable payRunnable = new Runnable() {



    @Override

    public void run() {

        PayTask alipay = new PayTask(DemoActivity.this);

        String result = alipay.payV2(orderInfo,true);



        Message msg = new Message();

        msg.what = SDK_PAY_FLAG;

        msg.obj = result;

        mHandler.sendMessage(msg);

    }

};

 // 必須異步調用

Thread payThread = new Thread(payRunnable);

payThread.start();
           

支付寶服務端調用異步通知接口處理

支付寶服務端調用異步通知接口,根據傳回資訊處理自己的業務邏輯,比如記入本地台賬,修改訂單狀态等

支付寶回調是要進行驗簽的,驗證通過後在進行操作

關鍵代碼:

/**

 * 支付寶異步回調

 * 

 * @return

 * @throws UnsupportedEncodingException

 */

@RequestMapping(value = "/vipBuy.do", method = RequestMethod.POST)

@ResponseBody

public void vipBuy(HttpServletRequest request,HttpServletResponse response)

        throws UnsupportedEncodingException {

    String str = "";

    // 擷取支付寶POST過來回報資訊

    Map<String, String> params = getReqParam(request);

    // 異步通知ID

    String notify_id = request.getParameter("notify_id");

    // 交易狀态

    String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");

    // 擷取支付寶的通知傳回參數//

    if (notify_id != "" && notify_id != null) {// //判斷接受的post通知中有無notify_id,如果有則是異步通知。

        boolean signVerified = false;//驗簽标志

        try {

            signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, "UTF-8");

        } catch (AlipayApiException e) {

            e.printStackTrace();

        }

        // 使用支付寶公鑰驗簽

        if (signVerified){

            //擷取回傳參數passback_params,即是訂單id

            String orderNum = vaan.getOut_trade_no();//訂單号

            String orderId = vaan.getPassback_params();//訂單id

            //通過訂單id和訂單編号擷取指定的訂單資訊

            VipOrder vo = new VipOrder();

            vo.setId(orderId);

            vo.setOrderNum(orderNum);

            vo = vipOrderMapper.findByIdOrderNum(vo);

            //驗證請求真實性

            boolean flag = checkTrue(vaan,vo);

            if(flag){

                //各狀态處理

                if (trade_status.equals("TRADE_FINISHED")) {

                    //沒有涉及退款流程,支付完成即是交易結束

                } else if (trade_status.equals("TRADE_SUCCESS")) {

                    //交易成功的邏輯處理

                }

                str = "success";

            }else{

                str = "failure";

            }

        } else{

            // 驗證簽名失敗

            str = "failure";

        }

    } 

    //傳回給支付寶,以免導緻重複發送資料

    //程式執行完後必須列印輸出“success”(不包含引号)。

    //如果商戶回報給支付寶的字元不是success這7個字元,支付寶伺服器會不斷重發通知,直到超過24小時22分鐘。

    //一般情況下,25小時以内完成8次通知(通知的間隔頻率一般是:4m,10m,10m,1h,2h,6h,15h);

    try {

        response.getWriter().print(str);

        System.out.println(str);

    } catch (IOException e) {

        e.printStackTrace();

    }

}



/**

 * 擷取支付寶回調傳入的參數,包含訂單的所有資訊

 * @param request

 * @return

 */

private Map<String, String> getReqParam(HttpServletRequest request) {

    Map<String, String> params = new HashMap<String, String>();

    Map<String, String[]> requestParams = request.getParameterMap();

    // 周遊參數

    for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {

        String name = (String) iter.next();

        String[] values = (String[]) requestParams.get(name);

        String valueStr = "";

        for (int i = ; i < values.length; i++) {

            valueStr = (i == values.length - ) ? valueStr + values[i]

                    : valueStr + values[i] + ",";

        }

        // 亂碼解決,這段代碼在出現亂碼時使用。如果mysign和sign不相等也可以使用這段代碼轉化

        // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");

        params.put(name, valueStr);

    }

    return params;

}



/**

 * 通過支付類型和支付傳回結果,擷取支付狀态 1-支付成功 2-支付失敗

 * @param return_code

 * @param string

 * @return

 */

private Integer getPayState(String returnCode, String payType) {

    if(payType.equals(VipOrder.PAYMODE_WX)){

        if(returnCode.equals("SUCCESS")){

            return ;

        }else{

            return ;

        }

    }else if(payType.equals(VipOrder.PAYMODE_ALIPAY)){

        if(returnCode.equals("TRADE_SUCCESS") || returnCode.equals("TRADE_FINISHED")){

            return ;

        }else{

            return ;

        }

    }

    return ;

}



/**

 * 驗證資料真實性

 * 一、需要驗證該通知資料中的out_trade_no是否為商戶系統中建立的訂單号

 * 二、判斷total_amount是否确實為該訂單的實際金額(即商戶訂單建立時的金額)

 * 三、校驗通知中的seller_id(或者seller_email) 是否為out_trade_no這筆單據的對應的操作方(有的時候,一個商戶可能有多個seller_id/seller_email)

 * 四、驗證app_id是否為該商戶本身

 * 五、驗證本地訂單狀态是否是已經成功的,避免重複購買會員

 * 上面驗證都通過,才可以進行後續工作

 * @param vaan

 * @return

 */

private boolean checkTrue(VipAlipayAsynNotify vaan,VipOrder vo) {

    //一、需要驗證該通知資料中的out_trade_no是否為商戶系統中建立的訂單号

    //如果不存在則說明回報的訂單号和訂單id對不上

    if(vo == null){

        return false;

    }

    //支付完成,也不在進行業務處理

    if(vo.getPayState().equals(VipOrder.PAYSTATE_SUCCESS) || vo.getPayState().equals(VipOrder.PAYSTATE_FINISHED)){

        return false;

    }

    //二、判斷total_amount是否确實為該訂單的實際金額(即商戶訂單建立時的金額)

    if(!vo.getCurrentPrice().equals(vaan.getTotal_amount())){

        return false;

    }

    //三、校驗通知中的seller_id(或者seller_email) 是否為out_trade_no這筆單據的對應的操作方(有的時候,一個商戶可能有多個seller_id/seller_email)

    //四、驗證app_id是否為該商戶本身

    //上面四步驗證都通過,才可以進行後續工作

    return true;

}