回眸曾经的项目,与第三方支付相关,所带来的沟通问题

7次阅读

共计 6326 个字符,预计需要花费 16 分钟才能阅读完成。

导读
笔者在校期间,通过自学 java。学校里也开过这门课,但是,讲的都是一些基础,比如 java 的表达式、基本类型、自定义类型等等。也都是很基础的东西,就连 lambda 表达式都没有。然而,让我们交的作业,是用 java-web 开发出的网站。我当时做的是与图书共享相关的网站。当时满腔热血地想着去创业,但是,因为自身还没离开学校,社会经验不是特别足,于是,这件事就搁浅了。
去年六月份毕业,参加了班级的散伙饭后,大家也都各奔东西。但大部分从事软件开发的行业,有些人进入外包公司,有些人进入了游戏公司。不管进入到什么行业,在最初的一段时间中,遇到一个教你的人很重要。这样,你可以学校到很多东西。当然,你自己也得努力学习。
我依稀记得第一次做项目,那个项目做得真是一塌糊涂,权当我个人练手用了。对于个人来说,成长是非常快的,但是,对于企业来说,这是一种损失。真的是损失。因为,企业让你来做事,不是让你来试验的。自从第一个项目失败后,也不能说失败吧,至少做得不够完美。项目没有达到松散耦合的程度。我在开发的过程中,遇到了各种各样的问题,在他人的帮助下,慢慢地适应了开发强度。
当时,我给自己定义的是 java 后端开发工程师,因而,接口都是通过 postman 来测试。我们的持久层使用的 hibernate 框架,于是,仿照 hibernate 写个框架,参考我的博客:模仿 hibernate 框架,详解 hibernate 部分方法设计;同时使用 spring 容器集合该框架,于是,仿照了 spring 写个框架,可以参考我的博客:模拟 spring 框架,深入讲解 spring 的对象的创建;数据过滤的框架是 Apache 下的 beanutils 框架,于是,模拟 beanutils 写个框架,参看我的博客:只因数据过滤,方可模拟 beanutils 框架
框架能写的出来,而这只是 java 端的,我并不知道前端的一些情况,比如前端和后端是如何进行数据交互的,前端如何在页面展示数据等等。于是,下载了前端的页面。我们前端的页面放置在 SVN 上,后端代码放置在 git 上。自己慢慢地根据前端页面去摸索,神奇地是能够展示出数据。带我的人看我做的还不错,于是,教我前后端一起开发。
我们这个是前后端分离的,前端调用后端的接口。在学校里面也学过前端的一些知识,比如 CSS3、HTML5,jQuery,JavaScript 等等,那时并不是项目开发,有些东西只是自己弄着玩的。但公司项目的开发和自己开发完全不是一回事,需要掌握很多的前端知识。
不久,做了个完整的前端项目,因为有学校的经验,有些东西很快就掌握了,但是,其他很多东西还不怎么会,真的很脑大。但随着项目的深入,才发现自己在学校学的知识,还是远远地不够项目开发所用的。于是,不断地充电,不断地向前辈的学习,现在,前端的很多东西也知道了。
现在,回过头看我写的前端代码,再看前辈给我写的前端代码,我发现我那时写的真的垃圾,可以用不堪入目这个词来形容。但是,当时设计的页面还是蛮酷的,也得到了老板的认可。这是我值得骄傲的事。
我不断地尝试前后端的开发,也从中知道了 vue.js,bootstrap,jQuery、echart 等前端框架。也知道了本地 ip 和局域网 ip 的区别,以及如何用小米球做本地调试。从而更知道了,如何实现前后端分离。我越来越相信这句话,只要你努力,就会有人帮助你。
随着时间地推进,老板接了一个项目,就是图书共享的项目。我当时听到这个项目后,我就感觉到有点难过。这和我毕设所做的项目思想是一致的,如果,我当时能够勇敢一点,也许,我就推广我的这个项目了。但是,我没有。
世界就是这么残酷,不允许你有丝毫地犹豫。于是,老板再接下一个项目后,项目名为云码兑换平台。用户收到某家公司给的代币(福利),拿到代币到这个平台上兑换成钱。钱可以存储在自己的余额中,这就相当于微信钱包,余额可以提现到银行卡的中。也可以使用余额来购买商品。这分为企业钱包和个人钱包,企业钱包和个人钱包是不一样的。
我没做个类似项目,于是,就接过来做了。老板说这个项目对我来说,难度系数还是比较大的。我就下定决心把这个项目给做好,因为我知道可以从这个项目学到很多东西。我们的第三方支付平台是连连支付,杭州的一家公司。
支付
这个项目可以说没有任何人带我,完全由我自己参考连连给的文档,边学习边尝试着去开发。这样,也培养了我调用第三方接口,参读他们文档的能力。可以说,未尝不是一种收获呢?
我们老总说过年前夕,只做支付相关的业务,也就是,用户提交代币兑换金额的申请,后台管理员接收到这个申请后,从后台给用户打款。如图所示:

后台管理员点击批量打款时,服务端会做数据的筛选,晒选出状态为待转让的客户打款,其他情况下一律不打款。就这么一个小小的支付按钮,其内部涉及太多的知识点。
我之所以害怕,是因为对未知的恐惧。一开始做支付非常难,其实,做完之后,也没有我想像的那么难。但是,我还是需要做一些准备工作。比如,下载连连支付的 SDK。但要考虑到 SDK 是什么 SDK?SDK 分为两种,一种是应用到 java 开发中,一种是应用到 Android 或 iOS 开发中。因为,连连那边没有将其区分开来,从而造成钱包项目的延误。这个会在下文提到。
下载好连连支付的 SDK 后,我们通过 maven 创建项目,使用的是阿里云的中央仓库,其并不存在连连 SDK。因而,我们需要配置本地的 Maven 库。这个网上都有教程的,我在这里就不细说了。
配置好了 SDK 后,我们需要了解签名机制,连连使用的 RSA 签名机制,如图所示:

至于连连为什么使用 RSA 签名,可以参考我的这篇博客:支付与签名原串的那些事,但选择排序生成签名原串。
我们将生成的 pkcs8 格式的公钥上传到连连商户站,再从连连的商户站下载其连连公钥。私钥用以加签,公钥用以验签,这用以提高数据的安全性。
私钥怎么加签?每个公司的加签方式是不一样的,支付宝有支付宝的加签方式,微信有微信的加签方式。这里,我就说说连连支付的加签方式。我们在向连连发送支付请求前,需要封装我们的请求参数,将请求参数以一定格式的方式存储,这就是签名原串,如图所示:

