看完不懂你来喷我

项目需要接入新的支付渠道:银联无跳转支付,花了点时间接入成功,这里发布一个踩坑记录吧,把过程中的问题都会给大家分享下QAQ,看完不懂你来喷我o(╯□╰)o 博客中有接入其他支付 支付宝:https://blog.csdn.net/hu15081398237/article/details/105680622 微信:https://blog.csdn.net/hu15081398237/article/details/94721290


最终会将所有源代码以及用到的资料文档,都会上传git上面

文章目录

  • 看完不懂你来喷我
  • 前言
  • 一、官网
  • 二、使用步骤
    • 1.下载官方提供的代码
    • 2.目录说明【一定要对着项目结构认真看这段内容】
    • 3. 配置项目启动相关参数
    • 4. 依赖jar
    • 5.tomcat启动项目
    • 6.支付
    • 7.银联自己的项目代码简单介绍
    • 8.整合后的SpringBoot项目
      • 自定义starter初始化项目
    • 9.springboot项目启动
    • 10.支付讲解,先看图,后面有Demo代码,注释很清楚
    • 11.示例代码讲解
  • 总结
  • 写到最后

前言

提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、官网

https://open.unionpay.com/tjweb/user/mchTest/param 个人登录后的相关参数查看


其实在接入支付之前建议大家了解下 对称加密,分对称加密RSA之类,摘要算法,https,证书等这些知识点,因为此代码后面的验签,判断都是基于此的。初始化加载证书,判断证书是否正确,过期,是否被串改都需要上面知识的支撑

二、使用步骤

1.下载官方提供的代码

https://open.unionpay.com/tjweb/acproduct/list?apiSvcId=449&index=5
支持3个语言的接入,这里只说java版本的。而且后面我也对代码进行了重构,毕竟demo的项目还是无法直接嵌入到生产项目中

项目展示(示例):因为我接入的是token版本的,所以都是查看token的代码,银联的支付涉及web 和token两种,大同小异,只是涉及到传入的参数类型不一样而已

2.目录说明【一定要对着项目结构认真看这段内容】

ACPSample-WuTiaoZhuan

