替换原有http请求,定义交易辅助接口,去除无用接口

This commit is contained in:
zzs
2017-03-07 20:24:17 +08:00
parent 17750ddb47
commit 205beab64b
36 changed files with 2224 additions and 482 deletions

View File

@@ -7,9 +7,9 @@ import java.util.concurrent.locks.ReentrantLock;
/**
* 支付基础配置存储
* @author egan
* @author: egan
* @email egzosn@gmail.com
* @date 2016-5-18 14:09:01
* @date 2017/3/5 20:33
*/
public abstract class BasePayConfigStorage implements PayConfigStorage{
@@ -31,13 +31,11 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{
//支付类型 aliPay 支付宝, wxPay微信..等等,开发者自定义,唯一
protected volatile String payType;
/**
* 消息来源类型
* @see PayConsts#MSG_XML
* @see PayConsts#MSG_TEXT
* @see PayConsts#MSG_JSON
*/
protected volatile MsgType msgType;
protected volatile MsgType msgType;
// 访问令牌 每次请求其他方法都要传入的值
@@ -47,98 +45,6 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{
//授权码锁
protected Lock accessTokenLock = new ReentrantLock();
protected volatile String httpProxyHost;
protected volatile int httpProxyPort;
protected volatile String httpProxyUsername;
protected volatile String httpProxyPassword;
/**
* 合作商唯一标识
* @see #getPartner 代替者
*/
public String getPid(){
throw null;
}
@Override
public String getInputCharset() {
return inputCharset;
}
public void setInputCharset(String inputCharset) {
this.inputCharset = inputCharset;
}
@Override
public String getNotifyUrl() {
return notifyUrl;
}
public void setNotifyUrl(String notifyUrl) {
this.notifyUrl = notifyUrl;
}
@Override
public String getReturnUrl() {
return returnUrl;
}
public void setReturnUrl(String returnUrl) {
this.returnUrl = returnUrl;
}
public void setSignType(String signType) {
this.signType = signType;
}
@Override
public String getSignType() {
return signType;
}
@Override
public String getHttpProxyHost() {
return httpProxyHost;
}
public void setHttpProxyHost(String httpProxyHost) {
this.httpProxyHost = httpProxyHost;
}
@Override
public int getHttpProxyPort() {
return httpProxyPort;
}
public void setHttpProxyPort(int httpProxyPort) {
this.httpProxyPort = httpProxyPort;
}
@Override
public String getHttpProxyUsername() {
return httpProxyUsername;
}
public void setHttpProxyUsername(String httpProxyUsername) {
this.httpProxyUsername = httpProxyUsername;
}
@Override
public String getHttpProxyPassword() {
return httpProxyPassword;
}
public void setHttpProxyPassword(String httpProxyPassword) {
this.httpProxyPassword = httpProxyPassword;
}
@Override
public String getKeyPrivate() {
return keyPrivate;
@@ -157,19 +63,43 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{
this.keyPublic = keyPublic;
}
@Override
public String getToken() {
return null;
public String getNotifyUrl() {
return notifyUrl;
}
public void setNotifyUrl(String notifyUrl) {
this.notifyUrl = notifyUrl;
}
/**
* 支付类型 自定义
* 这里暂定 aliPay 支付宝, wxPay微信支付
* @return
*/
@Override
public String getReturnUrl() {
return returnUrl;
}
public void setReturnUrl(String returnUrl) {
this.returnUrl = returnUrl;
}
@Override
public String getSignType() {
return signType;
}
public void setSignType(String signType) {
this.signType = signType;
}
@Override
public String getInputCharset() {
return inputCharset;
}
public void setInputCharset(String inputCharset) {
this.inputCharset = inputCharset;
}
@Override
public String getPayType() {
return payType;
}
@@ -187,7 +117,6 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{
this.msgType = msgType;
}
@Override
public String getAccessToken() {
return this.accessToken;
@@ -226,4 +155,9 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{
this.expiresTime = 0;
}
@Override
public String getToken() {
return null;
}
}

View File

@@ -1,107 +1,75 @@
package in.egan.pay.common.api;
import in.egan.pay.common.exception.PayErrorException;
import in.egan.pay.common.util.str.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import in.egan.pay.common.http.HttpConfigStorage;
import in.egan.pay.common.http.HttpRequestTemplate;
import in.egan.pay.common.util.sign.SignUtils;
import java.io.IOException;
import java.util.Map;
/**
* 支付基础服务
* @author: egan
* @email egzosn@gmail.com
* @date 2017/1/12 20:09
* @source chanjarster/weixin-java-tools
* @date 2017/3/5 20:36
*/
public abstract class BasePayService implements PayService {
protected PayConfigStorage payConfigStorage;
protected CloseableHttpClient httpClient;
protected HttpHost httpProxy;
protected HttpRequestTemplate requestTemplate;
protected int retrySleepMillis = 1000;
protected int maxRetryTimes = 5;
/**
*
* @param executor
* @param uri
* @param data
* @param <T>
* @param <E>
* @return
* @throws PayErrorException
*/
protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws PayErrorException {
try {
return executor.execute(getHttpClient(), httpProxy, uri, data);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public HttpHost getHttpProxy() {
return httpProxy;
}
public CloseableHttpClient getHttpClient() {
return httpClient;
}
/**
* 设置支付配置
* @param payConfigStorage 支付配置
*/
public void setPayConfigStorage(PayConfigStorage payConfigStorage) {
public BasePayService setPayConfigStorage(PayConfigStorage payConfigStorage) {
this.payConfigStorage = payConfigStorage;
String http_proxy_host = payConfigStorage.getHttpProxyHost();
int http_proxy_port = payConfigStorage.getHttpProxyPort();
String http_proxy_username = payConfigStorage.getHttpProxyUsername();
String http_proxy_password = payConfigStorage.getHttpProxyPassword();
if (StringUtils.isNotBlank(http_proxy_host)) {
// 使用代理服务器
if (StringUtils.isNotBlank(http_proxy_username)) {
// 需要用户认证的代理服务器
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(http_proxy_host, http_proxy_port),
new UsernamePasswordCredentials(http_proxy_username, http_proxy_password));
httpClient = HttpClients
.custom()
.setDefaultCredentialsProvider(credsProvider)
.build();
} else {
// 无需用户认证的代理服务器
httpClient = HttpClients.createDefault();
}
httpProxy = new HttpHost(http_proxy_host, http_proxy_port);
} else {
httpClient = HttpClients.createDefault();
}
return this;
}
@Override
public PayConfigStorage getPayConfigStorage() {
return payConfigStorage;
}
@Override
public HttpRequestTemplate getHttpRequestTemplate() {
return requestTemplate;
}
public BasePayService() {
/**
* 设置并创建请求模版, 代理请求配置这里是否合理??,
* @param configStorage http请求配置
* @return
*/
@Override
public BasePayService setRequestTemplateConfigStorage(HttpConfigStorage configStorage) {
this.requestTemplate = new HttpRequestTemplate(configStorage);
return this;
}
public BasePayService(PayConfigStorage payConfigStorage) {
setPayConfigStorage(payConfigStorage);
this(payConfigStorage, null);
}
public BasePayService(PayConfigStorage payConfigStorage, HttpConfigStorage configStorage) {
setPayConfigStorage(payConfigStorage);
setRequestTemplateConfigStorage(configStorage);
}
@Override
public String createSign(String content, String characterEncoding) {
return SignUtils.valueOf(payConfigStorage.getSignType()).createSign(content, payConfigStorage.getKeyPrivate(),characterEncoding);
}
@Override
public String createSign(Map<String, Object> content, String characterEncoding) {
return SignUtils.valueOf(payConfigStorage.getSignType()).sign(content, payConfigStorage.getKeyPrivate(),characterEncoding);
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2002-2017 the original huodull or egan.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package in.egan.pay.common.api;
import java.util.Map;
/**
* 回调,可用于类型转换
* @author: egan
* @email egzosn@gmail.com
* @date 2017/3/7 18:55
*/
public interface Callback<T> {
T perform(Map<String, Object> map);
}

View File

@@ -81,10 +81,7 @@ import java.util.concurrent.locks.Lock;
* 消息类型
* @see #getMsgType
* @see MsgType
* @return "text" 或者 "xml"
* @see MsgType#text
* @see MsgType#xml
* @see MsgType#json
* @return "text" 或者 "xml"json
*/
MsgType getMsgType();
@@ -129,29 +126,4 @@ import java.util.concurrent.locks.Lock;
*/
void updateAccessToken(String accessToken, long expiresTime);
/**
* http代理地址
* @return
*/
String getHttpProxyHost();
/**
* 代理端口
* @return
*/
int getHttpProxyPort();
/**
* 代理用户名
* @return
*/
String getHttpProxyUsername();
/**
* 代理密码
* @return
*/
String getHttpProxyPassword();
}

View File

@@ -3,8 +3,6 @@ package in.egan.pay.common.api;
import in.egan.pay.common.exception.PayErrorException;
/**
* PayErrorExceptionHandler处理器
*
@@ -14,6 +12,10 @@ import in.egan.pay.common.exception.PayErrorException;
*/
public interface PayErrorExceptionHandler {
public void handle(PayErrorException e);
/**
* 异常统一处理器
* @param e
*/
void handle(PayErrorException e);
}

View File

@@ -3,6 +3,7 @@ package in.egan.pay.common.api;
import in.egan.pay.common.bean.PayMessage;
import in.egan.pay.common.bean.PayOutMessage;
import in.egan.pay.common.exception.PayErrorException;
import java.util.Map;
@@ -22,8 +23,8 @@ public interface PayMessageHandler {
* @return xml,text格式的消息如果在异步规则里处理的话可以返回null
*/
public PayOutMessage handle(PayMessage payMessage,
Map<String, Object> context,
PayService payService
) throws PayErrorException;
Map<String, Object> context,
PayService payService
) throws PayErrorException;
}

View File

@@ -21,7 +21,7 @@ import java.util.concurrent.Future;
* 1. 配置路由规则时要按照从细到粗的原则,否则可能消息可能会被提前处理
* 2. 默认情况下消息只会被处理一次,除非使用 {@link PayMessageRouterRule#next()}
* 3. 规则的结束必须用{@link PayMessageRouterRule#end()}或者{@link PayMessageRouterRule#next()},否则不会生效
*
*
* 使用方法:
* PayMessageRouter router = new PayMessageRouter();
* router
@@ -33,10 +33,10 @@ import java.util.concurrent.Future;
* // 另外一个匹配规则
* .end()
* ;
*
*
* // 将PayMessage交给消息路由器
* router.route(message);
*
*
* </pre>
* @source chanjarster/weixin-java-tools
* @source Daniel Qian

View File

@@ -21,6 +21,7 @@ import java.util.regex.Pattern;
*/
public class PayMessageRouterRule {
private final PayMessageRouter routerBuilder;
private boolean async = true;
@@ -29,9 +30,9 @@ public class PayMessageRouterRule {
private String msgType;
private String event;
private String payType;
private String eventKey;
private String[] transactionType;
private String discount;
@@ -75,24 +76,24 @@ public class PayMessageRouterRule {
}
/**
* 如果event等于某值
* 如果payType等于某值
*
* @param event
* @param payType
* @return
*/
public PayMessageRouterRule event(String event) {
this.event = event;
public PayMessageRouterRule payType(String payType) {
this.payType = payType;
return this;
}
/**
* 如果eventKey等于某值
* 如果transactionType等于某值
*
* @param eventKey
* @param transactionType
* @return
*/
public PayMessageRouterRule eventKey(String eventKey) {
this.eventKey = eventKey;
public PayMessageRouterRule transactionType(String ... transactionType) {
this.transactionType = transactionType;
return this;
}
@@ -238,9 +239,9 @@ public class PayMessageRouterRule {
&&
(this.msgType == null || this.msgType.toLowerCase().equals((payMessage.getMsgType() ==null?null:payMessage.getMsgType().toLowerCase())))
&&
(this.event == null || this.event.equals((payMessage.getEvent() == null ? null : payMessage.getEvent())))
(this.payType == null || this.payType.equals((payMessage.getPayType() == null ? null : payMessage.getPayType())))
&&
(this.eventKey == null || this.eventKey.toLowerCase().equals((payMessage.getEventKey()==null?null:payMessage.getEventKey().toLowerCase())))
(this.transactionType == null || equalsTransactionType(payMessage.getTransactionType()))
&&
(this.discount == null || this.discount
.equals(payMessage.getDiscount() == null ? null : payMessage.getDiscount().trim()))
@@ -257,6 +258,27 @@ public class PayMessageRouterRule {
;
}
/**
* 匹配交易类型
* @param transactionType 交易类型
* @return
*/
public boolean equalsTransactionType(String transactionType) {
if (null == transactionType){
return false;
}
for (String type :this.getTransactionType()){
if (type.toLowerCase().equals((transactionType.toLowerCase()))){
return true;
}
}
return false;
}
/**
* 处理支付回调过来的消息
*
@@ -319,20 +341,20 @@ public class PayMessageRouterRule {
this.msgType = msgType;
}
public String getEvent() {
return event;
public String getPayType() {
return payType;
}
public void setEvent(String event) {
this.event = event;
public void setPayType(String payType) {
this.payType = payType;
}
public String getEventKey() {
return eventKey;
public String[] getTransactionType() {
return transactionType;
}
public void setEventKey(String eventKey) {
this.eventKey = eventKey;
public void setTransactionType(String[] transactionType) {
this.transactionType = transactionType;
}
public String getDiscount() {

View File

@@ -3,86 +3,87 @@ package in.egan.pay.common.api;
import in.egan.pay.common.bean.MethodType;
import in.egan.pay.common.bean.PayOrder;
import in.egan.pay.common.bean.PayOutMessage;
import in.egan.pay.common.exception.PayErrorException;
import in.egan.pay.common.bean.TransactionType;
import in.egan.pay.common.http.HttpConfigStorage;
import in.egan.pay.common.http.HttpRequestTemplate;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 支付通知
* 支付服务
*
* @author egan
* @email egzosn@gmail.com
* @date 2016-5-18 14:09:01
*/
public interface PayService {
public interface PayService {
/**
* 回调校验URL
* @return
*/
String getHttpsVerifyUrl();
/**
* 设置支付配置
*
* @param payConfigStorage
*/
void setPayConfigStorage(PayConfigStorage payConfigStorage);
PayService setPayConfigStorage(PayConfigStorage payConfigStorage);
/**
* 获取支付配置
*
* @return
*/
PayConfigStorage getPayConfigStorage();
PayConfigStorage getPayConfigStorage();
/**
* 获取http请求工具
*
* @return
*/
HttpRequestTemplate getHttpRequestTemplate();
/**
* 设置 请求工具配置
* @param configStorage http请求配置
* @return
*/
PayService setRequestTemplateConfigStorage(HttpConfigStorage configStorage);
/**
* 回调校验
*
* @param params 回调回来的参数集
* @return
*/
boolean verify(Map<String, String> params);
boolean verify(Map<String, String> params);
/**
* 签名校验
*
* @param params 参数集
* @param sign 签名
* @param sign 签名
* @return
*/
boolean getSignVerify(Map<String, String> params, String sign);
boolean signVerify(Map<String, String> params, String sign);
/**
* URL校验
* @param notify_id
* 校验数据来源
*
* @param id 业务id, 数据的真实性.
* @return
* @throws PayErrorException
*/
String verifyUrl(String notify_id) throws PayErrorException;
boolean verifySource(String id);
/**
* 请求接口
* @param executor 请求的具体执行者
* @param uri 请求地址
* @param data 请求数据
* @param <T> 返回类型
* @param <E> 请求数据类型
* @return
* @throws PayErrorException
* @source
*/
<T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws PayErrorException;
/**
* 返回创建的订单信息
*
* @param order 支付订单
* @return
* @see in.egan.pay.common.bean.PayOrder
* @see PayOrder
*/
Map orderInfo(PayOrder order);
Map orderInfo(PayOrder order);
/**
* 创建签名
@@ -91,18 +92,29 @@ import java.util.Map;
* @param characterEncoding 字符编码
* @return
*/
String createSign(String content, String characterEncoding);
String createSign(String content, String characterEncoding);
/**
* 创建签名
*
* @param content 需要签名的内容
* @param characterEncoding 字符编码
* @return
*/
String createSign(Map<String, Object> content, String characterEncoding);
/**
* 将请求参数或者请求流转化为 Map
*
* @param parameterMap 请求参数
* @param is 请求流
* @return
*/
Map<String, String> getParameter2Map(Map<String, String[]> parameterMap, InputStream is);
Map<String, String> getParameter2Map(Map<String, String[]> parameterMap, InputStream is);
/**
* 获取输出消息,用户返回给支付端
*
* @param code
* @param message
* @return
@@ -111,59 +123,133 @@ import java.util.Map;
/**
* 获取输出消息,用户返回给支付端, 针对于web端
*
* @param orderInfo 发起支付的订单信息
* @param method 请求方式 "post" "get",
* @see in.egan.pay.common.bean.MethodType
* @param method 请求方式 "post" "get",
* @return
* @see MethodType
*/
String buildRequest(Map<String, Object> orderInfo, MethodType method);
String buildRequest(Map<String, Object> orderInfo, MethodType method);
/**
* 获取输出二维码,用户返回给支付端,
*
* @param orderInfo 发起支付的订单信息
* @return
*/
BufferedImage genQrPay(Map<String, Object> orderInfo);
/**
* 交易查询接口
* @param tradeNo 支付平台订单号
* 交易查询接口
*
* @param tradeNo 支付平台订单号
* @param outTradeNo 商户单号
* @return
*/
Map<String, Object> query(String tradeNo, String outTradeNo);
/**
* 交易关闭接口
* @param tradeNo 支付平台订单号
* 交易查询接口
* @param tradeNo 支付平台订单号
* @param outTradeNo 商户单号
* @param callback 处理器
* @param <T> 返回类型
* @return
*/
<T>T query(String tradeNo, String outTradeNo, Callback<T> callback);
/**
* 交易关闭接口
*
* @param tradeNo 支付平台订单号
* @param outTradeNo 商户单号
* @return
*/
Map<String, Object> close(String tradeNo, String outTradeNo);
/**
* 交易关闭接口
* @param tradeNo 支付平台订单号
* 交易关闭接口
*
* @param tradeNo 支付平台订单号
* @param outTradeNo 商户单号
* @param callback 处理器
* @param <T> 返回类型
* @return
*/
<T>T close(String tradeNo, String outTradeNo, Callback<T> callback);
/**
* 交易关闭接口
*
* @param tradeNo 支付平台订单号
* @param outTradeNo 商户单号
* @return
*/
Map<String, Object> refund(String tradeNo, String outTradeNo);
/**
* 交易关闭接口
*
* @param tradeNo 支付平台订单号
* @param outTradeNo 商户单号
* @param callback 处理器
* @param <T> 返回类型
* @return
*/
<T>T refund(String tradeNo, String outTradeNo, Callback<T> callback);
/**
* 查询退款
* @param tradeNo 支付平台订单号
* 查询退款
*
* @param tradeNo 支付平台订单号
* @param outTradeNo 商户单号
* @return
*/
Map<String, Object> refundquery(String tradeNo, String outTradeNo);
/**
* 下载对账单
* @param billDate 支付平台订单号
* @param billType 商户单号
* 查询退款
*
* @param tradeNo 支付平台订单号
* @param outTradeNo 商户单号
* @param callback 处理器
* @param <T> 返回类型
* @return
*/
Object downloadbill(Date billDate, String billType);
<T>T refundquery(String tradeNo, String outTradeNo, Callback<T> callback);
/**
* 下载对账单
*
* @param billDate 账单类型商户通过接口或商户经开放平台授权后其所属服务商通过接口可以获取以下账单类型trade、signcustomertrade指商户基于支付宝交易收单的业务账单signcustomer是指基于商户支付宝余额收入及支出等资金变动的帐务账单
* @param billType 账单时间日账单格式为yyyy-MM-dd月账单格式为yyyy-MM。
* @return
*/
Object downloadbill(Date billDate, String billType);
/**
* 下载对账单
*
* @param billDate 账单时间:具体请查看对应支付平台
* @param billType 账单类型,具体请查看对应支付平台
* @param callback 处理器
* @param <T> 返回类型
* @return
*/
<T>T downloadbill(Date billDate, String billType, Callback<T> callback);
/**
* 交易辅助接口
*
* @param tradeNoOrBillDate 支付平台订单号或者账单类型, 具体请
* 类型为{@link String }或者 {@link Date },类型须强制限制,类型不对应则抛出异常{@link in.egan.pay.common.exception.PayErrorException}
* @param outTradeNoBillType 商户单号或者 账单类型
* @param transactionType 交易类型
* @param callback 处理器
* @param <T> 返回类型
* @return
*/
<T>T secondaryInterface(Object tradeNoOrBillDate, String outTradeNoBillType, TransactionType transactionType, Callback<T> callback);
}

View File

@@ -1,10 +1,10 @@
package in.egan.pay.common.bean;
import in.egan.pay.common.api.PayConsts;
import java.io.Serializable;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
@@ -13,14 +13,13 @@ import java.util.Map;
* 基础实现,具体可根据具体支付回调的消息去实现
* @author egan
* @email egzosn@gmail.com
* @date 2016-6-1 14:2:3
* @source chanjarster/weixin-java-tools
* @date 2017/3/7 16:37
*/
public class PayMessage implements Serializable {
private Map<String, String> payMessage = null;
private String msgType;
private String event;
private String eventKey;
private String payType;
private String transactionType;
private String fromPay;
private String describe;
@@ -28,12 +27,20 @@ public class PayMessage implements Serializable {
this.payMessage = payMessage;
}
public PayMessage(Map<String, String> payMessage, String event, String msgType) {
public PayMessage(Map<String, String> payMessage, String payType, String msgType) {
this(payMessage);
this.event = event;
this.payType = payType;
this.msgType = msgType;
}
public PayMessage(Map<String, String> payMessage, String msgType, String payType, String transactionType) {
this.payMessage = payMessage;
this.msgType = msgType;
this.payType = payType;
this.transactionType = transactionType;
}
public String getMsgType() {
return msgType;
}
@@ -42,20 +49,21 @@ public class PayMessage implements Serializable {
this.msgType = msgType;
}
public String getEvent() {
return event;
public String getPayType() {
return payType;
}
public void setEvent(String event) {
this.event = event;
public void setPayType(String payType) {
this.payType = payType;
}
public String getEventKey() {
return eventKey;
public String getTransactionType() {
return transactionType;
}
public void setEventKey(String eventKey) {
this.eventKey = eventKey;
public void setTransactionType(String transactionType) {
this.transactionType = transactionType;
}
public String getFromPay() {
@@ -288,4 +296,5 @@ public class PayMessage implements Serializable {
}
}

View File

@@ -1,6 +1,7 @@
package in.egan.pay.common.bean.outbuilder;
import in.egan.pay.common.api.PayConsts;
import in.egan.pay.common.bean.MsgType;
import in.egan.pay.common.before.api.PayConsts;
import in.egan.pay.common.bean.PayOutMessage;
/**
@@ -11,11 +12,13 @@ import in.egan.pay.common.bean.PayOutMessage;
public class PayJsonOutMessage extends PayOutMessage{
public PayJsonOutMessage() {
this.msgType = PayConsts.OUT_MSG_JSON;
this.msgType = MsgType.json.name();
}
@Override
public String toMessage() {
return getContent();
}
}

View File

@@ -1,6 +1,7 @@
package in.egan.pay.common.bean.outbuilder;
import in.egan.pay.common.api.PayConsts;
import in.egan.pay.common.bean.MsgType;
import in.egan.pay.common.before.api.PayConsts;
import in.egan.pay.common.bean.PayOutMessage;
/**
@@ -11,7 +12,7 @@ import in.egan.pay.common.bean.PayOutMessage;
public class PayTextOutMessage extends PayOutMessage{
public PayTextOutMessage() {
this.msgType = PayConsts.OUT_MSG_TEXT;
this.msgType = MsgType.text.name();
}
@Override

View File

@@ -1,6 +1,7 @@
package in.egan.pay.common.bean.outbuilder;
import in.egan.pay.common.api.PayConsts;
import in.egan.pay.common.bean.MsgType;
import in.egan.pay.common.before.api.PayConsts;
import in.egan.pay.common.bean.PayOutMessage;
/**
@@ -13,7 +14,7 @@ public class PayXmlOutMessage extends PayOutMessage{
private String code;
public PayXmlOutMessage() {
this.msgType = PayConsts.OUT_MSG_XML;
this.msgType = MsgType.xml.name();
}
public String getCode() {

View File

@@ -1,102 +1,32 @@
package in.egan.pay.common.bean.result;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import in.egan.pay.common.util.XML;
import java.io.Serializable;
import java.util.Map;
/**
* 支付错误码说明
* @author Daniel Qian
* @dete 2017/1/12 9:57
* @author: egan
* @source chanjarster/weixin-java-tools
*
* @author egan
* @email egzosn@gmail.com
* @date 2017-03-02 22:28:01
*/
public interface PayError {
public class PayError implements Serializable {
/**
* 获取错误码
*
* @return
*/
String getErrorCode();
private int errorCode;
/**
* 获取错误消息
*
* @return
*/
String getErrorMsg();
private String errorMsg;
private JSONObject json;
private String responseContent;
public PayError() {
}
public PayError(int errorCode, String errorMsg) {
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public PayError(int errorCode, String errorMsg, String responseContent) {
this(errorCode, errorMsg);
this.responseContent = responseContent;
}
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
public JSONObject getJson() {
return json;
}
public void setJson(JSONObject json) {
this.json = json;
}
public String getResponseContent() {
return responseContent;
}
public void setResponseContent(String responseContent) {
this.responseContent = responseContent;
}
public static PayError fromJson(String json) {
JSONObject jsonObject = JSON.parseObject(json);
PayError error = jsonObject.toJavaObject(PayError.class);
error.setJson(jsonObject);
error.setResponseContent(json);
return error;
}
public static PayError fromXml(String xml) {
JSONObject jsonObject = XML.toJSONObject(xml);
if (null == jsonObject.get("return_code")){
PayError error = new PayError(403, null == jsonObject.get("return_msg") ? "未知错误!" : jsonObject.get("return_msg").toString());
return error;
}
if ("FAIL".equals( jsonObject.get("return_code"))){
PayError error = new PayError(-1, jsonObject.get("return_msg").toString());
return error;
}
return null;
}
@Override
public String toString() {
return "支付错误: errcode=" + errorCode + ", errmsg=" + errorMsg + "\njson:" + json;
}
/**
* 获取异常信息
* @return
*/
String getString();
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2002-2017 the original huodull or egan.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package in.egan.pay.common.bean.result;
/**
* @author: egan
* @email egzosn@gmail.com
* @date 2017/3/7 12:32
*/
public class PayException implements PayError {
private String errorCode;
private String errorMsg;
private String content;
@Override
public String getErrorCode() {
return errorCode;
}
@Override
public String getErrorMsg() {
return errorMsg;
}
public PayException(String errorCode, String errorMsg) {
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public PayException(String errorCode, String errorMsg, String content) {
this.errorCode = errorCode;
this.errorMsg = errorMsg;
this.content = content;
}
@Override
public String getString() {
return "支付错误: errcode=" + errorCode + ", errmsg=" + errorMsg + (null == content ? "" : "\n content:" + content);
}
}

View File

@@ -0,0 +1,230 @@
package in.egan.pay.common.before.api;
import in.egan.pay.common.bean.MsgType;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 支付基础配置存储
* @author egan
* @email egzosn@gmail.com
* @date 2016-5-18 14:09:01
*/
@Deprecated
public abstract class BasePayConfigStorage implements PayConfigStorage{
// ali rsa_private 商户私钥pkcs8格式
//wx api_key 商户密钥
protected volatile String keyPrivate ;
// 支付公钥
protected volatile String keyPublic;
//异步回调地址
protected volatile String notifyUrl;
//同步回调地址
protected volatile String returnUrl;;
//签名加密类型
protected volatile String signType;
//字符类型
protected volatile String inputCharset;
//支付类型 aliPay 支付宝, wxPay微信..等等,开发者自定义,唯一
protected volatile String payType;
/**
* 消息来源类型
* @see PayConsts#MSG_XML
* @see PayConsts#MSG_TEXT
* @see PayConsts#MSG_JSON
*/
protected volatile MsgType msgType;
// 访问令牌 每次请求其他方法都要传入的值
protected volatile String accessToken;
// access token 到期时间时间戳
protected volatile long expiresTime;
//授权码锁
protected Lock accessTokenLock = new ReentrantLock();
protected volatile String httpProxyHost;
protected volatile int httpProxyPort;
protected volatile String httpProxyUsername;
protected volatile String httpProxyPassword;
/**
* 合作商唯一标识
* @see #getPartner 代替者
*/
public String getPid(){
throw null;
}
@Override
public String getInputCharset() {
return inputCharset;
}
public void setInputCharset(String inputCharset) {
this.inputCharset = inputCharset;
}
@Override
public String getNotifyUrl() {
return notifyUrl;
}
public void setNotifyUrl(String notifyUrl) {
this.notifyUrl = notifyUrl;
}
@Override
public String getReturnUrl() {
return returnUrl;
}
public void setReturnUrl(String returnUrl) {
this.returnUrl = returnUrl;
}
public void setSignType(String signType) {
this.signType = signType;
}
@Override
public String getSignType() {
return signType;
}
@Override
public String getHttpProxyHost() {
return httpProxyHost;
}
public void setHttpProxyHost(String httpProxyHost) {
this.httpProxyHost = httpProxyHost;
}
@Override
public int getHttpProxyPort() {
return httpProxyPort;
}
public void setHttpProxyPort(int httpProxyPort) {
this.httpProxyPort = httpProxyPort;
}
@Override
public String getHttpProxyUsername() {
return httpProxyUsername;
}
public void setHttpProxyUsername(String httpProxyUsername) {
this.httpProxyUsername = httpProxyUsername;
}
@Override
public String getHttpProxyPassword() {
return httpProxyPassword;
}
public void setHttpProxyPassword(String httpProxyPassword) {
this.httpProxyPassword = httpProxyPassword;
}
@Override
public String getKeyPrivate() {
return keyPrivate;
}
public void setKeyPrivate(String keyPrivate) {
this.keyPrivate = keyPrivate;
}
@Override
public String getKeyPublic() {
return keyPublic;
}
public void setKeyPublic(String keyPublic) {
this.keyPublic = keyPublic;
}
@Override
public String getToken() {
return null;
}
/**
* 支付类型 自定义
* 这里暂定 aliPay 支付宝, wxPay微信支付
* @return
*/
public String getPayType() {
return payType;
}
public void setPayType(String payType) {
this.payType = payType;
}
@Override
public MsgType getMsgType() {
return msgType;
}
public void setMsgType(MsgType msgType) {
this.msgType = msgType;
}
@Override
public String getAccessToken() {
return this.accessToken;
}
@Override
public Lock getAccessTokenLock() {
return this.accessTokenLock;
}
@Override
public long getExpiresTime() {
return expiresTime;
}
@Override
public boolean isAccessTokenExpired() {
return System.currentTimeMillis() > this.expiresTime;
}
@Override
public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) {
this.accessToken = accessToken;
this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 600) * 1000L;
}
@Override
public synchronized void updateAccessToken(String accessToken, long expiresTime) {
this.accessToken = accessToken;
this.expiresTime = expiresTime;
}
@Override
public void expireAccessToken() {
this.expiresTime = 0;
}
}

View File

@@ -0,0 +1,109 @@
package in.egan.pay.common.before.api;
import in.egan.pay.common.exception.PayErrorException;
import in.egan.pay.common.util.str.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import java.io.IOException;
/**
* @author: egan
* @email egzosn@gmail.com
* @date 2017/1/12 20:09
* @source chanjarster/weixin-java-tools
*/
@Deprecated
public abstract class BasePayService implements PayService {
protected PayConfigStorage payConfigStorage;
protected CloseableHttpClient httpClient;
protected HttpHost httpProxy;
protected int retrySleepMillis = 1000;
protected int maxRetryTimes = 5;
/**
*
* @param executor
* @param uri
* @param data
* @param <T>
* @param <E>
* @return
* @throws PayErrorException
*/
protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws PayErrorException {
try {
return executor.execute(getHttpClient(), httpProxy, uri, data);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public HttpHost getHttpProxy() {
return httpProxy;
}
public CloseableHttpClient getHttpClient() {
return httpClient;
}
/**
* 设置支付配置
* @param payConfigStorage 支付配置
*/
@Deprecated
public void setPayConfigStorage(PayConfigStorage payConfigStorage) {
this.payConfigStorage = payConfigStorage;
String http_proxy_host = payConfigStorage.getHttpProxyHost();
int http_proxy_port = payConfigStorage.getHttpProxyPort();
String http_proxy_username = payConfigStorage.getHttpProxyUsername();
String http_proxy_password = payConfigStorage.getHttpProxyPassword();
if (StringUtils.isNotBlank(http_proxy_host)) {
// 使用代理服务器
if (StringUtils.isNotBlank(http_proxy_username)) {
// 需要用户认证的代理服务器
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(http_proxy_host, http_proxy_port),
new UsernamePasswordCredentials(http_proxy_username, http_proxy_password));
httpClient = HttpClients
.custom()
.setDefaultCredentialsProvider(credsProvider)
.build();
} else {
// 无需用户认证的代理服务器
httpClient = HttpClients.createDefault();
}
httpProxy = new HttpHost(http_proxy_host, http_proxy_port);
} else {
httpClient = HttpClients.createDefault();
}
}
@Override
public PayConfigStorage getPayConfigStorage() {
return payConfigStorage;
}
public BasePayService() {
}
public BasePayService(PayConfigStorage payConfigStorage) {
setPayConfigStorage(payConfigStorage);
}
}

View File

@@ -0,0 +1,167 @@
package in.egan.pay.common.before.api;
import in.egan.pay.common.bean.MsgType;
import java.util.concurrent.locks.Lock;
/**
* 支付客户端配置存储
* @author egan
* @email egzosn@gmail.com
* @date 2016-5-18 14:09:01
* @source chanjarster/weixin-java-tools
* @see in.egan.pay.common.api.PayConfigStorage
*/
@Deprecated
public interface PayConfigStorage {
/*
* 应用id
*/
String getAppid();
/**
* 合作商唯一标识
*/
@Deprecated
String getPartner();
/**
* 合作商唯一标识
* @see #getPartner 代替者
*/
String getPid();
/**
* 获取收款账号
*/
String getSeller();
/**
* 授权令牌
*/
String getToken();
/**
* 服务端异步回调Url
*/
String getNotifyUrl();
/**
* 服务端同步回调Url
*/
String getReturnUrl();
/**
* 签名方式
*/
String getSignType();
// 字符编码格式 目前支持 gbk 或 utf-8
String getInputCharset();
/**
* 获取密钥 与 #getKeyPrivate 类似
*/
String getSecretKey();
/**
* 公钥
* @return
*/
String getKeyPublic();
/**
* 私钥
* @return
*/
String getKeyPrivate();
/**
* 支付类型 自定义
* 这里暂定 aliPay 支付宝, wxPay微信支付
* @return
*/
String getPayType();
/**
* 消息类型
* @see #getMsgType
* @see MsgType
* @return "text" 或者 "xml"
* @see MsgType#text
* @see MsgType#xml
* @see MsgType#json
*/
MsgType getMsgType();
/**
* 获取访问令牌
* @return
*/
String getAccessToken();
/**
* 访问令牌是否过期
* @return
*/
boolean isAccessTokenExpired();
/**
* 获取access token锁
* @return
*/
Lock getAccessTokenLock();
/**
* 强制将access token过期掉
*/
void expireAccessToken();
/**
* 强制将access token过期掉
*/
long getExpiresTime();
/**
* 应该是线程安全的
* @param accessToken 新的accessToken值
* @param expiresInSeconds 过期时间,以秒为单位 多少秒
*/
void updateAccessToken(String accessToken, int expiresInSeconds);
/**
* 应该是线程安全的
* @param accessToken 新的accessToken值
* @param expiresTime 过期时间,时间戳
*/
void updateAccessToken(String accessToken, long expiresTime);
/**
* http代理地址
* @return
* @see in.egan.pay.common.http.HttpConfigStorage#getHttpProxyHost()
*/
@Deprecated
String getHttpProxyHost();
/**
* 代理端口
* @return
* @see in.egan.pay.common.http.HttpConfigStorage#getHttpProxyPort()
*/
@Deprecated
int getHttpProxyPort();
/**
* 代理用户名
* @return
* @see in.egan.pay.common.http.HttpConfigStorage#getHttpProxyUsername()
*/
@Deprecated
String getHttpProxyUsername();
/**
* 代理密码
* @return
* @see in.egan.pay.common.http.HttpConfigStorage#getHttpProxyPassword()
*/
@Deprecated
String getHttpProxyPassword();
}

View File

@@ -1,4 +1,4 @@
package in.egan.pay.common.api;
package in.egan.pay.common.before.api;
/**
* 支付宝支付通知

View File

@@ -0,0 +1,31 @@
package in.egan.pay.common.before.api;
import in.egan.pay.common.bean.PayMessage;
import in.egan.pay.common.bean.PayOutMessage;
import in.egan.pay.common.before.api.*;
import in.egan.pay.common.exception.PayErrorException;
import java.util.Map;
/**
* 处理支付回调消息的处理器接口
* @source Daniel Qian
* @author egan
* @email egzosn@gmail.com
* @date 2016-6-1 11:40:30
*/
@Deprecated
public interface PayMessageHandler {
/**
* @param payMessage
* @param context 上下文如果handler或interceptor之间有信息要传递可以用这个
* @param payService
* @return xml,text格式的消息如果在异步规则里处理的话可以返回null
*/
public PayOutMessage handle(PayMessage payMessage,
Map<String, Object> context,
in.egan.pay.common.before.api.PayService payService
) throws PayErrorException;
}

View File

@@ -0,0 +1,29 @@
package in.egan.pay.common.before.api;
import in.egan.pay.common.bean.PayMessage;
import in.egan.pay.common.exception.PayErrorException;
import java.util.Map;
/**
* 支付消息拦截器,可以用来做验证
* @author Daniel Qian
*/
@Deprecated
public interface PayMessageInterceptor {
/**
* 拦截支付消息
*
* @param wxMessage
* @param context 上下文如果handler或interceptor之间有信息要传递可以用这个
* @param payService
* @return true代表OKfalse代表不OK
*/
public boolean intercept(PayMessage wxMessage,
Map<String, Object> context,
PayService payService
) throws PayErrorException;
}

View File

@@ -0,0 +1,166 @@
package in.egan.pay.common.before.api;
import in.egan.pay.common.api.PayErrorExceptionHandler;
import in.egan.pay.common.bean.PayMessage;
import in.egan.pay.common.bean.PayOutMessage;
import in.egan.pay.common.util.LogExceptionHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* <pre>
* 支付消息路由器通过代码化的配置把来自支付的消息交给handler处理
*
* 说明:
* 1. 配置路由规则时要按照从细到粗的原则,否则可能消息可能会被提前处理
* 2. 默认情况下消息只会被处理一次,除非使用 {@link PayMessageRouterRule#next()}
* 3. 规则的结束必须用{@link PayMessageRouterRule#end()}或者{@link PayMessageRouterRule#next()},否则不会生效
*
* 使用方法:
* PayMessageRouter router = new PayMessageRouter();
* router
* .rule()
* .msgType("MSG_TYPE").event("EVENT").eventKey("EVENT_KEY").content("CONTENT")
* .interceptor(interceptor, ...).handler(handler, ...)
* .end()
* .rule()
* // 另外一个匹配规则
* .end()
* ;
*
* // 将PayMessage交给消息路由器
* router.route(message);
*
* </pre>
* @source chanjarster/weixin-java-tools
* @source Daniel Qian
* @author egan
*
*/
@Deprecated
public class PayMessageRouter {
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 in.egan.pay.common.before.api.PayService payService;
private ExecutorService executorService;
private PayErrorExceptionHandler exceptionHandler;
public PayMessageRouter(in.egan.pay.common.before.api.PayService payService) {
this.payService = payService;
this.executorService = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE);
this.exceptionHandler = new LogExceptionHandler();
}
/**
* <pre>
* 设置自定义的 {@link ExecutorService}
* 如果不调用该方法,默认使用 Executors.newFixedThreadPool(100)
* </pre>
* @param executorService
*/
public void setExecutorService(ExecutorService executorService) {
this.executorService = executorService;
}
/**
* <pre>
* 设置自定义的{@link PayErrorExceptionHandler}
* 如果不调用该方法,默认使用 {@link LogExceptionHandler}
* </pre>
* @param exceptionHandler
*/
public void setExceptionHandler(PayErrorExceptionHandler exceptionHandler) {
this.exceptionHandler = exceptionHandler;
}
List<PayMessageRouterRule> getRules() {
return this.rules;
}
/**
* 开始一个新的Route规则
* @return
*/
public PayMessageRouterRule rule() {
return new PayMessageRouterRule(this);
}
/**
* 处理支付消息
* @param payMessage
*/
public PayOutMessage route(final PayMessage payMessage) {
final List<PayMessageRouterRule> matchRules = new ArrayList<PayMessageRouterRule>();
// 收集匹配的规则
for (final PayMessageRouterRule rule : rules) {
if (rule.test(payMessage)) {
matchRules.add(rule);
if(!rule.isReEnter()) {
break;
}
}
}
if (matchRules.size() == 0) {
return null;
}
PayOutMessage res = null;
final List<Future> futures = new ArrayList<Future>();
for (final PayMessageRouterRule rule : matchRules) {
// 返回最后一个非异步的rule的执行结果
if(rule.isAsync()) {
futures.add(
executorService.submit(new Runnable() {
public void run() {
rule.service(payMessage, payService, exceptionHandler);
}
})
);
} else {
res = rule.service(payMessage, payService, exceptionHandler);
// 在同步操作结束session访问结束
log.debug("End session access: async=false, fromPay=" + payMessage.getFromPay());
}
}
if (futures.size() > 0) {
executorService.submit(new Runnable() {
@Override
public void run() {
for (Future future : futures) {
try {
future.get();
log.debug("End session access: async=true, fromPay=" + payMessage.getFromPay());
} catch (InterruptedException e) {
log.error("Error happened when wait task finish", e);
} catch (ExecutionException e) {
log.error("Error happened when wait task finish", e);
}
}
}
});
}
return res;
}
}

View File

@@ -0,0 +1,414 @@
package in.egan.pay.common.before.api;
import in.egan.pay.common.api.PayErrorExceptionHandler;
import in.egan.pay.common.bean.PayMessage;
import in.egan.pay.common.bean.PayOutMessage;
import in.egan.pay.common.exception.PayErrorException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
/**
*
* @author egan
* @email egzosn@gmail.com
* @date 2016-6-1 11:28:01
* @source chanjarster/weixin-java-tools
*/
@Deprecated
public class PayMessageRouterRule {
private final PayMessageRouter routerBuilder;
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 boolean reEnter = false;
private List<PayMessageHandler> handlers = new ArrayList<PayMessageHandler>();
private List<PayMessageInterceptor> interceptors = new ArrayList<PayMessageInterceptor>();
public PayMessageRouterRule(PayMessageRouter routerBuilder) {
this.routerBuilder = routerBuilder;
}
/**
* 设置是否异步执行默认是true
*
* @param async
* @return
*/
public PayMessageRouterRule async(boolean async) {
this.async = async;
return this;
}
/**
* 如果msgType等于某值
*
* @param msgType
* @return
*/
public PayMessageRouterRule msgType(String msgType) {
this.msgType = msgType;
return this;
}
/**
* 如果payType等于某值
*
* @param payType
* @return
*/
public PayMessageRouterRule payType(String payType) {
this.payType = payType;
return this;
}
/**
* 如果transactionType等于某值
*
* @param transactionType
* @return
*/
public PayMessageRouterRule transactionType(String... transactionType) {
this.transactionType = transactionType;
return this;
}
/**
* 如果discount等于某值
*
* @param discount
* @return
*/
public PayMessageRouterRule discount(String discount) {
this.discount = discount;
return this;
}
/**
* 如果discount匹配该正则表达式
*
* @param regex
* @return
*/
public PayMessageRouterRule rDiscount(String regex) {
this.rDiscount = regex;
return this;
}
/**
* 如果discount等于某值
*
* @param subject
* @return
*/
public PayMessageRouterRule subject(String subject) {
this.subject = subject;
return this;
}
/**
* 如果discount匹配该正则表达式
*
* @param regex
* @return
*/
public PayMessageRouterRule rSubject(String regex) {
this.rSubject = regex;
return this;
}
/**
* 如果消息匹配某个matcher用在用户需要自定义更复杂的匹配规则的时候
*
* @param matcher
* @return
*/
/* public PayMessageRouterRule matcher(WxMpMessageMatcher matcher) {
this.matcher = matcher;
return this;
}*/
/**
* 设置微信消息拦截器
*
* @param interceptor
* @return
*/
public PayMessageRouterRule interceptor(PayMessageInterceptor interceptor) {
return interceptor(interceptor, (PayMessageInterceptor[]) null);
}
/**
* 设置微信消息拦截器
*
* @param interceptor
* @param otherInterceptors
* @return
*/
public PayMessageRouterRule interceptor(PayMessageInterceptor interceptor, PayMessageInterceptor... otherInterceptors) {
this.interceptors.add(interceptor);
if (otherInterceptors != null && otherInterceptors.length > 0) {
for (PayMessageInterceptor i : otherInterceptors) {
this.interceptors.add(i);
}
}
return this;
}
/**
* 设置微信消息处理器
*
* @param handler
* @return
*/
public PayMessageRouterRule handler(PayMessageHandler handler) {
return handler(handler, (PayMessageHandler[]) null);
}
/**
* 设置微信消息处理器
*
* @param handler
* @param otherHandlers
* @return
*/
public PayMessageRouterRule handler(PayMessageHandler handler, PayMessageHandler... otherHandlers) {
this.handlers.add(handler);
if (otherHandlers != null && otherHandlers.length > 0) {
for (PayMessageHandler i : otherHandlers) {
this.handlers.add(i);
}
}
return this;
}
/**
* 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则
*
* @return
*/
public PayMessageRouter end() {
this.routerBuilder.getRules().add(this);
return this.routerBuilder;
}
/**
* 规则结束,但是消息还会进入其他规则
*
* @return
*/
public PayMessageRouter next() {
this.reEnter = true;
return end();
}
/**
* 将支付事件修正为不区分大小写,
* 比如框架定义的事件常量为
* @param payMessage
* @return
*/
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.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.subject == null || this.subject
.equals(payMessage.getSubject() == null ? null : payMessage.getSubject().trim()))
&&
(this.rSubject == null || Pattern
.matches(this.rSubject, payMessage.getSubject() == null ? "" : payMessage.getSubject().trim()))
)
;
}
/**
* 匹配交易类型
* @param transactionType 交易类型
* @return
*/
public boolean equalsTransactionType(String transactionType) {
if (null == transactionType){
return false;
}
for (String type :this.getTransactionType()){
if (type.toLowerCase().equals((transactionType.toLowerCase()))){
return true;
}
}
return false;
}
/**
* 处理支付回调过来的消息
*
* @param payService
* @return true 代表继续执行别的routerfalse 代表停止执行别的router
*/
protected PayOutMessage service(PayMessage payMessage,
in.egan.pay.common.before.api.PayService payService,
PayErrorExceptionHandler exceptionHandler) {
try {
Map<String, Object> context = new HashMap<String, Object>();
// 如果拦截器不通过
for (PayMessageInterceptor interceptor : this.interceptors) {
if (!interceptor.intercept(payMessage, context, payService)) {
return null;
}
}
// 交给handler处理
PayOutMessage res = null;
for (PayMessageHandler handler : this.handlers) {
// 返回最后handler的结果
res = handler.handle(payMessage, context, payService);
}
return res;
} catch (PayErrorException e) {
exceptionHandler.handle(e);
}
return null;
}
public PayMessageRouter getRouterBuilder() {
return routerBuilder;
}
public boolean isAsync() {
return async;
}
public void setAsync(boolean async) {
this.async = async;
}
public String getFromPay() {
return fromPay;
}
public void setFromPay(String fromPay) {
this.fromPay = fromPay;
}
public String getMsgType() {
return msgType;
}
public void setMsgType(String msgType) {
this.msgType = msgType;
}
public String getPayType() {
return payType;
}
public void setPayType(String payType) {
this.payType = payType;
}
public String[] getTransactionType() {
return transactionType;
}
public void setTransactionType(String[] transactionType) {
this.transactionType = transactionType;
}
public String getDiscount() {
return discount;
}
public void setDiscount(String discount) {
this.discount = discount;
}
public String getrDiscount() {
return rDiscount;
}
public void setrDiscount(String rDiscount) {
this.rDiscount = rDiscount;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getrSubject() {
return rSubject;
}
public void setrSubject(String rSubject) {
this.rSubject = rSubject;
}
public boolean isReEnter() {
return reEnter;
}
public void setReEnter(boolean reEnter) {
this.reEnter = reEnter;
}
public List<PayMessageHandler> getHandlers() {
return handlers;
}
public void setHandlers(List<PayMessageHandler> handlers) {
this.handlers = handlers;
}
public List<PayMessageInterceptor> getInterceptors() {
return interceptors;
}
public void setInterceptors(List<PayMessageInterceptor> interceptors) {
this.interceptors = interceptors;
}
}

View File

@@ -0,0 +1,169 @@
package in.egan.pay.common.before.api;
import in.egan.pay.common.bean.MethodType;
import in.egan.pay.common.bean.PayOrder;
import in.egan.pay.common.bean.PayOutMessage;
import in.egan.pay.common.exception.PayErrorException;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.util.Date;
import java.util.Map;
/**
* 支付服务
*
* @author egan
* @email egzosn@gmail.com
* @date 2016-5-18 14:09:01
* @see in.egan.pay.common.api.PayService
*/
@Deprecated
public interface PayService {
/**
* 回调校验URL
* @return
*/
String getHttpsVerifyUrl();
/**
* 设置支付配置
* @param payConfigStorage
*/
void setPayConfigStorage(PayConfigStorage payConfigStorage);
/**
* 获取支付配置
* @return
*/
PayConfigStorage getPayConfigStorage();
/**
* 回调校验
* @param params 回调回来的参数集
* @return
*/
boolean verify(Map<String, String> params);
/**
* 签名校验
* @param params 参数集
* @param sign 签名
* @return
*/
boolean getSignVerify(Map<String, String> params, String sign);
/**
* URL校验
* @param notify_id
* @return
* @throws PayErrorException
*/
String verifyUrl(String notify_id) throws PayErrorException;
/**
* 请求接口
* @param executor 请求的具体执行者
* @param uri 请求地址
* @param data 请求数据
* @param <T> 返回类型
* @param <E> 请求数据类型
* @return
* @throws PayErrorException
* @source
*/
<T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws PayErrorException;
/**
* 返回创建的订单信息
*
* @param order 支付订单
* @return
* @see PayOrder
*/
Map orderInfo(PayOrder order);
/**
* 创建签名
*
* @param content 需要签名的内容
* @param characterEncoding 字符编码
* @return
*/
String createSign(String content, String characterEncoding);
/**
* 将请求参数或者请求流转化为 Map
* @param parameterMap 请求参数
* @param is 请求流
* @return
*/
Map<String, String> getParameter2Map(Map<String, String[]> parameterMap, InputStream is);
/**
* 获取输出消息,用户返回给支付端
* @param code
* @param message
* @return
*/
PayOutMessage getPayOutMessage(String code, String message);
/**
* 获取输出消息,用户返回给支付端, 针对于web端
* @param orderInfo 发起支付的订单信息
* @param method 请求方式 "post" "get",
* @see MethodType
* @return
*/
String buildRequest(Map<String, Object> orderInfo, MethodType method);
/**
* 获取输出二维码,用户返回给支付端,
* @param orderInfo 发起支付的订单信息
* @return
*/
BufferedImage genQrPay(Map<String, Object> orderInfo);
/**
* 交易查询接口
* @param tradeNo 支付平台订单号
* @param outTradeNo 商户单号
* @return
*/
Map<String, Object> query(String tradeNo, String outTradeNo);
/**
* 交易关闭接口
* @param tradeNo 支付平台订单号
* @param outTradeNo 商户单号
* @return
*/
Map<String, Object> close(String tradeNo, String outTradeNo);
/**
* 交易关闭接口
* @param tradeNo 支付平台订单号
* @param outTradeNo 商户单号
* @return
*/
Map<String, Object> refund(String tradeNo, String outTradeNo);
/**
* 查询退款
* @param tradeNo 支付平台订单号
* @param outTradeNo 商户单号
* @return
*/
Map<String, Object> refundquery(String tradeNo, String outTradeNo);
/**
* 下载对账单
* @param billDate 账单类型商户通过接口或商户经开放平台授权后其所属服务商通过接口可以获取以下账单类型trade、signcustomertrade指商户基于支付宝交易收单的业务账单signcustomer是指基于商户支付宝余额收入及支出等资金变动的帐务账单
* @param billType 账单时间日账单格式为yyyy-MM-dd月账单格式为yyyy-MM。
* @return
*/
Object downloadbill(Date billDate, String billType);
}

View File

@@ -1,9 +1,8 @@
package in.egan.pay.common.api;
package in.egan.pay.common.before.api;
import in.egan.pay.common.exception.PayErrorException;
import org.apache.http.HttpHost;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.impl.client.CloseableHttpClient;
import java.io.IOException;
@@ -15,6 +14,7 @@ import java.io.IOException;
* @param <E> 请求参数类型
* @source chanjarster/weixin-java-tools
*/
@Deprecated
public interface RequestExecutor<T, E> {
/**

View File

@@ -0,0 +1,107 @@
package in.egan.pay.common.before.bean.result;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import in.egan.pay.common.util.XML;
import java.io.Serializable;
/**
* 支付错误码说明
* @author Daniel Qian
* @dete 2017/1/12 9:57
* @author: egan
* @source chanjarster/weixin-java-tools
* @see in.egan.pay.common.bean.result.PayError
*/
@Deprecated
public class PayError implements in.egan.pay.common.bean.result.PayError, Serializable {
private int errorCode;
private String errorMsg;
private JSONObject json;
private String responseContent;
public PayError() {
}
public PayError(int errorCode, String errorMsg) {
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public PayError(int errorCode, String errorMsg, String responseContent) {
this(errorCode, errorMsg);
this.responseContent = responseContent;
}
public String getErrorCode() {
return errorCode + "";
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
@Override
public String getString() {
return "支付错误: errcode=" + errorCode + ", errmsg=" + errorMsg + "\njson:" + json;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
public JSONObject getJson() {
return json;
}
public void setJson(JSONObject json) {
this.json = json;
}
public String getResponseContent() {
return responseContent;
}
public void setResponseContent(String responseContent) {
this.responseContent = responseContent;
}
public static PayError fromJson(String json) {
JSONObject jsonObject = JSON.parseObject(json);
PayError error = jsonObject.toJavaObject(PayError.class);
error.setJson(jsonObject);
error.setResponseContent(json);
return error;
}
public static PayError fromXml(String xml) {
JSONObject jsonObject = XML.toJSONObject(xml);
if (null == jsonObject.get("return_code")){
PayError error = new PayError(403, null == jsonObject.get("return_msg") ? "未知错误!" : jsonObject.get("return_msg").toString());
return error;
}
if ("FAIL".equals( jsonObject.get("return_code"))){
PayError error = new PayError(-1, jsonObject.get("return_msg").toString());
return error;
}
return null;
}
@Override
public String toString() {
return "支付错误: errcode=" + errorCode + ", errmsg=" + errorMsg + "\njson:" + json;
}
}

View File

@@ -1,4 +1,4 @@
package in.egan.pay.common.util.http;
package in.egan.pay.common.before.util.http;
/**
* @author egan
@@ -7,8 +7,7 @@ package in.egan.pay.common.util.http;
* @source chanjarster/weixin-java-tools
*/
import in.egan.pay.common.api.RequestExecutor;
import in.egan.pay.common.bean.result.PayError;
import in.egan.pay.common.before.api.RequestExecutor;
import in.egan.pay.common.exception.PayErrorException;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
@@ -18,10 +17,6 @@ import org.apache.http.impl.client.CloseableHttpClient;
import java.io.IOException;
import org.apache.http.impl.client.CloseableHttpClient;
/**
* 简单的GET请求执行器请求的参数是String, 返回的结果也是String
* @author Daniel Qian

View File

@@ -1,7 +1,6 @@
package in.egan.pay.common.util.http;
package in.egan.pay.common.before.util.http;
import in.egan.pay.common.api.RequestExecutor;
import in.egan.pay.common.bean.result.PayError;
import in.egan.pay.common.before.api.RequestExecutor;
import in.egan.pay.common.exception.PayErrorException;
import org.apache.http.Consts;
import org.apache.http.HttpHost;

View File

@@ -1,4 +1,4 @@
package in.egan.pay.common.util.http;
package in.egan.pay.common.before.util.http;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
@@ -24,7 +24,7 @@ public class Utf8ResponseHandler implements ResponseHandler<String> {
public String handleResponse(final HttpResponse response) throws IOException {
final StatusLine statusLine = response.getStatusLine();
final HttpEntity entity = response.getEntity();
if (statusLine.getStatusCode() >= 300) {
if (statusLine.getStatusCode() >= 300 && statusLine.getStatusCode() != 304) {
EntityUtils.consume(entity);
throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
}

View File

@@ -1,23 +1,24 @@
package in.egan.pay.common.exception;
import com.alibaba.fastjson.JSON;
import in.egan.pay.common.bean.result.PayError;
/**
* @author egan
* @email egzosn@gmail.com
* @date 2016-5-18 14:09:01
* @source chanjarster/weixin-java-tools
*/
public class PayErrorException extends Exception {
public class PayErrorException extends RuntimeException {
private PayError error;
public PayErrorException(PayError error) {
super(error.toString());
super(error.getString());
this.error = error;
}
public PayError getError() {
public PayError getPayError() {
return error;
}
}

View File

@@ -0,0 +1,220 @@
package in.egan.pay.common.http;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import in.egan.pay.common.bean.MethodType;
import in.egan.pay.common.bean.result.PayException;
import in.egan.pay.common.exception.PayErrorException;
import in.egan.pay.common.util.XML;
import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
/**
* 一个HTTP请求的客户端
* @author: egan
* @email egzosn@gmail.com
* @date 2017/3/4 17:56
*/
public class ClientHttpRequest<T> extends HttpEntityEnclosingRequestBase implements org.apache.http.client.ResponseHandler<T>{
//http请求
private MethodType method;
//响应类型
private Class<T> responseType;
public ClientHttpRequest<T> setResponseType(Class<T> responseType) {
this.responseType = responseType;
return this;
}
public ClientHttpRequest() {
}
public ClientHttpRequest(URI uri, MethodType method, Object request) {
this.setURI(uri);
this.method = method;
setParameters(request);
}
public ClientHttpRequest(URI uri, MethodType method) {
this.setURI(uri);
this.method = method;
}
public ClientHttpRequest(URI uri) {
this.setURI(uri);
}
public ClientHttpRequest(String uri) {
this.setURI(URI.create(uri));
}
public ClientHttpRequest(String uri, MethodType method) {
this.setURI(URI.create(uri));
this.method = method;
}
public ClientHttpRequest(String uri, MethodType method, Object request) {
this.setURI(URI.create(uri));
this.method = method;
setParameters(request);
}
public void setMethod(MethodType method) {
this.method = method;
}
@Override
public String getMethod() {
return method.name();
}
/**
* 设置代理
* @param httpProxy http代理配置信息
* @return
*/
public ClientHttpRequest setProxy(HttpHost httpProxy){
if (httpProxy != null) {
RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build();
setConfig(config);
}
return this;
}
/**
* Map转化为对应得参数字符串
* @param pe
* @return
*/
public static String getMapToParameters(Map pe){
StringBuilder builder = new StringBuilder();
for (Object key : pe.keySet()) {
Object o = pe.get(key);
if (null == o) {
continue;
}
if (o instanceof List) {
o = ((List) o).toArray();
}
try {
if (o instanceof Object[]) {
Object[] os = (Object[]) o;
String valueStr = "";
for (int i = 0, len = os.length; i < len; i++) {
if (null == os[i]) {
continue;
}
String value = os[i].toString().trim();
valueStr += (i == len - 1) ? value : value + ",";
}
builder.append(key).append("=").append(URLEncoder.encode(valueStr, "utf-8")).append("&");
continue;
}
builder.append(key).append("=").append(URLEncoder.encode((String) pe.get(key), "utf-8")).append("&");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
if (builder.length() > 1) {
builder.deleteCharAt(builder.length() - 1);
}
return builder.toString();
}
/**
* 设置请求参数
*
* @param request 请求参数
* @return
*/
public ClientHttpRequest setParameters(Object request) {
if (null == request){
return this;
}
if (request instanceof Map) {
StringEntity entity = new StringEntity(getMapToParameters((Map) request), Consts.UTF_8);
setEntity(entity);
} else if (request instanceof String) {
StringEntity entity = new StringEntity((String) request, Consts.UTF_8);
setEntity(entity);
} else {
StringEntity entity = new StringEntity(JSON.toJSONString(request), ContentType.APPLICATION_JSON);
setEntity(entity);
}
return this;
}
@Override
public T handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
final StatusLine statusLine = response.getStatusLine();
final HttpEntity entity = response.getEntity();
if (statusLine.getStatusCode() >= 300 && statusLine.getStatusCode() != 304) {
EntityUtils.consume(entity);
throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
}
if (null == responseType){
responseType = (Class<T>) String.class;
}
String[] value = entity.getContentType().getValue().split(";");
if (ContentType.APPLICATION_OCTET_STREAM.getMimeType().equals(value[0])){
if (responseType.isAssignableFrom(InputStream.class)){
return (T)entity.getContent();
}
if (responseType.isAssignableFrom(OutputStream.class)){
try {
T t = responseType.newInstance();
entity.writeTo((OutputStream)t);
return t;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
throw new HttpResponseException(statusLine.getStatusCode(), responseType + " 无法进行类型转换");
}
}
String result = EntityUtils.toString(entity, value[1].substring( value[1].indexOf("=") + 1));
String frist = result.substring(0, 1);
if (ContentType.APPLICATION_JSON.getMimeType().equals( value[0]) || "{[".indexOf(frist) >= 0){
try {
return JSON.parseObject(result, responseType);
}catch (JSONException e){
throw new PayErrorException(new PayException("failure", "类型转化异常,contentType:" + entity.getContentType().getValue(), result));
}
}
if (ContentType.APPLICATION_XML.getMimeType().equals( value[0])){
return XML.toJSONObject(result).toJavaObject(responseType);
}
if (!responseType.isAssignableFrom(String.class)){
throw new PayErrorException(new PayException("failure", "类型转化异常,contentType:" + entity.getContentType().getValue(), result));
}
return (T)result;
}
}

View File

@@ -0,0 +1,70 @@
package in.egan.pay.common.http;
/**
* HTTP 配置
* @author: egan
* @email egzosn@gmail.com
* @date 2017/3/3 20:48
*/
public class HttpConfigStorage {
//http代理地址
protected String httpProxyHost;
//代理端口
protected int httpProxyPort;
//代理用户名
protected String httpProxyUsername;
//代理密码
protected String httpProxyPassword;
/**
* http代理地址
* @return
*/
public String getHttpProxyHost() {
return httpProxyHost;
}
public void setHttpProxyHost(String httpProxyHost) {
this.httpProxyHost = httpProxyHost;
}
/**
* 代理端口
* @return
*/
public int getHttpProxyPort() {
return httpProxyPort;
}
public void setHttpProxyPort(int httpProxyPort) {
this.httpProxyPort = httpProxyPort;
}
/**
* 代理用户名
* @return
*/
public String getHttpProxyUsername() {
return httpProxyUsername;
}
public void setHttpProxyUsername(String httpProxyUsername) {
this.httpProxyUsername = httpProxyUsername;
}
/**
* 代理密码
* @return
*/
public String getHttpProxyPassword() {
return httpProxyPassword;
}
public void setHttpProxyPassword(String httpProxyPassword) {
this.httpProxyPassword = httpProxyPassword;
}
}

View File

@@ -13,7 +13,6 @@ import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
/**

View File

@@ -71,7 +71,7 @@ public enum SignUtils {
* @param separator 分隔符
* @return 去掉空值与签名参数后的新签名,拼接后字符串
*/
public static String parameterText(Map parameters, String separator) {
/* public static String parameterText(Map parameters, String separator) {
if(parameters == null){
return "";
}
@@ -107,8 +107,7 @@ public enum SignUtils {
for (int i = 0; i < values.length; i++) {
String value = values[i].trim();
if ("".equals(value)){ continue;}
valueStr = (i == values.length - 1) ? valueStr + value
: valueStr + value + ",";
valueStr += (i == values.length - 1) ? value : value + ",";
}
} else if (o != null) {
valueStr = o.toString();
@@ -122,6 +121,79 @@ public enum SignUtils {
sb.deleteCharAt(sb.length() - 1);
}
return sb.toString();
}*/
/**
*
* 把数组所有元素排序,并按照“参数=参数值”的模式用“@param separator”字符拼接成字符串
* @param parameters 参数
* @param separator 分隔符
* @return 去掉空值与签名参数后的新签名,拼接后字符串
*/
public static String parameterText(Map parameters, String separator) {
return parameterText(parameters, separator, "sign", "key", "appId", "sign_type");
}
/**
*
* 把数组所有元素排序,并按照“参数=参数值”的模式用“@param separator”字符拼接成字符串
* @param parameters 参数
* @param separator 分隔符
* @param ignoreKey 需要忽略添加的key
* @return 去掉空值与签名参数后的新签名,拼接后字符串
*/
public static String parameterText(Map parameters, String separator, String... ignoreKey ) {
if(parameters == null){
return "";
}
StringBuffer sb = new StringBuffer();
if (null != ignoreKey){
Arrays.sort(ignoreKey);
}
// 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)) {
continue;
}
sb.append(k ).append("=").append( v.toString().trim()).append(separator);
}
if (sb.length() > 0 && !"".equals(separator)) {
sb.deleteCharAt(sb.length() - 1);
}
return sb.toString();
}
// TODO 2016/11/11 10:14 author: egan 未排序须处理
List<String> keys = new ArrayList<String>(parameters.keySet());
//排序
Collections.sort(keys);
for (String k : keys) {
String valueStr = "";
Object o = parameters.get(k);
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;}
valueStr += (i == values.length - 1) ? value : value + ",";
}
} else if (o != null) {
valueStr = o.toString();
}
if (null == valueStr || "".equals(valueStr.toString().trim()) || (null != ignoreKey && Arrays.binarySearch(ignoreKey, k ) >= 0)) {
continue;
}
sb.append(k ).append("=").append( valueStr).append(separator);
}
if (sb.length() > 0) {
sb.deleteCharAt(sb.length() - 1);
}
return sb.toString();
}
/**