Merge branch 'develop' of https://git.oschina.net/egzosn/pay-java-parent into develop-Actinia

# Conflicts:
#	README.md
#	pay-java-union/src/main/java/com/egzosn/pay/union/api/UnionPayConfigStorage.java
This commit is contained in:
Actinia-517
2017-12-05 16:28:21 +08:00
35 changed files with 1568 additions and 384 deletions

View File

@@ -16,22 +16,35 @@ import java.util.concurrent.locks.ReentrantLock;
public abstract class BasePayConfigStorage implements PayConfigStorage{
// ali rsa_private 商户私钥pkcs8格式
//wx api_key 应用私钥(生成签名时使用)
private volatile String keyPrivate ;
// 支付平台公钥(签名校验使用)
/**
* 应用私钥rsa_private pkcs8格式 生成签名时使用
*/
private volatile String keyPrivate;
/**
* 支付平台公钥(签名校验使用)
*/
private volatile String keyPublic;
//异步回调地址
/**
* 异步回调地址
*/
private volatile String notifyUrl;
//同步回调地址
private volatile String returnUrl;;
//签名加密类型
/**
* 同步回调地址,支付完成后展示的页面
*/
private volatile String returnUrl;
/**
* 签名加密类型
*/
private volatile String signType;
//字符类型
/**
* 字符类型
*/
private volatile String inputCharset;
//支付类型 aliPay 支付宝, wxPay微信..等等,开发者自定义,唯一
/**
* 支付类型 aliPay 支付宝, wxPay微信..等等,扩展支付模块定义唯一。
*/
private volatile String payType;
/**
@@ -40,13 +53,21 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{
private volatile MsgType msgType;
// 访问令牌 每次请求其他方法都要传入的值
/**
* 访问令牌 每次请求其他方法都要传入的值
*/
private volatile String accessToken;
// access token 到期时间时间戳
/**
* access token 到期时间时间戳
*/
private volatile long expiresTime;
//授权码锁
/**
* 授权码锁
*/
private Lock accessTokenLock = new ReentrantLock();
/**
* 是否为沙箱环境,默认为正式环境
*/
private boolean isTest = false;
@@ -77,6 +98,7 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{
this.notifyUrl = notifyUrl;
}
@Override
public String getReturnUrl() {
return returnUrl;

View File

@@ -14,21 +14,14 @@ import java.util.concurrent.locks.Lock;
*/
public interface PayConfigStorage {
/*
/**
* 应用id
* @return 应用id
*/
String getAppid();
/**
* 合作商唯一标识
* @see #getPid() 代替者
* @return 合作商唯一标识
*/
@Deprecated
String getPartner();
/**
* 合作商唯一标识
* @see #getPartner() 代替者
* @return 合作商唯一标识
*/
String getPid();

View File

@@ -2,6 +2,7 @@ package com.egzosn.pay.common.api;
import com.egzosn.pay.common.bean.PayMessage;
import com.egzosn.pay.common.bean.PayOutMessage;
import com.egzosn.pay.common.util.LogExceptionHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -43,18 +44,32 @@ import java.util.concurrent.Future;
*/
public class PayMessageRouter {
protected final Log log = LogFactory.getLog(PayMessageRouter.class);
protected final Log LOG = LogFactory.getLog(PayMessageRouter.class);
/**
* 异步线程大小
*/
private static final int DEFAULT_THREAD_POOL_SIZE = 100;
/**
* 规则集
*/
private final List<PayMessageRouterRule> rules = new ArrayList<PayMessageRouterRule>();
/**
* 支付服务
*/
private final PayService payService;
/**
* 异步线程处理器
*/
private ExecutorService executorService;
/**
* 支付异常处理器
*/
private PayErrorExceptionHandler exceptionHandler;
/**
* 根据支付服务创建路由
* @param payService 支付服务
*/
public PayMessageRouter(PayService payService) {
this.payService = payService;
this.executorService = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE);
@@ -130,6 +145,7 @@ public class PayMessageRouter {
if(rule.isAsync()) {
futures.add(
executorService.submit(new Runnable() {
@Override
public void run() {
rule.service(payMessage, payService, exceptionHandler);
}
@@ -138,7 +154,7 @@ public class PayMessageRouter {
} else {
res = rule.service(payMessage, payService, exceptionHandler);
// 在同步操作结束session访问结束
log.debug("End session access: async=false, fromPay=" + payMessage.getFromPay());
LOG.debug("End session access: async=false, fromPay=" + payMessage.getFromPay());
}
}
@@ -149,12 +165,12 @@ public class PayMessageRouter {
for (Future future : futures) {
try {
future.get();
log.debug("End session access: async=true, fromPay=" + payMessage.getFromPay());
LOG.debug("End session access: async=true, fromPay=" + payMessage.getFromPay());
} catch (InterruptedException e) {
log.error("Error happened when wait task finish", e);
LOG.error("Error happened when wait task finish", e);
} catch (ExecutionException e) {
log.error("Error happened when wait task finish", e);
LOG.error("Error happened when wait task finish", e);
}
}
}

View File

@@ -27,25 +27,39 @@ public class PayMessageRouterRule {
private final PayMessageRouter routerBuilder;
/**
* 默认同步
*/
private boolean async = false;
private boolean async = true;
private String fromPay;
/**
* 消息类型
*/
private String msgType;
/**
* 支付类型
*/
private String payType;
/**
* 交易类型
*/
private String[] transactionType;
private String discount;
private String rDiscount;
/**
* 简介
*/
private String subject;
/**
* 正则匹配
*/
private String rSubject;
/**
* 匹配的键名称
*/
private String key;
/**
* 匹配的键名称对应的值 正则
*/
private String rValue;
private boolean reEnter = false;
@@ -101,27 +115,7 @@ public class PayMessageRouterRule {
return this;
}
/**
* 如果discount等于某值
*
* @param discount discount等于某值
* @return Route规则
*/
public PayMessageRouterRule discount(String discount) {
this.discount = discount;
return this;
}
/**
* 如果discount匹配该正则表达式
*
* @param regex discount匹配该正则表达式
* @return Route规则
*/
public PayMessageRouterRule rDiscount(String regex) {
this.rDiscount = regex;
return this;
}
/**
* 如果subject等于某值
@@ -144,6 +138,18 @@ public class PayMessageRouterRule {
this.rSubject = regex;
return this;
}
/**
* 如果subject匹配该正则表达式
*
* @param key 需要匹配支付消息内键的名字
* @param regex key值对应的正则
* @return Route规则
*/
public PayMessageRouterRule key2RValue(String key, String regex) {
this.key = key;
this.rValue = regex;
return this;
}
/**
@@ -228,19 +234,14 @@ public class PayMessageRouterRule {
*/
protected boolean test(PayMessage payMessage) {
return (
(this.fromPay == null || this.fromPay.toLowerCase().equals((payMessage.getFromPay() ==null?null:payMessage.getFromPay().toLowerCase())))
&&
(this.msgType == null || this.msgType.toLowerCase().equals((payMessage.getMsgType() ==null?null:payMessage.getMsgType().toLowerCase())))
(this.msgType == null || this.msgType.toLowerCase().equals((payMessage.getMsgType() ==null?null:payMessage.getMsgType().toLowerCase())))
&&
(this.payType == null || this.payType.equals((payMessage.getPayType() == null ? null : payMessage.getPayType())))
&&
(this.transactionType == null || equalsTransactionType(payMessage.getTransactionType()))
&&
(this.discount == null || this.discount
.equals(payMessage.getDiscount() == null ? null : payMessage.getDiscount().trim()))
&&
(this.rDiscount == null || Pattern
.matches(this.rDiscount, payMessage.getDiscount() == null ? "" : payMessage.getDiscount().trim()))
(this.key == null ||this.rValue == null || Pattern
.matches(this.rValue, payMessage.getPayMessage().get(key) == null ? "" : payMessage.getPayMessage().get(key).toString().trim()))
&&
(this.subject == null || this.subject
.equals(payMessage.getSubject() == null ? null : payMessage.getSubject().trim()))
@@ -319,13 +320,6 @@ public class PayMessageRouterRule {
this.async = async;
}
public String getFromPay() {
return fromPay;
}
public void setFromPay(String fromPay) {
this.fromPay = fromPay;
}
public String getMsgType() {
return msgType;
@@ -351,20 +345,20 @@ public class PayMessageRouterRule {
this.transactionType = transactionType;
}
public String getDiscount() {
return discount;
public String getKey() {
return key;
}
public void setDiscount(String discount) {
this.discount = discount;
public void setKey(String key) {
this.key = key;
}
public String getrDiscount() {
return rDiscount;
public String getrValue() {
return rValue;
}
public void setrDiscount(String rDiscount) {
this.rDiscount = rDiscount;
public void setrValue(String rValue) {
this.rValue = rValue;
}
public String getSubject() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original huodull or egan.
* Copyright 2002-2017 the original egan.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@ package com.egzosn.pay.common.bean;
* email egzosn@gmail.com
* date 2017/2/7 9:52
* </pre>
* 请求方式
*/
public enum MethodType {
GET, POST

View File

@@ -22,11 +22,17 @@ public class PayOrder {
private String outTradeNo;
//银行卡类型
private String bankType;
//设备
//设备信息,
private String deviceInfo;
//支付创建ip
private String spbillCreateIp;
//付款条码串 与设备号类似???
private String authCode;
//
//WAP支付链接
private String wapUrl;
//WAP支付网页名称
private String wapName;
//微信会员唯一标识
private String openid;
//交易类型
private TransactionType transactionType;
@@ -119,6 +125,14 @@ public class PayOrder {
this.bankType = bankType;
}
public String getSpbillCreateIp() {
return spbillCreateIp;
}
public void setSpbillCreateIp(String spbillCreateIp) {
this.spbillCreateIp = spbillCreateIp;
}
public String getAuthCode() {
return authCode;
}
@@ -153,6 +167,22 @@ public class PayOrder {
this.outTradeNo = outTradeNo;
}
public String getWapUrl() {
return wapUrl;
}
public void setWapUrl(String wapUrl) {
this.wapUrl = wapUrl;
}
public String getWapName() {
return wapName;
}
public void setWapName(String wapName) {
this.wapName = wapName;
}
public String getOpenid() {
return openid;
}

View File

@@ -32,9 +32,13 @@ import static com.egzosn.pay.common.http.UriVariables.getMapToParameters;
* </pre>
*/
public class ClientHttpRequest<T> extends HttpEntityEnclosingRequestBase implements org.apache.http.client.ResponseHandler<T>{
//http请求
/**
* http请求方式 get pos
*/
private MethodType method;
//响应类型
/**
* 响应类型
*/
private Class<T> responseType;
@@ -43,40 +47,80 @@ public class ClientHttpRequest<T> extends HttpEntityEnclosingRequestBase impleme
return this;
}
/**
* 空构造
*/
public ClientHttpRequest() {
}
/**
* 根据请求地址 请求方法,请求内容对象
* @param uri 请求地址
* @param method 请求方法
* @param request 请求内容
*/
public ClientHttpRequest(URI uri, MethodType method, Object request) {
this.setURI(uri);
this.method = method;
this(uri, method);
setParameters(request);
}
/**
* 根据请求地址 请求方法
* @param uri 请求地址
* @param method 请求方法
*/
public ClientHttpRequest(URI uri, MethodType method) {
this.setURI(uri);
this.method = method;
}
/**
* 根据请求地址
* @param uri 请求地址
*/
public ClientHttpRequest(URI uri) {
this.setURI(uri);
}
/**
* 根据请求地址
* @param uri 请求地址
*/
public ClientHttpRequest(String uri) {
this.setURI(URI.create(uri));
}
/**
* 根据请求地址 请求方法
* @param uri 请求地址
* @param method 请求方法
*/
public ClientHttpRequest(String uri, MethodType method) {
this.setURI(URI.create(uri));
this.method = method;
}
/**
* 根据请求地址 请求方法,请求内容对象
* @param uri 请求地址
* @param method 请求方法
* @param request 请求内容
*/
public ClientHttpRequest(String uri, MethodType method, Object request) {
this.setURI(URI.create(uri));
this.method = method;
this(uri, method);
setParameters(request);
}
/**
* 设置请求方式
*
* @param method 请求方式
* {@link com.egzosn.pay.common.bean.MethodType} 请求方式
*/
public void setMethod(MethodType method) {
this.method = method;
}
/**
* 获取请求方式
* @return 请求方式
*/
@Override
public String getMethod() {
return method.name();
@@ -153,11 +197,11 @@ public class ClientHttpRequest<T> extends HttpEntityEnclosingRequestBase impleme
entity.writeTo((OutputStream)t);
return t;
} catch (InstantiationException e) {
e.printStackTrace();
throw new PayErrorException(new PayException("InstantiationException", e.getMessage()));
} catch (IllegalAccessException e) {
e.printStackTrace();
throw new PayErrorException(new PayException("IllegalAccessException", e.getMessage()));
}
throw new HttpResponseException(statusLine.getStatusCode(), responseType + " 无法进行类型转换");
}
}
String charset = "UTF-8";
@@ -174,7 +218,7 @@ public class ClientHttpRequest<T> extends HttpEntityEnclosingRequestBase impleme
try {
return JSON.parseObject(result, responseType);
}catch (JSONException e){
throw new PayErrorException(new PayException("failure", "类型转化异常,contentType:" + entity.getContentType().getValue(), result));
throw new PayErrorException(new PayException("failure", String.format("类型转化异常,contentType: %s\n%s", entity.getContentType().getValue(), e.getMessage() ), result));
}
}

View File

@@ -2,6 +2,8 @@ package com.egzosn.pay.common.util;
import com.alibaba.fastjson.JSONObject;
import com.egzosn.pay.common.bean.result.PayException;
import com.egzosn.pay.common.exception.PayErrorException;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
@@ -38,9 +40,9 @@ public class XML {
try (InputStream in = new ByteArrayInputStream(content.getBytes("UTF-8"))){
return (JSONObject) inputStream2Map(in, null);
} catch (IOException e) {
e.printStackTrace();
throw new PayErrorException(new PayException("IOException", e.getMessage()));
}
return null;
}
@@ -58,9 +60,8 @@ public class XML {
try {
return (JSONObject)inputStream2Map(in, null);
} catch (IOException e) {
e.printStackTrace();
throw new PayErrorException(new PayException("IOException", e.getMessage()));
}
return null;
}
@@ -95,7 +96,7 @@ public class XML {
m.put(k, v);
}
} catch (JDOMException e) {
e.printStackTrace();
throw new PayErrorException(new PayException("JDOMException", e.getMessage()));
}
return m;
}

View File

@@ -39,6 +39,7 @@ public enum SignUtils {
* @param characterEncoding 编码格式
* @return 签名结果
*/
@Override
public boolean verify(String text, String sign, String key, String characterEncoding) {
return com.egzosn.pay.common.util.sign.encrypt.MD5.verify(text, sign, key, characterEncoding);
}