├src┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈类文件夹
│ │
│ ├assets ┈┈┈┈┈┈┈┈┈相关资源目录
│ │ │
│ ├assets ┈┈┈┈┈┈┈┈┈相关资源目录
│ │ │
│ │ ├apache_httpclient┈┈┈┈┈┈┈┈┈apache中的http post方法
│ │ │
│ │ ├测试环境证书
│ │ │ │
│ │ │ ├acp_test_enc.cer ┈┈┈┈┈┈┈┈┈ 【重要】测试环境敏感信息加密证书(所有商户固定使用同一个)
│ │ │ │
│ │ │ ├acp_test_sign.pfx ┈┈┈┈┈┈┈┈┈ 【重要】 测试环境签名私钥证书(所有商户固定使用同一个)
│ │ │ │
│ │ │ ├acp_test_root.cer ┈┈┈┈┈┈┈┈┈ 【重要】 测试环境验签公钥证书根证书 (所有商户固定使用同一个)
│ │ │ │
│ │ │ └acp_test_middle.cer ┈┈┈┈┈┈┈┈┈【重要】 测试环境验签公钥证书中级证书 (所有商户固定使用同一个)
│ │ │
│ │ ├对账文件样例
│ │ │ │
│ │ │ └802310048993424_20150905.zip ┈┈┈┈┈┈┈┈┈提供的对账文件样例(如果需要可以参考)
│ │ │
│ │ ├收单机构接入需做改动
│ │ │ │
│ │ │ ├acp_test_sign_inst.pfx ┈┈┈┈┈┈┈┈┈【重要】 收单机构接入的测试环境签名私钥证书(所有机构固定使用同一个)
│ │ │ │
│ │ │ └机构接入需做改动.txt
│ │ │
│ │ ├测试环境配置文件
│ │ │ │
│ │ │ └acp_sdk.properties ┈┈┈┈┈┈┈┈┈【重要】 测试环境配置文件样例(证书方式签名)(使用方式请看文件里的说明)
│ │ │
│ │ ├生产环境配置文件
│ │ │ │
│ │ │ └acp_sdk.properties ┈┈┈┈┈┈┈┈┈【重要】 生产环境配置文件样例(证书方式签名)(使用方式请看文件里的说明)
│ │ │
│ │ └生产环境证书
│ │ │
│ │ ├acp_prod_enc.cer┈┈┈┈┈┈┈┈┈【重要】 生产环境敏感信息加密证书(所有商户固定使用同一个)
│ │ │
│ │ ├acp_prod_root.cer ┈┈┈┈┈┈┈┈┈【重要】 生产环境验签公钥根证书 (所有商户固定使用同一个)
│ │ │
│ │ └acp_prod_middle.cer ┈┈┈┈┈┈┈┈┈【重要】 生产环境验签公钥中级证书 (所有商户固定使用同一个)
│ │
│ ├com.unionpay.acp.demo
│ │ │
│ │ ├token ┈┈┈┈┈┈┈┈┈无跳转token交易相关
│ │ │ │
│ │ │ ├Form03_6_2_Token_OpenCard_Back.java┈┈┈┈┈商户侧开通示例类(后台)
│ │ │ │
│ │ │ ├Form03_6_2_Token_OpenCard_Front.java┈┈┈┈┈银联侧开通示例类(前台)
│ │ │ │
│ │ │ ├Form03_6_3_Token_OpenQuery.java┈┈┈┈┈开通查询示例类(后台)
│ │ │ │
│ │ │ ├Form03_6_4_Token_DeleteToken.java┈┈┈┈┈删除token示例类(后台)
│ │ │ │
│ │ │ ├Form03_6_5_Token_UpdateToken.java┈┈┈┈┈更新token示例类(后台)
│ │ │ │
│ │ │ ├Form03_6_6_Token_ConsumeSMS.java┈┈┈┈┈消费短信示例类(后台)
│ │ │ │
│ │ │ ├Form03_6_6_Token_OpenSMS.java┈┈┈┈┈开通短信示例类 (后台)
│ │ │ │
│ │ │ ├Form03_6_7_Token_Consume.java┈┈┈┈┈消费示例类 (后台)
│ │ │ │
│ │ │ ├Form03_6_7_Token_OpenAndConsume.java┈┈┈┈┈开通并付款示例类 (前台)
│ │ │ │
│ │ │ └Form03_6_Token_ApplyToken.java┈┈┈┈申请toke号示例类 (前台)
│ │ │
│ │ ├BackRcvResponse.java┈┈┈┈┈后台通知处理示例类
│ │ │
│ │ ├DemoBase.java┈┈┈┈┈基础类
│ │ │
│ │ ├EncryptCerUpdateQuery.java┈┈┈┈┈加密证书更新示例类(后台)
│ │ │
│ │ ├Form03_6_3_ConsumeUndo.java┈┈┈┈┈消费撤销示例类 (后台)
│ │ │
│ │ ├Form03_6_4_Refund.java┈┈┈┈┈退货示例类 (后台)
│ │ │
│ │ ├Form03_6_5_Query.java┈┈┈┈┈交易状态查询示例类 (后台)
│ │ │
│ │ ├Form03_7_FileTransfer.java┈┈┈┈┈对账文件下载示例(后台)
│ │ │
│ │ ├FrontRcvResponse.java┈┈┈┈┈前台通知处理示例类
│ │ │
│ │ └多个商户号各自使用自己的私钥证书(多证书)使用方法.txt
│ │
│ ├com.unionpay.acp.sdk
│ │ │
│ │ ├AcpService.java┈┈┈┈┈┈全渠道SDK API接口类
│ │ │
│ │ ├CertUtil.java┈┈┈┈┈┈证书处理工具类
│ │ │
│ │ ├HttpClient.java┈┈┈┈┈后台交易http post通讯类,如果要使用代理访问或者产生了问题那么可以自行解决或者使用apache httpClient
│ │ │
│ │ ├LogUtil.java┈┈┈┈┈日志工具类
│ │ │
│ │ ├SDKConfig.java┈┈┈┈┈┈┈读取acp_sdk.properties属性文件并填装配置的属性的配置类
│ │ │
│ │ ├SDKConstants.java┈┈┈┈┈┈┈常量类
│ │ │
│ │ ├SDKUtil.java┈┈┈┈┈┈┈SDK工具类,包含了对报文的签名,验签等方法
│ │ │
│ │ ├SecureUtil.java┈┈┈┈┈┈┈安全相关工具类
│ │ │
│ │ └SM3Digest.java┈┈┈┈┈┈┈sm3算法工具类
│ │
│ └web ┈┈┈┈┈┈┈┈┈ web相关类
│ │
│ ├AutoLoadServlet.java ┈┈┈┈┈┈初始化读取acp_sdk.properties初始化请求银联地址,证书等相关资源的servlet
│ │
│ └CharsetEncodingFilter.java ┈┈┈┈web请求编码过滤器

