zoukankan      html  css  js  c++  java
  • 设计模式的应用-策略模式实现支付方式回调策略

    简单了解下支付流程

    支付宝支付流程

    支付宝支付liuc

    微信扫码支付流程

    微信扫码支付流程

    项目代码查看:https://git.oschina.net/lkqm/ploy

    重构前的代码:

    Servlet

    以下代码有点乱,看注释,了解这个步骤即可,执行回调的Servlet:

    支付宝

    /**
     * 支付结果回调Servlet
     *
     * @author 
     */
    
    @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 
     * 
     */
    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执行以上步骤,将具体怎么执行交给策略类来做,AliPayNotifyPloyImplWeChatPayNotifyPloyImpl, 这样在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提示发现---WeChatPayNotifyServletAliPayNotifyServlet代码重复,是时候应用使用模版方法重构了

    PayNotifyUtil工具类

    /**
     * 支付之付款工具类
     * Created by  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  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);
    }
    

    现在你可以定义你的具体平台的实现类了!!!

    总结

    由于经验不足和对支付平台每种支付方式的接口了解不详细,重构的代码还有很多细节不足,比如异常的设计,代码已经传在git上,供参考,并求指点:https://git.oschina.net/lkqm/ploy

    注: 重构后的支付回调代码未测试

  • 相关阅读:
    e生保plus
    Exception analysis
    经验总结:5个应该避免的前端糟糕实践
    经验总结:应对中文输入法的字符串截断方案(带代码示例)
    这些年那些文
    fis入门-单文件编译之文件优化(optimize)
    《HTTP权威指南》读书笔记:缓存
    npm install —— 从一个简单例子,看本地安装与全局安装的区别
    chrome下的Grunt插件断点调试——基于node-inspector
    Yeoman的好基友:Grunt
  • 原文地址:https://www.cnblogs.com/lkqm/p/6476731.html
Copyright © 2011-2022 走看看