簡(jiǎn)單了解下支付流程

支付寶支付流程

萬(wàn)碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

微信掃碼支付流程

萬(wàn)碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

項(xiàng)目代碼查看:https://git.oschina.net/lkqm/ploy

重構(gòu)前的代碼:

Servlet

以下代碼有點(diǎn)亂,看注釋,了解這個(gè)步驟即可,執(zhí)行回調(diào)的Servlet:

支付寶

/**
 * 支付結(jié)果回調(diào)Servlet
 *
 * @author luokaiqiongmou
 */@WebServlet("/pay/notify/alipay.do")
public class AlipayNotifyServlet extends HttpServlet {

    private static final long serialVersionUID = 8158440606464368180L;

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {        // 1.獲得支付寶服務(wù)器post過(guò)來(lái)的參數(shù)
        Map<String, String> params = new HashMap<String, String>();        Map<String, String[]> requestParams = request.getParameterMap();        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {            String name = (String) iter.next();            String[] values = (String[]) 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);
        }        // 2.驗(yàn)證參數(shù)的合法性(根據(jù)簽名驗(yàn)證保證數(shù)據(jù)時(shí),從支付寶平臺(tái)的數(shù)據(jù))
        boolean verify_result = AlipayNotify.verify(params);        String trade_status = request.getParameter("trade_status");        if (verify_result
                && (trade_status.equals("TRADE_FINISHED") || trade_status
                .equals("TRADE_SUCCESS"))) {            try {                // 3.支付成功,執(zhí)行業(yè)務(wù)邏輯
                String out_trade_no = request.getParameter("out_trade_no");                String total_fee = request.getParameter("total_fee");                // 修改訂單狀態(tài)
                UserService userService = ServiceFactory.getService(UserService.class);
                userService.paySuccess(out_trade_no,                        String.valueOf(total_fee),                        String.valueOf(Order.PAY_WAY_ALIPAY));
                response.reset();
                PrintWriter out = response.getWriter();                // 4.返回執(zhí)行成功的標(biāo)識(shí)與支付寶服務(wù)器通信,否則支付寶服務(wù)器會(huì)多次再POST數(shù)據(jù)
                out.print("SUCCESS");
                out.flush();
            } catch (ServiceFailedException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

微信

/**
 * 微信支付回調(diào)地址
 * 
 * @author luokaiqiongmou
 * 
 */public class WechatpayNotifyServlet extends HttpServlet {    private static final long serialVersionUID = 8158440606464368180L;    private UserService userService = ServiceFactory.getService(UserService.class);    public void doPost(HttpServletRequest request,HttpServletResponse response) throws IOException{  
        
        // 1. 獲得請(qǐng)求參數(shù)(用戶支付成功后,微信服務(wù)器post數(shù)據(jù)過(guò)來(lái))
        InputStream inputStream = request.getInputStream();  
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));  
        StringBuilder sb = new StringBuilder();  
        String s ;  
        while ((s = in.readLine()) != null){  
            sb.append(s);  
        }  
        in.close();  
        inputStream.close();  
  
        //解析xml成map
        Map<String, String> parameterMap = null;        try {
            parameterMap = XMLUtil.doXMLParse(sb.toString());
        } catch (JDOMException e1) {
            e1.printStackTrace();
        }  
          
        //過(guò)濾空 設(shè)置 TreeMap  
        SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();        
        Iterator<String> it = parameterMap.keySet().iterator();  
        while (it.hasNext()) {  
            String parameter = it.next();  
            String parameterValue = parameterMap.get(parameter);  
              
            String v = "";  
            if(null != parameterValue) {  
                v = parameterValue.trim();  
            }  
            packageParams.put(parameter, v);  
        }          
        // 賬號(hào)信息  
        String key = PayConfigUtil.API_KEY; // key  
  
        //2. 判斷簽名是否正確  
        if(PayCommonUtil.isTenpaySign("UTF-8", packageParams,key)) {  
            //------------------------------  
            //處理業(yè)務(wù)開始  
            //------------------------------  
            String resXml = "";  
            if("SUCCESS".equals(packageParams.get("result_code"))){  
                // 3.這里是支付成功  
                //////////執(zhí)行自己的業(yè)務(wù)邏輯////////////////  
                String out_trade_no = (String)packageParams.get("out_trade_no");  
                String total_fee = (String)packageParams.get("total_fee"); 
                try{
                    double money = Integer.valueOf(total_fee)/100.0;  // 分轉(zhuǎn)化為員
                    userService.paySuccess(out_trade_no, String.valueOf(money), String.valueOf(Order.PAY_WAY_WECHAT));
                } catch(ServiceFailedException e) {
                    e.printStackTrace();
                } catch(Exception e) {
                    e.printStackTrace();
                }                  
                //////////執(zhí)行自己的業(yè)務(wù)邏輯////////////////  
                  
                //4. 通知微信.異步確認(rèn)成功.必寫.不然會(huì)一直通知后臺(tái).八次之后就認(rèn)為交易失敗了.  
                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"  
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";  
                  
            } else {  
                System.out.println("支付失敗,錯(cuò)誤信息:" + packageParams.get("err_code"));  
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"  
                        + "<return_msg><![CDATA[報(bào)文為空]]></return_msg>" + "</xml> ";  
            }  
            //------------------------------  
            //處理業(yè)務(wù)完畢  
            //------------------------------  
            BufferedOutputStream out = new BufferedOutputStream(  
                    response.getOutputStream());  
            out.write(resXml.getBytes());  
            out.flush();  
            out.close();  
        } else{  
            System.out.println("通知簽名驗(yàn)證失敗");  
        }
          
    }  

}

開始重構(gòu)

上面兩個(gè)Servlet像極了,獲取請(qǐng)求數(shù)據(jù),驗(yàn)證數(shù)據(jù),支付成功判斷,執(zhí)行成功業(yè)務(wù)邏輯...,這不是模版模式的應(yīng)用嗎?對(duì),但是這里先用策略模式重構(gòu)下支付回調(diào)的問(wèn)題?。。?/p>

定義一個(gè)支付工具類PayNotifyUtil執(zhí)行以上步驟,將具體怎么執(zhí)行交給策略類來(lái)做,AliPayNotifyPloyImplWeChatPayNotifyPloyImpl, 這樣在Servlet中就無(wú)須關(guān)心是什么支付平臺(tái)回調(diào)的。

目錄結(jié)構(gòu)

萬(wàn)碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

Servlet代碼

只需要關(guān)注使用的什么支付策略?。?!

**
 * 支付寶支付回調(diào)通知
 */@WebServlet("/pay/notify/alipay.do")
public class AlipayNotifyServlet extends HttpServlet {    @Override
    public void service(HttpServletRequest request, HttpServletResponse response)            throws IOException, ServletException {        // 1. 獲得支付策略
        PayNotifyPloy payNotifyPloy = new AliPayNotifyPloyImpl();        PayNotifyUtil payNotifyUtil = new PayNotifyUtil(payNotifyPloy);        // 2. 獲得請(qǐng)求參數(shù)
        Map<String, String> payInfo = payNotifyUtil.loadPayData(request);        // 3. 驗(yàn)證支付數(shù)據(jù)
        String result="";        if( !payNotifyUtil.verifyData(payInfo)) {            System.out.println("驗(yàn)證失敗");
        } else if (!payNotifyUtil.isPaySuccess(payInfo) ) {            // 支付失敗
            result = payNotifyUtil.getFailedResponseData();
        } else {            //4. 執(zhí)行業(yè)務(wù)邏輯
            OrderMode orderMode = payNotifyUtil.getServiceMode(payInfo);            // 修改訂單狀態(tài)
            UserService userService = ServiceFactory.getService(UserService.class);            try {
                userService.paySuccess(orderMode.getTradeNo(), orderMode.getTotalFee(), PayWayEnum.ALIPAY);                // 支付成功數(shù)據(jù)
                result = payNotifyUtil.getSuccessfulResponseData();
            } catch (Exception e) {                // 邏輯執(zhí)行失敗,等同于支付失敗,所以返回失敗數(shù)據(jù)
                result = payNotifyUtil.getFailedResponseData();
            }
        }

        response.reset();        PrintWriter out = response.getWriter();        // 返回?cái)?shù)據(jù)
        out.print(result);
        out.flush();
    }
}

將來(lái)的某一天,需要增加微信支付功能,對(duì)應(yīng)微信支付回調(diào),只需要copy上面代碼然后,修改策略的實(shí)現(xiàn)類即可。

這個(gè)時(shí)候IDEA IDE提示發(fā)現(xiàn)---WeChatPayNotifyServletAliPayNotifyServlet代碼重復(fù),是時(shí)候應(yīng)用使用模版方法重構(gòu)了

PayNotifyUtil工具類

/**
 * 支付之付款工具類
 * Created by luokaiqiongmou on 2017/2/25.
 */public class PayNotifyUtil {    // 支付策略
    private PayNotifyPloy payNotifyPloy;    public PayNotifyUtil(PayNotifyPloy payNotifyPloy) {        this.payNotifyPloy = payNotifyPloy;
    }    // 加載支付信息
    public Map<String, String> loadPayData(HttpServletRequest request) throws IOException {        return payNotifyPloy.loadPayInfo(request);
    }    // 驗(yàn)證參數(shù)
    public boolean verifyData(Map<String, String> postData) {        return payNotifyPloy.verifyData(postData);
    }    // 判斷是否支付成功
    public boolean isPaySuccess(Map<String, String> data) {        return payNotifyPloy.isPaySuccess(data);
    }    // 獲得支付成功的返回?cái)?shù)據(jù)
    public String getSuccessfulResponseData() {        return payNotifyPloy.getSuccessfulResponseData();
    }    // 獲得支付失敗的返回?cái)?shù)據(jù)
    public String getFailedResponseData() {        return payNotifyPloy.getFailedResponseData();
    }    // 獲得業(yè)務(wù)結(jié)果需要的數(shù)據(jù)
    public OrderMode getServiceMode(Map<String, String> params) {        return payNotifyPloy.getServiceMode(params);
    }
}

策略接口

/**
 * 支付回調(diào)策略接口
 * Created by luokaiqiongmou on 2017/2/25.
 */public interface PayNotifyPloy {    // 加載支付回調(diào)信息
    Map<String, String> loadPayInfo(HttpServletRequest request) throws IOException;    // 獲得返回給支付平臺(tái)代表成功的
    String getSuccessfulResponseData();    // 獲得返回給支付平臺(tái)代表失敗
    String getFailedResponseData();    // 判斷是否支付成功
    boolean isPaySuccess(Map<String, String> data);    // 驗(yàn)證數(shù)據(jù)的合法性
    boolean verifyData(Map<String, String> postData);    // 獲得需要的信息(比如支付的訂單號(hào)、支付的金額)
    OrderMode getServiceMode(Map<String, String> params);
}

現(xiàn)在你可以定義你的具體平臺(tái)的實(shí)現(xiàn)類了?。。?/p>