├acp_sdk.properties ┈┈┈┈【重要】测试环境配置文件,请求银联地址,私钥签名证书,验签公钥路径,多证书的配置文件(这个文件切换生产的时候要替换成生产环境的配置文件)

├log4j.properties ┈┈┈┈LogUtil.java日志工具类的配置文件

├WebContent ┈┈┈┈┈┈┈┈┈┈┈┈┈┈页面文件夹
│ │
│ ├index.jsp ┈┈┈┈┈┈┈┈┈调试入口页面
│ │
│ └WEB-INF
│ │
│ └lib(如果JAVA项目中包含这些架包,则不需要导入)
│ │
│ ├bcprov-jdk15on-1.54.jar---------注意包名后缀版本,低版本的bc包不支持sdk使用的部分方法
│ │
│ ├commons-codec-1.6.jar
│ │
│ ├commons-io-2.2.jar
│ │
│ ├commons-lang-2.5.jar
│ │
│ ├log4j-1.2.17.jar
│ │
│ ├slf4j-api-1.5.11.jar
│ │
│ └slf4j-log4j12-1.5.11.jar

└readme.txt ┈┈┈┈┈┈┈┈┈使用说明文本

───────────
注意

1.【接口规范】该接口参考文档位置:
接口产品规范:open.unionpay.com帮助中心 下载 产品接口规范 《无跳转产品接口规范》
应答码规范:《平台接入接口规范-第5部分-附录》
商户对账文件格式说明:《全渠道平台接入接口规范 第3部分 文件接口》

2.【测试商户号】开发包中使用的商户号777290058110097是open.unionpay.com注册的测试商户号,只能在入网测试环境使用;
可以先使用这个商户调通交易(当然您也可以自己在这个网站注册一个777开头的测试商户号,自己注册后要开通权限:https://open.unionpay.com 登陆后 右上角我的测试-我的产品-将未测试的产品点击成测试状态,过10分钟后就有权限了)
正式线上环境请替换成申请的正式商户号,并确保商户号有对应的权限,如果报了无此交易权限等错误,请联系您申请接入银联的业务人员确认您做的交易是否开通了对应的权限。

3.【关于配置文件】
配置文件在src/assets文件夹下可以找到,src下面默认使用的是测试环境使用证书方式签名的配置文件。请按配置文件中的说明进行修改。
使用时需要配置证书路径,证书文件除了生产环境的签名证书需要业务邮件发送下载方式下载,其余证书均在src/assets文件夹下面有提供,需要复制到配置文件配置的路径。

4.【测试过程遇到问题】
1)优先在open平台中查找答案:
调试过程中的问题或其他问题请在 https://open.unionpay.com/ajweb/help/faq/list 帮助中心 FAQ 搜索解决方案
测试过程中产生的7位应答码问题疑问请在https://open.unionpay.com/ajweb/help/respCode/respCodeList 输入应答码搜索解决方案
2)测试环境测试支付请使用测试卡号测试, FAQ搜索“测试卡”。
3)切换生产环境要点请FAQ搜索“切换”。

5.【生产环境遇到问题】连接银联生产环境测试遇到的问题 如果通过open平台无法解决 请登陆merchant.unionpay.com 菜单"服务单管理"->"创建服务单"请求排查问题。


