簡(jiǎ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)做,AliPayNotifyPloyImpl
和WeChatPayNotifyPloyImpl
, 這樣在Servlet中就無(wú)須關(guān)心是什么支付平臺(tái)回調(diào)的。
目錄結(jié)構(gòu)
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)---WeChatPayNotifyServlet
和AliPayNotifyServlet
代碼重復(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>