通用-聚合支付
<p>通用-聚合支付
线上环境地址: <a href="http://bs.qbwelink.cn/api/push/alipay">http://bs.qbwelink.cn/api/push/alipay</a>
/**</p>
<ul>
<li>公钥加密</li>
<li>
</li>
<li>@param publicKeyString 公钥</li>
<li>@param appSecret 待加密的 appSecret</li>
<li>@return 加密后的文本
*/
public static String encryptByPublicKey(String publicKeyString, String appSecret ) throws Exception
{
X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyString));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] result = cipher.doFinal(text.getBytes());
return Base64.encodeBase64String(result);
}</li>
</ul>
<p>简要描述
1、支付接口
请求URL
<a href="http://bs.qbwelink.cn/api/push/alipay">http://bs.qbwelink.cn/api/push/alipay</a>
请求方式
POST
Headers
参数名 必选 类型 说明
appId 是 string (登录平台,详见对接文档)
appSecret 是 string 加密后(encryptByPublicKey)
参数
参数名 必选 类型 说明
payChannel 是 string 支付类型 【wx_pub=微信,alipay_wap=支付宝】
money 是 string 金额 单位 元
comment 否 string 备注
minutes 是 string 续费周期
callBackUrl 是 string 回调地址
outtrxid 是 string 交易单号
startTime 是 string 缴费时间
返回示例
{
“msg”: “succ”,
“code”: 0,
“data”: {
“tradeNo”: 1554659929871224832,
“payUrl”: “”
}
}
返回参数说明
参数名 类型 说明
tradeNo long 交易流水号
outtrxid string
payUrl string 支付链接, 扫码后 调用接口, 跳转该地址 付款
简要描述
用户下单时填写的回调url</p>
<p>请求方式
POST form
{
“data”: “{“outtrxid”:”P01202309211913175093074”,”tradeNo”:”1704816063620976640”,”trxstatus”:”0000”}”,
“sign”: “aImC7Pl2gJJwgqY+2ndTwritqqReAvUUbPWVwRs+j44P9FdI4Ie9igy1GtnxIyFzA87FMdbl4z+B4qOVL9Pje+gsNqgvfS7WgRkoI5Gd60A2DwJbGnyEw4fuLRWaByNCctK2Jo0OUjUGrFnE8L6YnrOCUsv6CTQsaPzIo2N1KCQ=”
}</p>
<p>备注</p>
<p>/**</p>
<ul>
<li>验证签名,指定编码</li>
<li>@param content 待验证数据</li>
<li>@param sign 待验证签名</li>
<li>@param publicKey 公钥数据</li>
<li>@param charset 编码 UTF-8</li>
<li>@return 验证结果</li>
<li>
<p>@throws Exception 异常
*/
public static boolean verifySign(String content, String sign, String publicKey, String charset) throws Exception {
try {
PublicKey pubKey = getPublicKeyFromX509("RSA", new ByteArrayInputStream(publicKey.getBytes()));
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initVerify(pubKey);
if (charset==null||charset.length()==0) {
signature.update(content.getBytes());
} else {
signature.update(content.getBytes(charset));
}</p>
<pre><code>return signature.verify(Base64.decodeBase64(sign.getBytes()));</code></pre>
<p>} catch (Exception var6) {
throw new Exception("RSAcontent = " + content + ",sign=" + sign + ",charset = " + charset, var6);
}
}</p>
<p>/**</p>
</li>
<li>生成公钥</li>
<li>@param algorithm 签名算法</li>
<li>@param ins 公钥数据</li>
<li>@return 公钥</li>
<li>@throws Exception 异常
*/
public static PublicKey getPublicKeyFromX509(String algorithm, InputStream ins) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
StringWriter writer = new StringWriter();
StreamUtil.io(new InputStreamReader(ins), writer);
byte[] encodedKey = writer.toString().getBytes();
encodedKey = Base64.decodeBase64(encodedKey);
return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
}</li>
</ul>
<p>2.回调接口:(对接商家提供,并填入支付接口callBackUrl字段)
代码示例:
package com.example.payurldemo;</p>
<p>import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.payurldemo.utils.StreamUtil;
import org.apache.commons.io.IOUtils;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;</p>
<p>import java.io.;
import java.security.;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;</p>
<p>@RestController
public class CallBackController {</p>
<p>private static String publicKEy = "xxx";</p>
<p>private static String privateKey ="xxx";</p>
<p>@PostMapping("/alipay/callback")
public Map<String,Object> alipayCallback(@RequestBody AlipayCallbackRequest request) throws Exception {
// 获取请求中的数据和签名
String data = request.getData();
String sign = request.getSign();
// 这里写处理支付宝/微信回调的逻辑,验证回调数据的签名并比对
//验签
verifySign(data,sign,publicKEy,"UTF-8");
//TODO 处理业务逻辑</p>
<pre><code>// 处理完毕后返回给支付宝/微信的成功响应
Map&lt;String,Object&gt; resultMap = new HashMap&lt;&gt;();
resultMap.put(&quot;code&quot;,&quot;0000&quot;);
resultMap.put(&quot;msg&quot;,&quot;成功&quot;);
return resultMap;</code></pre>
<p>}</p>
<p>工具类和加验签方法如下:
/**</p>
<ul>
<li>验证签名,指定编码</li>
<li>@param content 待验证数据</li>
<li>@param sign 待验证签名</li>
<li>@param publicKey 公钥数据</li>
<li>@param charset 编码 UTF-8</li>
<li>@return 验证结果</li>
<li>
<p>@throws Exception 异常
*/
public static boolean verifySign(String content, String sign, String publicKey, String charset) throws Exception {
try {
PublicKey pubKey = getPublicKeyFromX509("RSA", new ByteArrayInputStream(publicKey.getBytes()));
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initVerify(pubKey);
if (charset==null||charset.length()==0) {
signature.update(content.getBytes());
} else {
signature.update(content.getBytes(charset));
}</p>
<pre><code>return signature.verify(Base64.decodeBase64(sign.getBytes()));</code></pre>
<p>} catch (Exception var6) {
throw new Exception("RSAcontent = " + content + ",sign=" + sign + ",charset = " + charset, var6);
}
}
/**</p>
</li>
<li>生成公钥</li>
<li>@param algorithm 签名算法</li>
<li>@param ins 公钥数据</li>
<li>@return 公钥</li>
<li>@throws Exception 异常
*/
public static PublicKey getPublicKeyFromX509(String algorithm, InputStream ins) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
StringWriter writer = new StringWriter();
StreamUtil.io(new InputStreamReader(ins), writer);
byte[] encodedKey = writer.toString().getBytes();
encodedKey = Base64.decodeBase64(encodedKey);
return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
}</li>
</ul>
<p>public static String sign(String content, String privateKey, String charset) throws Exception {
try {
PrivateKey priKey = getPrivateKeyFromPKCS8("RSA", new ByteArrayInputStream(privateKey.getBytes()));
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initSign(priKey);
if (charset == null || charset.isEmpty()) {
signature.update(content.getBytes());
} else {
signature.update(content.getBytes(charset));
}
byte[] signed = signature.sign();
return Base64.encodeBase64String(signed);
} catch (Exception var6) {
throw new Exception("Failed to sign content: " + content + ", charset: " + charset, var6);
}
}
public static PrivateKey getPrivateKeyFromPKCS8(String algorithm, InputStream ins) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = ins.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, length);
}
byte[] keyBytes = byteArrayOutputStream.toByteArray();
EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(keyBytes);
return keyFactory.generatePrivate(privateKeySpec);
}
public static String signData(String privateKeyStr, String data) throws Exception {
String algorithm = "SHA1withRSA"; // 默认算法为SHA256withRSA</p>
<pre><code>// 将私钥字符串转换为 PrivateKey 对象
byte[] privateKeyBytes = Base64.decodeBase64(privateKeyStr);
KeyFactory keyFactory = KeyFactory.getInstance(&quot;RSA&quot;);
PrivateKey privateKey = keyFactory.generatePrivate(new X509EncodedKeySpec(privateKeyBytes));
// 使用私钥进行数字签名
Signature signature = Signature.getInstance(algorithm);
signature.initSign(privateKey);
signature.update(data.getBytes(&quot;UTF-8&quot;));
byte[] signatureBytes = signature.sign();
// 将签名结果转换为字符串
return Base64.encodeBase64String(signatureBytes);</code></pre>
<p>}</p>
<p>/**</p>
<ul>
<li>对数据进行加签,指定编码</li>
<li>@param privateKeyStr 私钥字符串</li>
<li>@param data 待加签数据</li>
<li>@param charset 编码 UTF-8</li>
<li>@return 加签结果</li>
<li>
<p>@throws Exception 异常
*/
public static String signData(String privateKeyStr, String data, String charset) throws Exception {
try {
PrivateKey privateKey = getPrivateKeyFromString("RSA", privateKeyStr);
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initSign(privateKey);
if (charset == null || charset.length() == 0) {
signature.update(data.getBytes());
} else {
signature.update(data.getBytes(charset));
}</p>
<pre><code>byte[] signatureBytes = signature.sign();
return Base64.encodeBase64String(signatureBytes);</code></pre>
<p>} catch (Exception e) {
throw new Exception("data = " + data + ", privateKeyStr = " + privateKeyStr + ", charset = " + charset, e);
}
}</p>
</li>
</ul>
<p>/**</p>
<ul>
<li>从字符串中获取私钥</li>
<li>@param algorithm 签名算法</li>
<li>@param privateKeyStr 私钥字符串</li>
<li>@return 私钥</li>
<li>@throws Exception 异常
*/
public static PrivateKey getPrivateKeyFromString(String algorithm, String privateKeyStr) throws Exception {
byte[] privateKeyBytes = Base64.decodeBase64(privateKeyStr);
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
return keyFactory.generatePrivate(keySpec);
}</li>
</ul>
<p>}</p>
<p>实体类为:
package com.example.payurldemo;</p>
<p>import lombok.Data;</p>
<p>@Data
public class AlipayCallbackRequest {
private String data;
private String sign;</p>
<p>}</p>
<p>其他io工具类
package com.example.payurldemo.utils;</p>
<p>import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;</p>
<p>public class StreamUtil {</p>
<p>public static void io(InputStreamReader reader, StringWriter writer) throws IOException {
char[] buffer = new char[4096];
int bytesRead;
while ((bytesRead = reader.read(buffer)) != -1) {
writer.write(buffer, 0, bytesRead);
}
writer.flush();
}</p>
<p>}</p>