3. 配置项目启动相关参数

由于项目启动需要验证各种类型的证书,在本地他会找磁盘路径的证书位置,需要大家将 assert目录的证书拷贝到磁盘中 并对应到配置文件中的路径上 如下

4. 依赖jar

因为当前的项目不是一个maven项目只是一个普通的web项目,会涉及各种的jar依赖,大家自行配置项目中的web路径下lib目录,其中如果有问题请看当下目录的说明文件

5.tomcat启动项目


其实银联的这个文档写的还是相当不错的。就是在接的过程中他涉及的各种问题就是需要自己去体会理解。毕竟是老的版本,所以有些技术细节还是跟当下不一样的,比如传参居然不是json。

6.支付

项目已经正常启动,那么带大家了解下他的支付流程,这里先简单介绍下,后面直接上代码。其实所有的支付无非就是生产订单,请求第三方支付定义的接口,传递规范的参数,然后支付方会返回一个同步通知,还有一个异步通知,在这两个通知中实现你的业务处理。

== 同步,异步通知 都是需要外网能够访问的连接地址,所以你需要一个内网穿透工具,之前我一直在用natapp,https://blog.csdn.net/hu15081398237/article/details/94721290 这里面有我介绍使用natapp接入微信的步骤, 今天在这里使用的是uTools https://u.tools/docs/guide/about-uTools.html 它提供穿透功能==



当你项目启动成功,然后使用当前工具映射地址即可成功,然后你就可以使用链接访问自己项目。此项目能被外网访问

7.银联自己的项目代码简单介绍

建议大家先看下他们的代码,跑通后在自己整合,我们是大致瞅了一眼,我们架构就开始封装了,毕竟是大佬,但是后面我们也踩坑,我又调用它原始代码,分析入参,出参,结合我们的代码分析问题,一般都是出在了参数传递问题

在你都接入好后,需要用他们提供的信息进行测试,有问题就到这个地址找,搜索。银联这方面还是做得不错的
https://open.unionpay.com/tjweb/support/faq/mchlist?id=4

8.整合后的SpringBoot项目


自定义starter初始化项目


注意 相当于jdk spi,doubo spi 的特性:

9.springboot项目启动

10.支付讲解,先看图,后面有Demo代码,注释很清楚



上面填写的参数就是如下需要的信息



11.示例代码讲解

