You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
587 lines
20 KiB
587 lines
20 KiB
package com.hai.common.utils;
|
|
|
|
import com.alibaba.fastjson.JSON;
|
|
import com.google.common.collect.Maps;
|
|
import com.hai.common.pay.util.sdk.WXPayConstants;
|
|
import com.hai.common.pay.util.sdk.WXPayXmlUtil;
|
|
import com.thoughtworks.xstream.XStream;
|
|
import com.thoughtworks.xstream.io.naming.NoNameCoder;
|
|
import com.thoughtworks.xstream.io.xml.XppDriver;
|
|
|
|
import net.sf.cglib.beans.BeanMap;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
|
|
|
import javax.crypto.Mac;
|
|
import javax.crypto.spec.SecretKeySpec;
|
|
|
|
import javax.xml.transform.OutputKeys;
|
|
import javax.xml.transform.Transformer;
|
|
import javax.xml.transform.TransformerFactory;
|
|
import javax.xml.transform.dom.DOMSource;
|
|
import javax.xml.transform.stream.StreamResult;
|
|
|
|
import java.io.StringWriter;
|
|
import java.security.MessageDigest;
|
|
import java.security.SecureRandom;
|
|
import java.util.*;
|
|
|
|
public class WxUtils {
|
|
|
|
private static final Random RANDOM = new SecureRandom();
|
|
|
|
private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
|
|
|
|
/**
|
|
* 生成签名
|
|
*
|
|
* @param signMaps
|
|
* @return
|
|
* @throws Exception
|
|
*/
|
|
public static String generateSign(SortedMap<String, String> signMaps, String mchKey) {
|
|
StringBuffer sb = new StringBuffer();
|
|
|
|
// 字典序
|
|
for (Map.Entry signMap : signMaps.entrySet()) {
|
|
String key = (String) signMap.getKey();
|
|
String value = (String) signMap.getValue();
|
|
|
|
// 为空不参与签名、参数名区分大小写
|
|
if (null != value && !"".equals(value) && !"sign".equals(key) && !"key".equals(key)) {
|
|
sb.append(key).append("=").append(value).append("&");
|
|
}
|
|
}
|
|
|
|
// 拼接key
|
|
sb.append("key=").append(mchKey);
|
|
// MD5加密
|
|
String sign = MD5Encode(sb.toString(), "UTF-8").toUpperCase();
|
|
return sign;
|
|
}
|
|
|
|
public static String generateSignSHA256(SortedMap<String, String> signMaps,String mchKey)throws Exception{
|
|
StringBuffer sb = new StringBuffer();
|
|
|
|
// 字典序
|
|
for (Map.Entry signMap : signMaps.entrySet()) {
|
|
String key = (String) signMap.getKey();
|
|
String value = (String) signMap.getValue();
|
|
|
|
// 为空不参与签名、参数名区分大小写
|
|
if (null != value && !"".equals(value) && !"sign".equals(key) && !"key".equals(key)) {
|
|
sb.append(key).append("=").append(value).append("&");
|
|
}
|
|
}
|
|
|
|
// 拼接key
|
|
sb.append("key=").append(mchKey);
|
|
// HMACSHA256加密
|
|
String sign = HMACSHA256(sb.toString(), mchKey).toUpperCase();
|
|
return sign;
|
|
}
|
|
|
|
private static String byteArrayToHexString(byte b[]) {
|
|
StringBuffer resultSb = new StringBuffer();
|
|
for (int i = 0; i < b.length; i++)
|
|
resultSb.append(byteToHexString(b[i]));
|
|
|
|
return resultSb.toString();
|
|
}
|
|
|
|
private static String byteToHexString(byte b) {
|
|
int n = b;
|
|
if (n < 0)
|
|
n += 256;
|
|
int d1 = n / 16;
|
|
int d2 = n % 16;
|
|
return hexDigits[d1] + hexDigits[d2];
|
|
}
|
|
|
|
public static String MD5Encode(String origin, String charsetname) {
|
|
String resultString = null;
|
|
try {
|
|
resultString = new String(origin);
|
|
MessageDigest md = MessageDigest.getInstance("MD5");
|
|
if (charsetname == null || "".equals(charsetname))
|
|
resultString = byteArrayToHexString(md.digest(resultString
|
|
.getBytes()));
|
|
else
|
|
resultString = byteArrayToHexString(md.digest(resultString
|
|
.getBytes(charsetname)));
|
|
} catch (Exception exception) {
|
|
}
|
|
return resultString;
|
|
}
|
|
|
|
private static final String[] hexDigits = { "0", "1", "2", "3", "4", "5",
|
|
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
|
|
|
|
|
|
|
|
private static HashMap<String, String> sortAsc(Map<String, String> map) {
|
|
HashMap<String, String> tempMap = new LinkedHashMap<String, String>();
|
|
List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(map.entrySet());
|
|
//排序
|
|
infoIds.sort(new Comparator<Map.Entry<String, String>>() {
|
|
@Override
|
|
public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
|
|
return o1.getKey().compareTo(o2.getKey());
|
|
}
|
|
});
|
|
|
|
for (int i = 0; i < infoIds.size(); i++) {
|
|
Map.Entry<String, String> item = infoIds.get(i);
|
|
tempMap.put(item.getKey(), item.getValue());
|
|
}
|
|
return tempMap;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* 生成 HMACSHA256
|
|
* @param data 待处理数据
|
|
* @param key 密钥
|
|
* @return 加密结果
|
|
* @throws Exception
|
|
*/
|
|
public static String HMACSHA256(String data, String key) throws Exception {
|
|
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
|
|
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
|
|
sha256_HMAC.init(secret_key);
|
|
byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
|
|
StringBuilder sb = new StringBuilder();
|
|
for (byte item : array) {
|
|
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
|
|
}
|
|
return sb.toString().toUpperCase();
|
|
}
|
|
|
|
/**
|
|
* 获取随机字符串 Nonce Str
|
|
*
|
|
* @return String 随机字符串
|
|
*/
|
|
public static String makeNonStr() {
|
|
char[] nonceChars = new char[32];
|
|
for (int index = 0; index < nonceChars.length; ++index) {
|
|
nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
|
|
}
|
|
return new String(nonceChars);
|
|
}
|
|
|
|
/**
|
|
* 拼接签名数据
|
|
*
|
|
*/
|
|
public static String makeSign(BeanMap beanMap, String mchKey, String signType)throws Exception {
|
|
SortedMap<String, String> signMaps = Maps.newTreeMap();
|
|
|
|
for (Object key : beanMap.keySet()) {
|
|
Object value = beanMap.get(key);
|
|
|
|
// 排除空数据
|
|
if (value == null) {
|
|
continue;
|
|
}
|
|
signMaps.put(key + "", String.valueOf(value));
|
|
}
|
|
if(signType.equals("MD5")) {
|
|
// 生成签名
|
|
return generateSign(signMaps, mchKey);
|
|
}else if(signType.equals("SHA256")){
|
|
return generateSignSHA256(signMaps, mchKey);
|
|
}else{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 数据转换为xml格式
|
|
*
|
|
* @param object
|
|
* @param obj
|
|
* @return
|
|
*/
|
|
public static String truncateDataToXML(Class<?> object, Object obj) {
|
|
XStream xStream = new XStream(new XppDriver(new NoNameCoder()));
|
|
xStream.alias("xml", object);
|
|
return xStream.toXML(obj);
|
|
}
|
|
|
|
|
|
/**
|
|
* 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
|
|
*
|
|
* @param data 待签名数据
|
|
* @param key API密钥
|
|
* @param signType 签名方式
|
|
* @return 签名
|
|
*/
|
|
public static String generateSignature(final Map<String, String> data, String key, WXPayConstants.SignType signType) throws Exception {
|
|
Set<String> keySet = data.keySet();
|
|
String[] keyArray = keySet.toArray(new String[keySet.size()]);
|
|
Arrays.sort(keyArray);
|
|
StringBuilder sb = new StringBuilder();
|
|
for (String k : keyArray) {
|
|
if (k.equals(WXPayConstants.FIELD_SIGN)) {
|
|
continue;
|
|
}
|
|
if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
|
|
sb.append(k).append("=").append(data.get(k).trim()).append("&");
|
|
}
|
|
sb.append("key=").append(key);
|
|
if (WXPayConstants.SignType.MD5.equals(signType)) {
|
|
return MD5(sb.toString() , true);
|
|
}
|
|
else if (WXPayConstants.SignType.HMACSHA256.equals(signType)) {
|
|
return HMACSHA256(sb.toString(), key);
|
|
}
|
|
else {
|
|
throw new Exception(String.format("Invalid sign_type: %s", signType));
|
|
}
|
|
}
|
|
|
|
|
|
public static String generateSignatureAppSecret(final Map<String, Object> data, String key, WXPayConstants.SignType signType) throws Exception {
|
|
Set<String> keySet = data.keySet();
|
|
String[] keyArray = keySet.toArray(new String[keySet.size()]);
|
|
Arrays.sort(keyArray);
|
|
StringBuilder sb = new StringBuilder();
|
|
for (String k : keyArray) {
|
|
if (k.equals(WXPayConstants.FIELD_SIGN)) {
|
|
continue;
|
|
}
|
|
if (StringUtils.isBlank(sb.toString())) {
|
|
sb.append(k).append("=").append(data.get(k));
|
|
} else {
|
|
sb.append("&").append(k).append("=").append(data.get(k));
|
|
}
|
|
}
|
|
sb.append("&app_secret=").append(key);
|
|
if (WXPayConstants.SignType.MD5.equals(signType)) {
|
|
return MD5(sb.toString() , false);
|
|
}
|
|
else if (WXPayConstants.SignType.HMACSHA256.equals(signType)) {
|
|
return HMACSHA256(sb.toString(), key);
|
|
}
|
|
else {
|
|
throw new Exception(String.format("Invalid sign_type: %s", signType));
|
|
}
|
|
}
|
|
|
|
public static String generateSignature(final Map<String, Object> data) throws Exception {
|
|
Set<String> keySet = data.keySet();
|
|
String[] keyArray = keySet.toArray(new String[keySet.size()]);
|
|
Arrays.sort(keyArray);
|
|
StringBuilder sb = new StringBuilder();
|
|
for (String k : keyArray) {
|
|
if (k.equals(WXPayConstants.FIELD_SIGN)) {
|
|
continue;
|
|
}
|
|
if (StringUtils.isBlank(sb.toString())) {
|
|
sb.append(k).append("=").append(data.get(k));
|
|
} else {
|
|
sb.append("&").append(k).append("=").append(data.get(k));
|
|
}
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
public static String generateSignature2(final Map<String, Object> data, String sign, String key) throws Exception {
|
|
Set<String> keySet = data.keySet();
|
|
String[] keyArray = keySet.toArray(new String[keySet.size()]);
|
|
Arrays.sort(keyArray);
|
|
StringBuilder sb = new StringBuilder();
|
|
for (String k : keyArray) {
|
|
if (k.equals(WXPayConstants.FIELD_SIGN)) {
|
|
continue;
|
|
}
|
|
if (data.get(k) != null) // 参数值为空,则不参与签名
|
|
sb.append(k).append("=").append(data.get(k)).append("&");
|
|
}
|
|
if (key != null) {
|
|
sb.append("app_secret=").append(key);
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
/**
|
|
* 生成 MD5
|
|
*
|
|
* @param data 待处理数据
|
|
* @return MD5结果
|
|
*/
|
|
public static String MD5(String data , Boolean isUpperCase) throws Exception {
|
|
java.security.MessageDigest md = MessageDigest.getInstance("MD5");
|
|
byte[] array = md.digest(data.getBytes("UTF-8"));
|
|
StringBuilder sb = new StringBuilder();
|
|
for (byte item : array) {
|
|
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
|
|
}
|
|
if (isUpperCase) {
|
|
return sb.toString().toUpperCase();
|
|
} else {
|
|
return sb.toString();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* 将Map转换为XML格式的字符串
|
|
*
|
|
* @param data Map类型数据
|
|
* @return XML格式的字符串
|
|
* @throws Exception
|
|
*/
|
|
public static String mapToXml(Map<String, String> data) throws Exception {
|
|
org.w3c.dom.Document document = WXPayXmlUtil.newDocument();
|
|
org.w3c.dom.Element root = document.createElement("xml");
|
|
document.appendChild(root);
|
|
for (String key: data.keySet()) {
|
|
String value = data.get(key);
|
|
if (value == null) {
|
|
value = "";
|
|
}
|
|
value = value.trim();
|
|
org.w3c.dom.Element filed = document.createElement(key);
|
|
filed.appendChild(document.createTextNode(value));
|
|
root.appendChild(filed);
|
|
}
|
|
TransformerFactory tf = TransformerFactory.newInstance();
|
|
Transformer transformer = tf.newTransformer();
|
|
DOMSource source = new DOMSource(document);
|
|
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
|
|
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
|
StringWriter writer = new StringWriter();
|
|
StreamResult result = new StreamResult(writer);
|
|
transformer.transform(source, result);
|
|
String output = writer.getBuffer().toString(); //.replaceAll("|\r", "");
|
|
try {
|
|
writer.close();
|
|
}
|
|
catch (Exception ex) {
|
|
}
|
|
return output;
|
|
}
|
|
|
|
|
|
/**
|
|
* 千猪生成签名。
|
|
*
|
|
* @param data 待签名数据
|
|
* @param secret API密钥
|
|
* @param signType 签名方式
|
|
* @return 签名
|
|
*/
|
|
public static String generateSignaturePig(final Map<String, String> data, String secret, WXPayConstants.SignType signType) throws Exception {
|
|
Set<String> keySet = data.keySet();
|
|
String[] keyArray = keySet.toArray(new String[keySet.size()]);
|
|
Arrays.sort(keyArray);
|
|
StringBuilder sb = new StringBuilder();
|
|
for (String k : keyArray) {
|
|
if (k.equals(WXPayConstants.FIELD_SIGN)) {
|
|
continue;
|
|
}
|
|
if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
|
|
sb.append(k).append("=").append(data.get(k).trim()).append("&");
|
|
}
|
|
String s = sb.substring(0, sb.length() - 1) + secret;
|
|
|
|
if (WXPayConstants.SignType.MD5.equals(signType)) {
|
|
return MD5(sb.toString() , false);
|
|
}
|
|
else if (WXPayConstants.SignType.HMACSHA256.equals(signType)) {
|
|
return HMACSHA256(s, secret);
|
|
}
|
|
else {
|
|
throw new Exception(String.format("Invalid sign_type: %s", signType));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 生成龙阅签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
|
|
*
|
|
* @param data 待签名数据
|
|
* @param key API密钥
|
|
* @param signType 签名方式
|
|
* @return 签名
|
|
*/
|
|
public static String generateSignatureLy(final Map<String, Object> data, String key, WXPayConstants.SignType signType) throws Exception {
|
|
Set<String> keySet = data.keySet();
|
|
String[] keyArray = keySet.toArray(new String[keySet.size()]);
|
|
Arrays.sort(keyArray);
|
|
StringBuilder sb = new StringBuilder();
|
|
for (String k : keyArray) {
|
|
if (k.equals(WXPayConstants.FIELD_SIGN)) {
|
|
continue;
|
|
}
|
|
if (data.get(k) != null) // 参数值为空,则不参与签名
|
|
sb.append(k).append("=").append(data.get(k)).append("&");
|
|
}
|
|
sb.append("apikey=").append(key);
|
|
if (WXPayConstants.SignType.MD5.equals(signType)) {
|
|
return MD5(sb.toString() , true);
|
|
}
|
|
else if (WXPayConstants.SignType.HMACSHA256.equals(signType)) {
|
|
return HMACSHA256(sb.toString(), key);
|
|
}
|
|
else {
|
|
throw new Exception(String.format("Invalid sign_type: %s", signType));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 生成龙阅签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
|
|
*
|
|
* @param data 待签名数据
|
|
* @param key API密钥
|
|
* @param signType 签名方式
|
|
* @return 签名
|
|
*/
|
|
public static String generateSignatureCy(final Map<String, Object> data, String key, WXPayConstants.SignType signType) throws Exception {
|
|
Set<String> keySet = data.keySet();
|
|
String[] keyArray = keySet.toArray(new String[keySet.size()]);
|
|
Arrays.sort(keyArray);
|
|
StringBuilder sb = new StringBuilder();
|
|
for (String k : keyArray) {
|
|
if (k.equals(WXPayConstants.FIELD_SIGN)) {
|
|
continue;
|
|
}
|
|
if (data.get(k) != null) // 参数值为空,则不参与签名
|
|
sb.append(k).append("=").append(data.get(k)).append("&");
|
|
}
|
|
sb.append("appsecret=").append(key);
|
|
if (WXPayConstants.SignType.MD5.equals(signType)) {
|
|
return MD5(sb.toString() , true);
|
|
}
|
|
else if (WXPayConstants.SignType.HMACSHA256.equals(signType)) {
|
|
return HMACSHA256(sb.toString(), key);
|
|
}
|
|
else {
|
|
throw new Exception(String.format("Invalid sign_type: %s", signType));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 生成签名.
|
|
*
|
|
* @param data 待签名数据
|
|
* @param key API密钥
|
|
* @param signType 签名方式
|
|
* @return 签名
|
|
*/
|
|
public static String generateSignApi(final Map<String, Object> data, String key, WXPayConstants.SignType signType) throws Exception {
|
|
Set<String> keySet = data.keySet();
|
|
String[] keyArray = keySet.toArray(new String[keySet.size()]);
|
|
Arrays.sort(keyArray);
|
|
StringBuilder sb = new StringBuilder();
|
|
for (String k : keyArray) {
|
|
if (k.equals(WXPayConstants.FIELD_SIGN) || k.equals("apiKey")) {
|
|
continue;
|
|
}
|
|
if (data.get(k) != null) // 参数值为空,则不参与签名
|
|
{
|
|
sb.append(k).append("=").append(data.get(k)).append("&");
|
|
}
|
|
}
|
|
sb.append("apiKey=").append(key);
|
|
if (WXPayConstants.SignType.MD5.equals(signType)) {
|
|
return MD5(sb.toString() , true);
|
|
}
|
|
else if (WXPayConstants.SignType.HMACSHA256.equals(signType)) {
|
|
return HMACSHA256(sb.toString(), key);
|
|
}
|
|
else {
|
|
throw new Exception(String.format("Invalid sign_type: %s", signType));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 用SHA1算法生成安全签名
|
|
* @param token 票据
|
|
* @param timestamp 时间戳
|
|
* @param nonce 随机字符串
|
|
* @return 安全签名
|
|
* @throws Exception
|
|
*/
|
|
public static String getSHA1(String token, String timestamp, String nonce) throws Exception
|
|
{
|
|
try {
|
|
String[] array = new String[] { token, timestamp, nonce};
|
|
StringBuffer sb = new StringBuffer();
|
|
// 字符串排序
|
|
Arrays.sort(array);
|
|
for (int i = 0; i < 3; i++) {
|
|
sb.append(array[i]);
|
|
}
|
|
String str = sb.toString();
|
|
// SHA1签名生成
|
|
MessageDigest md = MessageDigest.getInstance("SHA-1");
|
|
md.update(str.getBytes());
|
|
byte[] digest = md.digest();
|
|
|
|
StringBuffer hexstr = new StringBuffer();
|
|
String shaHex = "";
|
|
for (int i = 0; i < digest.length; i++) {
|
|
shaHex = Integer.toHexString(digest[i] & 0xFF);
|
|
if (shaHex.length() < 2) {
|
|
hexstr.append(0);
|
|
}
|
|
hexstr.append(shaHex);
|
|
}
|
|
return hexstr.toString();
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
throw new Exception(String.format("Invalid sign_type: %s"));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 用SHA1算法生成安全签名
|
|
* @param data 数据
|
|
* @return 安全签名
|
|
* @throws Exception
|
|
*/
|
|
public static String getSHA1(final Map<String, Object> data) throws Exception
|
|
{
|
|
try {
|
|
Set<String> keySet = data.keySet();
|
|
String[] keyArray = keySet.toArray(new String[keySet.size()]);
|
|
Arrays.sort(keyArray);
|
|
StringBuilder sb = new StringBuilder();
|
|
for (String k : keyArray) {
|
|
if (k.equals(WXPayConstants.FIELD_SIGN) || k.equals("apiKey")) {
|
|
continue;
|
|
}
|
|
if (data.get(k) != null) // 参数值为空,则不参与签名
|
|
{
|
|
sb.append(k).append("=").append(data.get(k)).append("&");
|
|
}
|
|
}
|
|
String str = sb.substring(0 , sb.length()-1);
|
|
// SHA1签名生成
|
|
MessageDigest md = MessageDigest.getInstance("SHA-1");
|
|
md.update(str.getBytes());
|
|
byte[] digest = md.digest();
|
|
|
|
StringBuffer hexstr = new StringBuffer();
|
|
String shaHex = "";
|
|
for (int i = 0; i < digest.length; i++) {
|
|
shaHex = Integer.toHexString(digest[i] & 0xFF);
|
|
if (shaHex.length() < 2) {
|
|
hexstr.append(0);
|
|
}
|
|
hexstr.append(shaHex);
|
|
}
|
|
return hexstr.toString();
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
throw new Exception(String.format("Invalid sign_type: %s"));
|
|
}
|
|
}
|
|
|
|
}
|
|
|