支付宝网银直连SDK封装记下|强力去掉支付宝网银直连DEMO中56个坏味道 余下6个坏味道 Sonarqube无视阿里支付宝光环

 Yuema约吗?一起学技术,一起成长!学海无涯 高人带路系列

程序的世界,就是有坑的地方!分享踩坑的心得与体验!每天分享一点点!
关注公众号,进入学海无涯,高人带路模式!!支付再难,有人带路,轻松搞定

每次看动漫看美剧,都有狗血的前情回顾,占了好长的时间,有种说不同的酸痛感!腰疼!想不到,我也活成了自己讨厌的人,我也要写个前情回顾 

前情回顾

上回讲到接阿里蚂蚁金服支付宝网银直连的整体代码结构,提到封装了一个alipay-bankpay-sdk,并画了2个对比图,介绍了一下这么干的好处,代码清晰,通用性强。按文章的条理来讲,您应该先看上篇,再来看这篇。

关注Yuema约吗公众号,回复”bankpay”,查看《支付宝网银直连SDK封装记上|强力去掉支付宝网银直连DEMO中56个坏味道 余下6个坏味道 Sonarqube无视阿里支付宝光环》

本文向导

本文主要分享一下封装支付宝网银直连sdk的思路、坏味道清理,并做个小小的总结。完整的看完本文,您应该学会一种取巧的sdk封装思路并能运行于实战,并且能看到一些更加简洁的代码写法,并能学会如何从BTA中学东西,并从中剔除不良习惯。

封装思路

虽然阿里支付宝的程序员在代码中明确表明给出来的demo仅供参考blabla的。但是整体上来讲,封装sdk还是主要使用他们的demo,从作为sdk的角度对代码进行细微调整。

/* * *类名:AlipaySubmit *功能:支付宝各接口请求提交类 *详细:构造支付宝各接口表单HTML文本,获取远程HTTP数据 *版本:3.3 *日期:2012-08-13 *说明: *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。 *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。 */

封装思路一

做为sdk,我去掉了demo中的AlipayConfig.java,因为不同的项目所使用到的商户号、密钥等都不相同,放在sdk中,不妥当。去掉AlipayConfig.java后,其他的代码要相应的调整一下。我们将配置以参数的形式,传递进去。这样子确保,我们能通过其他方式配置网银直连所需的商户信息。我采用了这种思路,很简单很傻瓜式的调整一下。

封装思路二

可以参考最新的支付宝sdk的封装方式,抽象一个AlipayClient出来,初始化的时候,把AlipayConfig.java的工作做了。我没有使用这种思路,但是感觉这是一种不错的思路。调整稍微大点。

坏味道清理

程序的世界可以说很大很大,咱们就像盲人摸象。坏味道清理是将代码中不规范不合理的地方进行调整。通过使用sonarqube对阿里的网银直连demo进行扫描,发现了56个坏味道,还有1个bug,1个漏洞。

坏味道1:命名空间不规范

支付宝com.alipay.util.httpClientcom.alipay.util.httpclient

坏味道2:冗余写法,不够简洁

Replace the type specification in this constructor call with the diamond operator ("<>"). (sonar.java.source not set. Assuming 7 or greater.)            List<String> keys = new ArrayList<String>(sPara.keySet());            List<String> keys = new ArrayList<>(sPara.keySet());

坏味道3:多余的转化

String name = (String) keys.get(i);Remove this unnecessary cast to "String".

坏味道4:直接返回即可

String strResult = response.getStringResult(charset);return strResult;Immediately return this expression instead of assigning it to the temporary variable "strResult".

坏味道5:这里不要线程安全

Replace the synchronized class "StringBuffer" by an unsynchronized one such as "StringBuilder".StringBuffer result = new StringBuffer();

坏味道6:静态类不要初始化

Add a private constructor to hide the implicit public one.

坏味道7:一行代码搞定

修改前:if (isSign && responseTxt.equals("true")) {            return true;        } else {            return false;        }Replace this if-then-else statement by a single return statement.修正后:return isSign && responseTxt.equals("true");

坏味道8:局部变量命名不规范

input_charsetRename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.

坏味道9:static final变量命名不规范

 public static final String dtLong                  = "yyyyMMddHHmmss";  Rename this constant name to match the regular expression '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'.

坏味道10:参数不符合规范

Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.private static boolean getSignVeryfy(Map<String, String> Params, String sign,String signType,String key,String charset)