package com.ehs.union.pay.spring.boot.demo.controller;import com.esh.union.pay.sdk.bean.config.UnionPayConfig;
import com.esh.union.pay.sdk.bean.consts.*;
import com.esh.union.pay.sdk.bean.request.UnionOpenAllChannelAndPayRequest;
import com.esh.union.pay.sdk.service.UnionPayService;
import com.esh.union.pay.sdk.utils.UnionStrUtil;
import com.esh.union.pay.sdk.utils.sign.CertDescriptor;
import com.esh.union.pay.sdk.utils.sign.UnionSecureUtil;
import com.esh.union.pay.sdk.utils.sign.UnionSignUtil;
import com.esh.union.pay.sdk.utils.sign.encrypt.RSA2;
import com.esh.union.pay.sdk.utils.sign.encrypt.X509;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.PrivateKey;
import java.util.*;/*** 无跳转支付** @author huyufan* @date 2020/11/8 16:49*/
@Controller
@RequestMapping(value = "/pay")
public class PayController {protected static final Logger log = LoggerFactory.getLogger(PayController.class);@Autowiredprivate UnionPayService unionPayService;@Autowiredprivate CertDescriptor certDescriptor;/*** 支付请求 TO 银联* @param resp* @param openAllChannelAndPayRequest*/@RequestMapping(value = "/yinlian", method = RequestMethod.POST)public void toYinlianPay(HttpServletResponse resp, @ModelAttribute(value = "openAllChannelAndPayRequest") UnionOpenAllChannelAndPayRequest openAllChannelAndPayRequest) {UnionPayConfig config = unionPayService.getConfig();CertDescriptor certDescriptor = unionPayService.getCertDescriptor();openAllChannelAndPayRequest.setBizType(UnionBizTypeConsts.BIZ_TYPE_000902);openAllChannelAndPayRequest.setTxnTime(DateFormatUtils.format(new Date(), "yyyyMMddHHmmss"));//TODO 后台异步回调,暂未实现 backUrl 默认填官方要求的默认值,否则会校验openAllChannelAndPayRequest.setBackUrl(config.getBackUrl());openAllChannelAndPayRequest.setCurrencyCode("156");openAllChannelAndPayRequest.setTxnType(UnionTxnTypeConsts.TXN_TYPE_01);openAllChannelAndPayRequest.setTxnSubType(UnionTxnSubTypeConsts.TXN_SUB_TYPE_01);openAllChannelAndPayRequest.setAccessType(UnionAccessTypeConsts.ACCESS_TYPE_0);openAllChannelAndPayRequest.setSignature(UnionSignMethodConsts.SIGNMETHOD_01);openAllChannelAndPayRequest.setChannelType(UnionChannelTypeConsts.CHANNEL_TYPE_07);openAllChannelAndPayRequest.setAccType(UnionAccTypeConsts.ACC_TYPE_01);openAllChannelAndPayRequest.setTokenPayData("{trId=99988877766&tokenType=01}");openAllChannelAndPayRequest.setAccNo(null);//前台通知地址openAllChannelAndPayRequest.setFrontUrl(config.getFrontUrl());openAllChannelAndPayRequest.setPayTimeout(DateFormatUtils.format(DateUtils.addDays(new Date(), 1), "yyyyMMddHHmmss"));//requestopenAllChannelAndPayRequest.setCertId(certDescriptor.getSignCertId());openAllChannelAndPayRequest.setEncryptCertId(certDescriptor.getEncryptCertId());Map<String, String> paramMap = openAllChannelAndPayRequest.signAndGetMap(config,certDescriptor.getSignCertPrivateKey(config.getPrivateCertPwd()),config.getPrivateKeyString());String html = createAutoFormHtml(String.format(UnionUrlConsts.FRONT_TRANS_URL, "test.95516.com"), paramMap, "UTF-8");try {resp.getWriter().write(html);} catch (IOException e) {e.printStackTrace();}}/*** 银联同步通知* @param req* @return*/@RequestMapping("/frontRcvResponse")public ModelAndView frontRcvResponse(HttpServletRequest req) {String encoding = req.getParameter("encoding");log.info("返回报文中encoding=[" + encoding + "]");String pageResult = "";if ("UTF-8".equalsIgnoreCase(encoding)) {pageResult = "success";} else {pageResult = "error";ModelAndView modelAndView = new ModelAndView(pageResult);modelAndView.addObject("result", "交易出错,请联系管理员");return modelAndView;}//获取响应数据转换为mapMap<String, String> respParam = getAllRequestParam(req);// 验签集合Map<String, String> valideData = null;StringBuffer page = new StringBuffer();//组装集合数据if (null != respParam && !respParam.isEmpty()) {Iterator<Map.Entry<String, String>> it = respParam.entrySet().iterator();valideData = new HashMap<String, String>(respParam.size());while (it.hasNext()) {Map.Entry<String, String> e = it.next();String key = (String) e.getKey();String value = (String) e.getValue();valideData.put(key, value);}}//获取公钥证书/*X509Certificate x509Cert = SDK.genCertificateByStr(valideData.get("signPubKeyCert"));if (x509Cert == null) {log.info("convert signPubKeyCert failed");throw new RuntimeException();}*/// 2.验证证书链  以及是否过期/*if (!SDK.verifyCertificate(x509Cert, certDescriptor)) {log.info("验证公钥证书失败,证书信息:[" + valideData.get("signPubKeyCert") + "]");throw new RuntimeException();}*///验 签 处理String sign256 = DigestUtils.sha256Hex(UnionSignUtil.createQueryString(valideData, UnionParamConsts.getDefaultIgnoreSignParams()));boolean validate = RSA2.verify(sign256, valideData.get(UnionParamConsts.PARAM_SIGNATURE),X509.getPublicKey(valideData.get(UnionParamConsts.PARAM_SIGN_PUB_KEY_CERT)), "UTF-8");if (!validate) {log.info("验证签名结果[失败].");return null;} else {log.info("验证签名结果[成功].");//前台回调接口不涉及用户相关信息封装/*String customerInfo = valideData.get("customerInfo");if (null != customerInfo) {Map<String, String> customerInfoMap = this.parseCustomerInfo(customerInfo, "UTF-8");page.append("customerInfo明文: " + customerInfoMap);}String accNo = valideData.get("accNo");//如果返回的卡号是密文那么,可以用下边方法解密if (null != accNo) {accNo = AcpService.decryptData(accNo, "UTF-8");page.append("<br>accNo明文: " + accNo);}*///判断respCode=00、A6后,对涉及资金类的交易,请再发起查询接口查询,确定交易成功后更新数据库。String respCode = valideData.get("respCode");}if (StringUtils.equals(valideData.get("respCode"), "00")) {//解密卡号String accNo = UnionSecureUtil.decryptData(certDescriptor.getSignCertPrivateKey("000000"), valideData.get("accNo"), "UTF-8");respParam.put("accNo明文",accNo);ModelAndView modelAndView = new ModelAndView(pageResult);modelAndView.addObject("result", respParam);return modelAndView;} else {//TODO 交易码不正确  逻辑未完善ModelAndView modelAndView = new ModelAndView(pageResult);modelAndView.addObject("result", "交易出错,请联系管理员");return modelAndView;}}/*** 解析返回报文(后台通知)中的customerInfo域:<br>* 解base64,如果带敏感信息加密 encryptedInfo 则将其解密并将 encryptedInfo中的域放到customerInfoMap返回<br>** @param customerInfo<br>* @param encoding<br>* @return*/public Map<String, String> parseCustomerInfo(String customerInfo, String encoding) {Map<String, String> customerInfoMap = null;try {byte[] b = Base64.decodeBase64(customerInfo.getBytes(encoding));String customerInfoNoBase64 = new String(b, encoding);log.info("解base64后===>" + customerInfoNoBase64);//去掉前后的{}customerInfoNoBase64 = customerInfoNoBase64.substring(1, customerInfoNoBase64.length() - 1);customerInfoMap = UnionStrUtil.parseQString(customerInfoNoBase64);if (customerInfoMap.containsKey("encryptedInfo")) {String encInfoStr = customerInfoMap.get("encryptedInfo");customerInfoMap.remove("encryptedInfo");PrivateKey privateKey = certDescriptor.getSignCertPrivateKey("000000");String encryptedInfoStr = UnionSecureUtil.decryptData(privateKey, encInfoStr, encoding);Map<String, String> encryptedInfoMap = UnionStrUtil.parseQString(encryptedInfoStr);customerInfoMap.putAll(encryptedInfoMap);}} catch (UnsupportedEncodingException e) {log.info(e.getMessage(), e);} catch (IOException e) {log.info(e.getMessage(), e);}return customerInfoMap;}/*** 获取请求参数中所有的信息* 当商户上送frontUrl或backUrl地址中带有参数信息的时候,* 这种方式会将url地址中的参数读到map中,会导多出来这些信息从而致验签失败,这个时候可以自行修改过滤掉url中的参数或者使用getAllRequestParamStream方法。** @param request* @return*/public static Map<String, String> getAllRequestParam(final HttpServletRequest request) {Map<String, String> res = new HashMap<String, String>();Enumeration<?> temp = request.getParameterNames();if (null != temp) {while (temp.hasMoreElements()) {String en = (String) temp.nextElement();String value = request.getParameter(en);res.put(en, value);// 在报文上送时,如果字段的值为空,则不上送<下面的处理为在获取所有参数数据时,判断若值为空,则删除这个字段>if (res.get(en) == null || "".equals(res.get(en))) {// System.out.println("======为空的字段名===="+en);res.remove(en);}}}return res;}/*** 获取请求参数中所有的信息。* 非struts可以改用此方法获取,好处是可以过滤掉request.getParameter方法过滤不掉的url中的参数。* struts可能对某些content-type会提前读取参数导致从inputstream读不到信息,所以可能用不了这个方法。理论应该可以调整struts配置使不影响,但请自己去研究。* 调用本方法之前不能调用req.getParameter("key");这种方法,否则会导致request取不到输入流。** @param request* @return*/public static Map<String, String> getAllRequestParamStream(final HttpServletRequest request) {Map<String, String> res = new HashMap<String, String>();try {String notifyStr = new String(IOUtils.toByteArray(request.getInputStream()), "UTF-8");log.info("收到通知报文:" + notifyStr);String[] kvs = notifyStr.split("&");for (String kv : kvs) {String[] tmp = kv.split("=");if (tmp.length >= 2) {String key = tmp[0];String value = URLDecoder.decode(tmp[1], "UTF-8");res.put(key, value);}}} catch (UnsupportedEncodingException e) {log.info("getAllRequestParamStream.UnsupportedEncodingException error: " + e.getClass() + ":" + e.getMessage());} catch (IOException e) {log.info("getAllRequestParamStream.IOException error: " + e.getClass() + ":" + e.getMessage());}return res;}public static String createAutoFormHtml(String reqUrl, Map<String, String> hiddens, String encoding) {StringBuffer sf = new StringBuffer();sf.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=" + encoding + "\"/></head><body>");sf.append("<form id = \"pay_form\" action=\"" + reqUrl+ "\" method=\"post\">");if (null != hiddens && 0 != hiddens.size()) {Set<Map.Entry<String, String>> set = hiddens.entrySet();Iterator<Map.Entry<String, String>> it = set.iterator();while (it.hasNext()) {Map.Entry<String, String> ey = it.next();String key = ey.getKey();String value = ey.getValue();sf.append("<input type=\"hidden\" name=\"" + key + "\" id=\""+ key + "\" value=\"" + value + "\"/>");}}sf.append("</form>");sf.append("</body>");sf.append("<script type=\"text/javascript\">");sf.append("document.all.pay_form.submit();");sf.append("</script>");sf.append("</html>");return sf.toString();}}

总结

项目封装基础,业务处理我们架构都用了设计模式【sdk模块】,主要就是模板设计。建议大家好好理解下模板设计模式,真的各种项目框架的源代码不可能没有模板。需要项目源码请双击点赞留言+邮箱,毕竟整理不易。后面我抽出时间会整理个开源的sdk出来,这个的封装是我们架构封装,我只是嵌入业务功能代码实现。所以有些封装只是适合我们的业务处理,对于开源是我们没有考虑的。如果大家关注度高我就来整理下。主要最近沉迷于netty中,从入门到迷茫(>ω<)喵

写到最后

欢迎关注我的微信公众号 【猿之村】
来聊聊Java面试
加我的微信进一步交流和学习,微信手动搜索
【codeyuanzhicunup】添加即可
如有相关技术问题欢迎留言探讨,公众号主要用于技术分享,包括常见面试题剖析、以及源码解读、微服务框架、技术热点等。

SpringBoot整合银联无跳转支付附源码相关推荐

