最近公司的项目接了个建行生活生活支付,文档诟病良多,把一些坑记录一下防止大家踩坑。
一、首先需要接入授权登录,需要服务方公私钥加解密建行生活跳转带过来的参数,光这个就浪费了两天时间,建行的工作人员提供各种钥匙无果,我就是各种解密失败,直到第三天才提供了正确的服务方公私钥,然后第一个坑就来了,这是建行官方文档提供的解密方法:

/*** 解密及验签*/
// base64逆处理并用私钥解密
BASE64Decoder decoder = new BASE64Decoder();
enc_msg = new String(decoder.decodeBuffer(enc_msg),"UTF-8");
String dec_msg = RSAUtil.decrypt(enc_msg, privateKey);

但是文档上根本没有写在base64解密之前必须要先解码,这个又浪费了两个小时,要先加上

enc_msg = new String(URLDecoder.decode(enc_msg));

二、接入完登录就要接支付了,这里来第二个坑是自己踩得,这个坑浪费了几次三天时间,面壁思过…就是拉起支付的时候页面上加了JSON.Stringfy(paramStr),死活拉起不了支付,最后在别人的提醒下才解决

这里还有一个要注意的点,前面授权登录解密ccbParamSj 的时候需要使用privateKey私钥解密,到这里传参加密MAC的时候不需要加privateKey,只用 MD5Util.getMD5这个方法就可以了

三、接好支付后配置回调地址需要配置的是第二个反馈地址,并且这个地址有半个小时左右的延迟,配置了不会立刻生效,不知道是建行这样还是所有银行都这样的,不多试几次很难知道

四、支付回调验签的时候又是一个大坑,拉起支付的时候无论是否传了clientip参数,回调通知的时候就是不给你,诶,气不气,关键支付回调验签文档里这个参数又是必须参加验签的,却没地儿拿值

然后试了好多次才发现不传才能通过验签,不然就是过不了,真是大无语了

五、正式上线后是从首页banner点进去,建行的运营人员不熟悉业务,配置链接的时候没有勾选授权登录,新用户根本无法获取用户信息,得,又浪费我几个小时调试时间才把问题拋回去

最后放一下公用的代码把,这东西开发人员不能放一套示例代码到材料文档里吗,重复造轮子没有意思,放一下节约时间,要用的直接复制就行了

授权登录

     // 解码userCode = new String(URLDecoder.decode(userCode));// base64逆处理并用私钥解密BASE64Decoder decoder = new BASE64Decoder();userCode = new String(decoder.decodeBuffer(userCode),"UTF-8");String dec_msg = RSAUtil.decrypt(userCode, privateKey);String arr[] = dec_msg.split("&");String userId = null;String mobile = null;String timeStamp = null;for(String str :arr){if("USERID".equals(str.split("=")[0])){userId = str.split("=")[1];}if("MOBILE".equals(str.split("=")[0])){mobile = str.split("=")[1];}if("TIMESTAMP".equals("")){timeStamp = str.split("=")[1];}}logger.info("accessToken:{},获取用户信息返回报文:{}", dec_msg);

