接入指南
准备工作:
- 每个商户拥有独立应用id(appId),每个支付通道拥有独立的收款编码(paymentCode),请联系工作人员获取
- 每个商户拥有独立的参数加密私钥,请联系工作人员获取
- 接口参数名大小写敏感
- 接口返回为JSON格式
-
每次调用接口时都需要传参数签名
生产环境:
测试环境:http://payment.test.payol.cn/
项目登录密码: test/123456 可配置分账用户、分账比例、订单查询、支付撤销等
参数名 | 必选 | 类型 | 说明 | 备注 |
---|---|---|---|---|
data | 是 | String | 请求参数 | JSON数据序列化字符串 |
sign | 是 | String | 参数签名 | RSA方式,使用私钥对请求参数签名 |
请求参数签名Sample:
public static String PRIVATE_KEY = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDXYbSt91JOnZZaJXrt2CRM+TWsT/qx4ypJFx3lWXshcrS1KdJTJQv//lEEtluO9poQCRs0UAGLuCGlxGvZTVHtxSIPbPA36ITEVipekZ9FCugRZ8oIADsxdS4QnS8M8BDd3Qtl519kfs16fev7qNbf6tkMu/kPC8wO3VzBVOLUq3rRgCntTBfzyQBiH0ZEKGm3DefAynchvXy2MWKHfdgILF/x80TqYbv7LAub5hfsAasw4J05psXzNebRzugpoqDbfpNs8nkpz6U+QLJzdjKc9PMWw4S9ReCQnotNAaIp9RX8cxT6S8U1U0x33fERSYzYaGYVl5/x46rCOPCC7HVzAgMBAAECggEACmNrDI0GSkZtjxGJuVkYfyHyBcqhw9y6GGZmCb7kInve3XIT8/CwgHtquvh0uBOK4MUfq8lEGdIaxV0Q+p0xG2/LscTGXVv4s2OYjZEmhnT9NoG0C+i+8ia9vw1lzJDzr0/PEe4z+qvnC0ZxkGTXYFt6dpPGcoRWJk1lAOowOqOoEExcwsZhBkvGTWTv6AyBASBNhE2WAHzqRuF+Du4aEOirTyCfcgxb6hLVVVZWX2T5jRyq8lgn1RLg5ickVjtaWQBsPig32TImy0HKnRQa6WnKTNBaVOaDbsJzpxAq4OITgFjEg0L7QBjBJM1nVIh1kU73ixPCe1asqWTD7YutGQKBgQD0hGDxLe4Sm4IPkz/IStwJQpfUEskfPVbSGQS+KTMEPs2m2dB4mEV5x1JACekPxpUNe6KDt2YHYT9zRmxXGoJstuJ7C6qNAyxQB7jG0fxp20kweym81pBf7m9nSajw4i1Zq4axDTzLQ7YjF0dmdgR5BcJX8u5w3yj81sNFRuS4VwKBgQDhfw5z22Cg8n4gF0GLA4zrS/FeOD3lnQ7lQ91Hmp1ad5g0xyeHq53r/0+Ecyi1E0FK2el2pJVH0xmFW+xd7Q4teS3FZv5iw23NHyjFalipSqTmRjAAATRNGopMdwKwYqvtCTpkaNj/XRVTsDwmMA9f+C7vcA9YICkQjnOy++uqRQKBgDD/uiF6j8PAz+5pFpX/klp0stI3tYACHbzacJ3eya9nGnT+Hw2bjgiaTbwxgDe+Fq5uASIeBV8jOMDT8u/9ivdYKsh3jQTXBvE+quOEvu1DmUYS2ElUQfhHYqGzHByxZl8axVIDkhQ1jHE5wAAjVEAgTFKthuStg5wvOVBPpZPfAoGAawnJzXsUKjIRZqBDb3529PYuk7/0ubrM6E1Hi4a8LMZaTKtAe2keZHjjwQZ9Cz8hnitEZBoJ9nchRSl2ULuHIFTGQk76b90+kMC6tMMfZPTWw6wLeuUXc4YmoddYQmwEGldoDWOrpcQErJ4aXzIvCiof9W5nCjjx5TcJequUG7H2pQh3w==";
public static void main(String[] args) {
try {
// {"orderNo": "GK20231101123334817bS","payType": "wx_pub", "orderAmount" : 0.02, "paymentCode": "LSFPG5At5", "code": "071xVaGa1NGokG0OM4Ja149Vzo4xVaGJ"}
PaymentInfoRequest payment = new PaymentInfoRequest();
payment.setOrderNo("GK20231101123334817b1");
payment.setPayType("wx_pub");
payment.setOrderAmount(BigDecimal.valueOf(0.02));
payment.setPaymentCode("LSFPG5At5");
payment.setCode("071xVaGa1NGokG0OM4Ja149Vzo4xVaGJ");
String payInfo = JSON.toJSONString(payment);
// 请求参数签名
String sign = PanySign.sign(payInfo, PRIVATE_KEY);
//验签标记
//boolean checkSign = PanySign.verifySign(payInfo, sign, PUBLIC_KEY);
System.out.println("payInfo = " + payInfo);
System.out.println("sign = " + sign);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
签名Util
/**
* Pany签名工具类
*/
public class PanySign {
public static String sign(String content, String privateKey) throws Exception {
return sign(content, privateKey, "UTF-8");
}
public static boolean verifySign(String content, String sign, String publicKey) throws Exception {
return verifySign(content, sign, publicKey, "UTF-8");
}
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.length() != 0) {
signature.update(content.getBytes(charset));
} else {
signature.update(content.getBytes());
}
byte[] signed = signature.sign();
return new String(Base64.encodeBase64(signed));
} catch (Exception var6) {
throw new Exception("RSAcontent = " + content + "; charset = " + charset, var6);
}
}
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(charset));
} else {
signature.update(content.getBytes());
}
return signature.verify(Base64.decodeBase64(sign.getBytes()));
} catch (Exception var6) {
throw new Exception("RSAcontent = " + content + ",sign=" + sign + ",charset = " + charset, var6);
}
}
public static PrivateKey getPrivateKeyFromPKCS8(String algorithm, InputStream ins) throws Exception {
boolean validKey = ins != null && algorithm != null || algorithm.length() != 0;
if (validKey) {
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
byte[] encodedKey = StreamUtil.readText(ins).getBytes();
encodedKey = Base64.decodeBase64(encodedKey);
return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
} else {
return null;
}
}
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));
}
public static String getOriginalStr(Map<String, Object> map) {
List<String> listKeys = new ArrayList(map.keySet());
Collections.sort(listKeys);
StringBuilder stringBuilder = new StringBuilder();
for(int i = 0; i < listKeys.size(); ++i) {
if (map.get(listKeys.get(i)) != null && map.get(listKeys.get(i)).toString().length() != 0) {
stringBuilder.append((String)listKeys.get(i)).append("=").append(map.get(listKeys.get(i))).append("&");
}
}
return stringBuilder.length() == 0 ? "" : stringBuilder.toString().substring(0, stringBuilder.length() - 1);
}
}
StreamUtil:
public class StreamUtil {
private static final int DEFAULT_BUFFER_SIZE = 8192;
public StreamUtil() {
}
public static void io(InputStream in, OutputStream out, int bufferSize) throws IOException {
if (bufferSize == -1) {
bufferSize = 8192;
}
byte[] buffer = new byte[bufferSize];
int amount;
while((amount = in.read(buffer)) >= 0) {
out.write(buffer, 0, amount);
}
}
public static void io(Reader in, Writer out) throws IOException {
io((Reader)in, (Writer)out, -1);
}
public static void io(Reader in, Writer out, int bufferSize) throws IOException {
if (bufferSize == -1) {
bufferSize = 4096;
}
char[] buffer = new char[bufferSize];
int amount;
while((amount = in.read(buffer)) >= 0) {
out.write(buffer, 0, amount);
}
}
public static String readText(InputStream in) throws IOException {
return readText(in, (String)null, -1);
}
public static String readText(InputStream in, String encoding) throws IOException {
return readText(in, encoding, -1);
}
public static String readText(InputStream in, String encoding, int bufferSize) throws IOException {
Reader reader = encoding == null ? new InputStreamReader(in) : new InputStreamReader(in, encoding);
return readText(reader, bufferSize);
}
public static String readText(Reader reader, int bufferSize) throws IOException {
StringWriter writer = new StringWriter();
io((Reader)reader, (Writer)writer, bufferSize);
return writer.toString();
}
public static void closeQuietly(Reader input) {
try {
if (input != null) {
input.close();
}
} catch (IOException var2) {
}
}
public static void closeQuietly(Writer output) {
try {
if (output != null) {
output.close();
}
} catch (IOException var2) {
}
}
public static void closeQuietly(InputStream input) {
try {
if (input != null) {
input.close();
}
} catch (IOException var2) {
}
}
public static void closeQuietly(OutputStream output) {
try {
if (output != null) {
output.close();
}
} catch (IOException var2) {
}
}
}