简单了解下支付流程
支付宝支付流程
微信扫码支付流程
项目代码查看:https://git.oschina.net/lkqm/ploy
重构前的代码:
Servlet
以下代码有点乱,看注释,了解这个步骤即可,执行回调的Servlet:
支付宝
/** * 支付结果回调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.获得支付宝服务器post过来的参数 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.验证参数的合法性(根据签名验证保证数据时,从支付宝平台的数据) 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.支付成功,执行业务逻辑 String out_trade_no = request.getParameter("out_trade_no"); String total_fee = request.getParameter("total_fee"); // 修改订单状态 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.返回执行成功的标识与支付宝服务器通信,否则支付宝服务器会多次再POST数据 out.print("SUCCESS"); out.flush(); } catch (ServiceFailedException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } } }
微信
/** * 微信支付回调地址 * * @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. 获得请求参数(用户支付成功后,微信服务器post数据过来) 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(); } //过滤空 设置 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); } // 账号信息 String key = PayConfigUtil.API_KEY; // key //2. 判断签名是否正确 if(PayCommonUtil.isTenpaySign("UTF-8", packageParams,key)) { //------------------------------ //处理业务开始 //------------------------------ String resXml = ""; if("SUCCESS".equals(packageParams.get("result_code"))){ // 3.这里是支付成功 //////////执行自己的业务逻辑//////////////// 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; // 分转化为员 userService.paySuccess(out_trade_no, String.valueOf(money), String.valueOf(Order.PAY_WAY_WECHAT)); } catch(ServiceFailedException e) { e.printStackTrace(); } catch(Exception e) { e.printStackTrace(); } //////////执行自己的业务逻辑//////////////// //4. 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了. resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; } else { System.out.println("支付失败,错误信息:" + packageParams.get("err_code")); resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> "; } //------------------------------ //处理业务完毕 //------------------------------ BufferedOutputStream out = new BufferedOutputStream( response.getOutputStream()); out.write(resXml.getBytes()); out.flush(); out.close(); } else{ System.out.println("通知签名验证失败"); } } }
开始重构
上面两个Servlet像极了,获取请求数据,验证数据,支付成功判断,执行成功业务逻辑...,这不是模版模式的应用吗?对,但是这里先用策略模式重构下支付回调的问题!!!
定义一个支付工具类PayNotifyUtil
执行以上步骤,将具体怎么执行交给策略类来做,AliPayNotifyPloyImpl
和WeChatPayNotifyPloyImpl
, 这样在Servlet中就无须关心是什么支付平台回调的。
目录结构
Servlet代码
只需要关注使用的什么支付策略!!!
** * 支付宝支付回调通知 */@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. 获得请求参数 Map<String, String> payInfo = payNotifyUtil.loadPayData(request); // 3. 验证支付数据 String result=""; if( !payNotifyUtil.verifyData(payInfo)) { System.out.println("验证失败"); } else if (!payNotifyUtil.isPaySuccess(payInfo) ) { // 支付失败 result = payNotifyUtil.getFailedResponseData(); } else { //4. 执行业务逻辑 OrderMode orderMode = payNotifyUtil.getServiceMode(payInfo); // 修改订单状态 UserService userService = ServiceFactory.getService(UserService.class); try { userService.paySuccess(orderMode.getTradeNo(), orderMode.getTotalFee(), PayWayEnum.ALIPAY); // 支付成功数据 result = payNotifyUtil.getSuccessfulResponseData(); } catch (Exception e) { // 逻辑执行失败,等同于支付失败,所以返回失败数据 result = payNotifyUtil.getFailedResponseData(); } } response.reset(); PrintWriter out = response.getWriter(); // 返回数据 out.print(result); out.flush(); } }
将来的某一天,需要增加微信支付功能,对应微信支付回调,只需要copy上面代码然后,修改策略的实现类即可。
这个时候IDEA IDE提示发现---WeChatPayNotifyServlet
和AliPayNotifyServlet
代码重复,是时候应用使用模版方法重构了
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); } // 验证参数 public boolean verifyData(Map<String, String> postData) { return payNotifyPloy.verifyData(postData); } // 判断是否支付成功 public boolean isPaySuccess(Map<String, String> data) { return payNotifyPloy.isPaySuccess(data); } // 获得支付成功的返回数据 public String getSuccessfulResponseData() { return payNotifyPloy.getSuccessfulResponseData(); } // 获得支付失败的返回数据 public String getFailedResponseData() { return payNotifyPloy.getFailedResponseData(); } // 获得业务结果需要的数据 public OrderMode getServiceMode(Map<String, String> params) { return payNotifyPloy.getServiceMode(params); } }
策略接口
/** * 支付回调策略接口 * Created by luokaiqiongmou on 2017/2/25. */public interface PayNotifyPloy { // 加载支付回调信息 Map<String, String> loadPayInfo(HttpServletRequest request) throws IOException; // 获得返回给支付平台代表成功的 String getSuccessfulResponseData(); // 获得返回给支付平台代表失败 String getFailedResponseData(); // 判断是否支付成功 boolean isPaySuccess(Map<String, String> data); // 验证数据的合法性 boolean verifyData(Map<String, String> postData); // 获得需要的信息(比如支付的订单号、支付的金额) OrderMode getServiceMode(Map<String, String> params); }
现在你可以定义你的具体平台的实现类了!!!