  1. 一小时学会使用Springboot整合沙箱环境支付宝支付(附源码)

    0.前言 文章需求: 对于学生来说,目前网上确实没有比较统一而且质量好的支付教程.因为支付对个人开发者尤其是学生来说不太友好.因此,自己折腾两天,算是整理了一篇关于支付宝沙箱支付的文章. 那么为什么不 ...

  2. 中国银联-无跳转支付token(银联侧开通)

    银联支付一直在围绕支付安全性为主导进行相关支付业务的开展,接下来介绍下银联的无跳转支付token(银联侧绑定),这种的支付模式可能会受商户的喜爱,因为支付流程中的界面可以自定义: 做无跳转支付时,银联 ...

  3. Netty实战:Springboot+Netty+protobuf开发高性能服务器 (附源码下载)

    Springboot-cli 开发脚手架系列 Netty系列:Springboot使用Netty集成protobuf开发高性能服务器 文章目录 Springboot-cli 开发脚手架系列 简介 1. ...

  4. springboot+校园新闻数据化系统-计算机毕设 附源码99293

    springboot+校园新闻数据化系统 目  录 摘要 1 1 绪论 1 1.1研究目的和意义 1 1.2选题背景和意义 1 1.3系统开发技术的特色 1 1.4springboot框架介绍 1 1 ...