拉起支付报文

     String MERCHANTID ="商户代码";         // 商户代码 String POSID = "柜台代码";             // 柜台代码String BRANCHID = "分行代码";          // 分行代码String ORDERID = orderSn;   // 订单号String PAYMENT = realPay;    // 付款金额String CURCODE = "01";      // 币种 缺省为01-人民币(只支持人民币支付)String TXCODE = "520100";   // 交易码String REMARK1 = "ccbpay";  // 备注1String REMARK2 = serviceNo; // 备注2 上送YS开头的服务方编号String TYPE = "1";          // 接口类型 默认送1 - 防钓鱼接口String GATEWAY = "0";       // 网关类型 默认送0String CLIENTIP = "";       // 客户端IP 客户在商户系统中的IP,送空值即可String REGINFO = "";        // 客户注册信息String PROINFO = "";        //String REFERER = "";        // 商户URL 商户送空值即可String THIRDAPPINFO = "comccbpay1234567890cloudmerchant"; // 客户端标识String TIMEOUT =cn.hutool.core.date.DateUtil.format(cn.hutool.core.date.DateUtil.offsetHour(new Date(), 1), DatePattern.PURE_DATETIME_PATTERN);     // 订单超时时间 YYYYMMDDHHMMSSString PLATFORMPUB = publicKey;             //  服务方公钥 仅作为源串参加MD5摘要,不作为参数传递String MAC = "";                            // MD5加密串 采用标准MD5算法,对以上字段进行MAC加密(32位小写)String PLATFORMID = serviceNo;              // 服务方编号 仅作为参数传递,不参与MAC校验String ENCPUB = "";                         // 商户公钥密文 仅作为参数传递,不参与MAC校验StringBuffer macBuffer = new StringBuffer();macBuffer.append("MERCHANTID="+MERCHANTID);macBuffer.append("&POSID="+POSID);macBuffer.append("&BRANCHID="+BRANCHID);macBuffer.append("&ORDERID="+ORDERID);macBuffer.append("&PAYMENT="+PAYMENT);macBuffer.append("&CURCODE="+CURCODE);macBuffer.append("&TXCODE="+TXCODE);macBuffer.append("&REMARK1="+REMARK1);macBuffer.append("&REMARK2="+REMARK2);macBuffer.append("&TYPE="+TYPE);macBuffer.append("&GATEWAY="+GATEWAY);macBuffer.append("&CLIENTIP="+CLIENTIP);macBuffer.append("&REGINFO="+REGINFO);macBuffer.append("&PROINFO="+PROINFO);macBuffer.append("&REFERER="+REFERER);macBuffer.append("&THIRDAPPINFO="+THIRDAPPINFO);macBuffer.append("&TIMEOUT="+TIMEOUT);macBuffer.append("&PLATFORMPUB="+PLATFORMPUB);MAC = MD5Util.getMD5(macBuffer.toString()).toLowerCase();StringBuffer paramBuffer = new StringBuffer();paramBuffer.append("MERCHANTID="+MERCHANTID);paramBuffer.append("&POSID="+POSID);paramBuffer.append("&BRANCHID="+BRANCHID);paramBuffer.append("&ORDERID="+ORDERID);paramBuffer.append("&PAYMENT="+PAYMENT);paramBuffer.append("&CURCODE="+CURCODE);paramBuffer.append("&TXCODE="+TXCODE);paramBuffer.append("&REMARK1="+REMARK1);paramBuffer.append("&REMARK2="+REMARK2);paramBuffer.append("&TYPE="+TYPE);paramBuffer.append("&GATEWAY="+GATEWAY);paramBuffer.append("&CLIENTIP="+CLIENTIP);paramBuffer.append("&REGINFO="+REGINFO);paramBuffer.append("&PROINFO="+PROINFO);paramBuffer.append("&REFERER="+REFERER);paramBuffer.append("&THIRDAPPINFO="+THIRDAPPINFO);paramBuffer.append("&TIMEOUT="+TIMEOUT);paramBuffer.append("&MAC="+MAC);paramBuffer.append("&PLATFORMID="+PLATFORMID);String enc_msg = RSAUtil.encrypt(merPublicKeyStr, publicKey);BASE64Encoder encoder = new BASE64Encoder();enc_msg = encoder.encode(enc_msg.getBytes("UTF-8"));enc_msg = enc_msg.replaceAll("\r\n", "").replaceAll("\r", "").replaceAll("\n", "");ENCPUB = enc_msg;paramBuffer.append("&ENCPUB="+ENCPUB);

支付通知回调

