package com.kk.alipay.client;
import com.google.common.base.CaseFormat;
import com.kk.alipay.exception.AliPayException;
import com.kk.alipay.response.AliPayResponse;
import com.kk.util.BeanUtil;
import com.kk.util.SignUtils;
import com.kk.utils.HttpClientUtil;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.reflect.FieldUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
public class DefaultAliPayParser {
private Log logger = LogFactory.getLog(this.getClass());
private static final String SERVER_URL = "https://mapi.alipay.com/gateway.do";
private static final String CHARSET = "utf-8";
protected String partnerId;
protected String publicKey;
protected String privateKey;
protected String signType;
public DefaultAliPayParser(String signType, String partnerId, String publicKey) {
this.signType = signType;
this.partnerId = partnerId;
this.publicKey = publicKey;
}
public DefaultAliPayParser(String signType, String partnerId, String publicKey, String privateKey) {
this.signType = signType;
this.partnerId = partnerId;
this.publicKey = publicKey;
this.privateKey = privateKey;
}
protected boolean verify(String notifyId) throws AliPayException {
Map<String, String> params = new HashMap<String, String>();
params.put("service", "notify_verify");
params.put("partner", partnerId);
params.put("notify_id", notifyId);
String rsp = HttpClientUtil.sendGet(SERVER_URL + "?" + convert(params));
try {
return Boolean.parseBoolean(rsp);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return false;
}
/**
* 校验签名时候使用map(response中字段不一定全), 将json解析成 java实例
*
* @throws Exception
*/
public <T extends AliPayResponse> T parse(Class<T> clazz, String rsp) throws Exception {
Map<String, String> map = BeanUtil.jsonStr2Map(rsp);
T response = convert(clazz, map);
String sign = map.get("sign");
if (StringUtils.isBlank(sign)) {
throw new AliPayException("", "");
}
if (response.isSuccess() || (!response.isSuccess() && StringUtils.isNotBlank(response.getSign()))) {
boolean checkContent = SignUtils.checkRSASign(SignUtils.getSignContent(map, false), sign, publicKey);
if (checkContent) {
String notifyId = map.get("notify_id");
if (StringUtils.isBlank(notifyId)) { // 此处省略 校验notifyId步骤
throw new AliPayException("verify fail: verify notify fail!");
}
} else {
throw new AliPayException("sign check fail: check Sign and Data Fail!");
}
}
return response;
}
public static String convert(Map<String, String> params) {
StringBuilder buf = new StringBuilder();
Iterator<Map.Entry<String, String>> it = params.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
String k = entry.getKey();
if (StringUtils.isBlank(k)) {
continue;
}
String v = entry.getValue();
if (StringUtils.isBlank(v)) {
continue;
}
buf.append(k);
buf.append("=");
buf.append(v);
buf.append("&");
}
buf = buf.deleteCharAt(buf.length() - 1);
return buf.toString();
}
/**
* 解析的时候, 支持驼峰式写法,与下划线写法的转换
*
* @throws Exception
*/
public static <T extends AliPayResponse> T convert(Class<T> clazz, Map<String, String> data) throws Exception {
T rsp = clazz.newInstance();
BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
Method writeMethod = pd.getWriteMethod();
if (writeMethod == null) { // ignore read-only fields
continue;
}
String itemName = pd.getName();
// 驼峰式写法->下划线写法
String mapName = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, pd.getName());
Field field = FieldUtils.getField(clazz, itemName, true);
String value = data.get(mapName) == null ? data.get(itemName) : data.get(mapName);
if (value == null) {
continue;
}
Class<?> typeClass = field.getType();
if (String.class.isAssignableFrom(typeClass)) {
writeMethod.invoke(rsp, value.toString());
} else if (Long.class.isAssignableFrom(typeClass) || long.class.isAssignableFrom(typeClass)) {
if (StringUtils.isNumeric(value)) {
writeMethod.invoke(rsp, Long.valueOf(value.toString()));
}
} else if (Integer.class.isAssignableFrom(typeClass) || int.class.isAssignableFrom(typeClass)) {
if (StringUtils.isNumeric(value)) {
writeMethod.invoke(rsp, Integer.valueOf(value.toString()));
}
} else if (Boolean.class.isAssignableFrom(typeClass) || boolean.class.isAssignableFrom(typeClass)) {
if (value != null) {
writeMethod.invoke(rsp, Boolean.valueOf(value.toString()));
}
} else if (Short.class.isAssignableFrom(typeClass) || short.class.isAssignableFrom(typeClass)) {
if (value != null) {
writeMethod.invoke(rsp, Short.valueOf(value.toString()));
}
} else if (Double.class.isAssignableFrom(typeClass) || double.class.isAssignableFrom(typeClass)) {
if (value != null) {
writeMethod.invoke(rsp, Double.valueOf(value.toString()));
}
} else if (Float.class.isAssignableFrom(typeClass) || float.class.isAssignableFrom(typeClass)) {
if (value != null) {
writeMethod.invoke(rsp, Float.valueOf(value.toString()));
}
} else if (Date.class.isAssignableFrom(typeClass)) {
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
writeMethod.invoke(rsp, format.parse(value.toString()));
} else {
if (StringUtils.isNotBlank(value)) {
writeMethod.invoke(rsp, value);
}
}
}
return rsp;
}
}