  5. springboot高考志愿选择系统 -计算机毕设 附源码68335

    springboot高考志愿选择系统 目   录 摘要 第1章 绪论 1.1 研究背景与意义 1.2 研究现状 1.3论文结构与章节安排 第2章 相关技术 2.1开发技术 2.2 Java简介 2.3 ...

  6. springboot高考志愿选择系统-计算机毕设 附源码68335

    springboot高考志愿选择系统 目   录 摘要 第1章 绪论 1.1 研究背景与意义 1.2 研究现状 1.3论文结构与章节安排 第2章 相关技术 2.1开发技术 2.2 Java简介 2.3 ...

  7. Springboot高校学生实习档案管理毕业设计-附源码221508

    摘  要 21世纪的今天,随着社会的不断发展与进步,人们对于信息科学化的认识,已由低层次向高层次发展,由原来的感性认识向理性认识提高,管理工作的重要性已逐渐被人们所认识,科学化的管理,使信息存储达到准 ...

  8. 基于 Vue 和 SpringBoot 实现的博客系统(附源码)

    今天给大家分享一个基于 Vue 和 SpringBoot 实现的博客系统! 源码在文章结尾处,大家自行下载即可,我设置的免积分下载! 一.主要功能 1.前端 后台管理系统采用Vue开发. 文章模块,支 ...