坏味道11:局部变量命名不符合规范

String veryfy_url = HTTPS_VERIFY_URL + "partner=" + partner + "&notify_id=" + notify_id;Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.

坏味道12:多此一举

inputLine = in.readLine().toString();"readLine" returns a string, there's no need to call "toString()".

坏味道13:一行代码搞定

Replace this if-then-else statement by a single return statement.if(mysign.equals(sign)) {Replace this if-then-else statement by a single return statement.clumsy            return true;        }        else {            return false;        }

坏味道14:局部变量命名不规范

Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.private static String verifyResponse(String notify_id,String partner)

坏味道15:抛异常不规范

public static String query_timestamp(String partner,String charset) throws MalformedURLException, DocumentException, IOExceptionRemove the declaration of thrown exception 'java.net.MalformedURLException' which is a subclass of 'java.io.IOException'.

坏味道16:Use a StringBuilder instead

Use a StringBuilder instead.StringBuilder  prestr = new StringBuilder();        for (int i = 0; i < keys.size(); i++) {            String key = keys.get(i);            String value = params.get(key);            if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符               prestr.append(key + "=" + value);            } else {               prestr.append(key + "=" + value + "&");            }        }        return prestr.toString();    String prestr = "";        for (int i = 0; i < keys.size(); i++) {            String key = keys.get(i);            String value = params.get(key);            if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符                prestr = prestr + key + "=" + value;            } else {                prestr = prestr + key + "=" + value + "&";            }        }        return prestr;

坏味道17:不规范的变量命名

private static String              DEFAULT_CHARSET                     = "GBK";Rename this field "DEFAULT_CHARSET" to match the regular expression '^[a-z][a-zA-Z0-9]*$'.private static final String              DEFAULT_CHARSET                     = "GBK";

坏味道18:不规范的变量命名

/** 默认等待HttpConnectionManager返回连接超时(只有在达到最大连接数时起作用):1秒*/    private static final long          defaultHttpConnectionManagerTimeout = 3 * 1000L;        Rename this constant name to match the regular expression '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'.        private static final long          DEFAULT_HTTP_CONNECTION_MANAGER_TIMEOUT = 3 * 1000L;

坏味道19:不规范的变量命名

Iterate over the "entrySet" instead of the "keySet".When only the keys from a map are needed in a loop, iterating the keySet makes sense. But when both the key and the value are needed, it's more efficient to iterate the entrySet, which will give access to both the key and value, instead.for (String key : sArray.keySet()) {            String value = sArray.get(key);            if (value == null || value.equals("") || key.equalsIgnoreCase("sign")                || key.equalsIgnoreCase("sign_type")) {                continue;            }            result.put(key, value);        }                for (Entry<String,String> entry : sArray.entrySet()) {            String key = entry.getKey();            String value = entry.getValue();            if (value == null || value.equals("") || key.equalsIgnoreCase("sign")                || key.equalsIgnoreCase("sign_type")) {                continue;            }            result.put(key, value);        }

坏味道20:漏洞

Use a logger to log this exception.try {            URL url = new URL(urlvalue);            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();            BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));            inputLine = in.readLine();        } catch (Exception e) {            e.printStackTrace();//漏洞            inputLine = "";        }

还有几个坏味道,我也不想修改了。

从56个坏味道来看,变量命名规范、线程安全、代码简洁度、性能都有涉及,可以说阿里支付宝提供的这个demo,将一堆坏味道传染给了千千万万程序员。其实,也不用太惊慌,使用sonarqube这个开源的工具进行代码质量检查,就能防坑于未然,即能享受支付宝的demo成果,也能做得更好。
网银直连的demo比较老,最近看阿里支付宝的sdk,还是很规范的。不过,网银直连还是得在坑里爬行。希望这两篇支付宝网银直连的经验分享,能让更多的小伙伴快速出坑,节省些时间~

关注Yuema约吗公众号,回复”sq”,学习sonarqube代码质量检查工具使用与安装。

关注Yuema约吗公众号,回复”bankpay”,查看《支付宝网银直连SDK封装记上|强力去掉支付宝网银直连DEMO中56个坏味道 余下6个坏味道 Sonarqube无视阿里支付宝光环》,了解代码结构的艺术。

作者:钟代麒

出处:http://www.jishudao.com/
版权归作者所有,转载请注明出处

此条目发表在未分类分类目录。将固定链接加入收藏夹。

发表评论

邮箱地址不会被公开。 必填项已用*标注