@Transactional(rollbackFor = Exception.class)public void payCallback(Map<String, String> reqParam, HttpServletResponse resp) throws Exception {String SUCCESS = reqParam.get("SUCCESS");try {if ("Y".equals(SUCCESS)) {logger.info("建行生活支付通知-1-[支付]-回调成功");// 必填字段String POSID = reqParam.get("POSID");String BRANCHID = reqParam.get("BRANCHID");String ORDERID = reqParam.get("ORDERID");String PAYMENT = reqParam.get("PAYMENT");String CURCODE = reqParam.get("CURCODE");String REMARK1 = reqParam.get("REMARK1");String REMARK2 = reqParam.get("REMARK2");String ACC_TYPE = reqParam.get("ACC_TYPE");
//            String CLIENTIP = reqParam.get("CLIENTIP");String SIGN = reqParam.get("SIGN");// 优惠String  CCB_DISCOUNT_AMT = reqParam.get("CCB_DISCOUNT_AMT");String  CCB_DISCOUNT_AMT_DESC = reqParam.get("CCB_DISCOUNT_AMT_DESC");StringBuilder signBuilder = new StringBuilder();signBuilder.append("POSID=" + POSID);signBuilder.append("&BRANCHID=" + BRANCHID);signBuilder.append("&ORDERID=" + ORDERID);signBuilder.append("&PAYMENT=" + PAYMENT);signBuilder.append("&CURCODE=" + CURCODE);signBuilder.append("&REMARK1=" + REMARK1);signBuilder.append("&REMARK2=" + REMARK2);signBuilder.append("&ACC_TYPE=" + ACC_TYPE);signBuilder.append("&SUCCESS=" + SUCCESS);
//                signBuilder.append("&CLIENTIP="+CLIENTIP); // 这个不能加才能验签通过 是个坑LsOrder order = lsOrderService.getByOrderSn(ORDERID);// 订单实付价格BigDecimal realPrice = new BigDecimal(order.getRealPrice());BigDecimal divide = realPrice.divide(new BigDecimal("100"));DecimalFormat decimalFormat = new DecimalFormat("0.00");String realPay = decimalFormat.format(divide.doubleValue());RSASig rsaSig = new RSASig();rsaSig.setPublicKey(merPublicKey);boolean res = rsaSig.verifySigature(SIGN, signBuilder.toString());if (res) {logger.info("建行生活支付通知-2-[签名]-校验成功");// 无优惠券if(StringUtils.isBlank(CCB_DISCOUNT_AMT)){if (realPay.equals(PAYMENT)) {logger.info("建行生活支付通知-3-[金额]-校验成功");callBackHandler(ORDERID);} else {logger.error("建行生活支付通知-3-[金额]-校验失败");}}else {// 优惠金额BASE64Decoder decoder = new BASE64Decoder();CCB_DISCOUNT_AMT = RSAUtil.decrypt(new String(decoder.decodeBuffer(CCB_DISCOUNT_AMT), "UTF-8"), privateKey);// 商户获取金额 = 建行实付 + 优惠金额BigDecimal getMoney = new BigDecimal(PAYMENT).add(new BigDecimal(CCB_DISCOUNT_AMT));String getMoneyStr = decimalFormat.format(getMoney.doubleValue());if(realPay.equals(getMoneyStr)){logger.info("建行生活支付通知-3-[金额]-校验成功-[使用优惠券]");callBackHandler(ORDERID);}else{logger.info("建行生活支付通知-3-[金额]-校验失败-[使用优惠券]");}}} else {logger.error("建行生活支付通知-2-[签名]-校验失败");}} else {logger.error("建行生活支付通知-1-[支付失败]");}}catch (Exception e){logger.error("建行生活app-[支付通知回调接口异常]:{}", ExceptionUtils.getStackTrace(e));}}

其他的订单状态更新、退款都差不多,就不赘述了

【建行生活】记录一次建行生活接入的坑相关推荐

  1. html期末作业代码网页设计——个人生活记录设计(3页) 学生网站模板

    HTML5+CSS大作业--个人生活记录设计(3页) 常见网页设计作业题材有 个人. 美食. 公司. 学校. 旅游. 电商. 宠物. 电器. 茶叶. 家居. 酒店. 舞蹈. 动漫. 明星. 服装. 体 ...

  2. web大学生个人网站大作业模板 ——大学生活记录个人网站模板(6个页面) HTML+CSS+JavaScript...

    web大学生个人网站作业模板 :个人网站设计--大学生活记录个人网站模板(6个页面) HTML+CSS+JavaScript 期末作业HTML代码 学生网页课程设计期末作业下载 动漫大学生网页设计制作 ...

  3. 生活记录--2019.11

    生活记录--2019.11  今天是大雪,二十四节气中冬季的第三个节气. 郑州的雪比去年来的稍微晚些,目前还没有过来,盼望着元旦前能来场雪吧......(明年的小麦还能多收成些) 回顾十一月份,基本上 ...

  4. 工作/管理-生活方式:30个生活方式 : 教你如何让生活丰富多彩

    ylbtech-工作/管理-生活方式:30个生活方式 : 教你如何让生活丰富多彩 1.返回顶部 1. 1.读书 这一条像是老生常谈,但在这1000个回答中,几乎每位都提到了读书.如果你觉得读书很无趣, ...

  5. 信用卡APP评测系列——工银e生活5.0打造个人生活服务平台,引领用户美好生活

    易观:中国信用卡市场规模增速趋稳,线上成为存量用户经营主阵地, APP用户高质量经营成为新发力点,也是业务良性增长保障,对此,银行机构着力用户体验竞相升级信用卡APP.工商银行顺势升级工银e生活APP ...

  6. 想象中的同居生活 VS 真实的同居生活

    1 长颈鹿是怎么喝水的  2  为了防止雨伞被偷 设计师还是真动了不少脑筋呢-  3  睡在这样的床上,晒着太阳,肯定超赞  4  如何阻止猫咪上楼5 想象中的同居生活 VS 真实的同居生活 6 硬生 ...

  7. 怎样度过研究生生活,如何度过研究生生活

    目录 怎样度过研究生生活,如何度过研究生生活 明确几种好的心态 研究生期间应该做的事 具备能力 应该做什么(直面困境) 怎么确定方向 怎么知道牛人 急功近利反而事与愿违 1.从决定读博那天开始就拼命看 ...

  8. 在生活之中,要活在生活之上

    在生命的历程中,你要始终保持自己的本色,按照内心的指引过 自己想过的生活.除此之外,一切都是次要的.你的工作.生活.事业.人际关系.婚姻.艺术创作以及种种兴趣爱好,如果不是建立在自己的本色的基础上,一 ...

  9. 生活不像电影,生活比电影难多了

    Life isn't like in the movies. Life... is much harder. 生活不像电影,生活比电影难多了.<天堂电影院> 原文载于:爱词霸英语学习网-每 ...

  10. 用心感受生活,才会发现生活的乐趣。

    持续的努力,才会有持续的收获. 在变好的路上,比计划和行动更宝贵的是在看不到结果时,还能坚持自己的选择. 过好每一天,做好每一件事,用心去感受生活,才会发现生活的乐趣.用心将生活过成自己想要的模样,全 ...

最新文章

  1. 饶毅坚守教育学者的风骨,网友鼓励:远离精致利己主义的舒适区
  2. RHEL6.3配置文件共享(5) Samba服务之三
  3. python中read()、readline()、readlines()函数
  4. 消息 245,级别 16,状态 1,第 1 行 在将 varchar 值 '2,8' 转换成数据类型 int 时失败。...
  5. nginx $document_uri 参数使用
  6. SAP 电商云 Spartacus 5_0.md 迁移文档的编写格式
  7. oracle adf_Oracle ADF移动世界! 你好!
  8. kali linux改中文_【亲测实验】kali linux 2020 设置为中文方法
  9. TFS Training for Kunlun bank (http://www.klb.cn/) 微软研发流程(ALM)管理培训会议(昆仑银行) 2016.09.21...
  10. Spring Data Jpa的@Temporal注解
  11. Atitit 解析m4a文件的元数据标签音乐名,歌手 专辑 年代等信息 java版本 目录 1.1. 自己解析mp4 m4a结构 1 1.2. 格式返回 1 1.3. /bookmarksHtmlE
  12. 解决accuracy_score报错Classification metrics can‘t handle a mix of continuous and multiclass targets
  13. AVFoundation音视频采集(三)
  14. 朴实无华!注意力机制神经网络解析
  15. 解决的问题记录(持续更新)
  16. 手机上将png转pdf_如何在Linux上将多个jpg图像合并为pdf?
  17. 源码免杀教程 源码免杀思路详解
  18. matlab中画网格,matlab怎么画网格
  19. c语言画笔的使用方法,新手必看:Photoshop笔刷画笔工具基本使用教程
  20. 关于使用GPS天线需要注意的事项

热门文章

  1. 【技巧】美国5大免税州邮编
  2. 中国4K和8K超高清电视市场现状研究分析与发展前景预测报告
  3. linux find -size参数,Linux中find的用法
  4. 日本白光FX-888D焊台温度设置
  5. slither——区块链智能合约静态分析工具
  6. Unity使用滚动条Slider控制声音音量
  7. 一款免费的容器安全 SaaS 平台使用记录
  8. com.sun.proxy.$Proxy0 cannot be cast to com.chan.dao.IUserDao报错问题
  9. 在VS2019中新建DX12工程
  10. Revit学习笔记004--极客BIMRevit二次开发方法收集