  9. SpringBoot 和 Vue 前后端分离教程(附源码)

    编辑:业余草 来源:https://www.xttblog.com/?p=4851 昨天,一位网友问我要 SpringBoot + Vue 的源码项目.其实网上有很多,我这里分享一个项目的简单教程,授 ...

  10. springboot大学生综合素质测评系统-计算机毕设 附源码51615

    springboot大学生综合素质测评系统 摘  要 为全面提高教育管理水平,建立一个大学生综合素质测评管理系统已经成为目前各高校的共识.本文从实践经验出发,阐述目前高校学生工作管理的信息化现状﹔然后 ...

最新文章

  1. 基于DGCNN和概率图的轻量级信息抽取模型
  2. 在N + 1场景中使用@NamedEntityGraph更有选择地加载JPA实体
  3. 你辛苦来人间一趟,不是来作任务的,你应该好好享受阳光、雨露和爱 ...
  4. 数仓集群管理:单节点故障RTO机制分析
  5. 打脸往事!罗振宇2015年谈乐视、暴风 一口毒奶“奶死”不少人?
  6. 广义动量定理之质量m的应用案例分析
  7. TensorFlow 学习------第二天
  8. 动态规划——Russian Doll Envelopes
  9. linux 添加删除用户
  10. 20162319莫礼钟 2016-2017-2 《程序设计与数据结构》第2周学习总结
  11. html5 手机上传视频,【报Bug】手机h5端收不到选择视频以及上传视频回调
  12. VS2012 的快捷键使用
  13. matlab调和均值滤波_中值和均值滤波---matlab实现
  14. VTN联合GWI共同启动“全球健康登月计划”让更多人享受到健康新生活
  15. UIImageJPEGRepresentation 使用中存在的问题
  16. 一对一直播app源码开发的前端实现
  17. EAX、ECX、EDX、EBX
  18. 虚拟化 : VT-x VT-d VT-c的分别
  19. 大学英语四级考试必读必备
  20. UE4 安卓触摸事件相关问题

热门文章

  1. 使用Canvas绘制简单工程符号(续)
  2. Android虚拟电脑,如何让你的android模拟器连接上你电脑的网络
  3. Sonix SN9P701 OCR点读笔二维码识别源码
  4. 如何解决局域网共享报错0x80004005
  5. layui table切换html,解决Layui中切换tab时table样式错乱问题
  6. mac系统如何获取最好权限删除顽固文件?
  7. 智慧医疗整体解决方案(图文)
  8. python3 数据挖掘 之 爬取 智联招聘网站来巩固pandas
  9. 同步软件ActiveSync连接问题
  10. oo结尾的单词发音规律