将签名原串和我们的 pkcs8 格式的私钥共同加密,这就调用到 jdk 数字签名的这几个包:
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
得到加签后的签名字符串,再调用连连支付的 LianLianPaySecurity.encrypt(JSON.toJSONString(preq), PaymentConstant.LIAN_PUBLIC_RSA_KEY); 加密算法,该算法有两个参数,一个是包括签名的氢气参数,一个是下载下来的连连公钥。
如果请求连连支付成功的话,其会返回一段字符串,该字符串包含连连的签名原串、私钥签名串等其他信息。连连那边的签名串的加签方式,和我们这边的是一样的。我们从连连下载下来的连连公钥,其公钥也是其由私钥生成而来。其将请求参数封装成签名原串,将私钥和签名原串共同加签成签名串。
因而,我们这边拿到了连连的签名原串和签名串之后,就要进行验签了。怎么验签呢?我们这个时候,就用到了从连连的商户站下载的连连公钥了,如代码所示:
/**
* Created By zby on 17:28 2018/12/18
* RSA 签名验证
* <p>
* * @param reqObj: The obtained asynchronous notification body
* * @param rsa_public: The public key provided by LianLian
*/
public static boolean checkSignRSA(String response) {
logger.info(“【响应参数】申请付款的响应参数为:” + response);
if (StringUtils.isBlank(response)) {
return false;
}
JSONObject reqObj = JSONObject.parseObject(response);
String lianPubkey = PaymentConstant.LIAN_PUBLIC_RSA_KEY;
String lianSigned = reqObj.getString(“sign”);
String lianSignSrc = genSignData(reqObj);
ifNullThrow(lianPubkey, ResultCodeEnum.NOT_CONFIG_LIAN_PUBLIC_KEY_VALUE);
try {
if (TraderRSAUtil.checksign(lianPubkey, lianSigned, lianSignSrc)) {
return true;
} else {
return false;
}
} catch (Exception e) {
return false;
}
}
底部调用的是 TraderRSAUtil.checksign 这个方法,其内部如代码所示:
/**
* 签名验证
*
* @param lianPubkey 下载好的连连公钥
* @param lianSignSrc 连连的签名原串,也就是将返回串封装成 jsonObject
* @param lianSigned 连连加密签名签名,包括签名原串 + 私钥
* @return
*/
public static boolean checksign(String lianPubkey, String lianSigned,
String lianSignSrc) {
try {
//【1】获取公钥
// 获取 KeyFactory,指定 RSA 算法
KeyFactory keyFactory = KeyFactory.getInstance(PaymentConstant.SIGN_TYPE);
// 将 BASE64 编码的公钥字符串进行解码
BASE64Decoder decoder = new BASE64Decoder();
// 将 BASE64 解码后的字节数组,构造成 X509EncodedKeySpec 对象,生成公钥对象
PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(decoder.decodeBuffer(lianPubkey)));
byte[] signed = decoder.decodeBuffer(lianSigned);
//【2】使用公钥,进行验签
// 获取 Signature 实例,指定签名算法 (与之前一致)
Signature signature = Signature.getInstance(PaymentConstant.MD5_WITH_RSA);
// 加载公钥
signature.initVerify(publicKey);
// 更新原数据
signature.update(lianSignSrc.getBytes(BaseConstant.CHARSET));
// 公钥验签(true- 验签通过;false- 验签失败)
return signature.verify(signed);
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
这就是一个支付的流程,不论是任何第三方支付,其都要有加签和验签,因为,这是最基本的安全机制。只不过,各个公司的加签和验签方式有所不同而已。
当然,有些东西就没必要使用 RSA 加签和验签了,比如连连那边的绑定银行卡的业务,其加签方式就是用 MD5 加签的。但是,支付涉及到了金额,这个,只要与钱相关的业务。都需要谨慎处理,也许,RSA 不是最好的加密方式,但就目前而言,其还是比较安全的。
钱包
为什么要做钱包呢?做任何事都要有其目的。
我们做的是福利平台。届时,许多商户会入驻该平台,给其用户提供不同的优惠卡或者钱,比如流量充值卡、话费充值卡,中石油的加油卡等。不同商户提供不同的(虚拟)商品,不同的商品对应多少钱,比如话费卡 30 元,流量卡 30 元等。商户需要在钱包中充钱(充值),便于用户兑换。
用户拿到这些卡消费时,商户的钱包里的钱会减少。用户可以通过代币兑换这些充值卡,也可以通过代币兑换钱,商户的钱就会变少,而用户的钱包的钱增加,其可以提现到银行卡(提现),也可以购买其他产品(支付);在购买时,钱包余额不够,可以充值到连连钱包(充值)。如果已经购买了,也可以,申请退款(退款)。同时,也可以查看提现记录(提现查询),支付记录(支付查询);
总的来说,电子钱包可以存储用户的金额,相当于微信支付中的余额,也相当于我们现实中的钱包。用户可以支配钱包金额(余额),但并非任意支配。因为用户支配的额度不能超过钱包的额度。
今年都到了三月二十四号了,我们的钱包已经做一个月了。但是,我们这边的产品经理可能和连连那边的业务没有沟通好,其所提供给我们的 web 组件全部是走他们的页面。我当时问他们的页面支不支持响应式布局,他们坚决地回答说不支持。如图所示:

这在 PC 端的浏览器中看,界面还是可以的,但是,如果用手机端看的话,其会非常的别扭,如图所示:

你会发现,这简直不能使用。我当时和对方说,这种效果的用户体验不好。他们说我们这边提供的了手机端的 SDK 组件,我看了他们给的 SDK 组件,其完全是 Android 开发和 iOS 开发的 SDK 组件。他们以为我们是 Android 开发,而我们这是微信公众号,是嵌入在微信中的 h5 页面,自然是不能使用的。
这就是产品经理和业务没有沟通好带来的误会,产品经理说他们那边的业务不懂技术。他们那边的业务以为 SDK 就是 SDK,不区分是不是 Android 和 iOS,还是服务端 java 的 SDK。业务可能也没问他那边的技术。因而,浪费了这一个月的时间。我们这是从开年就开始做钱包了,做到现在就遇到了这个问题。所以,很多东西都要重新做。
对于企业来说,这是一个损失。但对于我个人来说,这是一种成长。不论是技术方面,还是与人沟通方面,都是一种成长。
我们后来和他们说,web 组件走不通了,能不能通过 API 的方式自定义界面,他们说他们这边也是提供的,不过,是最近刚开放的 API 的接口。我们这边的产品经理非常生气,说你们那边没有的话,就早点和我们说吗,免得浪费我们的时间。
我在开发的起始阶段,看了他们的 SDK,也有和对方沟通。我说我们这是公众号开发,你们这个 SDK 好像有问题,他们那边说你可以使用 web 组件,当时,也没有说到这个 API 的接口。
沟通问题
出现上述的问题,也不能说是谁的错。其实,谁都没有错,然而,谁貌似都有错。因为沟通的不及时,导致了上面的问题。
事情已经出了,生气也没用。因而,我就从这件事中吸取教训。凡是,都要先沟通好,比如,就这个 SDK 的问题。是什么样的 SDK?嵌入在 java 中的 SDK,还是纯安卓的 SDK。这个,就需要考虑清楚。沟通是非常重要,如果沟通的不及时,既浪费了人力和物力,也让双方都不开心。
因而,以后为人处事,一定要学会沟通。不过,这对于我来说,也是一次小小的成长吧。在成长的过程中,就会摔跟头的。但站起来之后,回头看看绊倒自己的是什么?是石头,还是香蕉皮?以后,再遇到这样的事情,能不能及时的沟通。
祝自己在成长的过程,愈挫愈勇吧。

正文完
 0