1. 撤销功能实现

2.代码相关优化,整理
This commit is contained in:
egzosn
2018-11-12 20:10:55 +08:00
parent f76598a2be
commit 37facbb952
33 changed files with 585 additions and 503 deletions

View File

@@ -5,20 +5,19 @@ import com.egzosn.pay.common.bean.result.PayException;
import com.egzosn.pay.common.exception.PayErrorException;
import com.egzosn.pay.common.util.sign.CertDescriptor;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 支付基础配置存储
*
* @author: egan
* <pre>
* email egzosn@gmail.com
* date 2017/3/5 20:33
* </pre>
*/
public abstract class BasePayConfigStorage implements PayConfigStorage{
public abstract class BasePayConfigStorage implements PayConfigStorage {
private volatile Object attach;
/**
@@ -27,39 +26,39 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{
private volatile CertDescriptor certDescriptor;
/**
* 应用私钥rsa_private pkcs8格式 生成签名时使用
* 应用私钥rsa_private pkcs8格式 生成签名时使用
*/
private volatile String keyPrivate;
private volatile String keyPrivate;
/**
* 应用私钥rsa_private pkcs8格式 生成签名时使用
* 应用私钥rsa_private pkcs8格式 生成签名时使用
*/
private volatile String keyPrivateCertPwd;
private volatile String keyPrivateCertPwd;
/**
* 支付平台公钥(签名校验使用)
* 支付平台公钥(签名校验使用)
*/
private volatile String keyPublic;
private volatile String keyPublic;
/**
* 异步回调地址
*/
private volatile String notifyUrl;
private volatile String notifyUrl;
/**
* 同步回调地址,支付完成后展示的页面
*/
private volatile String returnUrl;
private volatile String returnUrl;
/**
* 签名加密类型
*/
private volatile String signType;
private volatile String signType;
/**
* 字符类型
*/
private volatile String inputCharset;
private volatile String inputCharset;
/**
* 支付类型 aliPay 支付宝, wxPay微信..等等,扩展支付模块定义唯一。
*/
private volatile String payType;
private volatile String payType;
/**
* 消息来源类型
@@ -68,7 +67,7 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{
/**
* 访问令牌 每次请求其他方法都要传入的值
* 访问令牌 每次请求其他方法都要传入的值
*/
private volatile String accessToken;
/**
@@ -105,10 +104,10 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{
@Override
public CertDescriptor getCertDescriptor() {
if (!isCertSign){
throw new PayErrorException(new PayException("certDescriptor fail", "isCertSign is false"));
if (!isCertSign) {
throw new PayErrorException(new PayException("certDescriptor fail", "isCertSign is false"));
}
if(null == certDescriptor){
if (null == certDescriptor) {
certDescriptor = new CertDescriptor();
}
return certDescriptor;
@@ -265,7 +264,7 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{
public void setCertSign(boolean certSign) {
isCertSign = certSign;
if (certSign){
if (certSign) {
certDescriptor = new CertDescriptor();
}
}

View File

@@ -91,7 +91,7 @@ public abstract class BasePayService<PC extends PayConfigStorage> implements Pay
try {
base64ClientID = com.egzosn.pay.common.util.sign.encrypt.Base64.encode(String.format("%s:%s", user , password).getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
LOG.error(e);
}
return base64ClientID;
@@ -132,9 +132,9 @@ public abstract class BasePayService<PC extends PayConfigStorage> implements Pay
public Map<String, Object> getParameter2Map (Map<String, String[]> parameterMap, InputStream is) {
Map<String, Object> params = new TreeMap<String,Object>();
for (Iterator iter = parameterMap.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = parameterMap.get(name);
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
String name = (String) entry.getKey();
String[] values = entry.getValue();
String valueStr = "";
for (int i = 0,len = values.length; i < len; i++) {
valueStr += (i == len - 1) ? values[i] : values[i] + ",";
@@ -145,7 +145,7 @@ public abstract class BasePayService<PC extends PayConfigStorage> implements Pay
valueStr=new String(valueStr.getBytes("iso8859-1"), payConfigStorage.getInputCharset());
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
LOG.error(e);
}
}
params.put(name, valueStr);
@@ -181,6 +181,31 @@ public abstract class BasePayService<PC extends PayConfigStorage> implements Pay
public <T> T close(String tradeNo, String outTradeNo, Callback<T> callback) {
return callback.perform(close(tradeNo, outTradeNo));
}
/**
* 交易撤销
*
* @param tradeNo 支付平台订单号
* @param outTradeNo 商户单号
* @param callback 处理器
* @param <T> 返回类型
* @return 返回支付方交易撤销后的结果
*/
@Override
public <T> T cancel(String tradeNo, String outTradeNo, Callback<T> callback) {
return callback.perform(close(tradeNo, outTradeNo));
}
/**
* 交易交易撤销
*
* @param tradeNo 支付平台订单号
* @param outTradeNo 商户单号
* @return 返回支付方交易撤销后的结果
*/
@Override
public Map<String, Object> cancel(String tradeNo, String outTradeNo) {
return Collections.EMPTY_MAP;
}
/**
* 退款
@@ -375,7 +400,9 @@ public abstract class BasePayService<PC extends PayConfigStorage> implements Pay
@Override
public PayOutMessage payBack(Map<String, String[]> parameterMap, InputStream is) {
Map<String, Object> data = getParameter2Map(parameterMap, is);
LOG.debug("回调响应:" + JSON.toJSONString(data));
if (LOG.isDebugEnabled()) {
LOG.debug("回调响应:" + JSON.toJSONString(data));
}
if (!verify(data)){
return getPayOutMessage("fail", "失败");
}

View File

@@ -21,7 +21,7 @@ import java.util.Map;
*/
public class DefaultPayMessageHandler implements PayMessageHandler {
protected final Log log = LogFactory.getLog(DefaultPayMessageHandler.class);
protected final Log LOG = LogFactory.getLog(DefaultPayMessageHandler.class);
/**
* @param payMessage 支付消息
* @param context 上下文如果handler或interceptor之间有信息要传递可以用这个
@@ -30,7 +30,9 @@ public class DefaultPayMessageHandler implements PayMessageHandler {
*/
@Override
public PayOutMessage handle(PayMessage payMessage, Map<String, Object> context, PayService payService) throws PayErrorException {
log.info("回调支付消息处理器,回调消息:" + JSON.toJSONString(payMessage));
if (LOG.isInfoEnabled()) {
LOG.info("回调支付消息处理器,回调消息:" + JSON.toJSONString(payMessage));
}
return payService.successPayOutMessage(payMessage);
}
}

View File

@@ -22,10 +22,12 @@ import java.util.Map;
public interface PayMessageHandler {
/**
* 处理支付回调消息的处理器接口
* @param payMessage 支付消息
* @param context 上下文如果handler或interceptor之间有信息要传递可以用这个
* @param payService 支付服务
* @return xml,text格式的消息如果在异步规则里处理的话可以返回null
* @throws PayErrorException 支付错误异常
*/
PayOutMessage handle(PayMessage payMessage,
Map<String, Object> context,

View File

@@ -134,7 +134,7 @@ public class PayMessageRouter {
}
}
if (matchRules.size() == 0) {
if (matchRules.isEmpty()) {
return null;
}
@@ -154,7 +154,9 @@ public class PayMessageRouter {
} else {
res = rule.service(payMessage, payService, exceptionHandler);
// 在同步操作结束session访问结束
LOG.debug("End session access: async=false, fromPay=" + payMessage.getFromPay());
if (LOG.isDebugEnabled()) {
LOG.debug("End session access: async=false, fromPay=" + payMessage.getFromPay());
}
}
}

View File

@@ -9,7 +9,6 @@ import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
@@ -76,7 +75,6 @@ public interface PayService<PC extends PayConfigStorage> {
* @param id 业务id, 数据的真实性.
* @return true通过
*/
@Deprecated
boolean verifySource(String id);
@@ -187,6 +185,7 @@ public interface PayService<PC extends PayConfigStorage> {
*/
Map<String, Object> close(String tradeNo, String outTradeNo);
/**
* 交易关闭接口
*
@@ -198,6 +197,26 @@ public interface PayService<PC extends PayConfigStorage> {
*/
<T>T close(String tradeNo, String outTradeNo, Callback<T> callback);
/**
* 交易交易撤销
*
* @param tradeNo 支付平台订单号
* @param outTradeNo 商户单号
* @return 返回支付方交易撤销后的结果
*/
Map<String, Object> cancel(String tradeNo, String outTradeNo);
/**
* 交易交易撤销
*
* @param tradeNo 支付平台订单号
* @param outTradeNo 商户单号
* @param callback 处理器
* @param <T> 返回类型
* @return 返回支付方交易撤销后的结果
*/
<T>T cancel(String tradeNo, String outTradeNo, Callback<T> callback);
/**
* 申请退款接口
* 废弃
@@ -301,7 +320,7 @@ public interface PayService<PC extends PayConfigStorage> {
/**
*
* 通用查询接口
* @param tradeNoOrBillDate 支付平台订单号或者账单类型, 具体请
* 类型为{@link String }或者 {@link Date },类型须强制限制,类型不对应则抛出异常{@link PayErrorException}
* @param outTradeNoBillType 商户单号或者 账单类型

View File

@@ -101,11 +101,10 @@ public class PayMessage implements Serializable {
}
public Number getTotalFee(){
String total_fee = (String) payMessage.get("total_fee");
if (null == total_fee || "".equals(total_fee)){ return 0; }
if (isNumber(total_fee)){
BigDecimal totalFee = new BigDecimal(total_fee);
return totalFee;
String totalFee = (String) payMessage.get("total_fee");
if (null == totalFee || "".equals(totalFee)){ return 0; }
if (isNumber(totalFee)){
return new BigDecimal(totalFee);
}
return 0;
}
@@ -118,19 +117,7 @@ public class PayMessage implements Serializable {
return str.matches("^(-?[1-9]\\d*\\.?\\d*)|(-?0\\.\\d*[1-9])|(-?[0])|(-?[0]\\.\\d*)$");
}
public Date parseDate(String str){
if (null == str || "".equals(str)){
return null;
}
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
return format.parse(str);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
@Override
public String toString() {

View File

@@ -8,15 +8,5 @@ package com.egzosn.pay.common.bean;
*/
public interface TransferType extends TransactionType{
/**
* 获取转账类型
* @return 转账类型
*/
String getType();
/**
* 获取接口
* @return 接口
*/
String getMethod();
}

View File

@@ -32,7 +32,7 @@ import static com.egzosn.pay.common.http.UriVariables.getMapToParameters;
* </pre>
*/
public class ClientHttpRequest<T> extends HttpEntityEnclosingRequestBase implements org.apache.http.client.ResponseHandler<T>{
protected final Log log = LogFactory.getLog(ClientHttpRequest.class);
protected static final Log LOG = LogFactory.getLog(ClientHttpRequest.class);
public static final ContentType APPLICATION_FORM_URLENCODED_UTF_8 = ContentType.create("application/x-www-form-urlencoded", Consts.UTF_8);;
@@ -157,7 +157,9 @@ public class ClientHttpRequest<T> extends HttpEntityEnclosingRequestBase impleme
if (request instanceof HttpHeader){
HttpHeader entity = (HttpHeader)request;
if (null != entity.getHeaders() ){
log.debug("header : " + JSON.toJSONString(entity.getHeaders()));
if (LOG.isDebugEnabled()) {
LOG.debug("header : " + JSON.toJSONString(entity.getHeaders()));
}
for (Header header : entity.getHeaders()){
addHeader(header);
}
@@ -168,7 +170,9 @@ public class ClientHttpRequest<T> extends HttpEntityEnclosingRequestBase impleme
setEntity(entity);
}
if (null != entity.getHeaders() ){
log.debug("header : " + JSON.toJSONString(entity.getHeaders()));
if (LOG.isDebugEnabled()) {
LOG.debug("header : " + JSON.toJSONString(entity.getHeaders()));
}
for (Header header : entity.getHeaders()){
addHeader(header);
}
@@ -177,16 +181,22 @@ public class ClientHttpRequest<T> extends HttpEntityEnclosingRequestBase impleme
setEntity((HttpEntity)request);
} else if (request instanceof Map) {
String parameters = getMapToParameters((Map) request);
log.debug("Parameter : " + parameters);
if (LOG.isDebugEnabled()) {
LOG.debug("Parameter : " + parameters);
}
StringEntity entity = new StringEntity(parameters, APPLICATION_FORM_URLENCODED_UTF_8);
setEntity(entity);
} else if (request instanceof String) {
log.debug("Parameter : " + request);
if (LOG.isDebugEnabled()) {
LOG.debug("Parameter : " + request);
}
StringEntity entity = new StringEntity((String) request, APPLICATION_FORM_URLENCODED_UTF_8);
setEntity(entity);
} else {
String body = JSON.toJSONString(request);
log.debug("body : " + request);
if (LOG.isDebugEnabled()) {
LOG.debug("body : " + request);
}
StringEntity entity = new StringEntity(body, ContentType.APPLICATION_JSON);
setEntity(entity);
}

View File

@@ -1,19 +1,12 @@
package com.egzosn.pay.common.http;
import org.apache.http.Header;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static com.egzosn.pay.common.http.UriVariables.getMapToParameters;
/**
* 请求头
@@ -82,8 +75,8 @@ public class HttpHeader{
* @param headers 请求头集
*/
public void setHeaders(Map<String, String> headers) {
for (String key : headers.keySet()) {
addHeader(new BasicHeader(key, headers.get(key)));
for (Map.Entry<String, String> entry : headers.entrySet()) {
addHeader(new BasicHeader(entry.getKey(), entry.getValue()));
}
}

View File

@@ -42,7 +42,7 @@ import java.util.Map;
*/
public class HttpRequestTemplate {
protected final Log log = LogFactory.getLog(HttpRequestTemplate.class);
protected final Log LOG = LogFactory.getLog(HttpRequestTemplate.class);
protected CloseableHttpClient httpClient;
@@ -107,7 +107,7 @@ public class HttpRequestTemplate {
try {
return new SSLConnectionSocketFactory(SSLContext.getDefault());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
LOG.error(e);
}
}
@@ -133,9 +133,9 @@ public class HttpRequestTemplate {
return sslsf;
} catch (IOException e) {
e.printStackTrace();
LOG.error(e);
} catch (GeneralSecurityException e) {
e.printStackTrace();
LOG.error(e);
}
return null;
@@ -175,7 +175,9 @@ public class HttpRequestTemplate {
if (0 == configStorage.getMaxTotal() || 0 == configStorage.getDefaultMaxPerRoute()){
return null;
}
log.info(String.format("Initialize the PoolingHttpClientConnectionManager -- maxTotal:%s, defaultMaxPerRoute:%s", configStorage.getMaxTotal(), configStorage.getDefaultMaxPerRoute()));
if (LOG.isInfoEnabled()) {
LOG.info(String.format("Initialize the PoolingHttpClientConnectionManager -- maxTotal:%s, defaultMaxPerRoute:%s", configStorage.getMaxTotal(), configStorage.getDefaultMaxPerRoute()));
}
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
.register("https", createSSL(configStorage))
.register("http", new PlainConnectionSocketFactory())
@@ -324,7 +326,9 @@ public class HttpRequestTemplate {
* @return 类型对象
*/
public <T>T doExecute(URI uri, Object request, Class<T> responseType, MethodType method){
log.debug(String.format("uri:%s, httpMethod:%s ", uri, method.name()));
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("uri:%s, httpMethod:%s ", uri, method.name()));
}
ClientHttpRequest<T> httpRequest = new ClientHttpRequest(uri ,method, request);
//判断是否有代理设置
if (null == httpProxy){

View File

@@ -175,7 +175,7 @@ public class HttpStringEntity extends StringEntity {
public HttpStringEntity(String request, Header... headers) throws UnsupportedEncodingException {
super(request);
requestIsEmpty(request);
if (null == headers) {
if (null != headers) {
this.headers = Arrays.asList(headers);
}
}
@@ -192,8 +192,8 @@ public class HttpStringEntity extends StringEntity {
super(request);
requestIsEmpty(request);
this.headers = new ArrayList<>();
for (String key : headers.keySet()) {
this.headers.add(new BasicHeader(key, headers.get(key)));
for (Map.Entry<String, String> entry : headers.entrySet()) {
addHeader(new BasicHeader(entry.getKey(), entry.getValue()));
}
}
@@ -233,8 +233,8 @@ public class HttpStringEntity extends StringEntity {
* @param headers 请求头集
*/
public void setHeaders(Map<String, String> headers) {
for (String key : headers.keySet()) {
addHeader(new BasicHeader(key, headers.get(key)));
for (Map.Entry<String, String> entry : headers.entrySet()) {
addHeader(new BasicHeader(entry.getKey(), entry.getValue()));
}
}
/**

View File

@@ -8,6 +8,7 @@ import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* URL表达式处理器
@@ -66,13 +67,13 @@ public class UriVariables {
if (null == uriVariables){
return uri;
}
for (String key : uriVariables.keySet()){
Object uriVariable = uriVariables.get(key);
for (Map.Entry<String, Object> entry : uriVariables.entrySet()) {
Object uriVariable = entry.getValue();
if (null == uriVariable){
continue;
}
uri = uri.replace("{" + key + "}", uriVariable.toString());
uri = uri.replace("{" + entry.getKey() + "}", uriVariable.toString());
}
return uri;
}
@@ -86,8 +87,8 @@ public class UriVariables {
*/
public static String getMapToParameters(Map pe){
StringBuilder builder = new StringBuilder();
for (Object key : pe.keySet()) {
Object o = pe.get(key);
for (Map.Entry entry : (Set<Map.Entry>)pe.entrySet()) {
Object o = entry.getKey();
if (null == o) {
continue;
@@ -107,11 +108,11 @@ public class UriVariables {
String value = os[i].toString().trim();
valueStr += (i == len - 1) ? value : value + ",";
}
builder.append(key).append("=").append(URLEncoder.encode(valueStr, "utf-8")).append("&");
builder.append(entry.getKey()).append("=").append(URLEncoder.encode(valueStr, "utf-8")).append("&");
continue;
}
builder.append(key).append("=").append(URLEncoder.encode( pe.get(key).toString(), "utf-8")).append("&");
builder.append(entry.getKey()).append("=").append(URLEncoder.encode( entry.getValue().toString(), "utf-8")).append("&");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}

View File

@@ -65,7 +65,7 @@ public class Util{
*/
public static byte[] byteConvert32Bytes(BigInteger n)
{
byte tmpd[] = (byte[])null;
byte[] tmpd = (byte[])null;
if(n == null)
{
return null;
@@ -166,7 +166,7 @@ public class Util{
*/
public static byte[] hexStringToBytes(String hexString)
{
if (hexString == null || hexString.equals(""))
if (hexString == null || "".equals(hexString))
{
return null;
}
@@ -328,15 +328,15 @@ public class Util{
* @param content 字符串
* @return ASCII字符串
*/
public static String StringToAsciiString(String content) {
String result = "";
public static String stringToAsciiString(String content) {
StringBuilder result = new StringBuilder();
int max = content.length();
for (int i = 0; i < max; i++) {
char c = content.charAt(i);
String b = Integer.toHexString(c);
result = result + b;
result.append( b);
}
return result;
return result.toString();
}
/**
@@ -349,14 +349,14 @@ public class Util{
* @return 字符串
*/
public static String hexStringToString(String hexString, int encodeType) {
String result = "";
StringBuilder result = new StringBuilder();
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;
result.append( c);
}
return result;
return result.toString();
}
/**
@@ -391,60 +391,12 @@ public class Util{
*/
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;
}
result += Integer.toBinaryString( Character.digit(c,16));
}
return result;
}
@@ -455,7 +407,7 @@ public class Util{
* @param content ASCII字符串
* @return 字符串
*/
public static String AsciiStringToString(String content) {
public static String asciiStringToString(String content) {
String result = "";
int length = content.length() / 2;
for (int i = 0; i < length; i++) {
@@ -534,7 +486,7 @@ public class Util{
String result = "";
result = Integer.toHexString(algorism);
if (result.length() % 2 == 1) {
if (result.length() % 2 != 0) {
result = "0" + result;
}
@@ -552,15 +504,18 @@ public class Util{
* int 补充后十六进制字符串的长度
* @return 补充结果
*/
static public String patchHexString(String str, int maxLength) {
String temp = "";
public static String patchHexString(String str, int maxLength) {
StringBuilder temp = new StringBuilder();
for (int i = 0; i < maxLength - str.length(); i++) {
temp = "0" + temp;
temp.append(0);
}
str = (temp + str).substring(0, maxLength);
return str;
temp.append(str);
return temp.toString();
}
/**
* 将一个字符串转换为int
*
@@ -616,7 +571,7 @@ public class Util{
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();
b[j] = Integer.valueOf(byteint).byteValue();
}
return b;
}
@@ -628,22 +583,23 @@ public class Util{
* byte[] 需要转换的字节数组
* @return String 十六进制字符串
*/
public static String byteToHex(byte b[]) {
public static String byteToHex(byte[] b) {
if (b == null) {
throw new IllegalArgumentException(
"Argument b ( byte array ) is null! ");
}
String hs = "";
String stmp = "";
StringBuilder hs = new StringBuilder();
for (int n = 0; n < b.length; n++) {
stmp = Integer.toHexString(b[n] & 0xff);
String stmp = Integer.toHexString(b[n] & 0xff);
if (stmp.length() == 1) {
hs = hs + "0" + stmp;
} else {
hs.append(0);
// hs = hs + "0" + stmp;
} /*else {
hs = hs + stmp;
}
}*/
hs.append(stmp);
}
return hs.toUpperCase();
return hs.toString().toUpperCase();
}
public static byte[] subByte(byte[] input, int startIndex, int length) {
@@ -653,4 +609,5 @@ public class Util{
}
return bt;
}
}

View File

@@ -9,7 +9,6 @@ import com.egzosn.pay.common.exception.PayErrorException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -174,7 +173,6 @@ public class XML {
JSON json = getChildren(children);
return json.toJavaObject(clazz);
} catch (Exception e) {
// e.printStackTrace();
throw new PayErrorException(new PayException("XML failure", "XML解析失败\n" + e.getMessage()));
} finally {
in.close();
@@ -230,17 +228,17 @@ public class XML {
try {
document = newDocument();
} catch (ParserConfigurationException e) {
e.printStackTrace();
throw new PayErrorException(new PayException("ParserConfigurationException", e.getLocalizedMessage()));
}
org.w3c.dom.Element root = document.createElement("xml");
document.appendChild(root);
for (String key : data.keySet()) {
Object value = data.get(key);
for (Map.Entry<String, Object> entry : data.entrySet()) {
Object value = entry.getValue();
if (value == null) {
value = "";
}
value = value.toString().trim();
org.w3c.dom.Element filed = document.createElement(key);
org.w3c.dom.Element filed = document.createElement(entry.getKey());
filed.appendChild(document.createTextNode(value.toString()));
root.appendChild(filed);
}

View File

@@ -18,11 +18,10 @@ package com.egzosn.pay.common.util.sign;
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.math.BigInteger;
import java.security.*;
import java.security.cert.*;
import java.security.spec.RSAPublicKeySpec;
import java.util.*;
@@ -32,7 +31,7 @@ import java.util.*;
* 声明:以下代码只是为了方便接入方测试而提供的样例代码,商户可以根据自己需要,按照技术文档编写。该代码仅供参考,不提供编码,性能,规范性等方面的保障
*/
public class CertDescriptor {
protected static final Log log = LogFactory.getLog(CertDescriptor.class);
protected static final Log LOG = LogFactory.getLog(CertDescriptor.class);
/** 证书容器,存储对商户请求报文签名私钥证书. */
private KeyStore keyStore = null;
@@ -57,18 +56,19 @@ public class CertDescriptor {
in = new FileInputStream(path);
encryptCertTemp = (X509Certificate) cf.generateCertificate(in);
// 打印证书加载信息,供测试阶段调试
log.warn("[" + path + "][CertId="
+ encryptCertTemp.getSerialNumber().toString() + "]");
if (LOG.isWarnEnabled()) {
LOG.warn("[" + path + "][CertId=" + encryptCertTemp.getSerialNumber().toString() + "]");
}
} catch (CertificateException e) {
log.error("InitCert Error", e);
LOG.error("InitCert Error", e);
} catch (FileNotFoundException e) {
log.error("InitCert Error File Not Found", e);
LOG.error("InitCert Error File Not Found", e);
}finally {
if (null != in) {
try {
in.close();
} catch (IOException e) {
log.error(e.toString());
LOG.error(e.toString());
}
}
}
@@ -92,13 +92,13 @@ public class CertDescriptor {
pwd.toCharArray());
return privateKey;
} catch (KeyStoreException e) {
log.error("getSignCertPrivateKey Error", e);
LOG.error("getSignCertPrivateKey Error", e);
return null;
} catch (UnrecoverableKeyException e) {
log.error("getSignCertPrivateKey Error", e);
LOG.error("getSignCertPrivateKey Error", e);
return null;
} catch (NoSuchAlgorithmException e) {
log.error("getSignCertPrivateKey Error", e);
LOG.error("getSignCertPrivateKey Error", e);
return null;
}
}
@@ -122,7 +122,7 @@ public class CertDescriptor {
.getCertificate(keyAlias);
return cert.getSerialNumber().toString();
} catch (Exception e) {
log.error("getSignCertId Error", e);
LOG.error("getSignCertId Error", e);
return null;
}
}
@@ -143,12 +143,12 @@ public class CertDescriptor {
keyStore = null;
}
try {
keyStore = getKeyInfo(signCertPath,
signCertPwd,signCertType);
log.info("InitSignCert Successful. CertId=["
+ getSignCertId() + "]");
keyStore = getKeyInfo(signCertPath, signCertPwd,signCertType);
if (LOG.isInfoEnabled()) {
LOG.info("InitSignCert Successful. CertId=[" + getSignCertId() + "]");
}
} catch (IOException e) {
log.error("InitSignCert Error", e);
LOG.error("InitSignCert Error", e);
}
}
@@ -161,12 +161,15 @@ public class CertDescriptor {
* @return 证书对象
* @throws IOException
*/
private KeyStore getKeyInfo(String pfxkeyfile, String keypwd,
String type) throws IOException {
log.warn("加载签名证书==>" + pfxkeyfile);
private KeyStore getKeyInfo(String pfxkeyfile, String keypwd, String type) throws IOException {
if (LOG.isWarnEnabled()) {
LOG.warn("加载签名证书==>" + pfxkeyfile);
}
try(FileInputStream fis = new FileInputStream(pfxkeyfile);) {
KeyStore ks = KeyStore.getInstance(type);
log.warn("Load RSA CertPath=[" + pfxkeyfile + "],Pwd=["+ keypwd + "],type=["+type+"]");
if (LOG.isWarnEnabled()) {
LOG.warn("Load RSA CertPath=[" + pfxkeyfile + "],Pwd=["+ keypwd + "],type=["+type+"]");
}
char[] nPassword = null;
nPassword = null == keypwd || "".equals(keypwd.trim()) ? null: keypwd.toCharArray();
@@ -175,7 +178,7 @@ public class CertDescriptor {
}
return ks;
} catch (Exception e) {
log.error("getKeyInfo Error", e);
LOG.error("getKeyInfo Error", e);
return null;
}
}
@@ -198,7 +201,7 @@ public class CertDescriptor {
.getCertificate(keyAlias);
return cert.getSerialNumber().toString();
} catch (KeyStoreException e) {
log.error("getCertIdIdByStore Error", e);
LOG.error("getCertIdIdByStore Error", e);
return null;
}
}
@@ -209,12 +212,14 @@ public class CertDescriptor {
* 加载中级证书
* @param certPath 证书地址
*/
public void initPublicCert(String certPath) {
public void initPublicCert(String certPath) {
if (!StringUtils.isEmpty(certPath)) {
publicKeyCert = initCert(certPath);
log.info("Load PublicKeyCert Successful");
} else {
log.info("PublicKeyCert is empty");
if (LOG.isInfoEnabled()) {
LOG.info("Load PublicKeyCert Successful");
}
} else if (LOG.isInfoEnabled()) {
LOG.info("PublicKeyCert is empty");
}
}
@@ -225,9 +230,11 @@ public class CertDescriptor {
public void initRootCert(String certPath) {
if (!StringUtils.isEmpty(certPath)) {
rootKeyCert = initCert(certPath);
log.info("Load RootCert Successful");
} else {
log.info("RootCert is empty");
if (LOG.isInfoEnabled()) {
LOG.info("Load RootCert Successful");
}
} else if (LOG.isInfoEnabled()) {
LOG.info("RootCert is empty");
}
}
@@ -247,10 +254,4 @@ public class CertDescriptor {
return rootKeyCert;
}
}

View File

@@ -62,12 +62,12 @@ public enum SignUtils {
*/
@Override
public String createSign(String content, String key, String characterEncoding) {
Mac sha256_HMAC = null;
Mac sha256HMAC = null;
try {
sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(characterEncoding), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] array = sha256_HMAC.doFinal(content.getBytes(characterEncoding));
sha256HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(characterEncoding), "HmacSHA256");
sha256HMAC.init(secretKey);
byte[] array = sha256HMAC.doFinal(content.getBytes(characterEncoding));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
@@ -197,12 +197,12 @@ public enum SignUtils {
}
// TODO 2016/11/11 10:14 author: egan 已经排序好处理
if (parameters instanceof SortedMap) {
for (String k : ((Set<String>) parameters.keySet())) {
Object v = parameters.get(k);
if (null == v || "".equals(v.toString().trim()) || (null != ignoreKey && Arrays.binarySearch(ignoreKey, k ) >= 0)) {
for (Map.Entry<String, Object> entry : (Set<Map.Entry<String, Object>>)parameters.entrySet()) {
Object v = entry.getValue();
if (null == v || "".equals(v.toString().trim()) || (null != ignoreKey && Arrays.binarySearch(ignoreKey, entry.getKey() ) >= 0)) {
continue;
}
sb.append(k ).append("=").append( v.toString().trim()).append(separator);
sb.append(entry.getKey() ).append("=").append( v.toString().trim()).append(separator);
}
if (sb.length() > 0 && !"".equals(separator)) {
sb.deleteCharAt(sb.length() - 1);
@@ -219,9 +219,12 @@ public enum SignUtils {
for (String k : keys) {
String valueStr = "";
Object o = parameters.get(k);
if (null == o) {
continue;
}
if (o instanceof String[]) {
String[] values = (String[]) o;
if (null == values){continue;}
for (int i = 0; i < values.length; i++) {
String value = values[i].trim();
if ("".equals(value)){ continue;}

View File

@@ -312,9 +312,10 @@ public class Base64 {
*/
public int encode(byte[] src, byte[] dst) {
int len = outLength(src.length); // dst array size
if (dst.length < len)
if (dst.length < len) {
throw new IllegalArgumentException(
"Output byte array is too small for encoding all input bytes");
}
return encode0(src, 0, src.length, dst);
}
@@ -409,8 +410,9 @@ public class Base64 {
* padding character at the end
*/
public Encoder withoutPadding() {
if (!doPadding)
if (!doPadding) {
return this;
}
return new Encoder(isURL, newline, linemax, false);
}
@@ -575,9 +577,10 @@ public class Base64 {
* if {@code src} is not in valid Base64 scheme
*/
public byte[] decode(String src) {
if (null != src){
src = src.replaceAll("[\r\n]", "");
if (null == src){
return null;
}
src = src.replaceAll("[\r\n]", "");
return decode(src.getBytes(StandardCharsets.ISO_8859_1));
}
@@ -608,9 +611,10 @@ public class Base64 {
*/
public int decode(byte[] src, byte[] dst) {
int len = outLength(src, 0, src.length);
if (dst.length < len)
if (dst.length < len) {
throw new IllegalArgumentException(
"Output byte array is too small for decoding all input bytes");
}
return decode0(src, 0, src.length, dst);
}
@@ -703,8 +707,9 @@ public class Base64 {
len -= (sl - sp + 1);
break;
}
if ((b = base64[b]) == -1)
if ((b = base64[b]) == -1) {
n++;
}
}
len -= n;
} else {

View File

@@ -9,6 +9,10 @@ import static com.egzosn.pay.common.util.str.StringUtils.getContentBytes;
/**
* MD5签名工具
* @author egan
* <pre>
* email egzosn@gmail.com
*</pre>
*/
public class MD5 {
@@ -17,13 +21,13 @@ public class MD5 {
*
* @param text 需要签名的字符串
* @param key 密钥
* @param input_charset 编码格式
* @param inputCharset 编码格式
* @return 签名结果
*/
public static String sign(String text, String key, String input_charset) {
public static String sign(String text, String key, String inputCharset) {
//拼接key
text = text + key;
return DigestUtils.md5Hex(getContentBytes(text, input_charset));
return DigestUtils.md5Hex(getContentBytes(text, inputCharset));
}
/**
@@ -32,12 +36,12 @@ public class MD5 {
* @param text 需要签名的字符串
* @param sign 签名结果
* @param key 密钥
* @param input_charset 编码格式
* @param inputCharset 编码格式
* @return 签名结果
*/
public static boolean verify(String text, String sign, String key, String input_charset) {
public static boolean verify(String text, String sign, String key, String inputCharset) {
//判断是否一样
return StringUtils.equals(sign(text, key, input_charset).toUpperCase(), sign.toUpperCase());
return StringUtils.equals(sign(text, key, inputCharset).toUpperCase(), sign.toUpperCase());
}

View File

@@ -9,6 +9,13 @@ import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* RSA
* @author egan
* <pre>
* email egzosn@gmail.com
*</pre>
*/
public class RSA{
private static final String ALGORITHM = "RSA";
@@ -221,7 +228,7 @@ public class RSA{
* @return 公钥
*/
public static PublicKey getPublicKey(String key, String signAlgorithms) throws Exception {
return getPublicKey(new ByteArrayInputStream(key.getBytes()), signAlgorithms);
return getPublicKey(new ByteArrayInputStream(key.getBytes("ISO8859-1")), signAlgorithms);
}

View File

@@ -1,7 +1,6 @@
package com.egzosn.pay.common.util.sign.encrypt;
import java.nio.charset.Charset;
import java.security.PrivateKey;
import java.security.PublicKey;

View File

@@ -22,13 +22,13 @@ public class SHA1 {
*
* @param text 需要签名的字符串
* @param key 密钥
* @param input_charset 编码格式
* @param inputCharset 编码格式
* @return 签名结果
*/
public static String sign(String text, String key, String input_charset) {
public static String sign(String text, String key, String inputCharset) {
//拼接key
text = text + key;
return DigestUtils.sha1Hex( StringUtils.getContentBytes(text, input_charset));
return DigestUtils.sha1Hex( StringUtils.getContentBytes(text, inputCharset));
}
@@ -38,12 +38,12 @@ public class SHA1 {
* @param text 需要签名的字符串
* @param sign 签名结果
* @param key 密钥
* @param input_charset 编码格式
* @param inputCharset 编码格式
* @return 签名结果
*/
public static boolean verify(String text, String sign, String key, String input_charset) {
public static boolean verify(String text, String sign, String key, String inputCharset) {
//判断是否一样
return StringUtils.equals(sign(text, key, input_charset).toUpperCase(), sign.toUpperCase());
return StringUtils.equals(sign(text, key, inputCharset).toUpperCase(), sign.toUpperCase());
}
}

View File

@@ -21,13 +21,13 @@ public class SHA256 {
*
* @param text 需要签名的字符串
* @param key 密钥
* @param input_charset 编码格式
* @param inputCharset 编码格式
* @return 签名结果
*/
public static String sign(String text, String key, String input_charset) {
public static String sign(String text, String key, String inputCharset) {
//拼接key
text = text + key;
return DigestUtils.sha256Hex( StringUtils.getContentBytes(text, input_charset));
return DigestUtils.sha256Hex( StringUtils.getContentBytes(text, inputCharset));
}
@@ -37,12 +37,12 @@ public class SHA256 {
* @param text 需要签名的字符串
* @param sign 签名结果
* @param key 密钥
* @param input_charset 编码格式
* @param inputCharset 编码格式
* @return 签名结果
*/
public static boolean verify(String text, String sign, String key, String input_charset) {
public static boolean verify(String text, String sign, String key, String inputCharset) {
//判断是否一样
return StringUtils.equals(sign(text, key, input_charset).toUpperCase(), sign.toUpperCase());
return StringUtils.equals(sign(text, key, inputCharset).toUpperCase(), sign.toUpperCase());
}
}

View File

@@ -2,64 +2,54 @@ package com.egzosn.pay.common.util.sign.encrypt.sm3;
import com.egzosn.pay.common.util.Util;
public class SM3
{
public static final byte[] iv = { 0x73, (byte) 0x80, 0x16, 0x6f, 0x49,
public class SM3 {
public static final byte[] iv = {0x73, (byte) 0x80, 0x16, 0x6f, 0x49,
0x14, (byte) 0xb2, (byte) 0xb9, 0x17, 0x24, 0x42, (byte) 0xd7,
(byte) 0xda, (byte) 0x8a, 0x06, 0x00, (byte) 0xa9, 0x6f, 0x30,
(byte) 0xbc, (byte) 0x16, 0x31, 0x38, (byte) 0xaa, (byte) 0xe3,
(byte) 0x8d, (byte) 0xee, 0x4d, (byte) 0xb0, (byte) 0xfb, 0x0e,
0x4e };
0x4e};
public static int[] Tj = new int[64];
static
{
for (int i = 0; i < 16; i++)
{
static {
for (int i = 0; i < 16; i++) {
Tj[i] = 0x79cc4519;
}
for (int i = 16; i < 64; i++)
{
for (int i = 16; i < 64; i++) {
Tj[i] = 0x7a879d8a;
}
}
public static byte[] CF(byte[] V, byte[] B)
{
public static byte[] CF(byte[] V, byte[] B) {
int[] v, b;
v = convert(V);
b = convert(B);
return convert(CF(v, b));
}
private static int[] convert(byte[] arr)
{
private static int[] convert(byte[] arr) {
int[] out = new int[arr.length / 4];
byte[] tmp = new byte[4];
for (int i = 0; i < arr.length; i += 4)
{
for (int i = 0; i < arr.length; i += 4) {
System.arraycopy(arr, i, tmp, 0, 4);
out[i / 4] = bigEndianByteToInt(tmp);
}
return out;
}
private static byte[] convert(int[] arr)
{
private static byte[] convert(int[] arr) {
byte[] out = new byte[arr.length * 4];
byte[] tmp = null;
for (int i = 0; i < arr.length; i++)
{
for (int i = 0; i < arr.length; i++) {
tmp = bigEndianIntToByte(arr[i]);
System.arraycopy(tmp, 0, out, i * 4, 4);
}
return out;
}
public static int[] CF(int[] V, int[] B)
{
public static int[] CF(int[] V, int[] B) {
int a, b, c, d, e, f, g, h;
int ss1, ss2, tt1, tt2;
a = V[0];
@@ -75,8 +65,7 @@ public class SM3
int[] w = arr[0];
int[] w1 = arr[1];
for (int j = 0; j < 64; j++)
{
for (int j = 0; j < 64; j++) {
ss1 = (bitCycleLeft(a, 12) + e + bitCycleLeft(Tj[j], j));
ss1 = bitCycleLeft(ss1, 7);
ss2 = ss1 ^ bitCycleLeft(a, 12);
@@ -117,91 +106,72 @@ public class SM3
return out;
}
private static int[][] expand(int[] B)
{
int W[] = new int[68];
int W1[] = new int[64];
for (int i = 0; i < B.length; i++)
{
private static int[][] expand(int[] B) {
int[] W = new int[68];
int[] W1 = new int[64];
for (int i = 0; i < B.length; i++) {
W[i] = B[i];
}
for (int i = 16; i < 68; i++)
{
for (int i = 16; i < 68; i++) {
W[i] = P1(W[i - 16] ^ W[i - 9] ^ bitCycleLeft(W[i - 3], 15))
^ bitCycleLeft(W[i - 13], 7) ^ W[i - 6];
}
for (int i = 0; i < 64; i++)
{
for (int i = 0; i < 64; i++) {
W1[i] = W[i] ^ W[i + 4];
}
int arr[][] = new int[][] { W, W1 };
int[][] arr = new int[][]{W, W1};
return arr;
}
private static byte[] bigEndianIntToByte(int num)
{
private static byte[] bigEndianIntToByte(int num) {
return back(Util.intToBytes(num));
}
private static int bigEndianByteToInt(byte[] bytes)
{
private static int bigEndianByteToInt(byte[] bytes) {
return Util.byteToInt(back(bytes));
}
private static int FFj(int X, int Y, int Z, int j)
{
if (j >= 0 && j <= 15)
{
private static int FFj(int X, int Y, int Z, int j) {
if (j >= 0 && j <= 15) {
return FF1j(X, Y, Z);
}
else
{
} else {
return FF2j(X, Y, Z);
}
}
private static int GGj(int X, int Y, int Z, int j)
{
if (j >= 0 && j <= 15)
{
private static int GGj(int X, int Y, int Z, int j) {
if (j >= 0 && j <= 15) {
return GG1j(X, Y, Z);
}
else
{
} else {
return GG2j(X, Y, Z);
}
}
// 逻辑位运算函数
private static int FF1j(int X, int Y, int Z)
{
private static int FF1j(int X, int Y, int Z) {
int tmp = X ^ Y ^ Z;
return tmp;
}
private static int FF2j(int X, int Y, int Z)
{
private static int FF2j(int X, int Y, int Z) {
int tmp = ((X & Y) | (X & Z) | (Y & Z));
return tmp;
}
private static int GG1j(int X, int Y, int Z)
{
private static int GG1j(int X, int Y, int Z) {
int tmp = X ^ Y ^ Z;
return tmp;
}
private static int GG2j(int X, int Y, int Z)
{
private static int GG2j(int X, int Y, int Z) {
int tmp = (X & Y) | (~X & Z);
return tmp;
}
private static int P0(int X)
{
private static int P0(int X) {
int y = rotateLeft(X, 9);
y = bitCycleLeft(X, 9);
int z = rotateLeft(X, 17);
@@ -210,8 +180,7 @@ public class SM3
return t;
}
private static int P1(int X)
{
private static int P1(int X) {
int t = X ^ bitCycleLeft(X, 15) ^ bitCycleLeft(X, 23);
return t;
}
@@ -219,15 +188,13 @@ public class SM3
/**
* 对最后一个分组字节数据padding
*
* @param in 输入字节
* @param bLen 分组个数
* @return 分组好的字节
* @param in 输入字节
* @param bLen 分组个数
* @return 分组好的字节
*/
public static byte[] padding(byte[] in, int bLen)
{
public static byte[] padding(byte[] in, int bLen) {
int k = 448 - (8 * in.length + 1) % 512;
if (k < 0)
{
if (k < 0) {
k = 960 - (8 * in.length + 1) % 512;
}
k += 1;
@@ -251,47 +218,39 @@ public class SM3
* @param in 输入字节
* @return 排序好的字节
*/
private static byte[] back(byte[] in)
{
private static byte[] back(byte[] in) {
byte[] out = new byte[in.length];
for (int i = 0; i < out.length; i++)
{
for (int i = 0; i < out.length; i++) {
out[i] = in[out.length - i - 1];
}
return out;
}
public static int rotateLeft(int x, int n)
{
public static int rotateLeft(int x, int n) {
return (x << n) | (x >> (32 - n));
}
private static int bitCycleLeft(int n, int bitLen)
{
private static int bitCycleLeft(int n, int bitLen) {
bitLen %= 32;
byte[] tmp = bigEndianIntToByte(n);
int byteLen = bitLen / 8;
int len = bitLen % 8;
if (byteLen > 0)
{
if (byteLen > 0) {
tmp = byteCycleLeft(tmp, byteLen);
}
if (len > 0)
{
if (len > 0) {
tmp = bitSmall8CycleLeft(tmp, len);
}
return bigEndianByteToInt(tmp);
}
private static byte[] bitSmall8CycleLeft(byte[] in, int len)
{
private static byte[] bitSmall8CycleLeft(byte[] in, int len) {
byte[] tmp = new byte[in.length];
int t1, t2, t3;
for (int i = 0; i < tmp.length; i++)
{
for (int i = 0; i < tmp.length; i++) {
t1 = (byte) ((in[i] & 0x000000ff) << len);
t2 = (byte) ((in[(i + 1) % tmp.length] & 0x000000ff) >> (8 - len));
t3 = (byte) (t1 | t2);
@@ -301,8 +260,7 @@ public class SM3
return tmp;
}
private static byte[] byteCycleLeft(byte[] in, int byteLen)
{
private static byte[] byteCycleLeft(byte[] in, int byteLen) {
byte[] tmp = new byte[in.length];
System.arraycopy(in, byteLen, tmp, 0, in.length - byteLen);
System.arraycopy(in, 0, tmp, in.length - byteLen, byteLen);