文章目录

  • 前言
  • 对接杉德的一键快捷支付
  • 杉德的商家中心
  • 代码
  • 问题
  • 参考文献

前言

该支付就是调用他们的支付页面,绑卡无需我们操作,所有支付操作都有他们控制。对接的支付是,一键快捷支付,参考的文档是他们的demo,这个官方的demo不是springboot项目不是idea,需要自己配置tomcat运行。该篇文章中所涉及的代码,是本人自己根据官方demo以及GitHub上的开源项目所自己写的。

对接杉德的一键快捷支付

官方文档

杉德的商家中心

登录页面

  • 配置私钥、下载私钥公钥证书、设置私钥密码、配置支付链接回调地址、ip配置等

代码


<!-- 读取静态文件配置信息 一些常见依赖,这里就不做说明-->
<dependency><groupId>com.netflix.archaius</groupId><artifactId>archaius-core</artifactId><version>0.6.0</version>
</dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.73</version></dependency>
public class SandPayConst {/** 杉德支付-商户号 */public static final String MERCHANT_ID = "";/** 支付异步回调地址 */public static final String PAY_NOTIFY_URL = "http://api.cn/pay/sandpay_notify_url";/** 回调后的前端页面 */public static final String PAY_FRONT_URL = "http://api.cn/pay/pay_success_order";/** 杉德支付-绑卡异步回调 */public static final String CARD_NOTIFY_URL = "http://www.baidu.com";/** 杉德支付-解绑异步回调 */public static final String UN_CARD_NOTIFY_URL = "http://www.baidu.com";/** 杉德支付-发送签约短信 api */public static final String APPLY_BIND_CARD_URL = "";/** 杉德支付-绑卡确认 api */public static final String CONFIRM_BIND_CARD_URL = "";/** 杉德支付-解约 api */public static final String UNBIND_CARD_URL = "";/** 杉德支付-发起支付 api */public static final String SMS_PAY_URL= "";/** 杉德支付-确认支付 api */public static final String PAY_URL= "";/** 杉德支付-查询支付订单 api*/public static final String QUERY_PAY_ORDER_URL = "";/** 杉德支付-发起代付 api*/public static final String AGENT_PAY_URL = "";/** 杉德支付-查询代付订单 api*/public static final String QUERY_AGENT_ORDER_URL = "";/** 杉德支付-rmb代码:156 */public static final String CURRENCY_CODE = "156";// 人民币/** 杉德支付-版本 1.0 */public static final String VERSION = "1.0";/** 杉德支付-订单查询 */public static String ORDER_QUERY = "ODQU";                   //订单查询/** 杉德支付-实时代付 */public static String AGENT_PAY = "RTPM";                   //实时代付public static final String PRODUCT_ID_18 = "00000018";public static final String PRODUCT_ID_16 = "00000016";//=================================== method ============================================/** 杉德支付-申请绑卡  */public static final String SIGN_SMS_METHOD = "sandPay.fastPay.apiPay.applyBindCard";/** 杉德支付-确认绑卡  */public static final String SMS_SIGN_METHOD = "sandPay.fastPay.apiPay.confirmBindCard";/** 杉德支付-解绑  */public static final String UN_SIGN_METHOD = "sandPay.fastPay.apiPay.unbindCard";/** 杉德支付-发送支付短信  */public static final String PAY_SMS_METHOD = "sandPay.fastPay.common.sms";/** 杉德支付-支付  */public static final String SMS_PAY_METHOD = "sandPay.fastPay.apiPay.pay";/** 查询支付订单 */public static final String QUERY_PAY_METHOD = "sandpay.trade.query";
}
public class BusinessException extends RuntimeException {private static final long serialVersionUID = 1L;public BusinessException() {super();}public BusinessException(String message) {super(message);}public BusinessException(String message, Throwable cause) {super(message, cause);}public BusinessException(Throwable cause) {super(cause);}protected BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {super(message, cause, enableSuppression, writableStackTrace);}
}
public class HeadObject {private String version;private String method;private String access_token;private String productId;private String accessType;private String mid;private String plMid;private String channelType;private String reqTime;public HeadObject() {}public HeadObject(String version, String method, String access_token, String accessType, String mid,String reqTime) {this.version = version;this.method = method;this.access_token = access_token;this.accessType = accessType;this.mid = mid;this.reqTime = reqTime;}public HeadObject(String version, String method, String access_token, String productId, String accessType,String mid, String plMid, String channelType, String reqTime) {this.version = version;this.method = method;this.access_token = access_token;this.productId = productId;this.accessType = accessType;this.mid = mid;this.plMid = plMid;this.channelType = channelType;this.reqTime = reqTime;}public String getVersion() {return this.version;}public void setVersion(String version) {this.version = version;}public String getMethod() {return this.method;}public void setMethod(String method) {this.method = method;}public String getAccess_token() {return this.access_token;}public void setAccess_token(String access_token) {this.access_token = access_token;}public String getAccessType() {return this.accessType;}public void setAccessType(String accessType) {this.accessType = accessType;}public String getMid() {return this.mid;}public void setMid(String mid) {this.mid = mid;}public String getReqTime() {return this.reqTime;}public void setReqTime(String reqTime) {this.reqTime = reqTime;}public String getProductId() {return this.productId;}public void setProductId(String productId) {this.productId = productId;}public String getPlMid() {return this.plMid;}public void setPlMid(String plMid) {this.plMid = plMid;}public String getChannelType() {return this.channelType;}public void setChannelType(String channelType) {this.channelType = channelType;}
}
public class RequestData {private static final Logger logger = LoggerFactory.getLogger(RequestData.class);JSONObject dataJsonObject;JSONObject headJsonObject;JSONObject bodyJsonObject;HeadObject headObject;Map<String, Object> bodyMap;public RequestData() {}public RequestData(String data, Boolean decodeFlg) throws Exception {if (StringUtils.isBlank(data)) {logger.info("data参数为空!");return;}if (decodeFlg.booleanValue()) {data = Base64Util.decode(data);}this.dataJsonObject = JSONObject.parseObject(data);this.headJsonObject = this.dataJsonObject.getJSONObject("head");this.bodyJsonObject = this.dataJsonObject.getJSONObject("body");if (this.headJsonObject != null) {this.headObject = ((HeadObject) JSONObject.toJavaObject(this.headJsonObject, HeadObject.class));}if (this.bodyJsonObject != null) {this.bodyMap = ((Map) JSONObject.parseObject(this.bodyJsonObject.toJSONString(), new TypeReference() {}, new Feature[0]));}}public JSONObject getDataJsonObject() {return this.dataJsonObject;}public void setDataJsonObject(JSONObject dataJsonObject) {this.dataJsonObject = dataJsonObject;}public JSONObject getHeadJsonObject() {return this.headJsonObject;}public void setHeadJsonObject(JSONObject headJsonObject) {this.headJsonObject = headJsonObject;}public JSONObject getBodyJsonObject() {return this.bodyJsonObject;}public void setBodyJsonObject(JSONObject bodyJsonObject) {this.bodyJsonObject = bodyJsonObject;}public HeadObject getHeadObject() {return this.headObject;}public void setHeadObject(HeadObject headObject) {this.headObject = headObject;}public Map<String, Object> getBodyMap() {return this.bodyMap;}public void setBodyMap(Map<String, Object> bodyMap) {this.bodyMap = bodyMap;}
}
public class SandPayResponse {public SandPayResponseHead head;public SandPayResponseHead getHead() {return head;}public void setHead(SandPayResponseHead head) {this.head = head;}}
public class SandPayResponseHead {public String version;  // 版本号public String respTime;  // 响应时间public String respCode;  // 响应码public String respMsg;  // 响应描述public String getVersion() {return version;}public void setVersion(String version) {this.version = version;}public String getRespTime() {return respTime;}public void setRespTime(String respTime) {this.respTime = respTime;}public String getRespCode() {return respCode;}public void setRespCode(String respCode) {this.respCode = respCode;}public String getRespMsg() {return respMsg;}public void setRespMsg(String respMsg) {this.respMsg = respMsg;}
}
package com.chat.thirdparty.pay.sandpay.utils.encrypt;//一键快捷import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.concurrent.ConcurrentHashMap;public class CertUtil {private static final Logger logger = LoggerFactory.getLogger(CertUtil.class);private static final ConcurrentHashMap<String, Object> keys = new ConcurrentHashMap();public static void init(String publicKeyPath, String privateKeyPath, String keyPassword) throws Exception {initPulbicKey(publicKeyPath);initPrivateKey(privateKeyPath, keyPassword);}public static PublicKey getPublicKey() {return (PublicKey) keys.get("sandpay.public.key");}public static PrivateKey getPrivateKey() {return (PrivateKey) keys.get("sandpay.private.key");}private static void initPulbicKey(String publicKeyPath) throws Exception {String classpathKey = "classpath:";if (publicKeyPath != null) {try {InputStream inputStream = null;if (publicKeyPath.startsWith(classpathKey)) {inputStream = CryptoUtil.class.getClassLoader().getResourceAsStream(publicKeyPath.substring(classpathKey.length()));} else {inputStream = new FileInputStream(publicKeyPath);}PublicKey publicKey = getPublicKey(inputStream);keys.put("sandpay.public.key", publicKey);} catch (Exception e) {logger.error("无法加载银行公钥[{}]", new Object[] { publicKeyPath });logger.error(e.getMessage(), e);throw e;}}}private static void initPrivateKey(String privateKeyPath, String keyPassword) throws Exception {String classpathKey = "classpath:";try {InputStream inputStream = null;if (privateKeyPath.startsWith(classpathKey)) {inputStream = CryptoUtil.class.getClassLoader().getResourceAsStream(privateKeyPath.substring(classpathKey.length()));} else {inputStream = new FileInputStream(privateKeyPath);}PrivateKey privateKey = getPrivateKey(inputStream, keyPassword);keys.put("sandpay.private.key", privateKey);} catch (Exception e) {logger.error("无法加载本地私钥[{}]", new Object[] { privateKeyPath });logger.error(e.getMessage(), e);throw e;}}// 加载公钥证书public static PublicKey getPublicKey(InputStream inputStream) throws Exception {try {CertificateFactory cf = CertificateFactory.getInstance("X.509");X509Certificate oCert = (X509Certificate) cf.generateCertificate(inputStream);PublicKey publicKey = oCert.getPublicKey();return publicKey;} catch (Exception e) {throw new Exception("读取公钥异常");} finally {try {if (inputStream != null) {inputStream.close();}} catch (IOException e) {}}}/*** 获取私钥对象** @param inputStream  私钥输入流* @return 私钥对象* @throws Exception*/public static PrivateKey getPrivateKey(InputStream inputStream, String password) throws Exception {try {KeyStore ks = KeyStore.getInstance("PKCS12");char[] nPassword = null;if ((password == null) || (password.trim().equals(""))) {nPassword = null;} else {nPassword = password.toCharArray();}ks.load(inputStream, nPassword);Enumeration<String> enumas = ks.aliases();String keyAlias = null;if (enumas.hasMoreElements()) {keyAlias = (String) enumas.nextElement();}PrivateKey privateKey = (PrivateKey) ks.getKey(keyAlias, nPassword);return privateKey;} catch (FileNotFoundException e) {throw new Exception("私钥路径文件不存在");} catch (IOException e) {throw new Exception("读取私钥异常");} catch (NoSuchAlgorithmException e) {throw new Exception("生成私钥对象异常");} finally {try {if (inputStream != null) {inputStream.close();}} catch (IOException e) {}}}
}
package com.chat.thirdparty.pay.sandpay.utils.encrypt;import com.chat.thirdparty.pay.sandpay.utils.DynamicPropertyHelper;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URLEncoder;
import java.security.*;
import java.security.cert.X509Certificate;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;public abstract class CryptoUtil
{public static Logger logger;static {CryptoUtil.logger = LoggerFactory.getLogger((Class)CryptoUtil.class);}/*** 数字签名函数入口* @param plainBytes 待签名明文字节数组* @param privateKey 签名使用私钥* @param signAlgorithm 签名算法* @return 签名后的字节数组* @throws Exception*/public static byte[] digitalSign(final byte[] plainBytes, final PrivateKey privateKey, final String signAlgorithm) throws Exception {try {final Signature signature = Signature.getInstance(signAlgorithm);signature.initSign(privateKey);signature.update(plainBytes);final byte[] signBytes = signature.sign();return signBytes;}catch (NoSuchAlgorithmException e3) {throw new Exception(String.format("数字签名时没有[%s]此类算法", signAlgorithm));}catch (InvalidKeyException e) {throw new Exception("数字签名时私钥无效", e);}catch (SignatureException e2) {throw new Exception("数字签名时出现异常", e2);}}public static String digitalSign(final String data) throws Exception {if (null == data) {return null;}try {final String publicKeyPath = DynamicPropertyHelper.getStringProperty("sandpay.public.key", "").get();final String privateKeyPath = DynamicPropertyHelper.getStringProperty("sandpay.private.key", "").get();final String keyPassword = DynamicPropertyHelper.getStringProperty("sandpay.private.key.password", "").get();logger.info("publicKeyPath === {}", publicKeyPath);logger.info("privateKeyPath === {}", privateKeyPath);logger.info("keyPassword === {}", keyPassword);CertUtil.init(publicKeyPath, privateKeyPath, keyPassword);final byte[] dataBytes = data.getBytes("UTF-8");final String signData = new String(Base64.encodeBase64(digitalSign(dataBytes, CertUtil.getPrivateKey(), "SHA1WithRSA")), "UTF-8");CryptoUtil.logger.info("digitalSign(String) =>>>>>sign:{}", (Object)signData);return URLEncoder.encode(signData, "UTF-8");}catch (Exception e) {CryptoUtil.logger.error("digitalSign(String, String)", (Throwable)e);throw new Exception("签名异常", e);}}/*** 验证数字签名函数入口** @param plainBytes*            待验签明文字节数组* @param signBytes*            待验签签名后字节数组* @param publicKey*            验签使用公钥* @param signAlgorithm*            签名算法* @return 验签是否通过* @throws Exception*/public static boolean verifyDigitalSign(final byte[] plainBytes, final byte[] signBytes, final PublicKey publicKey, final String signAlgorithm) throws Exception {boolean isValid = false;try {final Signature signature = Signature.getInstance(signAlgorithm);signature.initVerify(publicKey);signature.update(plainBytes);isValid = signature.verify(signBytes);return isValid;}catch (NoSuchAlgorithmException e) {throw new Exception(String.format("验证数字签名时没有[%s]此类算法", signAlgorithm), e);}catch (InvalidKeyException e2) {throw new Exception("验证数字签名时私钥无效", e2);}catch (SignatureException e3) {throw new Exception("验证数字签名时出现异常", e3);}}/*** 验证数字签名函数入口** @param plainBytes*            待验签明文字节数组* @param signBytes*            待验签签名后字节数组* @param signAlgorithm*            签名算法* @return 验签是否通过* @throws Exception*/public static boolean verifyDigitalSign(final byte[] plainBytes, final byte[] signBytes, final X509Certificate cert, final String signAlgorithm) throws Exception {boolean isValid = false;try {final Signature signature = Signature.getInstance(signAlgorithm);signature.initVerify(cert);signature.update(plainBytes);isValid = signature.verify(signBytes);return isValid;}catch (NoSuchAlgorithmException e3) {throw new Exception(String.format("验证数字签名时没有[%s]此类算法", signAlgorithm));}catch (InvalidKeyException e) {throw new Exception("验证数字签名时公钥无效", e);}catch (SignatureException e2) {throw new Exception("验证数字签名时出现异常", e2);}}/*** RSA加密** @param plainBytes*            明文字节数组* @param publicKey*            公钥* @param keyLength*            密钥bit长度* @param reserveSize*            padding填充字节数,预留11字节* @param cipherAlgorithm*            加解密算法,一般为RSA/ECB/PKCS1Padding* @return 加密后字节数组,不经base64编码* @throws Exception*/public static byte[] RSAEncrypt(final byte[] plainBytes, final PublicKey publicKey, final int keyLength, final int reserveSize, final String cipherAlgorithm) throws Exception {final int keyByteSize = keyLength / 8;final int encryptBlockSize = keyByteSize - reserveSize;int nBlock = plainBytes.length / encryptBlockSize;if (plainBytes.length % encryptBlockSize != 0) {++nBlock;}try {final Cipher cipher = Cipher.getInstance(cipherAlgorithm);cipher.init(1, publicKey);final ByteArrayOutputStream outbuf = new ByteArrayOutputStream(nBlock * keyByteSize);for (int offset = 0; offset < plainBytes.length; offset += encryptBlockSize) {int inputLen = plainBytes.length - offset;if (inputLen > encryptBlockSize) {inputLen = encryptBlockSize;}final byte[] encryptedBlock = cipher.doFinal(plainBytes, offset, inputLen);outbuf.write(encryptedBlock);}outbuf.flush();outbuf.close();return outbuf.toByteArray();}catch (NoSuchAlgorithmException e5) {throw new Exception(String.format("没有[%s]此类加密算法", cipherAlgorithm));}catch (NoSuchPaddingException e6) {throw new Exception(String.format("没有[%s]此类填充模式", cipherAlgorithm));}catch (InvalidKeyException e) {throw new Exception("无效密钥", e);}catch (IllegalBlockSizeException e2) {throw new Exception("加密块大小不合适", e2);}catch (BadPaddingException e3) {throw new Exception("错误填充模式", e3);}catch (IOException e4) {throw new Exception("字节输出流异常", e4);}}/*** RSA解密** @param encryptedBytes*            加密后字节数组* @param privateKey*            私钥* @param keyLength*            密钥bit长度* @param reserveSize*            padding填充字节数,预留11字节* @param cipherAlgorithm*            加解密算法,一般为RSA/ECB/PKCS1Padding* @return 解密后字节数组,不经base64编码* @throws Exception*/public static byte[] RSADecrypt(final byte[] encryptedBytes, final PrivateKey privateKey, final int keyLength, final int reserveSize, final String cipherAlgorithm) throws Exception {final int keyByteSize = keyLength / 8;final int decryptBlockSize = keyByteSize - reserveSize;final int nBlock = encryptedBytes.length / keyByteSize;try {final Cipher cipher = Cipher.getInstance(cipherAlgorithm);cipher.init(2, privateKey);final ByteArrayOutputStream outbuf = new ByteArrayOutputStream(nBlock * decryptBlockSize);for (int offset = 0; offset < encryptedBytes.length; offset += keyByteSize) {int inputLen = encryptedBytes.length - offset;if (inputLen > keyByteSize) {inputLen = keyByteSize;}final byte[] decryptedBlock = cipher.doFinal(encryptedBytes, offset, inputLen);outbuf.write(decryptedBlock);}outbuf.flush();outbuf.close();return outbuf.toByteArray();}catch (NoSuchAlgorithmException e5) {throw new Exception(String.format("没有[%s]此类解密算法", cipherAlgorithm));}catch (NoSuchPaddingException e6) {throw new Exception(String.format("没有[%s]此类填充模式", cipherAlgorithm));}catch (InvalidKeyException e) {throw new Exception("无效密钥", e);}catch (IllegalBlockSizeException e2) {throw new Exception("加密块大小不合适", e2);}catch (BadPaddingException e3) {throw new Exception("错误填充模式", e3);}catch (IOException e4) {throw new Exception("字节输出流异常", e4);}}public static PublicKey toPublicKey(final BigInteger exponent, final BigInteger modulus) throws Exception {final KeyFactory keyFactory = KeyFactory.getInstance("RSA");final RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(modulus, exponent);final PublicKey key = keyFactory.generatePublic(pubSpec);return key;}public static PrivateKey toPrivateKey(final BigInteger exponent, final BigInteger modulus) throws Exception {final KeyFactory keyFactory = KeyFactory.getInstance("RSA");final RSAPrivateKeySpec prispec = new RSAPrivateKeySpec(modulus, exponent);final PrivateKey key = keyFactory.generatePrivate(prispec);return key;}/*** AES加密** @param plainBytes*            明文字节数组* @param keyBytes*            密钥字节数组* @param keyAlgorithm*            密钥算法* @param cipherAlgorithm*            加解密算法* @param IV*            随机向量* @return 加密后字节数组,不经base64编码* @throws Exception*/public static byte[] AESEncrypt(final byte[] plainBytes, final byte[] keyBytes, final String keyAlgorithm, final String cipherAlgorithm, final String IV) throws Exception {try {if (keyBytes.length % 8 != 0 || keyBytes.length < 16 || keyBytes.length > 32) {throw new Exception("AES密钥长度不合法");}final Cipher cipher = Cipher.getInstance(cipherAlgorithm);final SecretKey secretKey = new SecretKeySpec(keyBytes, keyAlgorithm);if (StringUtils.trimToNull(IV) != null) {final IvParameterSpec ivspec = new IvParameterSpec(IV.getBytes());cipher.init(1, secretKey, ivspec);}else {cipher.init(1, secretKey);}final byte[] encryptedBytes = cipher.doFinal(plainBytes);return encryptedBytes;}catch (NoSuchAlgorithmException e5) {throw new Exception(String.format("没有[%s]此类加密算法", cipherAlgorithm));}catch (NoSuchPaddingException e6) {throw new Exception(String.format("没有[%s]此类填充模式", cipherAlgorithm));}catch (InvalidKeyException e) {throw new Exception("无效密钥", e);}catch (InvalidAlgorithmParameterException e2) {throw new Exception("加密块大小不合适", e2);}catch (BadPaddingException e3) {throw new Exception("错误填充模式", e3);}catch (IllegalBlockSizeException e4) {throw new Exception("字节输出流异常", e4);}}/*** AES解密** @param encryptedBytes*            密文字节数组,不经base64编码* @param keyBytes*            密钥字节数组* @param keyAlgorithm*            密钥算法* @param cipherAlgorithm*            加解密算法* @param IV*            随机向量* @return 解密后字节数组* @throws Exception*/public static byte[] AESDecrypt(final byte[] encryptedBytes, final byte[] keyBytes, final String keyAlgorithm, final String cipherAlgorithm, final String IV) throws Exception {try {if (keyBytes.length % 8 != 0 || keyBytes.length < 16 || keyBytes.length > 32) {throw new Exception("AES密钥长度不合法");}final Cipher cipher = Cipher.getInstance(cipherAlgorithm);final SecretKey secretKey = new SecretKeySpec(keyBytes, keyAlgorithm);if (IV != null && StringUtils.trimToNull(IV) != null) {final IvParameterSpec ivspec = new IvParameterSpec(IV.getBytes());cipher.init(2, secretKey, ivspec);}else {cipher.init(2, secretKey);}final byte[] decryptedBytes = cipher.doFinal(encryptedBytes);return decryptedBytes;}catch (NoSuchAlgorithmException e5) {throw new Exception(String.format("没有[%s]此类加密算法", cipherAlgorithm));}catch (NoSuchPaddingException e6) {throw new Exception(String.format("没有[%s]此类填充模式", cipherAlgorithm));}catch (InvalidKeyException e) {throw new Exception("无效密钥", e);}catch (InvalidAlgorithmParameterException e2) {throw new Exception("无效密钥参数", e2);}catch (BadPaddingException e3) {throw new Exception("错误填充模式", e3);}catch (IllegalBlockSizeException e4) {throw new Exception("解密块大小不合法", e4);}}public static byte[] hexString2ByteArr(final String hexStr) {return new BigInteger(hexStr, 16).toByteArray();}public static final byte[] hexStrToBytes(final String s) {final byte[] bytes = new byte[s.length() / 2];for (int i = 0; i < bytes.length; ++i) {bytes[i] = (byte)Integer.parseInt(s.substring(2 * i, 2 * i + 2), 16);}return bytes;}public static String bytes2string(final byte[] bytes, final int radix) {int size = 2;if (radix == 2) {size = 8;}final StringBuilder sb = new StringBuilder(bytes.length * size);for (int i = 0; i < bytes.length; ++i) {int integer;for (integer = bytes[i]; integer < 0; integer += 256) {}final String str = Integer.toString(integer, radix);sb.append(StringUtils.leftPad(str.toUpperCase(), size, "0"));}return sb.toString();}}
package com.chat.thirdparty.pay.sandpay.utils.encrypt;import com.chat.thirdparty.pay.sandpay.utils.Base64Util;
import com.chat.thirdparty.pay.sandpay.utils.DynamicPropertyHelper;
import com.chat.thirdparty.pay.sandpay.utils.RandomStringGenerator;import com.chat.thirdparty.pay.sandpay.utils.SdkUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;public class EncryptUtil {private static final Logger logger = LoggerFactory.getLogger(EncryptUtil.class);private String publicKeyPath;private String privateKeyPath;private String keyPassword;public EncryptUtil(String publicKeyPath, String privateKeyPath, String keyPassword) {this.publicKeyPath = publicKeyPath;this.privateKeyPath = privateKeyPath;this.keyPassword = keyPassword;}public EncryptUtil() {this.publicKeyPath = DynamicPropertyHelper.getStringProperty("sandpay.public.key", "").get();this.privateKeyPath = DynamicPropertyHelper.getStringProperty("sandpay.private.key", "").get();this.keyPassword = DynamicPropertyHelper.getStringProperty("sandpay.private.key.password", "").get();}public List<NameValuePair> genEncryptData(String merchId, String transCode, String data) throws Exception {if ((null == merchId) || (null == transCode) || (null == data)) {logger.error("merchId or transCode or data is null");return null;}List<NameValuePair> formparams = new ArrayList();formparams.add(new BasicNameValuePair("merId", merchId));formparams.add(new BasicNameValuePair("transCode", transCode));try {CertUtil.init(this.publicKeyPath, this.privateKeyPath, this.keyPassword);byte[] plainBytes = data.getBytes("UTF-8");String aesKey = RandomStringGenerator.getRandomStringByLength(16);byte[] aesKeyBytes = aesKey.getBytes("UTF-8");String encryptData = new String(Base64.encodeBase64(CryptoUtil.AESEncrypt(plainBytes, aesKeyBytes, "AES", "AES/ECB/PKCS5Padding", null)),"UTF-8");String sign = new String(Base64.encodeBase64(CryptoUtil.digitalSign(plainBytes, CertUtil.getPrivateKey(), "SHA1WithRSA")),"UTF-8");String encryptKey = new String(Base64.encodeBase64(CryptoUtil.RSAEncrypt(aesKeyBytes, CertUtil.getPublicKey(), 2048, 11, "RSA/ECB/PKCS1Padding")),"UTF-8");formparams.add(new BasicNameValuePair("encryptData", encryptData));formparams.add(new BasicNameValuePair("encryptKey", encryptKey));formparams.add(new BasicNameValuePair("sign", sign));logger.info("encryptData:{}", encryptData);logger.info("encryptKey:{}", encryptKey);logger.info("sign:{}", sign);} catch (Exception e) {e.printStackTrace();throw e;}return formparams;}public List<NameValuePair> genEncryptData(String merchId, String transCode, String accessType, String plId,String data) throws Exception {if ((null == merchId) || (null == transCode) || (null == data)) {logger.error("merchId or transCode or data is null");return null;}List<NameValuePair> formparams = new ArrayList();formparams.add(new BasicNameValuePair("merId", merchId));formparams.add(new BasicNameValuePair("transCode", transCode));formparams.add(new BasicNameValuePair("accessType", accessType));formparams.add(new BasicNameValuePair("plId", plId));try {CertUtil.init(this.publicKeyPath, this.privateKeyPath, this.keyPassword);byte[] plainBytes = data.getBytes("UTF-8");String aesKey = RandomStringGenerator.getRandomStringByLength(16);byte[] aesKeyBytes = aesKey.getBytes("UTF-8");String encryptData = new String(Base64.encodeBase64(CryptoUtil.AESEncrypt(plainBytes, aesKeyBytes, "AES", "AES/ECB/PKCS5Padding", null)),"UTF-8");String sign = new String(Base64.encodeBase64(CryptoUtil.digitalSign(plainBytes, CertUtil.getPrivateKey(), "SHA1WithRSA")),"UTF-8");String encryptKey = new String(Base64.encodeBase64(CryptoUtil.RSAEncrypt(aesKeyBytes, CertUtil.getPublicKey(), 2048, 11, "RSA/ECB/PKCS1Padding")),"UTF-8");formparams.add(new BasicNameValuePair("encryptData", encryptData));formparams.add(new BasicNameValuePair("encryptKey", encryptKey));formparams.add(new BasicNameValuePair("sign", sign));logger.info("encryptData:{}", encryptData);logger.info("encryptKey:{}", encryptKey);logger.info("sign:{}", sign);} catch (Exception e) {e.printStackTrace();throw e;}return formparams;}public List<NameValuePair> genEncryptData(String merchId, String transCode, String accessType, String plId,String accessPlatform, String data) throws Exception {if ((null == merchId) || (null == transCode) || (null == data)) {logger.error("merchId or transCode or data is null");return null;}List<NameValuePair> formparams = new ArrayList();formparams.add(new BasicNameValuePair("merId", merchId));formparams.add(new BasicNameValuePair("transCode", transCode));formparams.add(new BasicNameValuePair("accessType", accessType));formparams.add(new BasicNameValuePair("plId", plId));formparams.add(new BasicNameValuePair("accessPlatform", accessPlatform));try {CertUtil.init(this.publicKeyPath, this.privateKeyPath, this.keyPassword);byte[] plainBytes = data.getBytes("UTF-8");String aesKey = RandomStringGenerator.getRandomStringByLength(16);byte[] aesKeyBytes = aesKey.getBytes("UTF-8");String encryptData = new String(Base64.encodeBase64(CryptoUtil.AESEncrypt(plainBytes, aesKeyBytes, "AES", "AES/ECB/PKCS5Padding", null)),"UTF-8");String sign = new String(Base64.encodeBase64(CryptoUtil.digitalSign(plainBytes, CertUtil.getPrivateKey(), "SHA1WithRSA")),"UTF-8");String encryptKey = new String(Base64.encodeBase64(CryptoUtil.RSAEncrypt(aesKeyBytes, CertUtil.getPublicKey(), 2048, 11, "RSA/ECB/PKCS1Padding")),"UTF-8");formparams.add(new BasicNameValuePair("encryptData", encryptData));formparams.add(new BasicNameValuePair("encryptKey", encryptKey));formparams.add(new BasicNameValuePair("sign", sign));logger.info("encryptData:{}", encryptData);logger.info("encryptKey:{}", encryptKey);logger.info("sign:{}", sign);} catch (Exception e) {e.printStackTrace();throw e;}return formparams;}public String decryptRetData(String data) throws Exception {Map<String, String> responseMap = convertResultStringToMap(data);String retEncryptKey = (String) responseMap.get("encryptKey");String retEncryptData = (String) responseMap.get("encryptData");String retSign = (String) responseMap.get("sign");logger.info("retEncryptKey:{}", retEncryptKey);logger.info("retEncryptData:{}", retEncryptData);logger.info("retSign:{}", retSign);byte[] decodeBase64KeyBytes = Base64.decodeBase64(retEncryptKey.getBytes("UTF-8"));byte[] merchantAESKeyBytes = CryptoUtil.RSADecrypt(decodeBase64KeyBytes, CertUtil.getPrivateKey(), 2048, 11,"RSA/ECB/PKCS1Padding");byte[] decodeBase64DataBytes = Base64.decodeBase64(retEncryptData.getBytes("UTF-8"));byte[] retDataBytes = CryptoUtil.AESDecrypt(decodeBase64DataBytes, merchantAESKeyBytes, "AES","AES/ECB/PKCS5Padding", null);logger.info("retData:{}", new String(retDataBytes, "UTF-8"));byte[] signBytes = Base64.decodeBase64(retSign.getBytes("UTF-8"));boolean isValid = CryptoUtil.verifyDigitalSign(retDataBytes, signBytes, CertUtil.getPublicKey(), "SHA1WithRSA");if (!isValid) {logger.error("报文验签不通过");throw new Exception("报文验签不通过");}logger.info("报文验签通过");String ret = new String(retDataBytes, "UTF-8");return ret;}private static Map<String, String> convertResultStringToMap(String result) {Map<String, String> map = null;if (StringUtils.isNotBlank(result)) {if ((result.startsWith("\"")) && (result.endsWith("\""))) {if (logger.isDebugEnabled()) {logger.debug("convertResultStringToMap(String) - " + result.length());}result = result.substring(1, result.length() - 1);}map = SdkUtil.convertResultStringToMap(result);}return map;}public void encryptFile(String decryptFileName, String encryptFileName) throws Exception {CertUtil.init(this.publicKeyPath, this.privateKeyPath, this.keyPassword);try {InputStream in = new FileInputStream(new File(decryptFileName));FileWriter fileWriter = new FileWriter(encryptFileName);byte[] plainBytes = new byte[in.available()];in.read(plainBytes);String aesKey = RandomStringGenerator.getRandomStringByLength(16);byte[] aesKeyBytes = aesKey.getBytes("UTF-8");String encryptData = new String(Base64.encodeBase64(CryptoUtil.AESEncrypt(plainBytes, aesKeyBytes, "AES", "AES/ECB/PKCS5Padding", null)),"UTF-8");String sign = new String(Base64.encodeBase64(CryptoUtil.digitalSign(plainBytes, CertUtil.getPrivateKey(), "SHA1WithRSA")),"UTF-8");String encryptKey = new String(Base64.encodeBase64(CryptoUtil.RSAEncrypt(aesKeyBytes, CertUtil.getPublicKey(), 2048, 11, "RSA/ECB/PKCS1Padding")),"UTF-8");logger.info("encryptData:{}", encryptData);logger.info("encryptKey:{}", encryptKey);logger.info("sign:{}", sign);fileWriter.write(encryptKey + "\n");fileWriter.write(sign + "\n");fileWriter.write(encryptData + "\n");if (in != null) {in.close();}if (fileWriter != null) {fileWriter.close();}} catch (Exception e) {e.printStackTrace();throw e;}}public void decryptFile(String encryptFileName, String decryptFileName) throws Exception {CertUtil.init(this.publicKeyPath, this.privateKeyPath, this.keyPassword);try {BufferedReader bReader = new BufferedReader(new FileReader(encryptFileName));FileWriter fileWriter = new FileWriter(decryptFileName);String encryptKey = bReader.readLine();String signature = bReader.readLine();String encryptData = bReader.readLine();byte[] decodeBase64KeyBytes = Base64.decodeBase64(encryptKey.getBytes("UTF-8"));byte[] merchantAESKeyBytes = CryptoUtil.RSADecrypt(decodeBase64KeyBytes, CertUtil.getPrivateKey(), 2048, 11,"RSA/ECB/PKCS1Padding");byte[] decodeBase64DataBytes = Base64.decodeBase64(encryptData.getBytes("UTF-8"));byte[] decryptBytes = CryptoUtil.AESDecrypt(decodeBase64DataBytes, merchantAESKeyBytes, "AES","AES/ECB/PKCS5Padding", null);logger.info("retData:{}", new String(decryptBytes, "UTF-8"));byte[] signBytes = Base64.decodeBase64(signature.getBytes("UTF-8"));boolean isValid = CryptoUtil.verifyDigitalSign(decryptBytes, signBytes, CertUtil.getPublicKey(),"SHA1WithRSA");if (!isValid) {logger.error("报文验签不通过");throw new Exception("报文验签不通过");}logger.info("报文验签通过");String decryptData = new String(decryptBytes, "UTF-8");fileWriter.write(decryptData);if (bReader != null) {bReader.close();}if (fileWriter != null) {fileWriter.close();}} catch (Exception e) {e.printStackTrace();throw e;}}public List<NameValuePair> getEncryptMerchData(String mid, String data, String extend) {if ((null == mid) || (null == data)) {return null;}List<NameValuePair> formParams = new ArrayList();formParams.add(new BasicNameValuePair("mid", mid));formParams.add(new BasicNameValuePair("plMid", mid));formParams.add(new BasicNameValuePair("extend", extend));try {String merchPublicKeyPath = DynamicPropertyHelper.getStringProperty("sandpay.merech.public.key", "").get();CertUtil.init(merchPublicKeyPath, this.privateKeyPath, this.keyPassword);byte[] dataBytes = data.getBytes("UTF-8");String aesKey = RandomStringGenerator.getRandomStringByLength(16);byte[] aesKeyBytes = aesKey.getBytes("UTF-8");String encryptData = new String(Base64.encodeBase64(CryptoUtil.AESEncrypt(dataBytes, aesKeyBytes, "AES", "AES/ECB/PKCS5Padding", null)),"UTF-8");String signData = new String(Base64.encodeBase64(CryptoUtil.digitalSign(dataBytes, CertUtil.getPrivateKey(), "SHA1WithRSA")),"UTF-8");String encryptKey = new String(Base64.encodeBase64(CryptoUtil.RSAEncrypt(aesKeyBytes, CertUtil.getPublicKey(), 2048, 11, "RSA/ECB/PKCS1Padding")),"UTF-8");formParams.add(new BasicNameValuePair("encryptData", encryptData));formParams.add(new BasicNameValuePair("encryptKey", encryptKey));formParams.add(new BasicNameValuePair("sign", signData));logger.info("encryptData:{}", encryptData);logger.info("encryptKey:{}", encryptKey);logger.info("sign:{}", signData);} catch (Exception e) {logger.error("getEncryptMerchData(String, String, String)", e);return formParams;}return formParams;}public String decryptMerchRetData(String data) throws Exception {logger.info("decryptMerchRetData(Map<String,String>, PublicKey) - start");Map<String, String> paramMap = SdkUtil.convertResultStringToMap(data);String encryptKey = (String) paramMap.get("encryptKey");String encryptData = (String) paramMap.get("encryptData");String signData = (String) paramMap.get("sign");logger.info("encryptKey:{}" + encryptKey);logger.info("encryptData:{}" + encryptData);logger.info("signData:{}" + signData);String merchPublicKeyPath = DynamicPropertyHelper.getStringProperty("sandpay.merech.public.key", "").get();CertUtil.init(merchPublicKeyPath, this.privateKeyPath, this.keyPassword);byte[] encryptKeyBytes = Base64Util.decodeBytes(encryptKey);byte[] keyBytes = CryptoUtil.RSADecrypt(encryptKeyBytes, CertUtil.getPrivateKey(), 2048, 11,"RSA/ECB/PKCS1Padding");byte[] decodeDataBytes = Base64Util.decodeBytes(encryptData);byte[] dataBytes = CryptoUtil.AESDecrypt(decodeDataBytes, keyBytes, "AES", "AES/ECB/PKCS5Padding", null);logger.info("dataBytes:{}" + new String(dataBytes, "UTF-8"));byte[] signDataBytes = Base64Util.decodeBytes(signData);boolean isValid = CryptoUtil.verifyDigitalSign(dataBytes, signDataBytes, CertUtil.getPublicKey(),"SHA1WithRSA");if (!isValid) {logger.error("报文验签不通过");throw new Exception("报文验签不通过");}logger.info("报文验签通过");String result = new String(dataBytes, "UTF-8");logger.info("decryptresData(Map<String,String>, PublicKey) - end");return result;}public List<NameValuePair> getEncryptGateWayData(String data, String extend) {logger.info("getEncryptGateWayData(String, String) - start =>>{}", data);if (null == data) {return null;}List<NameValuePair> formParams = new ArrayList();try {CertUtil.init(this.publicKeyPath, this.privateKeyPath, this.keyPassword);byte[] dataBytes = data.getBytes("UTF-8");String signData = new String(Base64.encodeBase64(CryptoUtil.digitalSign(dataBytes, CertUtil.getPrivateKey(), "SHA1WithRSA")),"UTF-8");formParams.add(new BasicNameValuePair("charset", "UTF-8"));formParams.add(new BasicNameValuePair("data", data));formParams.add(new BasicNameValuePair("signType", "01"));formParams.add(new BasicNameValuePair("sign", signData));formParams.add(new BasicNameValuePair("extend", extend));logger.info("(String, String) =>> sign:{}", signData);} catch (Exception e) {logger.error("getEncryptGateWayData(String, String)", e);return formParams;}logger.info("getEncryptGateWayData(String, String) - end");return formParams;}public String decryptGateWayRetData(String data) throws Exception {if (logger.isDebugEnabled()) {logger.debug("decryptGateWayRetData(String) - start");}Map<String, String> respMap = SdkUtil.convertResultStringToMap(data);String respData = (String) respMap.get("data");logger.info("decryptGateWayRetData(String) =>>respData:{}" + respData);String respSign = (String) respMap.get("sign");CertUtil.init(this.publicKeyPath, this.privateKeyPath, this.keyPassword);byte[] respDataBytes = respData.getBytes("UTF-8");byte[] signDataBytes = Base64.decodeBase64(respSign);boolean isValid = CryptoUtil.verifyDigitalSign(respDataBytes, signDataBytes, CertUtil.getPublicKey(),"SHA1WithRSA");if (!isValid) {logger.error("报文验签不通过");throw new Exception("报文验签不通过");}logger.info("报文验签通过");if (logger.isDebugEnabled()) {logger.debug("decryptGateWayRetData(String) - end");}return respData;}
}
package com.chat.thirdparty.pay.sandpay.utils.http;import com.chat.thirdparty.pay.sandpay.request.RequestData;
import com.chat.thirdparty.pay.sandpay.utils.encrypt.EncryptUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.List;public class HttpUtil extends SSLClient {private static final Logger logger = LoggerFactory.getLogger(HttpUtil.class);private EncryptUtil encyptUtil;public HttpUtil() {this.encyptUtil = new EncryptUtil();}public String post(String url, String merchId, String transCode, String data) throws Exception {String res = post(url, this.encyptUtil.genEncryptData(merchId, transCode, data));if (null == res) {return null;}return this.encyptUtil.decryptRetData(res);}public String post(String url, String merchId, String transCode, String accessType, String plId, String data)throws Exception {String res = post(url, this.encyptUtil.genEncryptData(merchId, transCode, accessType, plId, data));if (null == res) {return null;}return this.encyptUtil.decryptRetData(res);}public String post(String url, String merchId, String transCode, String accessType, String plId,String accessPlatform, String data) throws Exception {String res = post(url,this.encyptUtil.genEncryptData(merchId, transCode, accessType, plId, accessPlatform, data));if (null == res) {return null;}return this.encyptUtil.decryptRetData(res);}public String sendMerchPost(String url, String mid, String data, String extend) throws Exception {String result = post(url, this.encyptUtil.getEncryptMerchData(mid, data, extend));if (result == null) {return null;}return this.encyptUtil.decryptMerchRetData(result);}public String sendMerchPost(String url, String data, String extend) throws Exception {RequestData requestData = new RequestData(data, Boolean.valueOf(false));if (requestData.getHeadObject() == null) {return null;}String result = post(url,this.encyptUtil.getEncryptMerchData(requestData.getHeadObject().getPlMid(), data, extend));if (result == null) {return null;}return this.encyptUtil.decryptMerchRetData(result);}public String sendGateWayPost(String url, String data, String extend) throws Exception {String result = post(url, this.encyptUtil.getEncryptGateWayData(data, extend));if (result == null) {return null;}return this.encyptUtil.decryptGateWayRetData(result);}private String post(String url, List<NameValuePair> formParams) throws Exception {String result = "";init();CloseableHttpClient httpclient = httpClient;try {HttpPost httppost = new HttpPost(url);setRequestConfig(httppost);UrlEncodedFormEntity uefEntity = new UrlEncodedFormEntity(formParams, "UTF-8");httppost.setEntity(uefEntity);logger.info("executing request url:{} ", httppost.getURI());CloseableHttpResponse response = httpclient.execute(httppost);try {HttpEntity entity = response.getEntity();if (entity != null) {result = EntityUtils.toString(entity, "UTF-8");result = URLDecoder.decode(result, "UTF-8");if (StringUtils.isBlank(result)) {logger.info("null response");String str1 = null;response.close();return str1;}logger.info("--------------------------------------");logger.info("Response content: {} ", result);logger.info("--------------------------------------");}} finally {response.close();}return result;} catch (ClientProtocolException cpe) {cpe.printStackTrace();} catch (UnsupportedEncodingException uee) {uee.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {httpclient.close();} catch (IOException e) {e.printStackTrace();}}return result;}
}
package com.chat.thirdparty.pay.sandpay.utils.http;import com.chat.thirdparty.pay.sandpay.utils.DynamicPropertyHelper;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;public class SSLClient {protected static final String HTTP = "http";protected static final String HTTPS = "https";protected static CloseableHttpClient httpClient;protected static void init() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {SSLContext sslcontext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {return true;}}).build();SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();}protected static void setRequestConfig(HttpPost httppost) {Integer socketTimeout = Integer.valueOf(DynamicPropertyHelper.getIntProperty("sandpay.http.socketTimeout", 30000).get());Integer connectTimeout = Integer.valueOf(DynamicPropertyHelper.getIntProperty("sandpay.http.connectTimeout", 30000).get());if ((socketTimeout != null) && (connectTimeout != null)) {RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout.intValue()).setConnectTimeout(connectTimeout.intValue()).build();httppost.setConfig(requestConfig);}}
}
package com.chat.thirdparty.pay.sandpay.utils;import java.io.*;public class Base64Util {private static char[] alphabet;private static byte[] codes;public static String encode(final String data) {return new String(encode(data.getBytes()));}public static byte[] decodeBytes(String data) {if (null == data) {return null;}data = data.replace(" ", "+");return decode(data.toCharArray());}public static String decode(String data) {try {data = data.replace(" ", "+");return new String(decode(data.toCharArray()), "UTF-8");} catch (UnsupportedEncodingException e) {return null;}}public static char[] encode(final byte[] data) {final char[] out = new char[(data.length + 2) / 3 * 4];for (int i = 0, index = 0; i < data.length; i += 3, index += 4) {boolean quad = false;boolean trip = false;int val = 0xFF & data[i];val <<= 8;if (i + 1 < data.length) {val |= (0xFF & data[i + 1]);trip = true;}val <<= 8;if (i + 2 < data.length) {val |= (0xFF & data[i + 2]);quad = true;}out[index + 3] = Base64Util.alphabet[quad ? (val & 0x3F) : 64];val >>= 6;out[index + 2] = Base64Util.alphabet[trip ? (val & 0x3F) : 64];val >>= 6;out[index + 1] = Base64Util.alphabet[val & 0x3F];val >>= 6;out[index + 0] = Base64Util.alphabet[val & 0x3F];}return out;}public static byte[] decode(final char[] data) {int tempLen = data.length;for (int ix = 0; ix < data.length; ++ix) {if (data[ix] > '\u00ff' || Base64Util.codes[data[ix]] < 0) {--tempLen;}}int len = tempLen / 4 * 3;if (tempLen % 4 == 3) {len += 2;}if (tempLen % 4 == 2) {++len;}final byte[] out = new byte[len];int shift = 0;int accum = 0;int index = 0;for (int ix2 = 0; ix2 < data.length; ++ix2) {final int value = (data[ix2] > '\u00ff') ? -1 : Base64Util.codes[data[ix2]];if (value >= 0) {accum <<= 6;shift += 6;accum |= value;if (shift >= 8) {shift -= 8;out[index++] = (byte) (accum >> shift & 0xFF);}}}if (index != out.length) {throw new Error("Miscalculated data length (wrote " + index + " instead of " + out.length + ")");}return out;}public static void encode(File file) throws IOException {if (!file.exists()) {System.exit(0);} else {final byte[] decoded = readBytes(file);final char[] encoded = encode(decoded);writeChars(file, encoded);}file = null;}public static void decode(File file) throws IOException {if (!file.exists()) {System.exit(0);} else {final char[] encoded = readChars(file);final byte[] decoded = decode(encoded);writeBytes(file, decoded);}file = null;}private static byte[] readBytes(final File file) throws IOException {final ByteArrayOutputStream baos = new ByteArrayOutputStream();byte[] b = null;InputStream fis = null;InputStream is = null;try {fis = new FileInputStream(file);is = new BufferedInputStream(fis);int count = 0;final byte[] buf = new byte[16384];while ((count = is.read(buf)) != -1) {if (count > 0) {baos.write(buf, 0, count);}}b = baos.toByteArray();} finally {try {if (fis != null) {fis.close();}if (is != null) {is.close();}if (baos != null) {baos.close();}} catch (Exception e) {System.out.println(e);}}return b;}private static char[] readChars(final File file) throws IOException {final CharArrayWriter caw = new CharArrayWriter();Reader fr = null;Reader in = null;try {fr = new FileReader(file);in = new BufferedReader(fr);int count = 0;final char[] buf = new char[16384];while ((count = in.read(buf)) != -1) {if (count > 0) {caw.write(buf, 0, count);}}} finally {try {if (caw != null) {caw.close();}if (in != null) {in.close();}if (fr != null) {fr.close();}} catch (Exception e) {System.out.println(e);}}return caw.toCharArray();}private static void writeBytes(final File file, final byte[] data) throws IOException {OutputStream fos = null;OutputStream os = null;try {fos = new FileOutputStream(file);os = new BufferedOutputStream(fos);os.write(data);} finally {try {if (os != null) {os.close();}if (fos != null) {fos.close();}} catch (Exception e) {System.out.println(e);}}}private static void writeChars(final File file, final char[] data) throws IOException {Writer fos = null;Writer os = null;try {fos = new FileWriter(file);os = new BufferedWriter(fos);os.write(data);} finally {try {if (os != null) {os.close();}if (fos != null) {fos.close();}} catch (Exception e) {e.printStackTrace();}}}static {Base64Util.alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();Base64Util.codes = new byte[256];for (int i = 0; i < 256; ++i) {Base64Util.codes[i] = -1;}for (int i = 65; i <= 90; ++i) {Base64Util.codes[i] = (byte) (i - 65);}for (int i = 97; i <= 122; ++i) {Base64Util.codes[i] = (byte) (26 + i - 97);}for (int i = 48; i <= 57; ++i) {Base64Util.codes[i] = (byte) (52 + i - 48);}Base64Util.codes[43] = 62;Base64Util.codes[47] = 63;}
}
package com.chat.thirdparty.pay.sandpay.utils;import java.io.IOException;public class ConfigurationManager extends com.netflix.config.ConfigurationManager {public static void loadProperties(String[] configNames) throws IOException {for (int i = 0; i < configNames.length; i++) {System.out.println("configNames = " + configNames[i]);loadAppOverrideProperties(configNames[i]);}}
}
package com.chat.thirdparty.pay.sandpay.utils;import com.netflix.config.DynamicBooleanProperty;
import com.netflix.config.DynamicIntProperty;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.config.DynamicStringProperty;public class DynamicPropertyHelper {private static final DynamicPropertyFactory dynamicPropertyFactory;public static DynamicPropertyFactory getDynamicPropertyFactory() {return DynamicPropertyHelper.dynamicPropertyFactory;}public static DynamicStringProperty getStringProperty(final String propName) {return getDynamicPropertyFactory().getStringProperty(propName, "");}public static DynamicStringProperty getStringProperty(final String propName, final String defaultValue) {return getDynamicPropertyFactory().getStringProperty(propName, defaultValue);}public static DynamicIntProperty getIntProperty(final String propName, final int defaultValue) {return getDynamicPropertyFactory().getIntProperty(propName, defaultValue);}public static DynamicBooleanProperty getBooleanProperty(final String propName, final boolean defaultValue) {return getDynamicPropertyFactory().getBooleanProperty(propName, defaultValue);}static {dynamicPropertyFactory = DynamicPropertyFactory.getInstance();}
}
package com.chat.thirdparty.pay.sandpay.utils;import java.util.Random;public class RandomStringGenerator {public static String getRandomStringByLength(int length) {String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";Random random = new Random();StringBuffer sb = new StringBuffer();for (int i = 0; i < length; i++) {int number = random.nextInt(base.length());sb.append(base.charAt(number));}return sb.toString();}
}
package com.chat.thirdparty.pay.sandpay.utils;import org.apache.commons.lang.StringUtils;import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;public class SdkUtil {public static Map<String, String> convertResultStringToMap(String result) {Map<String, String> map = null;try {if (StringUtils.isNotBlank(result)) {if ((result.startsWith("{")) && (result.endsWith("}"))) {result = result.substring(1, result.length() - 1);}map = parseQString(result);}} catch (UnsupportedEncodingException e) {e.printStackTrace();}return map;}public static Map<String, String> parseQString(String str) throws UnsupportedEncodingException {Map<String, String> map = new HashMap();int len = str.length();StringBuilder temp = new StringBuilder();String key = null;boolean isKey = true;boolean isOpen = false;char openName = '\000';if (len > 0) {for (int i = 0; i < len; i++) {char curChar = str.charAt(i);if (isKey) {if (curChar == '=') {key = temp.toString();temp.setLength(0);isKey = false;} else {temp.append(curChar);}} else {if (isOpen) {if (curChar == openName) {isOpen = false;}} else {if (curChar == '{') {isOpen = true;openName = '}';}if (curChar == '[') {isOpen = true;openName = ']';}}if ((curChar == '&') && (!isOpen)) {putKeyValueToMap(temp, isKey, key, map);temp.setLength(0);isKey = true;} else {temp.append(curChar);}}}putKeyValueToMap(temp, isKey, key, map);}return map;}private static void putKeyValueToMap(StringBuilder temp, boolean isKey, String key, Map<String, String> map)throws UnsupportedEncodingException {if (isKey) {key = temp.toString();if (key.length() == 0) {throw new RuntimeException("QString format illegal");}map.put(key, "");} else {if (key.length() == 0) {throw new RuntimeException("QString format illegal");}map.put(key, temp.toString());}}
}
package com.chat.thirdparty.pay.sandpay;import com.alibaba.fastjson.JSONObject;
import com.chat.thirdparty.pay.sandpay.ex.BusinessException;
import com.chat.thirdparty.pay.sandpay.utils.ConfigurationManager;
import com.chat.thirdparty.pay.sandpay.utils.http.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import java.math.BigDecimal;import static com.chat.thirdparty.pay.sandpay.common.SandPayConst.*;@Slf4j
@Component
public class SandPayService {// 初始化static {try {log.info("加载衫德安全证书...start");ConfigurationManager.loadProperties(new String[] { "sandPayConfig"});log.info("加载衫德安全证书...end");} catch (Exception e) {e.printStackTrace();log.info("加载衫德安全证书失败...");throw new BusinessException("支付证书加载失败");}}/*** 杉德支付-发送银行卡签约短信* @param orderNo 订单号* @param userId* @param payerName* @param idNo* @param mobileNo* @param bankCardNo* @param reqTime 下单时间,格式: yyyyMMddHHmmss* @return*/public String sendCardBindingSms(String orderNo, String userId, String payerName, String idNo, String mobileNo, String bankCardNo, String reqTime) {// bodyJSONObject body = new JSONObject();body.put("userId", userId);body.put("applyNo", orderNo);body.put("cardNo", bankCardNo);body.put("userName", payerName);body.put("phoneNo", mobileNo);body.put("certificateType", "01");body.put("certificateNo", idNo);body.put("creditFlag", "1");body.put("extend", "");// 发送请求return sendGet(PRODUCT_ID_18,"发送绑卡签约短信",SIGN_SMS_METHOD,APPLY_BIND_CARD_URL,reqTime, body);}/*** 确认绑卡* @param userId* @param sdMsgNo* @param phoneNo* @param smsCode* @param reqTime* @return* @throws Exception*/public String confirmBindingCard(String userId, String sdMsgNo, String phoneNo, String smsCode, String reqTime) {// bodyJSONObject body = new JSONObject();body.put("userId", userId);body.put("sdMsgNo", sdMsgNo);body.put("phoneNo", phoneNo);body.put("smsCode", smsCode);body.put("notifyUrl", CARD_NOTIFY_URL);body.put("extend", "");// 发送请求return sendGet(PRODUCT_ID_18,"确认绑卡", SMS_SIGN_METHOD, CONFIRM_BIND_CARD_URL,reqTime,body);}/*** 银行卡-解约* @param userId* @param applyNo* @param bid* @param reqTime* @return*/public String bankCardUnbinding(String userId, String applyNo, String bid, String reqTime) {// bodyJSONObject body = new JSONObject();body.put("userId", userId);body.put("bid", bid);body.put("applyNo", applyNo);body.put("notifyUrl", UN_CARD_NOTIFY_URL);body.put("extend", "");// 发送请求return sendGet(PRODUCT_ID_18,"银行卡解约", UN_SIGN_METHOD, UNBIND_CARD_URL,reqTime, body);}/*** 发起支付* @param userId* @param phoneNo* @param bid 银行卡唯一* @param orderNo 必填 订单号* @param reqTime 下单时间,格式: yyyyMMddHHmmss* @return*/public String rechargePaySms(String userId, String phoneNo, String bid, String orderNo, String reqTime) {// bodyJSONObject body = new JSONObject();body.put("userId", userId);body.put("orderCode", orderNo);body.put("bid", bid);body.put("phoneNo", phoneNo);body.put("extend", "");// 发送请求return sendGet(PRODUCT_ID_18,"发起支付", PAY_SMS_METHOD, SMS_PAY_URL, reqTime, body);}/*** 确认支付* @param userId* @param bid* @param phoneNo* @param orderCode* @param smsCode* @param tranAmount* @param extend 选填 扩展域 输入需要字段,异步回调获取* @param reqTime 下单时间,格式: yyyyMMddHHmmss* @param subjectName 支付标题* @param bodyName 支付说明* @return*/public String rechargeSmsPay(String userId, String bid, String phoneNo, String orderCode,String smsCode, String tranAmount, String extend, String reqTime, String subjectName, String bodyName){// 需要转换金额格式: 将 201 变成 0000 0000 0201BigDecimal bigDecimal = new BigDecimal(tranAmount);String money = bigDecimal.multiply(new BigDecimal(100)).toBigInteger().toString();while (money.length() < 12) {money = "0" + money;}// bodyJSONObject body = new JSONObject();body.put("userId", userId);body.put("bid", bid);body.put("phoneNo", phoneNo);body.put("orderCode", orderCode);body.put("orderTime", reqTime);body.put("smsCode", smsCode);body.put("totalAmount", money);body.put("subject", subjectName);body.put("body", bodyName);body.put("currencyCode", "156");body.put("notifyUrl", PAY_NOTIFY_URL);body.put("clearCycle", "0");  // 0-T1, 1-T0, 2-D0body.put("extend", extend);// 发送请求return sendGet(PRODUCT_ID_18,"确认支付", SMS_PAY_METHOD, PAY_URL, reqTime, body);}/*** 支付订单查询* @param orderNo* @param reqTime* @return*/public String querySandPayOrder(String orderNo, String reqTime) {// 报文体JSONObject bodyJson = new JSONObject();bodyJson.put("orderCode", orderNo); //商户订单号bodyJson.put("extend", ""); //扩展域return sendGet(PRODUCT_ID_16,"查询支付订单", QUERY_PAY_METHOD, QUERY_PAY_ORDER_URL, reqTime, bodyJson);}/***  代付对私* @param orderNo 必填 订单号* @param tranAmount 必填 金额* @param accNo 收款人账户号* @param accName 收款人账户名* @param remark 摘要* @param reqReserved 选填 如需发送交易结果至收款方,则必填,值为收款方的短信通知内容* @param extend 选填 扩展域* @param phone 选填 如需发送交易结果至收款方,则必填* @param reqTime 时间格式:yyyyMMddHHmmss* @return*/public String agentPay(String orderNo, String tranAmount, String accNo, String accName, String remark, String reqReserved, String phone, String extend, String reqTime) throws Exception{JSONObject jsonObject = new JSONObject();jsonObject.put("productId", "00000004");jsonObject.put("orderCode",orderNo);jsonObject.put("version", "01");jsonObject.put("tranTime", reqTime);jsonObject.put("tranAmt", tranAmount);jsonObject.put("currencyCode", CURRENCY_CODE);jsonObject.put("accAttr","0");// 0-对私jsonObject.put("accType", "4");// 4-对私jsonObject.put("accNo", accNo);// 收款人账号jsonObject.put("accName", accName);// 收款人账号名jsonObject.put("remark", remark);// 摘要jsonObject.put("reqReserved", reqReserved);jsonObject.put("phone", phone);jsonObject.put("extend", extend);String jsonstr =  jsonObject.toJSONString();return new HttpUtil().post(AGENT_PAY_URL, MERCHANT_ID, AGENT_PAY, jsonstr);}/*** 代付对私查询* 基于单笔订单查询每次间隔如下:5秒、10秒、30秒、60秒、120秒、600秒、3600秒* @param orderNo 必填 订单号* @param tranTime 必填 原订单交易时间* @return*/public String queryAgentPayOrder(String orderNo, String tranTime) throws Exception {JSONObject jsonObject = new JSONObject();jsonObject.put("productId", "00000004");jsonObject.put("orderCode",orderNo);jsonObject.put("version", "01");jsonObject.put("tranTime", tranTime);jsonObject.put("extend", "");String jsonstr =  jsonObject.toJSONString();return new HttpUtil().post(QUERY_AGENT_ORDER_URL, MERCHANT_ID, ORDER_QUERY, jsonstr);}/*** 封装发送请求* @param productId 00000018, 查询订单用:00000016* @param description 说明 方便后续排查问题,绑卡、支付...* @param methodName 方法说明* @param requestUrl 请求api* @param reqTime 下单时间,格式: yyyyMMddHHmmss* @param bodyJson body json请求数据* @return*/public String sendGet(String productId,String description, String methodName, String requestUrl, String reqTime, JSONObject bodyJson) {// headJSONObject head = new JSONObject();head.put("version", VERSION);head.put("method", methodName);head.put("productId", productId);head.put("accessType", "1");head.put("mid", MERCHANT_ID);head.put("plMid", "");head.put("channelType", "07");head.put("reqTime", reqTime);// dataJSONObject dataJson = new JSONObject();dataJson.put("head", head);dataJson.put("body", bodyJson);// json >>> stringString data = dataJson.toJSONString();try {log.info(description+">>> 发送请求-----start");new HttpUtil().sendGateWayPost(requestUrl, data, "");} catch (Exception e) {e.printStackTrace();log.error(description+">>> 发送请求异常: {}", e.getMessage());} finally {log.info(description+">>> 发送请求-----end");}return null;}}

问题

  • 根据文档上的调用接口,苹果端、postman测试工具均无法跳转到杉德的官网支付页面

  • 解决:服务端做个跳转页面,让安卓、ios端调用自身浏览器访问

  • 测试只能通过静态页面(demo里有)发送(从后端拿到sign和data封装的数据)

参考文献

文献一
官方文档

【项目】关于杉德支付接口对接相关推荐

  1. java对接杉德支付完整代码

    /*** 商户编号*/@Value("${sdpay.merch_mid}")private String merchMid;/*** 商户密钥*/@Value("${s ...

  2. 杉德支付php代码实现_杉德ecshop,thinkphp,shopnc在线支付接口,支付插件(payment plugin含源码)...

    最近应一个客户的要求,给他的一个ecshop网站开发杉德在线支付接口和代付接口. 杉德有自己的收银台,集成了各类银行,也是不错. 杉德支持H5,APP,网银快捷等支付接口.文档还算比较齐全. 比较有特 ...

  3. 杉德支付收银台支付Demo解析,聚合支付

    文章目录 CryptoUtil工具类 CashierPaySignServlet数据处理Servlet sandPayConfig.properties 配置文件 web.xml配置 pom.xml配 ...

  4. 支付宝支付接口对接的总结

    本周工作最大的困难还是支付宝支付接口的对接. 遇到主要的问题是两个:1. 发送订单给支付宝接口,接口验证签名失败. 2.支付宝付款结束后,发送信息给网站接收方进行二次验签,还是签名过不了.验签的方式是 ...

  5. 特殊格式的 汇潮支付接口对接

    在公司业务中,对接汇潮支付,--------该需求是调用汇潮的支付接口,他们作为中台,由他们调用支付宝接口 在异步回调的时候,遇到了"参数通过 post 方式提交, Content-Type ...

  6. 杉德支付php代码实现_[转]PHP语言开发Paypal支付demo的具体实现

    一.paypal支付接口准备工作 首先去申请一个paypal账号,https://www.paypal.com/. 申请完毕并登录,进入https://developer.paypal.com/dev ...

  7. 第三方银联支付接口对接_聊聊三方支付对接那点事儿(附Demo)

    每一个做过支付对接的少年上辈子都是折翼的天使.--题记 三方支付对接是一件比较有意思的事儿,今天就拿这个话题来掰扯掰扯.相信每个做过支付对接的小伙伴都有段血与火的经历,那段日子只有痛苦与煎熬,恨不得大 ...

  8. 项目中的第三方支付接口

    在项目中遇到需要进行支付的场景,需要接入第三方资金管理平台,这里以支付宝为例介绍一下项目中遇到资金管理接口的使用: 进入支付宝官网(https://www.alipay.com/),进入"我 ...

  9. Paypal REST API Java 版 PC端商城支付接口对接。

    引言: 同类文借鉴链接:http://blog.csdn.net/change_on/article/details/73881791(对此博主万分感谢) Paypal账号注册网址:https://w ...

最新文章

  1. 2017 Q3 ,互联网人的薪资发生了哪些变化?
  2. opencv3 for python 之 创建图片绘制简单几何图形
  3. 2.myql数据导入到solr,并建立solr索引(学习笔记)
  4. python工程技巧_python 19个值得学习的编程技巧
  5. myeclipse2014删除antlr-2.7.2.jar--解决struts和hibernate包冲突
  6. 万字详述 MySQL ProxySQL
  7. 解决“(1146, “Table ‘mydb.django_session‘ doesn‘t exist“)”报错的方法
  8. 4个你未必知道的内存小知识
  9. Java 6 变量 代码块
  10. java 写文件缓存_使用java NIO及高速缓冲区写入文件过程解析
  11. 对磁盘做完整镜像(按扇区对扇区备份)的目的
  12. Ubuntu系统配置Java环境
  13. 计算机考研408的优势和劣势,为什么说计算机考研408是大趋势
  14. 教你电脑微信多开方法,超级简单_多啦咪
  15. PyMouse模拟鼠标键盘操作
  16. SiameseNet
  17. 关于COM类工厂80070005和8000401a错误分析及解决办法(DCOM)
  18. 二级域名配置以及nginx解析二级域名到html页面
  19. greensock又出重量级产品 - LoaderMax (转)
  20. python量化实战_Python量化交易实战

热门文章

  1. 设计师们如何高调拒绝免费工作
  2. electron-builder 打包 exe 异常错误集锦
  3. 【sqlplus】SQL*Plus命令使用大全
  4. Diana and Liana
  5. C#多线程顺序依赖执行控制
  6. 腾讯又签下一工作室,游戏建模未来发展无法想象,你还不抓紧时间?
  7. JQuery 日期选择框,精确到时分秒类型。
  8. html里的常用特殊符号表示大全
  9. vt-x+linux子系统,虚拟机安装linux 系统(二 )解决 Intel VT-x 报错
  10. 2022CCPC广州 CM