true 传换成小写格式 , false 传换成大写格式
+ * @return 十六进制char[]
+ */
+ public static char[] encodeHex(byte[] data, boolean toLowerCase) {
+ return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
+ }
+
+ /**
+ * 将字节数组转换为十六进制字符数组
+ *
+ * @param data byte[]
+ * @param toDigits 用于控制输出的char[]
+ * @return 十六进制char[]
+ */
+ protected static char[] encodeHex(byte[] data, char[] toDigits) {
+ int l = data.length;
+ char[] out = new char[l << 1];
+ // two characters form the hex value.
+ for (int i = 0, j = 0; i < l; i++) {
+ out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
+ out[j++] = toDigits[0x0F & data[i]];
+ }
+ return out;
+ }
+
+ /**
+ * 将字节数组转换为十六进制字符串
+ *
+ * @param data byte[]
+ * @return 十六进制String
+ */
+ public static String encodeHexString(byte[] data) {
+ return encodeHexString(data, true);
+ }
+
+ /**
+ * 将字节数组转换为十六进制字符串
+ *
+ * @param data byte[]
+ * @param toLowerCase true 传换成小写格式 , false 传换成大写格式
+ * @return 十六进制String
+ */
+ public static String encodeHexString(byte[] data, boolean toLowerCase) {
+ return encodeHexString(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
+ }
+
+ /**
+ * 将字节数组转换为十六进制字符串
+ *
+ * @param data byte[]
+ * @param toDigits 用于控制输出的char[]
+ * @return 十六进制String
+ */
+ protected static String encodeHexString(byte[] data, char[] toDigits) {
+ return new String(encodeHex(data, toDigits));
+ }
+
+ /**
+ * 将十六进制字符数组转换为字节数组
+ *
+ * @param data 十六进制char[]
+ * @return byte[]
+ * @throws RuntimeException 如果源十六进制字符数组是一个奇怪的长度,将抛出运行时异常
+ */
+ public static byte[] decodeHex(char[] data) {
+ int len = data.length;
+
+ if ((len & 0x01) != 0) {
+ throw new RuntimeException("Odd number of characters.");
+ }
+
+ byte[] out = new byte[len >> 1];
+
+ // two characters form the hex value.
+ for (int i = 0, j = 0; j < len; i++) {
+ int f = toDigit(data[j], j) << 4;
+ j++;
+ f = f | toDigit(data[j], j);
+ j++;
+ out[i] = (byte) (f & 0xFF);
+ }
+
+ return out;
+ }
+
+ /**
+ * 将十六进制字符转换成一个整数
+ *
+ * @param ch 十六进制char
+ * @param index 十六进制字符在字符数组中的位置
+ * @return 一个整数
+ * @throws RuntimeException 当ch不是一个合法的十六进制字符时,抛出运行时异常
+ */
+ protected static int toDigit(char ch, int index) {
+ int digit = Character.digit(ch, 16);
+ if (digit == -1) {
+ throw new RuntimeException("Illegal hexadecimal character " + ch
+ + " at index " + index);
+ }
+ return digit;
+ }
+
+ /**
+ * 数字字符串转ASCII码字符串
+ *
+ * @param String
+ * 字符串
+ * @return ASCII字符串
+ */
+ public static String StringToAsciiString(String content) {
+ String result = "";
+ int max = content.length();
+ for (int i = 0; i < max; i++) {
+ char c = content.charAt(i);
+ String b = Integer.toHexString(c);
+ result = result + b;
+ }
+ return result;
+ }
+
+ /**
+ * 十六进制转字符串
+ *
+ * @param hexString
+ * 十六进制字符串
+ * @param encodeType
+ * 编码类型4:Unicode,2:普通编码
+ * @return 字符串
+ */
+ public static String hexStringToString(String hexString, int encodeType) {
+ String result = "";
+ int max = hexString.length() / encodeType;
+ for (int i = 0; i < max; i++) {
+ char c = (char) hexStringToAlgorism(hexString
+ .substring(i * encodeType, (i + 1) * encodeType));
+ result += c;
+ }
+ return result;
+ }
+
+ /**
+ * 十六进制字符串装十进制
+ *
+ * @param hex
+ * 十六进制字符串
+ * @return 十进制数值
+ */
+ public static int hexStringToAlgorism(String hex) {
+ hex = hex.toUpperCase();
+ int max = hex.length();
+ int result = 0;
+ for (int i = max; i > 0; i--) {
+ char c = hex.charAt(i - 1);
+ int algorism = 0;
+ if (c >= '0' && c <= '9') {
+ algorism = c - '0';
+ } else {
+ algorism = c - 55;
+ }
+ result += Math.pow(16, max - i) * algorism;
+ }
+ return result;
+ }
+
+ /**
+ * 十六转二进制
+ *
+ * @param hex
+ * 十六进制字符串
+ * @return 二进制字符串
+ */
+ public static String hexStringToBinary(String hex) {
+ hex = hex.toUpperCase();
+ String result = "";
+ int max = hex.length();
+ for (int i = 0; i < max; i++) {
+ char c = hex.charAt(i);
+ switch (c) {
+ case '0':
+ result += "0000";
+ break;
+ case '1':
+ result += "0001";
+ break;
+ case '2':
+ result += "0010";
+ break;
+ case '3':
+ result += "0011";
+ break;
+ case '4':
+ result += "0100";
+ break;
+ case '5':
+ result += "0101";
+ break;
+ case '6':
+ result += "0110";
+ break;
+ case '7':
+ result += "0111";
+ break;
+ case '8':
+ result += "1000";
+ break;
+ case '9':
+ result += "1001";
+ break;
+ case 'A':
+ result += "1010";
+ break;
+ case 'B':
+ result += "1011";
+ break;
+ case 'C':
+ result += "1100";
+ break;
+ case 'D':
+ result += "1101";
+ break;
+ case 'E':
+ result += "1110";
+ break;
+ case 'F':
+ result += "1111";
+ break;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * ASCII码字符串转数字字符串
+ *
+ * @param String
+ * ASCII字符串
+ * @return 字符串
+ */
+ public static String AsciiStringToString(String content) {
+ String result = "";
+ int length = content.length() / 2;
+ for (int i = 0; i < length; i++) {
+ String c = content.substring(i * 2, i * 2 + 2);
+ int a = hexStringToAlgorism(c);
+ char b = (char) a;
+ String d = String.valueOf(b);
+ result += d;
+ }
+ return result;
+ }
+
+ /**
+ * 将十进制转换为指定长度的十六进制字符串
+ *
+ * @param algorism
+ * int 十进制数字
+ * @param maxLength
+ * int 转换后的十六进制字符串长度
+ * @return String 转换后的十六进制字符串
+ */
+ public static String algorismToHexString(int algorism, int maxLength) {
+ String result = "";
+ result = Integer.toHexString(algorism);
+
+ if (result.length() % 2 == 1) {
+ result = "0" + result;
+ }
+ return patchHexString(result.toUpperCase(), maxLength);
+ }
+
+ /**
+ * 字节数组转为普通字符串(ASCII对应的字符)
+ *
+ * @param bytearray
+ * byte[]
+ * @return String
+ */
+ public static String byteToString(byte[] bytearray) {
+ String result = "";
+ char temp;
+
+ int length = bytearray.length;
+ for (int i = 0; i < length; i++) {
+ temp = (char) bytearray[i];
+ result += temp;
+ }
+ return result;
+ }
+
+ /**
+ * 二进制字符串转十进制
+ *
+ * @param binary
+ * 二进制字符串
+ * @return 十进制数值
+ */
+ public static int binaryToAlgorism(String binary) {
+ int max = binary.length();
+ int result = 0;
+ for (int i = max; i > 0; i--) {
+ char c = binary.charAt(i - 1);
+ int algorism = c - '0';
+ result += Math.pow(2, max - i) * algorism;
+ }
+ return result;
+ }
+
+ /**
+ * 十进制转换为十六进制字符串
+ *
+ * @param algorism
+ * int 十进制的数字
+ * @return String 对应的十六进制字符串
+ */
+ public static String algorismToHEXString(int algorism) {
+ String result = "";
+ result = Integer.toHexString(algorism);
+
+ if (result.length() % 2 == 1) {
+ result = "0" + result;
+
+ }
+ result = result.toUpperCase();
+
+ return result;
+ }
+
+ /**
+ * HEX字符串前补0,主要用于长度位数不足。
+ *
+ * @param str
+ * String 需要补充长度的十六进制字符串
+ * @param maxLength
+ * int 补充后十六进制字符串的长度
+ * @return 补充结果
+ */
+ static public String patchHexString(String str, int maxLength) {
+ String temp = "";
+ for (int i = 0; i < maxLength - str.length(); i++) {
+ temp = "0" + temp;
+ }
+ str = (temp + str).substring(0, maxLength);
+ return str;
+ }
+
+ /**
+ * 将一个字符串转换为int
+ *
+ * @param s
+ * String 要转换的字符串
+ * @param defaultInt
+ * int 如果出现异常,默认返回的数字
+ * @param radix
+ * int 要转换的字符串是什么进制的,如16 8 10.
+ * @return int 转换后的数字
+ */
+ public static int parseToInt(String s, int defaultInt, int radix) {
+ int i = 0;
+ try {
+ i = Integer.parseInt(s, radix);
+ } catch (NumberFormatException ex) {
+ i = defaultInt;
+ }
+ return i;
+ }
+
+ /**
+ * 将一个十进制形式的数字字符串转换为int
+ *
+ * @param s
+ * String 要转换的字符串
+ * @param defaultInt
+ * int 如果出现异常,默认返回的数字
+ * @return int 转换后的数字
+ */
+ public static int parseToInt(String s, int defaultInt) {
+ int i = 0;
+ try {
+ i = Integer.parseInt(s);
+ } catch (NumberFormatException ex) {
+ i = defaultInt;
+ }
+ return i;
+ }
+
+ /**
+ * 十六进制串转化为byte数组
+ *
+ * @return the array of byte
+ */
+ public static byte[] hexToByte(String hex)
+ throws IllegalArgumentException {
+ if (hex.length() % 2 != 0) {
+ throw new IllegalArgumentException();
+ }
+ char[] arr = hex.toCharArray();
+ byte[] b = new byte[hex.length() / 2];
+ for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {
+ String swap = "" + arr[i++] + arr[i];
+ int byteint = Integer.parseInt(swap, 16) & 0xFF;
+ b[j] = new Integer(byteint).byteValue();
+ }
+ return b;
+ }
+
+ /**
+ * 字节数组转换为十六进制字符串
+ *
+ * @param b
+ * byte[] 需要转换的字节数组
+ * @return String 十六进制字符串
+ */
+ public static String byteToHex(byte b[]) {
+ if (b == null) {
+ throw new IllegalArgumentException(
+ "Argument b ( byte array ) is null! ");
+ }
+ String hs = "";
+ String stmp = "";
+ for (int n = 0; n < b.length; n++) {
+ stmp = Integer.toHexString(b[n] & 0xff);
+ if (stmp.length() == 1) {
+ hs = hs + "0" + stmp;
+ } else {
+ hs = hs + stmp;
+ }
+ }
+ return hs.toUpperCase();
+ }
+
+ public static byte[] subByte(byte[] input, int startIndex, int length) {
+ byte[] bt = new byte[length];
+ for (int i = 0; i < length; i++) {
+ bt[i] = input[i + startIndex];
+ }
+ return bt;
+ }
+}
\ No newline at end of file
diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/SecureUtil.java b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/SecureUtil.java
new file mode 100644
index 0000000..3982fdd
--- /dev/null
+++ b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/SecureUtil.java
@@ -0,0 +1,166 @@
+package com.egzosn.pay.common.util.sign;
+
+import com.egzosn.pay.common.util.sign.SM3.SM3Digest;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.PublicKey;
+import java.security.Signature;
+
+public class SecureUtil {
+ //日志
+ protected static final Log log = LogFactory.getLog(SecureUtil.class);
+ /**
+ * 算法常量: SHA1
+ */
+ private static final String ALGORITHM_SHA1 = "SHA-1";
+ /**
+ * 算法常量: SHA256
+ */
+ private static final String ALGORITHM_SHA256 = "SHA-256";
+ /**
+ * 算法常量:SHA1withRSA
+ */
+ private static final String BC_PROV_ALGORITHM_SHA1RSA = "SHA1withRSA";
+ /**
+ * 算法常量:SHA256withRSA
+ */
+ private static final String BC_PROV_ALGORITHM_SHA256RSA = "SHA256withRSA";
+
+ /**
+ * 获取摘要
+ *
+ * @param data 待计算的数据
+ * @param algorithm 算法名
+ * @return 计算结果
+ */
+ private static byte[] digestByData (byte[] data,String algorithm) {
+ MessageDigest md = null;
+ try {
+ md = MessageDigest.getInstance(algorithm);
+ md.reset();
+ md.update(data);
+ return md.digest();
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * sha1计算后进行16进制转换
+ *
+ * @param data 待计算的数据
+ * @param encoding 编码
+ * @return 计算结果
+ */
+ public static byte[] sha1X16 (String data, String encoding) {
+ try {
+ byte[] bytes = digestByData(data.getBytes(encoding),ALGORITHM_SHA1);
+ StringBuilder sha1StrBuff = new StringBuilder();
+ for (int i = 0; i < bytes.length; i++) {
+ if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {
+ sha1StrBuff.append("0").append(
+ Integer.toHexString(0xFF & bytes[i]));
+ } else {
+ sha1StrBuff.append(Integer.toHexString(0xFF & bytes[i]));
+ }
+ }
+ return sha1StrBuff.toString().getBytes(encoding);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+
+
+ /**
+ * sha256计算后进行16进制转换
+ *
+ * @param data
+ * 待计算的数据
+ * @param encoding
+ * 编码
+ * @return 计算结果
+ */
+ public static String sha256X16Str(String data, String encoding) {
+ byte[] bytes =null;
+ try {
+ bytes = digestByData(data.getBytes(encoding),ALGORITHM_SHA1);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ StringBuilder sha256StrBuff = new StringBuilder();
+ for (int i = 0; i < bytes.length; i++) {
+ if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {
+ sha256StrBuff.append("0").append(
+ Integer.toHexString(0xFF & bytes[i]));
+ } else {
+ sha256StrBuff.append(Integer.toHexString(0xFF & bytes[i]));
+ }
+ }
+ return sha256StrBuff.toString();
+ }
+
+ /**
+ * SM3计算.
+ *
+ * @param data
+ * 待计算的数据
+ * @return 计算结果
+ */
+ private static byte[] sm3(byte[] data) {
+
+ SM3Digest sm3 = new SM3Digest();
+ sm3.update(data, 0, data.length);
+ byte[] result = new byte[sm3.getDigestSize()];
+ sm3.doFinal(result, 0);
+ return result;
+ }
+
+ /**
+ * sm3计算后进行16进制转换
+ *
+ * @param data
+ * 待计算的数据
+ * @param encoding
+ * 编码
+ * @return 计算结果
+ */
+ public static String sm3X16Str(String data, String encoding) {
+ byte[] bytes = new byte[new SM3Digest().getDigestSize()];
+ try {
+ bytes = SecureUtil.sm3(data.getBytes(encoding));
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ StringBuilder sm3StrBuff = new StringBuilder();
+ for (int i = 0; i < bytes.length; i++) {
+ if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {
+ sm3StrBuff.append("0").append(
+ Integer.toHexString(0xFF & bytes[i]));
+ } else {
+ sm3StrBuff.append(Integer.toHexString(0xFF & bytes[i]));
+ }
+ }
+ return sm3StrBuff.toString();
+ }
+
+ public static boolean validateSignBySoft256(PublicKey publicKey, byte[] signData, byte[] srcData) throws Exception {
+ Signature st = Signature.getInstance(BC_PROV_ALGORITHM_SHA256RSA, "BC");
+ st.initVerify(publicKey);
+ st.update(srcData);
+ return st.verify(signData);
+ }
+
+ public static boolean validateSignBySoft(PublicKey publicKey,
+ byte[] signData, byte[] srcData) throws Exception {
+ Signature st = Signature.getInstance(BC_PROV_ALGORITHM_SHA1RSA, "BC");
+ st.initVerify(publicKey);
+ st.update(srcData);
+ return st.verify(signData);
+ }
+}
diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/RSA.java b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/RSA.java
index 32a50c0..430dd01 100644
--- a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/RSA.java
+++ b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/RSA.java
@@ -47,6 +47,29 @@ public class RSA{
return null;
}
+ /**
+ * RSA签名
+ * @param content 待签名数据
+ * @param privateKey 私钥
+ * @return 签名值
+ */
+ public static String sign(byte[] content,PrivateKey privateKey) {
+ try {
+
+ java.security.Signature signature = java.security.Signature.getInstance(privateKey.getAlgorithm());
+
+ signature.initSign(privateKey);
+ signature.update(content);
+
+ byte[] signed = signature.sign();
+
+ return Base64.encode(signed);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
/**
* RSA签名
diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/SHA256.java b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/SHA256.java
new file mode 100644
index 0000000..a2ae7f1
--- /dev/null
+++ b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/SHA256.java
@@ -0,0 +1,89 @@
+package com.egzosn.pay.common.util.sign.encrypt;/**
+ * Description:
+ * author: Fuzx
+ * date: 2017/11/27 0027
+ */
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+
+/**
+ * @author Actinia
+ * @email hayesfu@qq.com
+ * @create 2017 2017/11/27 0027
+ */
+public class SHA256 {
+ //日志
+ protected static final Log log = LogFactory.getLog(SHA256.class);
+
+ /**
+ * 算法常量: SHA256
+ */
+ private static final String ALGORITHM_SHA256 = "SHA-256";
+ /**
+ * sha256计算后进行16进制转换
+ *
+ * @param data
+ * 待计算的数据
+ * @param encoding
+ * 编码
+ * @return 计算结果
+ */
+ public static byte[] sha256X16(String data, String encoding) {
+ byte[] bytes = sha256(data, encoding);
+ StringBuilder sha256StrBuff = new StringBuilder();
+ for (int i = 0; i < bytes.length; i++) {
+ if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {
+ sha256StrBuff.append("0").append(
+ Integer.toHexString(0xFF & bytes[i]));
+ } else {
+ sha256StrBuff.append(Integer.toHexString(0xFF & bytes[i]));
+ }
+ }
+ try {
+ return sha256StrBuff.toString().getBytes(encoding);
+ } catch (UnsupportedEncodingException e) {
+ log.error(e.getMessage(), e);
+ return null;
+ }
+ }
+ /**
+ * sha256计算
+ *
+ * @param datas
+ * 待计算的数据
+ * @param encoding
+ * 字符集编码
+ * @return
+ */
+ private static byte[] sha256(String datas, String encoding) {
+ try {
+ return sha256(datas.getBytes(encoding));
+ } catch (UnsupportedEncodingException e) {
+ log.error("SHA256计算失败", e);
+ return null;
+ }
+ }
+ /**
+ * sha256计算.
+ *
+ * @param data
+ * 待计算的数据
+ * @return 计算结果
+ */
+ private static byte[] sha256(byte[] data) {
+ MessageDigest md = null;
+ try {
+ md = MessageDigest.getInstance(ALGORITHM_SHA256);
+ md.reset();
+ md.update(data);
+ return md.digest();
+ } catch (Exception e) {
+ log.error("SHA256计算失败", e);
+ return null;
+ }
+ }
+}
diff --git a/pay-java-demo/pom.xml b/pay-java-demo/pom.xml
index 43905b5..5449e0d 100644
--- a/pay-java-demo/pom.xml
+++ b/pay-java-demo/pom.xml
@@ -79,6 +79,11 @@
+create 2017 2017/11/4 0004 + *+ */ +public class UnionPayMessageHandler extends BasePayMessageHandler { + + + + + public UnionPayMessageHandler (Integer payId) { + super(payId); + } + + @Override + public PayOutMessage handle(PayMessage payMessage, Map
* create 2017 2017/1/16 0016 *diff --git a/pay-java-fuiou/src/main/java/com/egzosn/pay/fuiou/api/FuiouPayService.java b/pay-java-fuiou/src/main/java/com/egzosn/pay/fuiou/api/FuiouPayService.java index a52f920..dcde16f 100644 --- a/pay-java-fuiou/src/main/java/com/egzosn/pay/fuiou/api/FuiouPayService.java +++ b/pay-java-fuiou/src/main/java/com/egzosn/pay/fuiou/api/FuiouPayService.java @@ -20,8 +20,9 @@ import java.text.SimpleDateFormat; import java.util.*; /** - * @author Fuzx - *
+ * @author Actinia + * @email hayesfu@qq.com + ** create 2017 2017/1/16 0016 **/ diff --git a/pay-java-fuiou/src/main/java/com/egzosn/pay/fuiou/bean/FuiouCurType.java b/pay-java-fuiou/src/main/java/com/egzosn/pay/fuiou/bean/FuiouCurType.java index 9fea7a1..264c1ed 100644 --- a/pay-java-fuiou/src/main/java/com/egzosn/pay/fuiou/bean/FuiouCurType.java +++ b/pay-java-fuiou/src/main/java/com/egzosn/pay/fuiou/bean/FuiouCurType.java @@ -4,8 +4,11 @@ import com.egzosn.pay.common.bean.CurType; /** * 货币类型 - * @author Fuzx - * create 2017 2017/1/24 0024 + * @author Actinia + * @email hayesfu@qq.com + *+ * create 2017 2017/1/16 0016 + **/ public enum FuiouCurType implements CurType { diff --git a/pay-java-fuiou/src/main/java/com/egzosn/pay/fuiou/bean/FuiouTransactionType.java b/pay-java-fuiou/src/main/java/com/egzosn/pay/fuiou/bean/FuiouTransactionType.java index 273b383..9280ecf 100644 --- a/pay-java-fuiou/src/main/java/com/egzosn/pay/fuiou/bean/FuiouTransactionType.java +++ b/pay-java-fuiou/src/main/java/com/egzosn/pay/fuiou/bean/FuiouTransactionType.java @@ -4,8 +4,11 @@ import com.egzosn.pay.common.bean.TransactionType; /** * 支付类型 - * @author Fuzx - * create 2017 2017/1/24 0024 + * @author Actinia + * @email hayesfu@qq.com + *+ * create 2017 2017/1/16 0016 + **/ public enum FuiouTransactionType implements TransactionType { B2B("B2B"), diff --git a/pay-java-union/pom.xml b/pay-java-union/pom.xml index 5bd46e2..e1ce040 100644 --- a/pay-java-union/pom.xml +++ b/pay-java-union/pom.xml @@ -19,6 +19,9 @@pay-java-common - ++ \ No newline at end of file diff --git a/pay-java-union/resource/acp_sdk.properties b/pay-java-union/resource/acp_sdk.properties new file mode 100644 index 0000000..a998100 --- /dev/null +++ b/pay-java-union/resource/acp_sdk.properties @@ -0,0 +1,69 @@ +##############SDKļ֤鷽ʽǩ################ +# ˵ +# 1. ʹʱɾġ.֤顱ļƵsrcļ滻ԭacp_sdk.properties +# 2. עġ +# +################################################ + +##########################Ի͵ַϲҪʹַ############################# + +##ַ +acpsdk.frontTransUrl=https://gateway.test.95516.com/gateway/api/frontTransReq.do +acpsdk.backTransUrl=https://gateway.test.95516.com/gateway/api/backTransReq.do +acpsdk.singleQueryUrl=https://gateway.test.95516.com/gateway/api/queryTrans.do +acpsdk.batchTransUrl=https://gateway.test.95516.com/gateway/api/batchTrans.do +acpsdk.fileTransUrl=https://filedownload.test.95516.com/ +acpsdk.appTransUrl=https://gateway.test.95516.com/gateway/api/appTransReq.do +acpsdk.cardTransUrl=https://gateway.test.95516.com/gateway/api/cardTransReq.do + +#½ɷѲƷʹãƷò +acpsdk.jfFrontTransUrl=https://gateway.test.95516.com/jiaofei/api/frontTransReq.do +acpsdk.jfBackTransUrl=https://gateway.test.95516.com/jiaofei/api/backTransReq.do +acpsdk.jfSingleQueryUrl=https://gateway.test.95516.com/jiaofei/api/queryTrans.do +acpsdk.jfCardTransUrl=https://gateway.test.95516.com/jiaofei/api/cardTransReq.do +acpsdk.jfAppTransUrl=https://gateway.test.95516.com/jiaofei/api/appTransReq.do + +######################################################################## + +# İ汾ţ̶5.1.0Ķ +acpsdk.version=5.1.0 + +# ǩʽ֤鷽ʽ̶01Ķ +acpsdk.signMethod=01 + +# Ƿ֤ǩ֤CNԻfalsetruefalseֵĬ϶true +acpsdk.ifValidateCNName=false + +# Ƿ֤https֤飬ԻfalseȳtruefalsetrueֵĬ϶false +acpsdk.ifValidateRemoteCert=false + +#ַ̨֪ͨд̨֪ͨĵַܷ +#acpsdk.backUrl=http://222.222.222.222:8080/ACPSample_B2C/backRcvResponse +acpsdk.backUrl=http://sailinmu.iok.la:19088/backRcvResponse + +#ǰַ̨֪ͨдǰ̨֪ͨĵַܷ +acpsdk.frontUrl=http://sailinmu.iok.la:19088/frontRcvResponse + +#########################Իǩ֤ ################################ +# ֤֤·ΪָɲԴ˿á +# ǩ֤·ʹþ·ʹþ·ʵ·ȡ֤ķ֤̻ÿеIJǩ֤飬cfcaصõ +# windows +acpsdk.signCert.path=D:/certs/acp_test_sign.pfx +# linuxע⣺linux¶ȡ֤Ҫ֤֤бӦöȨޣ·Ҳͬ˵ +#acpsdk.signCert.path=/SERVICE01/usr/ac_frnas/conf/ACPtest/acp_test_sign.pfx + +# ǩ֤룬Ի̶000000Ϊcfcaصʽ֤룬ʽ֤λСڵ6λϴ̻վʧ +acpsdk.signCert.pwd=000000 +# ǩ̶֤ͣҪ +acpsdk.signCert.type=PKCS12 + +##########################֤################################ +# Ϣ֤·(̻ſ̻ͨϢܵȨޣҪ accNopinphoneNocvn2expiredܣЩ͵ĻϢʹ) +acpsdk.encryptCert.path=d:/certs/acp_test_enc.cer + +##########################ǩ֤################################ +# ǩм֤·(ṩ) +acpsdk.middleCert.path=D:/certs/acp_test_middle.cer +# ǩ֤·(ṩ) +acpsdk.rootCert.path=D:/certs/acp_test_root.cer + diff --git a/pay-java-union/resource/acp_test_enc.cer b/pay-java-union/resource/acp_test_enc.cer new file mode 100644 index 0000000..74f23d4 --- /dev/null +++ b/pay-java-union/resource/acp_test_enc.cer @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIFEAJkkicwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UEBhMC +Q04xMDAuBgNVBAoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eTEXMBUGA1UEAxMOQ0ZDQSBURVNUIE9DQTEwHhcNMTUxMjE1MDkxMTM1WhcN +MTcxMjE1MDkxMTM1WjCBgTELMAkGA1UEBhMCY24xFzAVBgNVBAoTDkNGQ0EgVEVT +VCBPQ0ExMRIwEAYDVQQLEwlDRkNBIFRFU1QxFDASBgNVBAsTC0VudGVycHJpc2Vz +MS8wLQYDVQQDFCYwNDFAWjIwMTQtMTEtMTFAMDAwNDAwMDA6U0lHTkAwMDAwMDAw +NTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANHnoPx0JZKZmFjIURxN +AbLlWAw2jiFFWBnDF2MIGkya2r0fGiR0knq8zkKUnoIyC+tzEiOavniQaSu0ucuv +/V4ugz66PSRxw1gaPcR2dDVdgojF00TcewxlJEA65fK3eKhUYfC3NbRaVQOMMdwv +7nNEvzxvdExE47ceMya7FmsUPyLFu9X++chFQiYfr8nH+wdDeYo8w8vCX+Jd2vRu +qDOah29CQfkAmXsx3D68zg0q4AjlLI1t5gLKiU5YoG6yWrigPyreEHh716rV8HkT +jGWx3cxF/HsLZ/E4SgIr5yIZA6qw8RFqaSXuyw3iDrNf6aSJGO0GKlvxnvD20oGR +JokCAwEAAaOB6TCB5jAfBgNVHSMEGDAWgBTPcJ1h6518Lrj3ywJA9wmd/jN0gDBI +BgNVHSAEQTA/MD0GCGCBHIbvKgEBMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cu +Y2ZjYS5jb20uY24vdXMvdXMtMTQuaHRtMDgGA1UdHwQxMC8wLaAroCmGJ2h0dHA6 +Ly91Y3JsLmNmY2EuY29tLmNuL1JTQS9jcmw0NTE3LmNybDALBgNVHQ8EBAMCA+gw +HQYDVR0OBBYEFGjriHHUE1MnYX7H6GrFi+8R2zmUMBMGA1UdJQQMMAoGCCsGAQUF +BwMCMA0GCSqGSIb3DQEBBQUAA4IBAQAjsN0fyDqcxS9YKMpY3CIdlarCjvnus+wS +ExjNnPv7n2urqhz2Jf3yJuhxVVPzdgKT51C2UiR+/i1OJPWFx0IUos/v8js/TM5j +mTdPkBsRSxSDieHHiuE1nPUwGXUEO7mlOVkkzmLI75bJ86foxNflbQCF0+VvpMe7 +KwQoNOR8DxIBxHdlsjSxE2RKM/ftXLhptrK4GK3K4FAcSiqBMEn5PF/5V9mHp5N6 +3LdkMYqBj4pRcy8vrclucq99b2glmMLw7CI6Kxu22WVoRnZESjcgXiMVLLe+qy55 +0pWcZ2BChS7Ln19tj49LnS3vFp6xf4qNSqxEBaQuNLEx0ObjI6pz +-----END CERTIFICATE----- \ No newline at end of file diff --git a/pay-java-union/resource/acp_test_middle.cer b/pay-java-union/resource/acp_test_middle.cer new file mode 100644 index 0000000..3275b90 --- /dev/null +++ b/pay-java-union/resource/acp_test_middle.cer @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDzjCCAragAwIBAgIKGNDz/H99Hd/CxjANBgkqhkiG9w0BAQUFADBZMQswCQYD +VQQGEwJDTjEwMC4GA1UEChMnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5MRgwFgYDVQQDEw9DRkNBIFRFU1QgQ1MgQ0EwHhcNMTIwODMwMDMx +NDMzWhcNMzEwNTExMDMxNDMzWjBYMQswCQYDVQQGEwJDTjEwMC4GA1UEChMnQ2hp +bmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRcwFQYDVQQDEw5D +RkNBIFRFU1QgT0NBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALiL +J/BrdvHSbXNfLIMTwUg9tDtVjMRGXOl6aZnu9IpxjI5SMUJ4hVwgJnmbTokxs6GF +IXKsCLSm5H1jHLI22ysc/ltByEybLWj5jjJuC9+Uknbl3/Ls1RBG6MogUCqZckuo +hKrf5DmlV3C/jVLxGn3pUeanvmqVUi4TKpXxgm5QqKSPF8VtQY4qCpNcQwwZqbMr +D+IfJtfpGAeVrP+Kg6i1t65seeEnVSaLhqpRUDU0PTblOuUv3OhiKJWA3cYWxUrg +7U7SIHNJLSEUWmjy4mKty+g7Cnjzt29F9qXFb6oB2mR8yt4GHCilw1Rc5RBXY63H +eTuOwdtGE3M2p7Q++OECAwEAAaOBmDCBlTAfBgNVHSMEGDAWgBR03sWNCn0QGqpp +g1tNIc6Gm8xxODAMBgNVHRMEBTADAQH/MDgGA1UdHwQxMC8wLaAroCmGJ2h0dHA6 +Ly8yMTAuNzQuNDIuMy90ZXN0cmNhL1JTQS9jcmwxLmNybDALBgNVHQ8EBAMCAQYw +HQYDVR0OBBYEFM9wnWHrnXwuuPfLAkD3CZ3+M3SAMA0GCSqGSIb3DQEBBQUAA4IB +AQC0JOazrbkk0XMxMMeBCc3lgBId1RjQLgWUZ7zaUISpPstGIrE5A9aB6Ppq0Sxl +pt2gkFhPEKUqgOFN1CzCDEbP3n4H0chqK1DOMrgTCD8ID5UW+ECTYNe35rZ+1JiF +lOPEhFL3pv6XSkiKTfDnjum8+wFwUBGlfoWK1Hcx0P2Hk1jcZZKwGTx1IAkesF83 +pufhxHE2Ur7W4d4tfp+eC7XXcA91pdd+VUrAfkj9eKHcDEYZz66HvHzmt6rtJVBa +pwrtCi9pW3rcm8c/1jSnEETZIaokai0fD7260h/LkD/GrNCibSWxFj1CqyP9Y5Yv +cj6aA5LnUcJYeNkrQ3V4XvVc +-----END CERTIFICATE----- diff --git a/pay-java-union/resource/acp_test_root.cer b/pay-java-union/resource/acp_test_root.cer new file mode 100644 index 0000000..779647c --- /dev/null +++ b/pay-java-union/resource/acp_test_root.cer @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIKUhN+zB19hbc65jANBgkqhkiG9w0BAQUFADBZMQswCQYD +VQQGEwJDTjEwMC4GA1UEChMnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5MRgwFgYDVQQDEw9DRkNBIFRFU1QgQ1MgQ0EwHhcNMTIwODI5MDUw +MTI5WhcNMzIwODI5MDUwMTI5WjBZMQswCQYDVQQGEwJDTjEwMC4GA1UEChMnQ2hp +bmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRgwFgYDVQQDEw9D +RkNBIFRFU1QgQ1MgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa +rMJGruH6rOBPFxUI7T1ybydSRRtOM1xvkVjQNX0qmYir8feE6Tb0ctgtKR7a20DI +YCj9kZ5ANBQqjRcj3Soq9XH3cirqhYHJ723OKyTpS0RPQ0N6vtVt3P5JQ+ztjWHd +qIbbTOQ6O024TGTiqi6uHgMuz9/OVur81X3a5YVkK7jFeZ9o8cTcvQxD853/1sgZ +QcmR9aUSw0RXH4XFLTrn7n4QSfWKiNotlD8Ag5gS1pH9ONUb6nGkMn3gh1xfJqjm +ONMSknPXTGiNpXtqvYi8oIvByVCbUDO59IwPP1r1SYyE3P8Nr7DdQRu0KQSdXLoG +iugSR3fn+toObVAQmplDAgMBAAGjXTBbMB8GA1UdIwQYMBaAFHTexY0KfRAaqmmD +W00hzoabzHE4MAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBR0 +3sWNCn0QGqppg1tNIc6Gm8xxODANBgkqhkiG9w0BAQUFAAOCAQEAM0eTkM35D4hj +RlGC63wY0h++wVPUvOrObqAVBbzEEQ7ScBienmeY8Q6lWMUTXM9ALibZklpJPcJv +3ntht7LL6ztd4wdX7E9RzZCQnRvbL9A/BU3NxWdeSpCg/OyPod5oCKP+6Uc7kApi +F9OtYNWnt3l2Zp/NiedzEQD8H4qEWQLAq+0dFo5BkfVhb/jPcktndpfPOuH1IMhP +tVcvo6jpFHw4U/nP2Jv59osIE97KJz/SPt2JAYnZOlIDqWwp9/Afvt0/MDr8y0PK +Q9c6eqIzBx7a9LpUTUl5u1jS+xSDZ/KF2lXnjwaFp7jICLWEMlBstCoogi7KwH9A +LpJP7/dj9g== +-----END CERTIFICATE----- diff --git a/pay-java-union/resource/acp_test_sign.pfx b/pay-java-union/resource/acp_test_sign.pfx new file mode 100644 index 0000000..e69de29 diff --git a/pay-java-union/src/main/java/com/egzosn/pay/union/SDK/CertUtil.java b/pay-java-union/src/main/java/com/egzosn/pay/union/SDK/CertUtil.java new file mode 100644 index 0000000..f90c2e4 --- /dev/null +++ b/pay-java-union/src/main/java/com/egzosn/pay/union/SDK/CertUtil.java @@ -0,0 +1,822 @@ +/** + * + * Licensed Property to China UnionPay Co., Ltd. + * + * (C) Copyright of China UnionPay Co., Ltd. 2010 + * All Rights Reserved. + * + * + * Modification History: + * ============================================================================= + * Author Date Description + * ------------ ---------- --------------------------------------------------- + * xshu 2014-05-28 证书工具类. + * ============================================================================= + */ +package com.egzosn.pay.union.SDK; + +import com.egzosn.pay.common.util.str.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import java.io.*; +import java.math.BigInteger; +import java.security.*; +import java.security.cert.*; +import java.security.spec.RSAPublicKeySpec; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @ClassName: CertUtil + * @Description: acpsdk证书工具类,主要用于对证书的加载和使用 + * @date 2016-7-22 下午2:46:20 + * + */ +public class CertUtil { + //日志 + protected static final Log log = LogFactory.getLog(CertUtil.class); + + public static final String UNIONPAY_CNNAME = "中国银联股份有限公司"; + + /** 证书容器,存储对商户请求报文签名私钥证书. */ + private static KeyStore keyStore = null; + /** 敏感信息加密公钥证书 */ + private static X509Certificate encryptCert = null; + /** 磁道加密公钥 */ + private static PublicKey encryptTrackKey = null; + /** 验证银联返回报文签名证书. */ + private static X509Certificate validateCert = null; + /** 验签中级证书 */ + private static X509Certificate middleCert = null; + /** 验签根证书 */ + private static X509Certificate rootCert = null; + /** 验证银联返回报文签名的公钥证书存储Map. */ + private static Maporg.bouncycastle +bcprov-debug-jdk15on +certMap = new HashMap (); + /** 商户私钥存储Map */ + private final static Map keyStoreMap = new ConcurrentHashMap (); + + + + /** + * 请求报文签名(使用配置文件中配置的私钥证书或者对称密钥签名)
+ * 功能:对请求报文进行签名,并计算赋值certid,signature字段并返回
+ * @param reqData 请求报文map
+ * @param encoding 上送请求报文域encoding字段的值
+ * @return 签名后的map对象
+ */ + public static Mapsign(Map reqData,String encoding) { + reqData = filterBlank(reqData); + SDKUtils.signParams(reqData, encoding); + return reqData; + } + /** + * 过滤请求报文中的空字符串或者空字符串 + * @param contentData + * @return + */ + public static Map filterBlank(Map contentData){ + Map submitFromData = new HashMap (); + Set keyset = contentData.keySet(); + for(String key:keyset){ + String value = contentData.get(key); + if (StringUtils.isNotBlank(value)) { + // 对value值进行去除前后空处理 + submitFromData.put(key, value.trim()); + } + } + return submitFromData; + } + + + + + + static { + init(); + } + + /** + * 初始化所有证书. + */ + private static void init() { + try { + addProvider();//向系统添加BC provider + initSignCert();//初始化签名私钥证书 + initMiddleCert();//初始化验签证书的中级证书 + initRootCert();//初始化验签证书的根证书 + initEncryptCert();//初始化加密公钥 + initTrackKey();//构建磁道加密公钥 + initValidateCertFromDir();//初始化所有的验签证书 + } catch (Exception e) { + e.printStackTrace(); + log.error("init失败。(如果是用对称密钥签名的可无视此异常。)", e); + } + } + + /** + * 添加签名,验签,加密算法提供者 + */ + private static void addProvider(){ + if (Security.getProvider("BC") == null) { + log.info("add BC provider"); + Security.addProvider(new BouncyCastleProvider()); + } else { + Security.removeProvider("BC"); //解决eclipse调试时tomcat自动重新加载时,BC存在不明原因异常的问题。 + Security.addProvider(new BouncyCastleProvider()); + log.info("re-add BC provider"); + } +// printSysInfo(); + } + + /** + * 用配置文件acp_sdk.properties中配置的私钥路径和密码 加载签名证书 + */ + private static void initSignCert() { + if(!"01".equals(SDKConfig.getConfig().getSignMethod())){ + log.info("非rsa签名方式,不加载签名证书。"); + return; + } + if (SDKConfig.getConfig().getSignCertPath() == null + || SDKConfig.getConfig().getSignCertPwd() == null + || SDKConfig.getConfig().getSignCertType() == null) { + log.error("WARN: " + SDKConfig.SDK_SIGNCERT_PATH + "或" + SDKConfig.SDK_SIGNCERT_PWD + + "或" + SDKConfig.SDK_SIGNCERT_TYPE + "为空。 停止加载签名证书。"); + return; + } + if (null != keyStore) { + keyStore = null; + } + try { + keyStore = getKeyInfo(SDKConfig.getConfig().getSignCertPath(), + SDKConfig.getConfig().getSignCertPwd(), SDKConfig + .getConfig().getSignCertType()); + log.info("InitSignCert Successful. CertId=[" + + getSignCertId() + "]"); + } catch (IOException e) { + e.printStackTrace(); + log.error("InitSignCert Error", e); + } + } + + /** + * 用配置文件acp_sdk.properties配置路径 加载敏感信息加密证书 + */ + private static void initMiddleCert() { +// log.info("加载中级证书==>"+SDKConfig.getConfig().getMiddleCertPath()); + if (!StringUtils.isEmpty(SDKConfig.getConfig().getMiddleCertPath())) { + middleCert = initCert(SDKConfig.getConfig().getMiddleCertPath()); + log.info("Load MiddleCert Successful"); + } else { + log.info("WARN: acpsdk.middle.path is empty"); + } + } + + /** + * 用配置文件acp_sdk.properties配置路径 加载敏感信息加密证书 + */ + private static void initRootCert() { +// log.info("加载根证书==>"+SDKConfig.getConfig().getRootCertPath()); + if (!StringUtils.isEmpty(SDKConfig.getConfig().getRootCertPath())) { + rootCert = initCert(SDKConfig.getConfig().getRootCertPath()); + log.info("Load RootCert Successful"); + } else { + log.info("WARN: acpsdk.rootCert.path is empty"); + } + } + + /** + * 用配置文件acp_sdk.properties配置路径 加载银联公钥上级证书(中级证书) + */ + private static void initEncryptCert() { +// log.info("加载敏感信息加密证书==>"+SDKConfig.getConfig().getEncryptCertPath()); + if (!StringUtils.isEmpty(SDKConfig.getConfig().getEncryptCertPath())) { + encryptCert = initCert(SDKConfig.getConfig().getEncryptCertPath()); + log.info("Load EncryptCert Successful"); + } else { + log.info("WARN: acpsdk.encryptCert.path is empty"); + } + } + + /** + * 用配置文件acp_sdk.properties配置路径 加载磁道公钥 + */ + private static void initTrackKey() { + if (!StringUtils.isEmpty(SDKConfig.getConfig().getEncryptTrackKeyModulus()) + && !StringUtils.isEmpty(SDKConfig.getConfig().getEncryptTrackKeyExponent())) { + encryptTrackKey = getPublicKey(SDKConfig.getConfig().getEncryptTrackKeyModulus(), + SDKConfig.getConfig().getEncryptTrackKeyExponent()); + log.info("LoadEncryptTrackKey Successful"); + } else { + log.info("WARN: acpsdk.encryptTrackKey.modulus or acpsdk.encryptTrackKey.exponent is empty"); + } + } + + /** + * 用配置文件acp_sdk.properties配置路径 加载验证签名证书 + */ + private static void initValidateCertFromDir() { + if(!"01".equals(SDKConfig.getConfig().getSignMethod())){ + log.info("非rsa签名方式,不加载验签证书。"); + return; + } + certMap.clear(); + String dir = SDKConfig.getConfig().getValidateCertDir(); + log.info("加载验证签名证书目录==>" + dir +" 注:如果请求报文中version=5.1.0那么此验签证书目录使用不到,可以不需要设置(version=5.0.0必须设置)。"); + if (StringUtils.isEmpty(dir)) { + log.error("WARN: acpsdk.validateCert.dir is empty"); + return; + } + CertificateFactory cf = null; + FileInputStream in = null; + try { + cf = CertificateFactory.getInstance("X.509", "BC"); + }catch (NoSuchProviderException e) { + log.error("LoadVerifyCert Error: No BC Provider", e); + return ; + } catch (CertificateException e) { + log.error("LoadVerifyCert Error", e); + return ; + } + File fileDir = new File(dir); + File[] files = fileDir.listFiles(new CerFilter()); + for (int i = 0; i < files.length; i++) { + File file = files[i]; + try { + in = new FileInputStream(file.getAbsolutePath()); + validateCert = (X509Certificate) cf.generateCertificate(in); + if(validateCert == null) { + log.error("Load verify cert error, " + file.getAbsolutePath() + " has error cert content."); + continue; + } + certMap.put(validateCert.getSerialNumber().toString(), + validateCert); + // 打印证书加载信息,供测试阶段调试 + log.info("[" + file.getAbsolutePath() + "][CertId=" + + validateCert.getSerialNumber().toString() + "]"); + } catch (CertificateException e) { + log.error("LoadVerifyCert Error", e); + e.printStackTrace(); + }catch (FileNotFoundException e) { + log.error("LoadVerifyCert Error File Not Found", e); + e.printStackTrace(); + }finally { + if (null != in) { + try { + in.close(); + } catch (IOException e) { + log.error(e.toString()); + e.printStackTrace(); + } + } + } + } + log.info("LoadVerifyCert Finish"); + } + + /** + * 用给定的路径和密码 加载签名证书,并保存到certKeyStoreMap + * + * @param certFilePath + * @param certPwd + */ + private static void loadSignCert(String certFilePath, String certPwd) { + KeyStore keyStore = null; + try { + keyStore = getKeyInfo(certFilePath, certPwd, "PKCS12"); + keyStoreMap.put(certFilePath, keyStore); + log.info("LoadRsaCert Successful"); + } catch (IOException e) { + log.error("LoadRsaCert Error", e); + e.printStackTrace(); + } + } + + /** + * 通过证书路径初始化为公钥证书 + * @param path + * @return + */ + private static X509Certificate initCert(String path) { + X509Certificate encryptCertTemp = null; + CertificateFactory cf = null; + FileInputStream in = null; + try { + cf = CertificateFactory.getInstance("X.509", "BC"); + in = new FileInputStream(path); + encryptCertTemp = (X509Certificate) cf.generateCertificate(in); + // 打印证书加载信息,供测试阶段调试 + log.info("[" + path + "][CertId=" + + encryptCertTemp.getSerialNumber().toString() + "]"); + } catch (CertificateException e) { + log.error("InitCert Error", e); + e.printStackTrace(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + log.error("InitCert Error File Not Found", e); + } catch (NoSuchProviderException e) { + e.printStackTrace(); + log.error("LoadVerifyCert Error No BC Provider", e); + } finally { + if (null != in) { + try { + in.close(); + } catch (IOException e) { + e.printStackTrace(); + log.error(e.toString()); + } + } + } + return encryptCertTemp; + } + + /** + * 通过keyStore 获取私钥签名证书PrivateKey对象 + * + * @return + */ + public static PrivateKey getSignCertPrivateKey() { + try { + Enumeration aliasenum = keyStore.aliases(); + String keyAlias = null; + if (aliasenum.hasMoreElements()) { + keyAlias = aliasenum.nextElement(); + } + PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias, + SDKConfig.getConfig().getSignCertPwd().toCharArray()); + return privateKey; + } catch (KeyStoreException e) { + e.printStackTrace(); + log.error("getSignCertPrivateKey Error", e); + return null; + } catch (UnrecoverableKeyException e) { + e.printStackTrace(); + log.error("getSignCertPrivateKey Error", e); + return null; + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + log.error("getSignCertPrivateKey Error", e); + return null; + } + } + /** + * 通过指定路径的私钥证书 获取PrivateKey对象 + * + * @return + */ + public static PrivateKey getSignCertPrivateKeyByStoreMap(String certPath, + String certPwd) { + if (!keyStoreMap.containsKey(certPath)) { + loadSignCert(certPath, certPwd); + } + try { + Enumeration aliasenum = keyStoreMap.get(certPath) + .aliases(); + String keyAlias = null; + if (aliasenum.hasMoreElements()) { + keyAlias = aliasenum.nextElement(); + } + PrivateKey privateKey = (PrivateKey) keyStoreMap.get(certPath) + .getKey(keyAlias, certPwd.toCharArray()); + return privateKey; + } catch (KeyStoreException e) { + e.printStackTrace(); + log.error("getSignCertPrivateKeyByStoreMap Error", e); + return null; + } catch (UnrecoverableKeyException e) { + e.printStackTrace(); + log.error("getSignCertPrivateKeyByStoreMap Error", e); + return null; + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + log.error("getSignCertPrivateKeyByStoreMap Error", e); + return null; + } + } + + /** + * 获取敏感信息加密证书PublicKey + * + * @return + */ + public static PublicKey getEncryptCertPublicKey() { + if (null == encryptCert) { + String path = SDKConfig.getConfig().getEncryptCertPath(); + if (!StringUtils.isEmpty(path)) { + encryptCert = initCert(path); + return encryptCert.getPublicKey(); + } else { + log.error("acpsdk.encryptCert.path is empty"); + return null; + } + } else { + return encryptCert.getPublicKey(); + } + } + + /** + * 重置敏感信息加密证书公钥 + */ + public static void resetEncryptCertPublicKey() { + encryptCert = null; + } + + /** + * 获取磁道加密证书PublicKey + * + * @return + */ + public static PublicKey getEncryptTrackPublicKey() { + if (null == encryptTrackKey) { + initTrackKey(); + } + return encryptTrackKey; + } + + /** + * 通过certId获取验签证书Map中对应证书PublicKey + * + * @param certId 证书物理序号 + * @return 通过证书编号获取到的公钥 + */ + public static PublicKey getValidatePublicKey(String certId) { + X509Certificate cf = null; + if (certMap.containsKey(certId)) { + // 存在certId对应的证书对象 + cf = certMap.get(certId); + return cf.getPublicKey(); + } else { + // 不存在则重新Load证书文件目录 + initValidateCertFromDir(); + if (certMap.containsKey(certId)) { + // 存在certId对应的证书对象 + cf = certMap.get(certId); + return cf.getPublicKey(); + } else { + log.error("缺少certId=[" + certId + "]对应的验签证书."); + return null; + } + } + } + + /** + * 获取配置文件acp_sdk.properties中配置的签名私钥证书certId + * + * @return 证书的物理编号 + */ + public static String getSignCertId() { + try { + Enumeration aliasenum = keyStore.aliases(); + String keyAlias = null; + if (aliasenum.hasMoreElements()) { + keyAlias = aliasenum.nextElement(); + } + X509Certificate cert = (X509Certificate) keyStore + .getCertificate(keyAlias); + return cert.getSerialNumber().toString(); + } catch (Exception e) { + log.error("getSignCertId Error", e); + return null; + } + } + + /** + * 获取敏感信息加密证书的certId + * + * @return + */ + public static String getEncryptCertId() { + if (null == encryptCert) { + String path = SDKConfig.getConfig().getEncryptCertPath(); + if (!StringUtils.isEmpty(path)) { + encryptCert = initCert(path); + return encryptCert.getSerialNumber().toString(); + } else { + log.error("acpsdk.encryptCert.path is empty"); + return null; + } + } else { + return encryptCert.getSerialNumber().toString(); + } + } + + /** + * 将签名私钥证书文件读取为证书存储对象 + * + * @param pfxkeyfile + * 证书文件名 + * @param keypwd + * 证书密码 + * @param type + * 证书类型 + * @return 证书对象 + * @throws IOException + */ + private static KeyStore getKeyInfo(String pfxkeyfile, String keypwd, + String type) throws IOException { + log.info("加载签名证书==>" + pfxkeyfile); + FileInputStream fis = null; + try { + KeyStore ks = KeyStore.getInstance(type, "BC"); + log.info("Load RSA CertPath=[" + pfxkeyfile + "],Pwd=["+ keypwd + "],type=["+type+"]"); + fis = new FileInputStream(pfxkeyfile); + char[] nPassword = null; + nPassword = null == keypwd || "".equals(keypwd.trim()) ? null: keypwd.toCharArray(); + if (null != ks) { + ks.load(fis, nPassword); + } + return ks; + } catch (Exception e) { + log.error("getKeyInfo Error", e); + e.printStackTrace(); + return null; + } finally { + if(null!=fis) + fis.close(); + } + } + + /** + * 通过签名私钥证书路径,密码获取私钥证书certId + * @param certPath + * @param certPwd + * @return + */ + public static String getCertIdByKeyStoreMap(String certPath, String certPwd) { + if (!keyStoreMap.containsKey(certPath)) { + // 缓存中未查询到,则加载RSA证书 + loadSignCert(certPath, certPwd); + } + return getCertIdIdByStore(keyStoreMap.get(certPath)); + } + + /** + * 通过keystore获取私钥证书的certId值 + * @param keyStore + * @return + */ + private static String getCertIdIdByStore(KeyStore keyStore) { + Enumeration aliasenum = null; + try { + aliasenum = keyStore.aliases(); + String keyAlias = null; + if (aliasenum.hasMoreElements()) { + keyAlias = aliasenum.nextElement(); + } + X509Certificate cert = (X509Certificate) keyStore + .getCertificate(keyAlias); + return cert.getSerialNumber().toString(); + } catch (KeyStoreException e) { + log.error("getCertIdIdByStore Error", e); + return null; + } + } + + /** + * 使用模和指数生成RSA公钥 注意:此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同 + * + * @param modulus + * 模 + * @param exponent + * 指数 + * @return + */ + private static PublicKey getPublicKey(String modulus, String exponent) { + try { + BigInteger b1 = new BigInteger(modulus); + BigInteger b2 = new BigInteger(exponent); + KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC"); + RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2); + return keyFactory.generatePublic(keySpec); + } catch (Exception e) { + log.error("构造RSA公钥失败:" + e); + return null; + } + } + + /** + * 将字符串转换为X509Certificate对象. + * + * @param x509CertString + * @return + */ + public static X509Certificate genCertificateByStr(String x509CertString) { + X509Certificate x509Cert = null; + try { + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + InputStream tIn = new ByteArrayInputStream( + x509CertString.getBytes("ISO-8859-1")); + x509Cert = (X509Certificate) cf.generateCertificate(tIn); + } catch (Exception e) { + log.error("gen certificate error", e); + } + return x509Cert; + } + + /** + * 从配置文件acp_sdk.properties中获取验签公钥使用的中级证书 + * @return + */ + public static X509Certificate getMiddleCert() { + if (null == middleCert) { + String path = SDKConfig.getConfig().getMiddleCertPath(); + if (!StringUtils.isEmpty(path)) { + initMiddleCert(); + } else { + log.error(SDKConfig.SDK_MIDDLECERT_PATH + " not set in " + SDKConfig.FILE_NAME); + return null; + } + } + return middleCert; + } + + /** + * 从配置文件acp_sdk.properties中获取验签公钥使用的根证书 + * @return + */ + public static X509Certificate getRootCert() { + if (null == rootCert) { + String path = SDKConfig.getConfig().getRootCertPath(); + if (!StringUtils.isEmpty(path)) { + initRootCert(); + } else { + log.error(SDKConfig.SDK_ROOTCERT_PATH + " not set in " + SDKConfig.FILE_NAME); + return null; + } + } + return rootCert; + } + + /** + * 获取证书的CN + * @param aCert + * @return + */ + private static String getIdentitiesFromCertficate(X509Certificate aCert) { + String tDN = aCert.getSubjectDN().toString(); + String tPart = ""; + if ((tDN != null)) { + String tSplitStr[] = tDN.substring(tDN.indexOf("CN=")).split("@"); + if (tSplitStr != null && tSplitStr.length > 2 + && tSplitStr[2] != null) + tPart = tSplitStr[2]; + } + return tPart; + } + + /** + * 验证书链。 + * @param cert + * @return + */ + private static boolean verifyCertificateChain(X509Certificate cert){ + + if ( null == cert) { + log.error("cert must Not null"); + return false; + } + + X509Certificate middleCert = CertUtil.getMiddleCert(); + if (null == middleCert) { + log.error("middleCert must Not null"); + return false; + } + + X509Certificate rootCert = CertUtil.getRootCert(); + if (null == rootCert) { + log.error("rootCert or cert must Not null"); + return false; + } + + try { + + X509CertSelector selector = new X509CertSelector(); + selector.setCertificate(cert); + + Set trustAnchors = new HashSet (); + trustAnchors.add(new TrustAnchor(rootCert, null)); + PKIXBuilderParameters pkixParams = new PKIXBuilderParameters( + trustAnchors, selector); + + Set intermediateCerts = new HashSet (); + intermediateCerts.add(rootCert); + intermediateCerts.add(middleCert); + intermediateCerts.add(cert); + + pkixParams.setRevocationEnabled(false); + + CertStore intermediateCertStore = CertStore.getInstance("Collection", + new CollectionCertStoreParameters(intermediateCerts), "BC"); + pkixParams.addCertStore(intermediateCertStore); + + CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", "BC"); + + @SuppressWarnings("unused") + PKIXCertPathBuilderResult result = (PKIXCertPathBuilderResult) builder + .build(pkixParams); + log.info("verify certificate chain succeed."); + return true; + } catch (CertPathBuilderException e){ + log.error("verify certificate chain fail.", e); + } catch (Exception e) { + log.error("verify certificate chain exception: ", e); + } + return false; + } + + /** + * 检查证书链 + * + * @param cert + * 待验证的证书 + * @return + */ + public static boolean verifyCertificate(X509Certificate cert) { + + if ( null == cert) { + log.error("cert must Not null"); + return false; + } + try { + cert.checkValidity();//验证有效期 +// cert.verify(middleCert.getPublicKey()); + if(!verifyCertificateChain(cert)){ + return false; + } + } catch (Exception e) { + log.error("verifyCertificate fail", e); + return false; + } + + if(SDKConfig.getConfig().isIfValidateCNName()){ + // 验证公钥是否属于银联 + if(!UNIONPAY_CNNAME.equals(CertUtil.getIdentitiesFromCertficate(cert))) { + log.error("cer owner is not CUP:" + CertUtil.getIdentitiesFromCertficate(cert)); + return false; + } + } else { + // 验证公钥是否属于银联 + if(!UNIONPAY_CNNAME.equals(CertUtil.getIdentitiesFromCertficate(cert)) + && !"00040000:SIGN".equals(CertUtil.getIdentitiesFromCertficate(cert))) { + log.error("cer owner is not CUP:" + CertUtil.getIdentitiesFromCertficate(cert)); + return false; + } + } + return true; + } + + /** + * 打印系统环境信息 + */ + private static void printSysInfo() { + log.info("================= SYS INFO begin===================="); + log.info("os_name:" + System.getProperty("os.name")); + log.info("os_arch:" + System.getProperty("os.arch")); + log.info("os_version:" + System.getProperty("os.version")); + log.info("java_vm_specification_version:" + + System.getProperty("java.vm.specification.version")); + log.info("java_vm_specification_vendor:" + + System.getProperty("java.vm.specification.vendor")); + log.info("java_vm_specification_name:" + + System.getProperty("java.vm.specification.name")); + log.info("java_vm_version:" + + System.getProperty("java.vm.version")); + log.info("java_vm_name:" + System.getProperty("java.vm.name")); + log.info("java.version:" + System.getProperty("java.version")); + log.info("java.vm.vendor=[" + System.getProperty("java.vm.vendor") + "]"); + log.info("java.version=[" + System.getProperty("java.version") + "]"); +// printProviders(); + log.info("================= SYS INFO end====================="); + } + + /** + * 打jre中印算法提供者列表 + */ + private static void printProviders() { + log.info("Providers List:"); + Provider[] providers = Security.getProviders(); + for (int i = 0; i < providers.length; i++) { + log.info(i + 1 + "." + providers[i].getName()); + } + } + + /** + * 证书文件过滤器 + * + */ + static class CerFilter implements FilenameFilter { + public boolean isCer(String name) { + if (name.toLowerCase().endsWith(".cer")) { + return true; + } else { + return false; + } + } + @Override + public boolean accept(File dir, String name) { + return isCer(name); + } + } + +} diff --git a/pay-java-union/src/main/java/com/egzosn/pay/union/SDK/SDKConfig.java b/pay-java-union/src/main/java/com/egzosn/pay/union/SDK/SDKConfig.java new file mode 100644 index 0000000..f94fa41 --- /dev/null +++ b/pay-java-union/src/main/java/com/egzosn/pay/union/SDK/SDKConfig.java @@ -0,0 +1,690 @@ +package com.egzosn.pay.union.SDK; + +import com.egzosn.pay.common.util.str.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.*; +import java.util.Properties; + +/** + * + * @ClassName SDKConfig + * @Description acpsdk配置文件acp_sdk.properties配置信息类 + * @date 2016-7-22 下午4:04:55 + * @lastUpdate Actinia Date:2017/11/7 0007 21:55 + * + */ +public class SDKConfig { + protected final Log log = LogFactory.getLog(SDKConfig.class); + + public static final String FILE_NAME = "acp_sdk.properties"; + /** 前台请求URL. */ + private String frontRequestUrl; + /** 后台请求URL. */ + private String backRequestUrl; + /** 单笔查询 */ + private String singleQueryUrl; + /** 批量查询 */ + private String batchQueryUrl; + /** 批量交易 */ + private String batchTransUrl; + /** 文件传输 */ + private String fileTransUrl; + /** 签名证书路径. */ + private String signCertPath; + /** 签名证书密码. */ + private String signCertPwd; + /** 签名证书类型. */ + private String signCertType; + /** 加密公钥证书路径. */ + private String encryptCertPath; + /** 验证签名公钥证书目录. */ + private String validateCertDir; + /** 按照商户代码读取指定签名证书目录. */ + private String signCertDir; + /** 磁道加密证书路径. */ + private String encryptTrackCertPath; + /** 磁道加密公钥模数. */ + private String encryptTrackKeyModulus; + /** 磁道加密公钥指数. */ + private String encryptTrackKeyExponent; + /** 有卡交易. */ + private String cardRequestUrl; + /** app交易 */ + private String appRequestUrl; + /** 证书使用模式(单证书/多证书) */ + private String singleMode; + /** 安全密钥(SHA256和SM3计算时使用) */ + private String secureKey; + /** 中级证书路径 */ + private String middleCertPath; + /** 根证书路径 */ + private String rootCertPath; + /** 是否验证验签证书CN,除了false都验 */ + private boolean ifValidateCNName = true; + /** 是否验证https证书,默认都不验 */ + private boolean ifValidateRemoteCert = false; + /** signMethod,没配按01吧 */ + private String signMethod = "01"; + /** version,没配按5.0.0 */ + private String version = "5.0.0"; + /** frontUrl */ + private String frontUrl; + /** backUrl */ + private String backUrl; + + /*缴费相关地址*/ + private String jfFrontRequestUrl; + private String jfBackRequestUrl; + private String jfSingleQueryUrl; + private String jfCardRequestUrl; + private String jfAppRequestUrl; + + private String qrcBackTransUrl; + private String qrcB2cIssBackTransUrl; + private String qrcB2cMerBackTransUrl; + + /** 配置文件中的前台URL常量. */ + public static final String SDK_FRONT_URL = "acpsdk.frontTransUrl"; + /** 配置文件中的后台URL常量. */ + public static final String SDK_BACK_URL = "acpsdk.backTransUrl"; + /** 配置文件中的单笔交易查询URL常量. */ + public static final String SDK_SIGNQ_URL = "acpsdk.singleQueryUrl"; + /** 配置文件中的批量交易查询URL常量. */ + public static final String SDK_BATQ_URL = "acpsdk.batchQueryUrl"; + /** 配置文件中的批量交易URL常量. */ + public static final String SDK_BATTRANS_URL = "acpsdk.batchTransUrl"; + /** 配置文件中的文件类交易URL常量. */ + public static final String SDK_FILETRANS_URL = "acpsdk.fileTransUrl"; + /** 配置文件中的有卡交易URL常量. */ + public static final String SDK_CARD_URL = "acpsdk.cardTransUrl"; + /** 配置文件中的app交易URL常量. */ + public static final String SDK_APP_URL = "acpsdk.appTransUrl"; + + /** 以下缴费产品使用,其余产品用不到,无视即可 */ + // 前台请求地址 + public static final String JF_SDK_FRONT_TRANS_URL= "acpsdk.jfFrontTransUrl"; + // 后台请求地址 + public static final String JF_SDK_BACK_TRANS_URL="acpsdk.jfBackTransUrl"; + // 单笔查询请求地址 + public static final String JF_SDK_SINGLE_QUERY_URL="acpsdk.jfSingleQueryUrl"; + // 有卡交易地址 + public static final String JF_SDK_CARD_TRANS_URL="acpsdk.jfCardTransUrl"; + // App交易地址 + public static final String JF_SDK_APP_TRANS_URL="acpsdk.jfAppTransUrl"; + // 人到人 + public static final String QRC_BACK_TRANS_URL="acpsdk.qrcBackTransUrl"; + // 人到人 + public static final String QRC_B2C_ISS_BACK_TRANS_URL="acpsdk.qrcB2cIssBackTransUrl"; + // 人到人 + public static final String QRC_B2C_MER_BACK_TRANS_URL="acpsdk.qrcB2cMerBackTransUrl"; + + + /** 配置文件中签名证书路径常量. */ + public static final String SDK_SIGNCERT_PATH = "acpsdk.signCert.path"; + /** 配置文件中签名证书密码常量. */ + public static final String SDK_SIGNCERT_PWD = "acpsdk.signCert.pwd"; + /** 配置文件中签名证书类型常量. */ + public static final String SDK_SIGNCERT_TYPE = "acpsdk.signCert.type"; + /** 配置文件中密码加密证书路径常量. */ + public static final String SDK_ENCRYPTCERT_PATH = "acpsdk.encryptCert.path"; + /** 配置文件中磁道加密证书路径常量. */ + public static final String SDK_ENCRYPTTRACKCERT_PATH = "acpsdk.encryptTrackCert.path"; + /** 配置文件中磁道加密公钥模数常量. */ + public static final String SDK_ENCRYPTTRACKKEY_MODULUS = "acpsdk.encryptTrackKey.modulus"; + /** 配置文件中磁道加密公钥指数常量. */ + public static final String SDK_ENCRYPTTRACKKEY_EXPONENT = "acpsdk.encryptTrackKey.exponent"; + /** 配置文件中验证签名证书目录常量. */ + public static final String SDK_VALIDATECERT_DIR = "acpsdk.validateCert.dir"; + + /** 配置文件中是否加密cvn2常量. */ + public static final String SDK_CVN_ENC = "acpsdk.cvn2.enc"; + /** 配置文件中是否加密cvn2有效期常量. */ + public static final String SDK_DATE_ENC = "acpsdk.date.enc"; + /** 配置文件中是否加密卡号常量. */ + public static final String SDK_PAN_ENC = "acpsdk.pan.enc"; + /** 配置文件中证书使用模式 */ + public static final String SDK_SINGLEMODE = "acpsdk.singleMode"; + /** 配置文件中安全密钥 */ + public static final String SDK_SECURITYKEY = "acpsdk.secureKey"; + /** 配置文件中根证书路径常量 */ + public static final String SDK_ROOTCERT_PATH = "acpsdk.rootCert.path"; + /** 配置文件中根证书路径常量 */ + public static final String SDK_MIDDLECERT_PATH = "acpsdk.middleCert.path"; + /** 配置是否需要验证验签证书CN,除了false之外的值都当true处理 */ + public static final String SDK_IF_VALIDATE_CN_NAME = "acpsdk.ifValidateCNName"; + /** 配置是否需要验证https证书,除了true之外的值都当false处理 */ + public static final String SDK_IF_VALIDATE_REMOTE_CERT = "acpsdk.ifValidateRemoteCert"; + /** signmethod */ + public static final String SDK_SIGN_METHOD ="acpsdk.signMethod"; + /** version */ + public static final String SDK_VERSION = "acpsdk.version"; + /** 后台通知地址 */ + public static final String SDK_BACKURL = "acpsdk.backUrl"; + /** 前台通知地址 */ + public static final String SDK_FRONTURL = "acpsdk.frontUrl"; + /** 操作对象. */ + private static SDKConfig config = new SDKConfig(); + /** 属性文件对象. */ + private Properties properties; + + + private SDKConfig () { + super(); + } + + /** + * 获取config对象. + * @return + */ + public static SDKConfig getConfig() { + return config; + } + + /** + * 从classpath路径下加载配置参数 + */ + public void loadPropertiesFromSrc() { + InputStream in = null; + try { + log.info("从classpath: " +SDKConfig.class.getClassLoader().getResource("").getPath()+" 获取属性文件"+FILE_NAME); + in = SDKConfig.class.getClassLoader().getResourceAsStream(FILE_NAME); + if (null != in) { + properties = new Properties(); + try { + properties.load(in); + } catch (IOException e) { + throw e; + } + } else { + log.info(FILE_NAME + "属性文件未能在classpath指定的目录下 "+SDKConfig.class.getClassLoader().getResource("").getPath()+" 找到!"); + return; + } + loadProperties(properties); + } catch (IOException e) { + log.info(e.getMessage(), e); + } finally { + if (null != in) { + try { + in.close(); + } catch (IOException e) { + log.info(e.getMessage(), e); + } + } + } + } + + /** + * 根据传入的 {@link #load(java.util.Properties)}对象设置配置参数 + * + * @param pro + */ + public void loadProperties(Properties pro) { + log.info("开始从属性文件中加载配置项"); + String value = null; + + value = pro.getProperty(SDK_SIGNCERT_PATH); + if (!StringUtils.isEmpty(value)) { + this.signCertPath = value.trim(); + } + value = pro.getProperty(SDK_SIGNCERT_PWD); + if (!StringUtils.isEmpty(value)) { + this.signCertPwd = value.trim(); + } + value = pro.getProperty(SDK_SIGNCERT_TYPE); + if (!StringUtils.isEmpty(value)) { + this.signCertType = value.trim(); + } + value = pro.getProperty(SDK_ENCRYPTCERT_PATH); + if (!StringUtils.isEmpty(value)) { + this.encryptCertPath = value.trim(); + } + value = pro.getProperty(SDK_VALIDATECERT_DIR); + if (!StringUtils.isEmpty(value)) { + this.validateCertDir = value.trim(); + } + value = pro.getProperty(SDK_FRONT_URL); + if (!StringUtils.isEmpty(value)) { + this.frontRequestUrl = value.trim(); + } + value = pro.getProperty(SDK_BACK_URL); + if (!StringUtils.isEmpty(value)) { + this.backRequestUrl = value.trim(); + } + value = pro.getProperty(SDK_BATQ_URL); + if (!StringUtils.isEmpty(value)) { + this.batchQueryUrl = value.trim(); + } + value = pro.getProperty(SDK_BATTRANS_URL); + if (!StringUtils.isEmpty(value)) { + this.batchTransUrl = value.trim(); + } + value = pro.getProperty(SDK_FILETRANS_URL); + if (!StringUtils.isEmpty(value)) { + this.fileTransUrl = value.trim(); + } + value = pro.getProperty(SDK_SIGNQ_URL); + if (!StringUtils.isEmpty(value)) { + this.singleQueryUrl = value.trim(); + } + value = pro.getProperty(SDK_CARD_URL); + if (!StringUtils.isEmpty(value)) { + this.cardRequestUrl = value.trim(); + } + value = pro.getProperty(SDK_APP_URL); + if (!StringUtils.isEmpty(value)) { + this.appRequestUrl = value.trim(); + } + value = pro.getProperty(SDK_ENCRYPTTRACKCERT_PATH); + if (!StringUtils.isEmpty(value)) { + this.encryptTrackCertPath = value.trim(); + } + + value = pro.getProperty(SDK_SECURITYKEY); + if (!StringUtils.isEmpty(value)) { + this.secureKey = value.trim(); + } + value = pro.getProperty(SDK_ROOTCERT_PATH); + if (!StringUtils.isEmpty(value)) { + this.rootCertPath = value.trim(); + } + value = pro.getProperty(SDK_MIDDLECERT_PATH); + if (!StringUtils.isEmpty(value)) { + this.middleCertPath = value.trim(); + } + + /**缴费部分**/ + value = pro.getProperty(JF_SDK_FRONT_TRANS_URL); + if (!StringUtils.isEmpty(value)) { + this.jfFrontRequestUrl = value.trim(); + } + + value = pro.getProperty(JF_SDK_BACK_TRANS_URL); + if (!StringUtils.isEmpty(value)) { + this.jfBackRequestUrl = value.trim(); + } + + value = pro.getProperty(JF_SDK_SINGLE_QUERY_URL); + if (!StringUtils.isEmpty(value)) { + this.jfSingleQueryUrl = value.trim(); + } + + value = pro.getProperty(JF_SDK_CARD_TRANS_URL); + if (!StringUtils.isEmpty(value)) { + this.jfCardRequestUrl = value.trim(); + } + + value = pro.getProperty(JF_SDK_APP_TRANS_URL); + if (!StringUtils.isEmpty(value)) { + this.jfAppRequestUrl = value.trim(); + } + + value = pro.getProperty(QRC_BACK_TRANS_URL); + if (!StringUtils.isEmpty(value)) { + this.qrcBackTransUrl = value.trim(); + } + + value = pro.getProperty(QRC_B2C_ISS_BACK_TRANS_URL); + if (!StringUtils.isEmpty(value)) { + this.qrcB2cIssBackTransUrl = value.trim(); + } + + value = pro.getProperty(QRC_B2C_MER_BACK_TRANS_URL); + if (!StringUtils.isEmpty(value)) { + this.qrcB2cMerBackTransUrl = value.trim(); + } + + value = pro.getProperty(SDK_ENCRYPTTRACKKEY_EXPONENT); + if (!StringUtils.isEmpty(value)) { + this.encryptTrackKeyExponent = value.trim(); + } + + value = pro.getProperty(SDK_ENCRYPTTRACKKEY_MODULUS); + if (!StringUtils.isEmpty(value)) { + this.encryptTrackKeyModulus = value.trim(); + } + + value = pro.getProperty(SDK_IF_VALIDATE_CN_NAME); + if (!StringUtils.isEmpty(value)) { + if( "false".equals(value.trim())) { + this.ifValidateCNName = false; + } + } + + value = pro.getProperty(SDK_IF_VALIDATE_REMOTE_CERT); + if (!StringUtils.isEmpty(value)) { + if( "true".equals(value.trim())) { + this.ifValidateRemoteCert = true; + } + } + + value = pro.getProperty(SDK_SIGN_METHOD); + if (!StringUtils.isEmpty(value)) { + this.signMethod = value.trim(); + } + + value = pro.getProperty(SDK_SIGN_METHOD); + if (!StringUtils.isEmpty(value)) { + this.signMethod = value.trim(); + } + value = pro.getProperty(SDK_VERSION); + if (!StringUtils.isEmpty(value)) { + this.version = value.trim(); + } + value = pro.getProperty(SDK_FRONTURL); + if (!StringUtils.isEmpty(value)) { + this.frontUrl = value.trim(); + } + value = pro.getProperty(SDK_BACKURL); + if (!StringUtils.isEmpty(value)) { + this.backUrl = value.trim(); + } + } + + public String getSignMethod () { + return signMethod; + } + + public void setSignMethod (String signMethod) { + this.signMethod = signMethod; + } + + public String getSignMethodByStr(String signStr) { + if(StringUtils.isBlank(signStr)){ + return SDKConstants.SIGNMETHOD_RSA; + } + signStr = signStr.toUpperCase(); + switch (signStr) { + case "RSA": + return SDKConstants.SIGNMETHOD_RSA; + case "SHA256": + return SDKConstants.SIGNMETHOD_SHA256; + case "SM3": + return SDKConstants.SIGNMETHOD_SM3; + default: + return SDKConstants.SIGNMETHOD_RSA; + } + } + + public String getFrontRequestUrl() { + return frontRequestUrl; + } + + public void setFrontRequestUrl(String frontRequestUrl) { + this.frontRequestUrl = frontRequestUrl; + } + + public String getBackRequestUrl() { + return backRequestUrl; + } + + public void setBackRequestUrl(String backRequestUrl) { + this.backRequestUrl = backRequestUrl; + } + + public String getSignCertPath() { + return signCertPath; + } + + public void setSignCertPath(String signCertPath) { + this.signCertPath = signCertPath; + } + + public String getSignCertPwd() { + return signCertPwd; + } + + public void setSignCertPwd(String signCertPwd) { + this.signCertPwd = signCertPwd; + } + + public String getSignCertType() { + return signCertType; + } + + public void setSignCertType(String signCertType) { + this.signCertType = signCertType; + } + + public String getEncryptCertPath() { + return encryptCertPath; + } + + public void setEncryptCertPath(String encryptCertPath) { + this.encryptCertPath = encryptCertPath; + } + + public String getValidateCertDir() { + return validateCertDir; + } + + public void setValidateCertDir(String validateCertDir) { + this.validateCertDir = validateCertDir; + } + + public String getSingleQueryUrl() { + return singleQueryUrl; + } + + public void setSingleQueryUrl(String singleQueryUrl) { + this.singleQueryUrl = singleQueryUrl; + } + + public String getBatchQueryUrl() { + return batchQueryUrl; + } + + public void setBatchQueryUrl(String batchQueryUrl) { + this.batchQueryUrl = batchQueryUrl; + } + + public String getBatchTransUrl() { + return batchTransUrl; + } + + public void setBatchTransUrl(String batchTransUrl) { + this.batchTransUrl = batchTransUrl; + } + + public String getFileTransUrl() { + return fileTransUrl; + } + + public void setFileTransUrl(String fileTransUrl) { + this.fileTransUrl = fileTransUrl; + } + + public String getSignCertDir() { + return signCertDir; + } + + public void setSignCertDir(String signCertDir) { + this.signCertDir = signCertDir; + } + + public Properties getProperties() { + return properties; + } + + public void setProperties(Properties properties) { + this.properties = properties; + } + + public String getCardRequestUrl() { + return cardRequestUrl; + } + + public void setCardRequestUrl(String cardRequestUrl) { + this.cardRequestUrl = cardRequestUrl; + } + + public String getAppRequestUrl() { + return appRequestUrl; + } + + public void setAppRequestUrl(String appRequestUrl) { + this.appRequestUrl = appRequestUrl; + } + + public String getEncryptTrackCertPath() { + return encryptTrackCertPath; + } + + public void setEncryptTrackCertPath(String encryptTrackCertPath) { + this.encryptTrackCertPath = encryptTrackCertPath; + } + + public String getJfFrontRequestUrl() { + return jfFrontRequestUrl; + } + + public void setJfFrontRequestUrl(String jfFrontRequestUrl) { + this.jfFrontRequestUrl = jfFrontRequestUrl; + } + + public String getJfBackRequestUrl() { + return jfBackRequestUrl; + } + + public void setJfBackRequestUrl(String jfBackRequestUrl) { + this.jfBackRequestUrl = jfBackRequestUrl; + } + + public String getJfSingleQueryUrl() { + return jfSingleQueryUrl; + } + + public void setJfSingleQueryUrl(String jfSingleQueryUrl) { + this.jfSingleQueryUrl = jfSingleQueryUrl; + } + + public String getJfCardRequestUrl() { + return jfCardRequestUrl; + } + + public void setJfCardRequestUrl(String jfCardRequestUrl) { + this.jfCardRequestUrl = jfCardRequestUrl; + } + + public String getJfAppRequestUrl() { + return jfAppRequestUrl; + } + + public void setJfAppRequestUrl(String jfAppRequestUrl) { + this.jfAppRequestUrl = jfAppRequestUrl; + } + + public String getSingleMode() { + return singleMode; + } + + public void setSingleMode(String singleMode) { + this.singleMode = singleMode; + } + + public String getEncryptTrackKeyExponent() { + return encryptTrackKeyExponent; + } + + public void setEncryptTrackKeyExponent(String encryptTrackKeyExponent) { + this.encryptTrackKeyExponent = encryptTrackKeyExponent; + } + + public String getEncryptTrackKeyModulus() { + return encryptTrackKeyModulus; + } + + public void setEncryptTrackKeyModulus(String encryptTrackKeyModulus) { + this.encryptTrackKeyModulus = encryptTrackKeyModulus; + } + + public String getSecureKey() { + return secureKey; + } + + public void setSecureKey(String securityKey) { + this.secureKey = securityKey; + } + + public String getMiddleCertPath() { + return middleCertPath; + } + + public void setMiddleCertPath(String middleCertPath) { + this.middleCertPath = middleCertPath; + } + + public boolean isIfValidateCNName() { + return ifValidateCNName; + } + + public void setIfValidateCNName(boolean ifValidateCNName) { + this.ifValidateCNName = ifValidateCNName; + } + + public boolean isIfValidateRemoteCert() { + return ifValidateRemoteCert; + } + + public void setIfValidateRemoteCert(boolean ifValidateRemoteCert) { + this.ifValidateRemoteCert = ifValidateRemoteCert; + } + + public String getQrcBackTransUrl() { + return qrcBackTransUrl; + } + + public void setQrcBackTransUrl(String qrcBackTransUrl) { + this.qrcBackTransUrl = qrcBackTransUrl; + } + + public String getQrcB2cIssBackTransUrl() { + return qrcB2cIssBackTransUrl; + } + + public void setQrcB2cIssBackTransUrl(String qrcB2cIssBackTransUrl) { + this.qrcB2cIssBackTransUrl = qrcB2cIssBackTransUrl; + } + + public String getQrcB2cMerBackTransUrl() { + return qrcB2cMerBackTransUrl; + } + + public void setQrcB2cMerBackTransUrl(String qrcB2cMerBackTransUrl) { + this.qrcB2cMerBackTransUrl = qrcB2cMerBackTransUrl; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getFrontUrl() { + return frontUrl; + } + + public void setFrontUrl(String frontUrl) { + this.frontUrl = frontUrl; + } + + public String getBackUrl() { + return backUrl; + } + + public void setBackUrl(String backUrl) { + this.backUrl = backUrl; + } + + public String getRootCertPath() { + return rootCertPath; + } + + public void setRootCertPath(String rootCertPath) { + this.rootCertPath = rootCertPath; + } + +} diff --git a/pay-java-union/src/main/java/com/egzosn/pay/union/SDK/SDKConstants.java b/pay-java-union/src/main/java/com/egzosn/pay/union/SDK/SDKConstants.java new file mode 100644 index 0000000..3599713 --- /dev/null +++ b/pay-java-union/src/main/java/com/egzosn/pay/union/SDK/SDKConstants.java @@ -0,0 +1,402 @@ +/** + * Licensed Property to China UnionPay Co., Ltd. + * + * (C) Copyright of China UnionPay Co., Ltd. 2010 + * All Rights Reserved. + *
+ *
+ * Modification History: + * ============================================================================= + * Author Date Description + * ------------ ---------- --------------------------------------------------- + * xshu 2014-05-28 MPI插件包常量定义 + * ============================================================================= + */ +package com.egzosn.pay.union.SDK; + +/** + * + * @ClassName SDKConstants + * @Description acpsdk常量类 + * @date 2016-7-22 下午4:05:54 + * + */ +public class SDKConstants { + + public final static String COLUMN_DEFAULT = "-"; + + public final static String KEY_DELIMITER = "#"; + + /** memeber variable: blank. */ + public static final String BLANK = ""; + + /** member variabel: space. */ + public static final String SPACE = " "; + + /** memeber variable: unline. */ + public static final String UNLINE = "_"; + + /** memeber varibale: star. */ + public static final String STAR = "*"; + + /** memeber variable: line. */ + public static final String LINE = "-"; + + /** memeber variable: add. */ + public static final String ADD = "+"; + + /** memeber variable: colon. */ + public final static String COLON = "|"; + + /** memeber variable: point. */ + public final static String POINT = "."; + + /** memeber variable: comma. */ + public final static String COMMA = ","; + + /** memeber variable: slash. */ + public final static String SLASH = "/"; + + /** memeber variable: div. */ + public final static String DIV = "/"; + + /** memeber variable: left . */ + public final static String LB = "("; + + /** memeber variable: right. */ + public final static String RB = ")"; + + /** memeber variable: rmb. */ + public final static String CUR_RMB = "RMB"; + + /** memeber variable: .page size */ + public static final int PAGE_SIZE = 10; + + /** memeber variable: String ONE. */ + public static final String ONE = "1"; + + /** memeber variable: String ZERO. */ + public static final String ZERO = "0"; + + /** memeber variable: number six. */ + public static final int NUM_SIX = 6; + + /** memeber variable: equal mark. */ + public static final String EQUAL = "="; + + /** memeber variable: operation ne. */ + public static final String NE = "!="; + + /** memeber variable: operation le. */ + public static final String LE = "<="; + + /** memeber variable: operation ge. */ + public static final String GE = ">="; + + /** memeber variable: operation lt. */ + public static final String LT = "<"; + + /** memeber variable: operation gt. */ + public static final String GT = ">"; + + /** memeber variable: list separator. */ + public static final String SEP = "./"; + + /** memeber variable: Y. */ + public static final String Y = "Y"; + + /** memeber variable: AMPERSAND. */ + public static final String AMPERSAND = "&"; + + /** memeber variable: SQL_LIKE_TAG. */ + public static final String SQL_LIKE_TAG = "%"; + + /** memeber variable: @. */ + public static final String MAIL = "@"; + + /** memeber variable: number zero. */ + public static final int NZERO = 0; + + public static final String LEFT_BRACE = "{"; + + public static final String RIGHT_BRACE = "}"; + + /** memeber variable: string true. */ + public static final String TRUE_STRING = "true"; + /** memeber variable: string false. */ + public static final String FALSE_STRING = "false"; + + /** memeber variable: forward success. */ + public static final String SUCCESS = "success"; + /** memeber variable: forward fail. */ + public static final String FAIL = "fail"; + /** memeber variable: global forward success. */ + public static final String GLOBAL_SUCCESS = "$success"; + /** memeber variable: global forward fail. */ + public static final String GLOBAL_FAIL = "$fail"; + + public static final String UTF_8_ENCODING = "UTF-8"; + public static final String GBK_ENCODING = "GBK"; + public static final String CONTENT_TYPE = "Content-type"; + public static final String APP_XML_TYPE = "application/xml;charset=utf-8"; + public static final String APP_FORM_TYPE = "application/x-www-form-urlencoded;charset="; + + public static final String VERSION_1_0_0 = "1.0.0"; + public static final String VERSION_5_0_0 = "5.0.0"; + public static final String VERSION_5_0_1 = "5.0.1"; + public static final String VERSION_5_1_0 = "5.1.0"; + public static final String SIGNMETHOD_RSA = "01"; + public static final String SIGNMETHOD_SHA256 = "11"; + public static final String SIGNMETHOD_SM3 = "12"; + public static final String UNIONPAY_CNNAME = "中国银联股份有限公司"; + public static final String CERTTYPE_01 = "01";// 敏感信息加密公钥 + public static final String CERTTYPE_02 = "02";// 磁道加密公钥 + + /******************************************** 5.0报文接口定义 ********************************************/ + /** 版本号. */ + public static final String param_version = "version"; + /** 证书ID. */ + public static final String param_certId = "certId"; + /** 签名. */ + public static final String param_signature = "signature"; + /** 签名方法. */ + public static final String param_signMethod = "signMethod"; + /** 编码方式. */ + public static final String param_encoding = "encoding"; + /** 交易类型. */ + public static final String param_txnType = "txnType"; + /** 交易子类. */ + public static final String param_txnSubType = "txnSubType"; + /** 业务类型. */ + public static final String param_bizType = "bizType"; + /** 前台通知地址 . */ + public static final String param_frontUrl = "frontUrl"; + /** 后台通知地址. */ + public static final String param_backUrl = "backUrl"; + /** 接入类型. */ + public static final String param_accessType = "accessType"; + /** 收单机构代码. */ + public static final String param_acqInsCode = "acqInsCode"; + /** 商户类别. */ + public static final String param_merCatCode = "merCatCode"; + /** 商户类型. */ + public static final String param_merType = "merType"; + /** 商户代码. */ + public static final String param_merId = "merId"; + /** 商户名称. */ + public static final String param_merName = "merName"; + /** 商户简称. */ + public static final String param_merAbbr = "merAbbr"; + /** 二级商户代码. */ + public static final String param_subMerId = "subMerId"; + /** 二级商户名称. */ + public static final String param_subMerName = "subMerName"; + /** 二级商户简称. */ + public static final String param_subMerAbbr = "subMerAbbr"; + /** Cupsecure 商户代码. */ + public static final String param_csMerId = "csMerId"; + /** 商户订单号. */ + public static final String param_orderId = "orderId"; + /** 交易时间. */ + public static final String param_txnTime = "txnTime"; + /** 发送时间. */ + public static final String param_txnSendTime = "txnSendTime"; + /** 订单超时时间间隔. */ + public static final String param_orderTimeoutInterval = "orderTimeoutInterval"; + /** 支付超时时间. */ + public static final String param_payTimeoutTime = "payTimeoutTime"; + /** 默认支付方式. */ + public static final String param_defaultPayType = "defaultPayType"; + /** 支持支付方式. */ + public static final String param_supPayType = "supPayType"; + /** 支付方式. */ + public static final String param_payType = "payType"; + /** 自定义支付方式. */ + public static final String param_customPayType = "customPayType"; + /** 物流标识. */ + public static final String param_shippingFlag = "shippingFlag"; + /** 收货地址-国家. */ + public static final String param_shippingCountryCode = "shippingCountryCode"; + /** 收货地址-省. */ + public static final String param_shippingProvinceCode = "shippingProvinceCode"; + /** 收货地址-市. */ + public static final String param_shippingCityCode = "shippingCityCode"; + /** 收货地址-地区. */ + public static final String param_shippingDistrictCode = "shippingDistrictCode"; + /** 收货地址-详细. */ + public static final String param_shippingStreet = "shippingStreet"; + /** 商品总类. */ + public static final String param_commodityCategory = "commodityCategory"; + /** 商品名称. */ + public static final String param_commodityName = "commodityName"; + /** 商品URL. */ + public static final String param_commodityUrl = "commodityUrl"; + /** 商品单价. */ + public static final String param_commodityUnitPrice = "commodityUnitPrice"; + /** 商品数量. */ + public static final String param_commodityQty = "commodityQty"; + /** 是否预授权. */ + public static final String param_isPreAuth = "isPreAuth"; + /** 币种. */ + public static final String param_currencyCode = "currencyCode"; + /** 账户类型. */ + public static final String param_accType = "accType"; + /** 账号. */ + public static final String param_accNo = "accNo"; + /** 支付卡类型. */ + public static final String param_payCardType = "payCardType"; + /** 发卡机构代码. */ + public static final String param_issInsCode = "issInsCode"; + /** 持卡人信息. */ + public static final String param_customerInfo = "customerInfo"; + /** 交易金额. */ + public static final String param_txnAmt = "txnAmt"; + /** 余额. */ + public static final String param_balance = "balance"; + /** 地区代码. */ + public static final String param_districtCode = "districtCode"; + /** 附加地区代码. */ + public static final String param_additionalDistrictCode = "additionalDistrictCode"; + /** 账单类型. */ + public static final String param_billType = "billType"; + /** 账单号码. */ + public static final String param_billNo = "billNo"; + /** 账单月份. */ + public static final String param_billMonth = "billMonth"; + /** 账单查询要素. */ + public static final String param_billQueryInfo = "billQueryInfo"; + /** 账单详情. */ + public static final String param_billDetailInfo = "billDetailInfo"; + /** 账单金额. */ + public static final String param_billAmt = "billAmt"; + /** 账单金额符号. */ + public static final String param_billAmtSign = "billAmtSign"; + /** 绑定标识号. */ + public static final String param_bindId = "bindId"; + /** 风险级别. */ + public static final String param_riskLevel = "riskLevel"; + /** 绑定信息条数. */ + public static final String param_bindInfoQty = "bindInfoQty"; + /** 绑定信息集. */ + public static final String param_bindInfoList = "bindInfoList"; + /** 批次号. */ + public static final String param_batchNo = "batchNo"; + /** 总笔数. */ + public static final String param_totalQty = "totalQty"; + /** 总金额. */ + public static final String param_totalAmt = "totalAmt"; + /** 文件类型. */ + public static final String param_fileType = "fileType"; + /** 文件名称. */ + public static final String param_fileName = "fileName"; + /** 批量文件内容. */ + public static final String param_fileContent = "fileContent"; + /** 商户摘要. */ + public static final String param_merNote = "merNote"; + /** 商户自定义域. */ + // public static final String param_merReserved = "merReserved";//接口变更删除 + /** 请求方保留域. */ + public static final String param_reqReserved = "reqReserved";// 新增接口 + /** 保留域. */ + public static final String param_reserved = "reserved"; + /** 终端号. */ + public static final String param_termId = "termId"; + /** 终端类型. */ + public static final String param_termType = "termType"; + /** 交互模式. */ + public static final String param_interactMode = "interactMode"; + /** 发卡机构识别模式. */ + // public static final String param_recognitionMode = "recognitionMode"; + public static final String param_issuerIdentifyMode = "issuerIdentifyMode";// 接口名称变更 + /** 商户端用户号. */ + public static final String param_merUserId = "merUserId"; + /** 持卡人IP. */ + public static final String param_customerIp = "customerIp"; + /** 查询流水号. */ + public static final String param_queryId = "queryId"; + /** 原交易查询流水号. */ + public static final String param_origQryId = "origQryId"; + /** 系统跟踪号. */ + public static final String param_traceNo = "traceNo"; + /** 交易传输时间. */ + public static final String param_traceTime = "traceTime"; + /** 清算日期. */ + public static final String param_settleDate = "settleDate"; + /** 清算币种. */ + public static final String param_settleCurrencyCode = "settleCurrencyCode"; + /** 清算金额. */ + public static final String param_settleAmt = "settleAmt"; + /** 清算汇率. */ + public static final String param_exchangeRate = "exchangeRate"; + /** 兑换日期. */ + public static final String param_exchangeDate = "exchangeDate"; + /** 响应时间. */ + public static final String param_respTime = "respTime"; + /** 原交易应答码. */ + public static final String param_origRespCode = "origRespCode"; + /** 原交易应答信息. */ + public static final String param_origRespMsg = "origRespMsg"; + /** 应答码. */ + public static final String param_respCode = "respCode"; + /** 应答码信息. */ + public static final String param_respMsg = "respMsg"; + // 新增四个报文字段merUserRegDt merUserEmail checkFlag activateStatus + /** 商户端用户注册时间. */ + public static final String param_merUserRegDt = "merUserRegDt"; + /** 商户端用户注册邮箱. */ + public static final String param_merUserEmail = "merUserEmail"; + /** 验证标识. */ + public static final String param_checkFlag = "checkFlag"; + /** 开通状态. */ + public static final String param_activateStatus = "activateStatus"; + /** 加密证书ID. */ + public static final String param_encryptCertId = "encryptCertId"; + /** 用户MAC、IMEI串号、SSID. */ + public static final String param_userMac = "userMac"; + /** 关联交易. */ + // public static final String param_relationTxnType = "relationTxnType"; + /** 短信类型 */ + public static final String param_smsType = "smsType"; + + /** 风控信息域 */ + public static final String param_riskCtrlInfo = "riskCtrlInfo"; + + /** IC卡交易信息域 */ + public static final String param_ICTransData = "ICTransData"; + + /** VPC交易信息域 */ + public static final String param_VPCTransData = "VPCTransData"; + + /** 安全类型 */ + public static final String param_securityType = "securityType"; + + /** 银联订单号 */ + public static final String param_tn = "tn"; + + /** 分期付款手续费率 */ + public static final String param_instalRate = "instalRate"; + + /** 分期付款手续费率 */ + public static final String param_mchntFeeSubsidy = "mchntFeeSubsidy"; + + /** 签名公钥证书 */ + public static final String param_signPubKeyCert = "signPubKeyCert"; + + /** 加密公钥证书 */ + public static final String param_encryptPubKeyCert = "encryptPubKeyCert"; + + /** 证书类型 */ + public static final String param_certType = "certType"; + + /** 渠道类型*/ + public static final String param_channelType = "channelType"; + + /** C2B码,1-20位数字*/ + public static final String param_qrNo = "qrNo"; + + /*原交易商户订单号*/ + public static final String param_origOrderId = "origOrderId"; + + /*原交易商户发送交易时间*/ + public static final String param_origTxnTime = "origTxnTime"; +} diff --git a/pay-java-union/src/main/java/com/egzosn/pay/union/SDK/SDKUtils.java b/pay-java-union/src/main/java/com/egzosn/pay/union/SDK/SDKUtils.java new file mode 100644 index 0000000..c8918dc --- /dev/null +++ b/pay-java-union/src/main/java/com/egzosn/pay/union/SDK/SDKUtils.java @@ -0,0 +1,204 @@ +package com.egzosn.pay.union.SDK;/** + * Description: + * author: Fuzx + * date: 2017/11/27 0027 + */ + +import com.egzosn.pay.common.util.sign.SecureUtil; +import com.egzosn.pay.common.util.sign.SignUtils; +import com.egzosn.pay.common.util.sign.encrypt.Base64; +import com.egzosn.pay.common.util.sign.encrypt.RSA; +import com.egzosn.pay.common.util.sign.encrypt.SHA256; +import com.egzosn.pay.common.util.str.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.*; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.zip.Inflater; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import static com.egzosn.pay.union.SDK.SDKConstants.*; + +/** + * @author Actinia + * @email hayesfu@qq.com + * @create 2017 2017/11/27 0027 + */ +public class SDKUtils { + //日志 + protected static final Log log = LogFactory.getLog(SDKUtils.class); + + /** + * 验证签名 + * + * @param resData + * 返回报文数据 + * @param encoding + * 编码格式 + * @return + */ + public static boolean validate(Map
resData, String encoding) { + log.info("验签处理开始"); + if (StringUtils.isEmpty(encoding)) { + encoding = "UTF-8"; + } + String signMethod = resData.get(SDKConstants.param_signMethod).toString(); + String version = resData.get(SDKConstants.param_version).toString(); + if (SIGNMETHOD_RSA.equals(signMethod) || VERSION_1_0_0.equals(version) || VERSION_5_0_1.equals(version)) { + // 获取返回报文的版本号 + if (VERSION_5_0_0.equals(version) || VERSION_1_0_0.equals(version) || VERSION_5_0_1.equals(version)) { + String stringSign = resData.get(SDKConstants.param_signature).toString(); + log.info("签名原文:["+stringSign+"]"); + // 从返回报文中获取certId ,然后去证书静态Map中查询对应验签证书对象 + String certId = resData.get(SDKConstants.param_certId).toString(); + log.info("对返回报文串验签使用的验签公钥序列号:["+certId+"]"); + // 将Map信息转换成key1=value1&key2=value2的形式 + String stringData = SignUtils.parameterText(resData); + log.info("待验签返回报文串:["+stringData+"]"); + try { + // 验证签名需要用银联发给商户的公钥证书. + return SecureUtil.validateSignBySoft(CertUtil.getValidatePublicKey(certId), Base64.decode(stringSign), + SecureUtil.sha1X16(stringData, encoding)); + } catch (UnsupportedEncodingException e) { + log.error(e.getMessage(), e); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } else if (VERSION_5_1_0.equals(version)) { + // 1.从返回报文中获取公钥信息转换成公钥对象 + String strCert = resData.get(SDKConstants.param_signPubKeyCert).toString(); + log.info("验签公钥证书:["+strCert+"]"); + X509Certificate x509Cert = CertUtil.genCertificateByStr(strCert); + if(x509Cert == null) { + log.error("convert signPubKeyCert failed"); + return false; + } + // 2.验证证书链 + if (!CertUtil.verifyCertificate(x509Cert)) { + log.error("验证公钥证书失败,证书信息:["+strCert+"]"); + return false; + } + + // 3.验签 + String stringSign = resData.get(SDKConstants.param_signature).toString(); + log.info("签名原文:["+stringSign+"]"); + // 将Map信息转换成key1=value1&key2=value2的形式 + String stringData = SignUtils.parameterText(resData); + log.info("待验签返回报文串:["+stringData+"]"); + try { + // 验证签名需要用银联发给商户的公钥证书. + boolean result = SecureUtil.validateSignBySoft256(x509Cert + .getPublicKey(), Base64.decode(stringSign + ), SHA256.sha256X16( + stringData, encoding)); + log.info("验证签名" + (result? "成功":"失败")); + return result; + } catch (UnsupportedEncodingException e) { + log.error(e.getMessage(), e); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + + } else if (SIGNMETHOD_SHA256.equals(signMethod)) { + // 1.进行SHA256验证 + String stringSign = resData.get(SDKConstants.param_signature).toString(); + log.info("签名原文:["+stringSign+"]"); + // 将Map信息转换成key1=value1&key2=value2的形式 + String stringData = SignUtils.parameterText(resData); + log.info("待验签返回报文串:["+stringData+"]"); + String strBeforeSha256 = stringData + + SDKConstants.AMPERSAND + + SecureUtil.sha256X16Str(SDKConfig.getConfig() + .getSecureKey(), encoding); + String strAfterSha256 = SecureUtil.sha256X16Str(strBeforeSha256, + encoding); + boolean result = stringSign.equals(strAfterSha256); + log.info("验证签名" + (result? "成功":"失败")); + return result; + } else if (SIGNMETHOD_SM3.equals(signMethod)) { + // 1.进行SM3验证 + String stringSign = resData.get(SDKConstants.param_signature).toString(); + log.info("签名原文:["+stringSign+"]"); + // 将Map信息转换成key1=value1&key2=value2的形式 + String stringData = SignUtils.parameterText(resData); + log.info("待验签返回报文串:["+stringData+"]"); + String strBeforeSM3 = stringData + + SDKConstants.AMPERSAND + + SecureUtil.sm3X16Str(SDKConfig.getConfig() + .getSecureKey(), encoding); + String strAfterSM3 = SecureUtil + .sm3X16Str(strBeforeSM3, encoding); + boolean result = stringSign.equals(strAfterSM3); + log.info("验证签名" + (result? "成功":"失败")); + return result; + } + return false; + } + + /** + * 对参数加密 + * @param data + * @param encoding + * @return + */ + public static boolean signParams(Map data,String encoding){ + if (StringUtils.isBlank(encoding)) { + encoding = "UTF-8"; + } + String signMethod = data.get(SDKConstants.param_signMethod); + String version = data.get(SDKConstants.param_version); + if(StringUtils.isBlank(signMethod)){ + log.info("银联签名方式不能为空"); + return false; + } + if(StringUtils.isBlank(version)){ + log.info("版本号不能为空"); + return false; + } + if (SIGNMETHOD_RSA.equals(signMethod)|| VERSION_1_0_0.equals(version) || SDKConstants.VERSION_5_0_1.equals(version)) { + if (SDKConstants.VERSION_5_0_0.equals(version) || VERSION_1_0_0.equals(version) || SDKConstants.VERSION_5_0_1.equals(version)) { + data.put(SDKConstants.param_certId, CertUtil.getSignCertId()); + String stringData = SignUtils.parameterText(data); + String stringSign = null; + try { + // 通过SHA1进行摘要并转16进制 + byte[] signDigest = SecureUtil + .sha1X16(stringData, encoding); + stringSign = RSA.sign(signDigest, CertUtil.getSignCertPrivateKey()); + // 设置签名域值 + data.put(SDKConstants.param_signature, stringSign); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + }else if (SDKConstants.SIGNMETHOD_SHA256.equals(signMethod)) { + String stringData = SignUtils.parameterText(data); + String strBeforeSha256 = stringData + + SDKConstants.AMPERSAND + + SecureUtil.sha256X16Str(SDKConfig.getConfig().getSecureKey(), encoding); + String strAfterSha256 = SecureUtil.sha256X16Str(strBeforeSha256, + encoding); + data.put(SDKConstants.param_signature, strAfterSha256); + } else if (SDKConstants.SIGNMETHOD_SM3.equals(signMethod)) { + String stringData = SignUtils.parameterText(data); + String strBeforeSM3 = stringData + + SDKConstants.AMPERSAND + + SecureUtil.sm3X16Str(SDKConfig.getConfig().getSecureKey(), encoding); + String strAfterSM3 = SecureUtil.sm3X16Str(strBeforeSM3, encoding); + // 设置签名域值 + data.put(SDKConstants.param_signature, strAfterSM3); + } + + return false; + } + + +} diff --git a/pay-java-union/src/main/java/com/egzosn/pay/union/api/UnionPayConfigStorage.java b/pay-java-union/src/main/java/com/egzosn/pay/union/api/UnionPayConfigStorage.java index 0b847ee..650e608 100644 --- a/pay-java-union/src/main/java/com/egzosn/pay/union/api/UnionPayConfigStorage.java +++ b/pay-java-union/src/main/java/com/egzosn/pay/union/api/UnionPayConfigStorage.java @@ -3,83 +3,88 @@ package com.egzosn.pay.union.api; import com.egzosn.pay.common.api.BasePayConfigStorage; /** - * 支付客户端配置存储 - * author egan - * - * email egzosn@gmail.com - * date 2016-5-18 14:09:01 + * @author Actinia + * @email hayesfu@qq.com + * + create 2017 2017/11/4 0004 + **/ public class UnionPayConfigStorage extends BasePayConfigStorage { - // 商户PID - public volatile String merId ; - // 商户签约拿到的pid,partner_id的简称,合作伙伴身份等同于 partner - public volatile String pid ; - //partner_id的简称,合作伙伴身份 -// public volatile String partner ; + /** + * 商户号 + */ + public volatile String merId; - // 商户收款账号 - public volatile String seller; + /** + * 商户收款账号 + */ + public volatile String seller; //公钥 private volatile String aliPublicKey; - //全渠道固定值 - public static String version = "5.0.0"; - public String getAliPublicKey() { + + + public String getAliPublicKey () { return aliPublicKey; } - public void setAliPublicKey(String aliPublicKey) { + public void setAliPublicKey (String aliPublicKey) { setKeyPublic(aliPublicKey); this.aliPublicKey = aliPublicKey; } - @Override - public String getAppid() { + public String getAppid () { return null; } /** - * @see #getPid() * @return 合作者id + * @see #getPid() */ @Deprecated @Override - public String getPartner() { - return pid; + public String getPartner () { + return merId; } /** * 设置合作者id - * @see #setPid(String) + * * @param partner 合作者id + * @see #setPid(String) */ @Deprecated - public void setPartner(String partner) { - this.pid = partner; + public void setPartner (String partner) { + this.merId = partner; } @Override - public String getPid() { - return pid; + public String getPid () { + return merId; } - public void setPid(String pid) { - this.pid = pid; + public void setPid (String pid) { + this.merId = pid; } - - public String getSeller() { + @Override + public String getSeller () { return seller; } - public void setSeller(String seller) { + public void setSeller (String seller) { this.seller = seller; } + public String getMerId () { + return merId; + } - + public void setMerId (String merId) { + this.merId = merId; + } } diff --git a/pay-java-union/src/main/java/com/egzosn/pay/union/api/UnionPayService.java b/pay-java-union/src/main/java/com/egzosn/pay/union/api/UnionPayService.java new file mode 100644 index 0000000..3136169 --- /dev/null +++ b/pay-java-union/src/main/java/com/egzosn/pay/union/api/UnionPayService.java @@ -0,0 +1,464 @@ +package com.egzosn.pay.union.api; + +import com.alibaba.fastjson.JSONObject; +import com.egzosn.pay.common.api.BasePayService; +import com.egzosn.pay.common.api.Callback; +import com.egzosn.pay.common.api.PayConfigStorage; +import com.egzosn.pay.common.bean.*; +import com.egzosn.pay.common.bean.result.PayException; +import com.egzosn.pay.common.exception.PayErrorException; +import com.egzosn.pay.common.http.HttpConfigStorage; +import com.egzosn.pay.common.util.MatrixToImageWriter; +import com.egzosn.pay.common.util.str.StringUtils; +import com.egzosn.pay.union.SDK.CertUtil; +import com.egzosn.pay.union.SDK.SDKConfig; +import com.egzosn.pay.union.SDK.SDKConstants; +import com.egzosn.pay.union.SDK.SDKUtils; +import com.egzosn.pay.union.enums.UnionTransactionType; +import com.egzosn.pay.union.request.UnionQueryOrder; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.awt.image.BufferedImage; +import java.io.InputStream; +import java.math.BigDecimal; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Actinia + * @email hayesfu@qq.com + * @create 2017 2017/11/5 0005 + */ +public class UnionPayService extends BasePayService { + //日志 + protected static final Log log = LogFactory.getLog(UnionPayService.class); + + + public UnionPayService (PayConfigStorage payConfigStorage) { + super(payConfigStorage); + } + + public UnionPayService (PayConfigStorage payConfigStorage, HttpConfigStorage configStorage) { + super(payConfigStorage, configStorage); + SDKConfig.getConfig().loadPropertiesFromSrc(); + } + + /** + * 银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改 + * @return 返回参数集合 + */ + private MapgetCommonParam(){ + Map params = new HashMap<>(); + params.put(SDKConstants.param_version, SDKConfig.getConfig().getVersion()); + params.put(SDKConstants.param_encoding, payConfigStorage.getInputCharset().toUpperCase()); + params.put(SDKConstants.param_signMethod, SDKConfig.getConfig().getSignMethodByStr(payConfigStorage.getSignType())); + params.put(SDKConstants.param_merId, payConfigStorage.getPid()); + //接入类型,商户接入填0 ,不需修改(0:直连商户, 1: 收单机构 2:平台商户) + params.put(SDKConstants.param_accessType, "0"); + DateFormat df = new SimpleDateFormat("YYYYMMDDhhmmss"); + params.put(SDKConstants.param_txnTime, df.format(new Date())); + params.put(SDKConstants.param_backUrl, SDKConfig.getConfig().getBackUrl()); + return params; + } + + + /** + * 回调校验 + * + * @param result 回调回来的参数集 + * @return 签名校验 true通过 + */ + @Override + public boolean verify (Map result) { + if(result != null){ + if(SDKUtils.validate(result, payConfigStorage.getInputCharset())){ + String respCode = result.get("respCode").toString(); + if(("00").equals(respCode)){ + + //成功,获取tn号 + //String tn = resmap.get("tn"); + //TODO + return true; + }else{ + //其他应答码为失败请排查原因或做失败处理 + //TODO + } + }else{ +// 校验失败 + } + }else{ + + } + return false; + } + + /** + * 签名校验 + * + * @param params 参数集 + * @param sign 签名 + * @return 签名校验 true通过 + */ + @Override + public boolean signVerify (Map params, String sign) { + return false; + } + + /** + * 支付宝需要,微信是否也需要再次校验来源,进行订单查询 + * 校验数据来源 + * + * @param id 业务id, 数据的真实性. + * @return true通过 + */ + @Override + public boolean verifySource (String id) { + return false; + } + + /** + * 返回创建的订单信息 + * + * @param order 支付订单 + * @return 订单信息 + * @see PayOrder 支付订单信息 + */ + @Override + public Map orderInfo (PayOrder order) { + Map params = this.getCommonParam(); + UnionTransactionType type = (UnionTransactionType)order.getTransactionType(); + type.convertMap(params); + switch (type){ + case APPLY_QR_CODE: + params.put(SDKConstants.param_orderId, order.getOutTradeNo()); + params.put(SDKConstants.param_txnAmt, order.getPrice().toString()); + params.put(SDKConstants.param_currencyCode, "156"); + break; + case CONSUME: + params.put(SDKConstants.param_orderId, order.getOutTradeNo()); + params.put(SDKConstants.param_txnAmt, order.getPrice().toString()); + params.put(SDKConstants.param_currencyCode, "156"); + + params.put(SDKConstants.param_qrNo, order.getAuthCode()); + params.put(SDKConstants.param_termId, order.getDeviceInfo()); + break; + default: + } + + return params; + } + + + /** + * 获取输出二维码,用户返回给支付端, + * + * @param order 发起支付的订单信息 + * @return 返回图片信息,支付时需要的 + */ + @Override + public BufferedImage genQrPay (PayOrder order) { + Map params = orderInfo(order); + CertUtil.sign(params,payConfigStorage.getInputCharset().toUpperCase()); + JSONObject response = getHttpRequestTemplate().postForObject(SDKConfig.getConfig().getBackRequestUrl(),params,JSONObject.class); + if(SDKUtils.validate(response,payConfigStorage.getInputCharset().toUpperCase())){ + if("00".equals(response.getString(SDKConstants.param_respCode))){ + //成功,获取tn号 + return MatrixToImageWriter.writeInfoToJpgBuff( response.getString(SDKConstants.param_respCode)); + }else{ + throw new PayErrorException(new PayException(response.getString(SDKConstants.param_respCode), response.getString(SDKConstants.param_respMsg), response.toJSONString())); + } + }else{ + throw new PayErrorException(new PayException("1000", "验证签名失败", response.toJSONString())); + } + } + + /** + * 刷卡付,pos主动扫码付款(条码付) + * + * @param order 发起支付的订单信息 + * @return 返回支付结果 + */ + @Override + public Map microPay (PayOrder order) { + Map params = orderInfo(order); + CertUtil.sign(params,payConfigStorage.getInputCharset().toUpperCase()); + return getHttpRequestTemplate().postForObject(SDKConfig.getConfig().getBackRequestUrl(),params,JSONObject.class); + } + + + /** + * 交易查询接口 + * + * @param tradeNo 支付平台订单号 + * @param outTradeNo 商户单号 + * @return 返回查询回来的结果集,支付方原值返回 + */ + @Override + public Map query (String tradeNo, String outTradeNo) { + Map params = this.getCommonParam(); + UnionTransactionType.QUERY.convertMap(params); + params.put(SDKConstants.param_orderId,outTradeNo); + CertUtil.sign(params,payConfigStorage.getInputCharset().toUpperCase()); + JSONObject response = getHttpRequestTemplate().postForObject(SDKConfig.getConfig().getBackRequestUrl(),params,JSONObject.class); + if(SDKUtils.validate(response,payConfigStorage.getInputCharset().toUpperCase())){ + if("00".equals(response.getString(SDKConstants.param_respCode))){ + String origRespCode = response.getString(SDKConstants.param_origRespCode); + if(("00").equals(origRespCode)){ + //交易成功,更新商户订单状态 + //TODO + return response; + }else{ + throw new PayErrorException(new PayException(response.getString(SDKConstants.param_respCode), response.getString(SDKConstants.param_respMsg), response.toJSONString())); + } + }else{ + throw new PayErrorException(new PayException(response.getString(SDKConstants.param_respCode), response.getString(SDKConstants.param_respMsg), response.toJSONString())); + } + }else{ + throw new PayErrorException(new PayException("1000", "验证签名失败", response.toJSONString())); + } + } + + /** + * 消费撤销/退货接口 + * + * @return 返回支付方申请退款后的结果 + */ + public Map unionRefundOrConsumeUndo (UnionQueryOrder queryOrder,UnionTransactionType type) { + Map params = this.getCommonParam(); + type.convertMap(params); + params.put(SDKConstants.param_orderId,queryOrder.getOrderId()); + params.put(SDKConstants.param_txnAmt,queryOrder.getTxnAmt()); + if(StringUtils.isNotBlank(queryOrder.getOrigQryId())) { + params.put(SDKConstants.param_origQryId, queryOrder.getOrigQryId()); + } + if(StringUtils.isNotBlank(queryOrder.getOrigOrderId())){ + params.put(SDKConstants.param_origOrderId,queryOrder.getOrigOrderId()); + } + if(StringUtils.isNotBlank(queryOrder.getOrigTxnTime())) { + params.put(SDKConstants.param_origTxnTime, queryOrder.getOrigOrderId()); + } + CertUtil.sign(params,payConfigStorage.getInputCharset().toUpperCase()); + JSONObject response = getHttpRequestTemplate().postForObject(SDKConfig.getConfig().getBackRequestUrl(),params,JSONObject.class); + if(SDKUtils.validate(response,payConfigStorage.getInputCharset().toUpperCase())){ + if("00".equals(response.getString(SDKConstants.param_respCode))){ + String origRespCode = response.getString(SDKConstants.param_origRespCode); + //交易成功,更新商户订单状态 + //TODO + return response; + + }else{ + throw new PayErrorException(new PayException(response.getString(SDKConstants.param_respCode), response.getString(SDKConstants.param_respMsg), response.toJSONString())); + } + }else{ + throw new PayErrorException(new PayException("1000", "验证签名失败", response.toJSONString())); + } + } + + /** + * 将请求参数或者请求流转化为 Map + * + * @param parameterMap 请求参数 + * @param is 请求流 + * @return 获得回调的请求参数 + */ + @Override + public Map getParameter2Map (Map parameterMap, InputStream is) { + return null; + } + + /** + * 获取输出消息,用户返回给支付端 + * + * @param code 状态 + * @param message 消息 + * @return 返回输出消息 + */ + @Override + public PayOutMessage getPayOutMessage (String code, String message) { + return null; + } + + /** + * 获取成功输出消息,用户返回给支付端 + * 主要用于拦截器中返回 + * + * @param payMessage 支付回调消息 + * @return 返回输出消息 + */ + @Override + public PayOutMessage successPayOutMessage (PayMessage payMessage) { + return null; + } + + /** + * 获取输出消息,用户返回给支付端, 针对于web端 + * + * @param orderInfo 发起支付的订单信息 + * @param method 请求方式 "post" "get", + * @return 获取输出消息,用户返回给支付端, 针对于web端 + * @see MethodType 请求类型 + */ + @Override + public String buildRequest (Map orderInfo, MethodType method) { + return null; + } + + + /** + * 交易查询接口,带处理器 + * + * @param tradeNo 支付平台订单号 + * @param outTradeNo 商户单号 + * @param callback 处理器 + * @return 返回查询回来的结果集 + */ + @Override + public T query (String tradeNo, String outTradeNo, Callback callback) { + return null; + } + + /** + * 交易关闭接口 + * + * @param tradeNo 支付平台订单号 + * @param outTradeNo 商户单号 + * @return 返回支付方交易关闭后的结果 + */ + @Override + public Map close (String tradeNo, String outTradeNo) { + return null; + } + + /** + * 交易关闭接口 + * + * @param tradeNo 支付平台订单号 + * @param outTradeNo 商户单号 + * @param callback 处理器 + * @return 返回支付方交易关闭后的结果 + */ + @Override + public T close (String tradeNo, String outTradeNo, Callback callback) { + return null; + } + + /** + * 申请退款接口 + * + * @param tradeNo 支付平台订单号 + * @param outTradeNo 商户单号 + * @param refundAmount 退款金额 + * @param totalAmount 总金额 + * @return 返回支付方申请退款后的结果 + */ + @Override + public Map refund (String tradeNo, String outTradeNo, BigDecimal refundAmount, BigDecimal totalAmount) { + return null; + } + + + + /** + * 申请退款接口 + * + * @param tradeNo 支付平台订单号 + * @param outTradeNo 商户单号 + * @param refundAmount 退款金额 + * @param totalAmount 总金额 + * @param callback 处理器 + * @return 返回支付方申请退款后的结果 + */ + @Override + public T refund (String tradeNo, String outTradeNo, BigDecimal refundAmount, BigDecimal totalAmount, Callback callback) { + return null; + } + + /** + * 查询退款 + * + * @param tradeNo 支付平台订单号 + * @param outTradeNo 商户单号 + * @return 返回支付方查询退款后的结果 + */ + @Override + public Map refundquery (String tradeNo, String outTradeNo) { + return null; + } + + /** + * 查询退款 + * + * @param tradeNo 支付平台订单号 + * @param outTradeNo 商户单号 + * @param callback 处理器 + * @return 返回支付方查询退款后的结果 + */ + @Override + public T refundquery (String tradeNo, String outTradeNo, Callback callback) { + return null; + } + + /** + * 下载对账单 + * + * @param billDate 账单时间 + * @param billType 账单类型 + * @return 返回fileContent 请自行将数据落地 + */ + @Override + public Object downloadbill (Date billDate, String billType) { + Map params = this.getCommonParam(); + UnionTransactionType.File_Transfer.convertMap(params); + DateFormat df = new SimpleDateFormat("MMDD"); + params.put(SDKConstants.param_settleDate,df.format(new Date())); + params.put(SDKConstants.param_fileType,billType); + CertUtil.sign(params,payConfigStorage.getInputCharset().toUpperCase()); + Map response = getHttpRequestTemplate().postForObject(SDKConfig.getConfig().getBackRequestUrl(),params,Map.class); + if(SDKUtils.validate(response,payConfigStorage.getInputCharset().toUpperCase())){ + if("00".equals(response.get(SDKConstants.param_respCode))){ + + return response.get(SDKConstants.param_fileContent).toString(); + + }else{ + throw new PayErrorException(new PayException(response.get(SDKConstants.param_respCode).toString(), response.get(SDKConstants.param_respMsg).toString(), response.toString())); + } + }else{ + throw new PayErrorException(new PayException("1000", "验证签名失败", response.toString())); + } + } + + /** + * 下载对账单 + * + * @param billDate 账单时间:具体请查看对应支付平台 + * @param billType 账单类型,具体请查看对应支付平台 + * @param callback 处理器 + * @return 返回支付方下载对账单的结果 + */ + @Override + public T downloadbill (Date billDate, String billType, Callback callback) { + return null; + } + + /** + * 通用查询接口 + * + * @param tradeNoOrBillDate 支付平台订单号或者账单日期, 具体请 类型为{@link String }或者 {@link Date },类型须强制限制,类型不对应则抛出异常{@link PayErrorException} + * @param outTradeNoBillType 商户单号或者 账单类型 + * @param transactionType 交易类型 + * @param callback 处理器 + * @return 返回支付方对应接口的结果 + */ + @Override + public T secondaryInterface (Object tradeNoOrBillDate, String outTradeNoBillType, TransactionType transactionType, Callback callback) { + return null; + } + + + + +} diff --git a/pay-java-union/src/main/java/com/egzosn/pay/union/enums/UnionTransactionType.java b/pay-java-union/src/main/java/com/egzosn/pay/union/enums/UnionTransactionType.java new file mode 100644 index 0000000..19b2318 --- /dev/null +++ b/pay-java-union/src/main/java/com/egzosn/pay/union/enums/UnionTransactionType.java @@ -0,0 +1,98 @@ +package com.egzosn.pay.union.enums; + +import com.egzosn.pay.common.bean.TransactionType; +import com.egzosn.pay.union.SDK.SDKConstants; + +import java.util.Map; + +/** + * @author Actinia + * @email hayesfu@qq.com + * + create 2017 2017/11/4 0004 + *+ */ +public enum UnionTransactionType implements TransactionType{ + //申码(主扫场景) + APPLY_QR_CODE("01","07","000000","08"), + //消费(被扫场景) + CONSUME("01","06","000000","08"), + //消费撤销 + CONSUME_UNDO("31","00","000000","08"), + //查询 + QUERY("00","00","000201",""), + //退款 + REFUND("04","00","000000","08"), + //对账文件下载 + File_Transfer("00","00","000201","") + ; + + /** + * 交易类型 + */ + private String txnType; + /** + * 交易子类 + */ + private String txnSubType; + + /** + * 业务类型 + */ + private String bizType; + + /** + * 渠道类型 + */ + private String channelType; + + + UnionTransactionType (String txnType, String txnSubType, String bizType, String channelType) { + this.txnType = txnType; + this.txnSubType = txnSubType; + this.bizType = bizType; + this.channelType = channelType; + } + + public void convertMap(MapcontentData){ + contentData.put(SDKConstants.param_txnType, this.getTxnType()); + contentData.put(SDKConstants.param_txnSubType,this.getTxnSubType()); + contentData.put(SDKConstants.param_bizType,this.getBizType()); + contentData.put(SDKConstants.param_channelType,this.getChannelType()); + } + + + public String getTxnType () { + return txnType; + } + + public String getTxnSubType () { + return txnSubType; + } + + public String getBizType () { + return bizType; + } + + public String getChannelType () { + return channelType; + } + + /** + *获取交易对类型枚举 + * + * @return 交易类型 + */ + @Override + public String getType () { + return this.name(); + } + + /** + * + */ + @Override + public String getMethod () { + return null; + } +} diff --git a/pay-java-union/src/main/java/com/egzosn/pay/union/request/UnionQueryOrder.java b/pay-java-union/src/main/java/com/egzosn/pay/union/request/UnionQueryOrder.java new file mode 100644 index 0000000..8aad82a --- /dev/null +++ b/pay-java-union/src/main/java/com/egzosn/pay/union/request/UnionQueryOrder.java @@ -0,0 +1,82 @@ +package com.egzosn.pay.union.request; + +/** + * @author Actinia + * @email hayesfu@qq.com + * +create 2017 2017/11/4 0004 + *+ */ +public class UnionQueryOrder { + + private Integer payId; + /** + * 支付平台订单号 + */ + private String orderId; + /** + * 金额 + */ + private String txnAmt; + /** + * 原交易查询流水号 + */ + private String origQryId; + /** + * 原交易商户订单号 + */ + private String origOrderId; + /** + * 原交易商户发送交易时间: + */ + private String origTxnTime; + + + public Integer getPayId() { + return payId; + } + + public void setPayId(Integer payId) { + this.payId = payId; + } + + public String getOrderId () { + return orderId; + } + + public void setOrderId (String orderId) { + this.orderId = orderId; + } + + public String getTxnAmt () { + return txnAmt; + } + + public void setTxnAmt (String txnAmt) { + this.txnAmt = txnAmt; + } + + public String getOrigQryId () { + return origQryId; + } + + public void setOrigQryId (String origQryId) { + this.origQryId = origQryId; + } + + public String getOrigOrderId () { + return origOrderId; + } + + public void setOrigOrderId (String origOrderId) { + this.origOrderId = origOrderId; + } + + public String getOrigTxnTime () { + return origTxnTime; + } + + public void setOrigTxnTime (String origTxnTime) { + this.origTxnTime = origTxnTime; + } +} diff --git a/pom.xml b/pom.xml index 4ee3d9f..27e4dc2 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@@@ -76,7 +76,12 @@ Actinia -412605202@qq.com +hayesfu@qq.com https://github.com/Actinian fastjson 1.2.17 - + ++ org.bouncycastle +bcprov-debug-jdk15on +1.58 +