Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
jinli gu
Jeepay
Commits
d53783a9
Commit
d53783a9
authored
Aug 12, 2017
by
jmdhappy
Browse files
初始化提交
parent
324ccaaf
Changes
465
Hide whitespace changes
Inline
Side-by-side
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/alipay/util/UtilDate.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.alipay.util
;
import
java.text.DateFormat
;
import
java.text.SimpleDateFormat
;
import
java.util.Date
;
import
java.util.Random
;
/* *
*类名:UtilDate
*功能:自定义订单类
*详细:工具类,可以用作获取系统日期、订单编号等
*版本:3.3
*日期:2012-08-17
*说明:
*以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
*该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
*/
public
class
UtilDate
{
/** 年月日时分秒(无下划线) yyyyMMddHHmmss */
public
static
final
String
dtLong
=
"yyyyMMddHHmmss"
;
/** 完整时间 yyyy-MM-dd HH:mm:ss */
public
static
final
String
simple
=
"yyyy-MM-dd HH:mm:ss"
;
/** 年月日(无下划线) yyyyMMdd */
public
static
final
String
dtShort
=
"yyyyMMdd"
;
/**
* 返回系统当前时间(精确到毫秒),作为一个唯一的订单编号
* @return
* 以yyyyMMddHHmmss为格式的当前系统时间
*/
public
static
String
getOrderNum
(){
Date
date
=
new
Date
();
DateFormat
df
=
new
SimpleDateFormat
(
dtLong
);
return
df
.
format
(
date
);
}
/**
* 获取系统当前日期(精确到毫秒),格式:yyyy-MM-dd HH:mm:ss
* @return
*/
public
static
String
getDateFormatter
(){
Date
date
=
new
Date
();
DateFormat
df
=
new
SimpleDateFormat
(
simple
);
return
df
.
format
(
date
);
}
/**
* 获取系统当期年月日(精确到天),格式:yyyyMMdd
* @return
*/
public
static
String
getDate
(){
Date
date
=
new
Date
();
DateFormat
df
=
new
SimpleDateFormat
(
dtShort
);
return
df
.
format
(
date
);
}
/**
* 产生随机的三位数
* @return
*/
public
static
String
getThree
(){
Random
rad
=
new
Random
();
return
rad
.
nextInt
(
1000
)+
""
;
}
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/alipay/util/httpClient/HttpProtocolHandler.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.alipay.util.httpClient
;
import
org.apache.commons.httpclient.*
;
import
org.apache.commons.httpclient.methods.GetMethod
;
import
org.apache.commons.httpclient.methods.PostMethod
;
import
org.apache.commons.httpclient.methods.multipart.*
;
import
org.apache.commons.httpclient.params.HttpMethodParams
;
import
org.apache.commons.httpclient.util.IdleConnectionTimeoutThread
;
import
java.io.File
;
import
java.io.IOException
;
import
java.net.UnknownHostException
;
import
java.util.ArrayList
;
import
java.util.List
;
/* *
*类名:HttpProtocolHandler
*功能:HttpClient方式访问
*详细:获取远程HTTP数据
*版本:3.3
*日期:2012-08-17
*说明:
*以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
*该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
*/
public
class
HttpProtocolHandler
{
private
static
String
DEFAULT_CHARSET
=
"GBK"
;
/** 连接超时时间,由bean factory设置,缺省为8秒钟 */
private
int
defaultConnectionTimeout
=
8000
;
/** 回应超时时间, 由bean factory设置,缺省为30秒钟 */
private
int
defaultSoTimeout
=
30000
;
/** 闲置连接超时时间, 由bean factory设置,缺省为60秒钟 */
private
int
defaultIdleConnTimeout
=
60000
;
private
int
defaultMaxConnPerHost
=
30
;
private
int
defaultMaxTotalConn
=
80
;
/** 默认等待HttpConnectionManager返回连接超时(只有在达到最大连接数时起作用):1秒*/
private
static
final
long
defaultHttpConnectionManagerTimeout
=
3
*
1000
;
/**
* HTTP连接管理器,该连接管理器必须是线程安全的.
*/
private
HttpConnectionManager
connectionManager
;
private
static
HttpProtocolHandler
httpProtocolHandler
=
new
HttpProtocolHandler
();
/**
* 工厂方法
*
* @return
*/
public
static
HttpProtocolHandler
getInstance
()
{
return
httpProtocolHandler
;
}
/**
* 私有的构造方法
*/
private
HttpProtocolHandler
()
{
// 创建一个线程安全的HTTP连接池
connectionManager
=
new
MultiThreadedHttpConnectionManager
();
connectionManager
.
getParams
().
setDefaultMaxConnectionsPerHost
(
defaultMaxConnPerHost
);
connectionManager
.
getParams
().
setMaxTotalConnections
(
defaultMaxTotalConn
);
IdleConnectionTimeoutThread
ict
=
new
IdleConnectionTimeoutThread
();
ict
.
addConnectionManager
(
connectionManager
);
ict
.
setConnectionTimeout
(
defaultIdleConnTimeout
);
ict
.
start
();
}
/**
* 执行Http请求
*
* @param request 请求数据
* @param strParaFileName 文件类型的参数名
* @param strFilePath 文件路径
* @return
* @throws HttpException, IOException
*/
public
HttpResponse
execute
(
HttpRequest
request
,
String
strParaFileName
,
String
strFilePath
)
throws
HttpException
,
IOException
{
HttpClient
httpclient
=
new
HttpClient
(
connectionManager
);
// 设置连接超时
int
connectionTimeout
=
defaultConnectionTimeout
;
if
(
request
.
getConnectionTimeout
()
>
0
)
{
connectionTimeout
=
request
.
getConnectionTimeout
();
}
httpclient
.
getHttpConnectionManager
().
getParams
().
setConnectionTimeout
(
connectionTimeout
);
// 设置回应超时
int
soTimeout
=
defaultSoTimeout
;
if
(
request
.
getTimeout
()
>
0
)
{
soTimeout
=
request
.
getTimeout
();
}
httpclient
.
getHttpConnectionManager
().
getParams
().
setSoTimeout
(
soTimeout
);
// 设置等待ConnectionManager释放connection的时间
httpclient
.
getParams
().
setConnectionManagerTimeout
(
defaultHttpConnectionManagerTimeout
);
String
charset
=
request
.
getCharset
();
charset
=
charset
==
null
?
DEFAULT_CHARSET
:
charset
;
HttpMethod
method
=
null
;
//get模式且不带上传文件
if
(
request
.
getMethod
().
equals
(
HttpRequest
.
METHOD_GET
))
{
method
=
new
GetMethod
(
request
.
getUrl
());
method
.
getParams
().
setCredentialCharset
(
charset
);
// parseNotifyConfig会保证使用GET方法时,request一定使用QueryString
method
.
setQueryString
(
request
.
getQueryString
());
}
else
if
(
strParaFileName
.
equals
(
""
)
&&
strFilePath
.
equals
(
""
))
{
//post模式且不带上传文件
method
=
new
PostMethod
(
request
.
getUrl
());
((
PostMethod
)
method
).
addParameters
(
request
.
getParameters
());
method
.
addRequestHeader
(
"Content-Type"
,
"application/x-www-form-urlencoded; text/html; charset="
+
charset
);
}
else
{
//post模式且带上传文件
method
=
new
PostMethod
(
request
.
getUrl
());
List
<
Part
>
parts
=
new
ArrayList
<
Part
>();
for
(
int
i
=
0
;
i
<
request
.
getParameters
().
length
;
i
++)
{
parts
.
add
(
new
StringPart
(
request
.
getParameters
()[
i
].
getName
(),
request
.
getParameters
()[
i
].
getValue
(),
charset
));
}
//增加文件参数,strParaFileName是参数名,使用本地文件
parts
.
add
(
new
FilePart
(
strParaFileName
,
new
FilePartSource
(
new
File
(
strFilePath
))));
// 设置请求体
((
PostMethod
)
method
).
setRequestEntity
(
new
MultipartRequestEntity
(
parts
.
toArray
(
new
Part
[
0
]),
new
HttpMethodParams
()));
}
// 设置Http Header中的User-Agent属性
method
.
addRequestHeader
(
"User-Agent"
,
"Mozilla/4.0"
);
HttpResponse
response
=
new
HttpResponse
();
try
{
httpclient
.
executeMethod
(
method
);
if
(
request
.
getResultType
().
equals
(
HttpResultType
.
STRING
))
{
response
.
setStringResult
(
method
.
getResponseBodyAsString
());
}
else
if
(
request
.
getResultType
().
equals
(
HttpResultType
.
BYTES
))
{
response
.
setByteResult
(
method
.
getResponseBody
());
}
response
.
setResponseHeaders
(
method
.
getResponseHeaders
());
}
catch
(
UnknownHostException
ex
)
{
return
null
;
}
catch
(
IOException
ex
)
{
return
null
;
}
catch
(
Exception
ex
)
{
return
null
;
}
finally
{
method
.
releaseConnection
();
}
return
response
;
}
/**
* 将NameValuePairs数组转变为字符串
*
* @param nameValues
* @return
*/
protected
String
toString
(
NameValuePair
[]
nameValues
)
{
if
(
nameValues
==
null
||
nameValues
.
length
==
0
)
{
return
"null"
;
}
StringBuffer
buffer
=
new
StringBuffer
();
for
(
int
i
=
0
;
i
<
nameValues
.
length
;
i
++)
{
NameValuePair
nameValue
=
nameValues
[
i
];
if
(
i
==
0
)
{
buffer
.
append
(
nameValue
.
getName
()
+
"="
+
nameValue
.
getValue
());
}
else
{
buffer
.
append
(
"&"
+
nameValue
.
getName
()
+
"="
+
nameValue
.
getValue
());
}
}
return
buffer
.
toString
();
}
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/alipay/util/httpClient/HttpRequest.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.alipay.util.httpClient
;
import
org.apache.commons.httpclient.NameValuePair
;
/* *
*类名:HttpRequest
*功能:Http请求对象的封装
*详细:封装Http请求
*版本:3.3
*日期:2011-08-17
*说明:
*以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
*该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
*/
public
class
HttpRequest
{
/** HTTP GET method */
public
static
final
String
METHOD_GET
=
"GET"
;
/** HTTP POST method */
public
static
final
String
METHOD_POST
=
"POST"
;
/**
* 待请求的url
*/
private
String
url
=
null
;
/**
* 默认的请求方式
*/
private
String
method
=
METHOD_POST
;
private
int
timeout
=
0
;
private
int
connectionTimeout
=
0
;
/**
* Post方式请求时组装好的参数值对
*/
private
NameValuePair
[]
parameters
=
null
;
/**
* Get方式请求时对应的参数
*/
private
String
queryString
=
null
;
/**
* 默认的请求编码方式
*/
private
String
charset
=
"GBK"
;
/**
* 请求发起方的ip地址
*/
private
String
clientIp
;
/**
* 请求返回的方式
*/
private
HttpResultType
resultType
=
HttpResultType
.
BYTES
;
public
HttpRequest
(
HttpResultType
resultType
)
{
super
();
this
.
resultType
=
resultType
;
}
/**
* @return Returns the clientIp.
*/
public
String
getClientIp
()
{
return
clientIp
;
}
/**
* @param clientIp The clientIp to set.
*/
public
void
setClientIp
(
String
clientIp
)
{
this
.
clientIp
=
clientIp
;
}
public
NameValuePair
[]
getParameters
()
{
return
parameters
;
}
public
void
setParameters
(
NameValuePair
[]
parameters
)
{
this
.
parameters
=
parameters
;
}
public
String
getQueryString
()
{
return
queryString
;
}
public
void
setQueryString
(
String
queryString
)
{
this
.
queryString
=
queryString
;
}
public
String
getUrl
()
{
return
url
;
}
public
void
setUrl
(
String
url
)
{
this
.
url
=
url
;
}
public
String
getMethod
()
{
return
method
;
}
public
void
setMethod
(
String
method
)
{
this
.
method
=
method
;
}
public
int
getConnectionTimeout
()
{
return
connectionTimeout
;
}
public
void
setConnectionTimeout
(
int
connectionTimeout
)
{
this
.
connectionTimeout
=
connectionTimeout
;
}
public
int
getTimeout
()
{
return
timeout
;
}
public
void
setTimeout
(
int
timeout
)
{
this
.
timeout
=
timeout
;
}
/**
* @return Returns the charset.
*/
public
String
getCharset
()
{
return
charset
;
}
/**
* @param charset The charset to set.
*/
public
void
setCharset
(
String
charset
)
{
this
.
charset
=
charset
;
}
public
HttpResultType
getResultType
()
{
return
resultType
;
}
public
void
setResultType
(
HttpResultType
resultType
)
{
this
.
resultType
=
resultType
;
}
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/alipay/util/httpClient/HttpResponse.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.alipay.util.httpClient
;
import
org.apache.commons.httpclient.Header
;
import
org.xxpay.service.channel.alipay.config.AlipayConfig
;
import
java.io.UnsupportedEncodingException
;
/* *
*类名:HttpResponse
*功能:Http返回对象的封装
*详细:封装Http返回信息
*版本:3.3
*日期:2011-08-17
*说明:
*以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
*该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
*/
public
class
HttpResponse
{
/**
* 返回中的Header信息
*/
private
Header
[]
responseHeaders
;
/**
* String类型的result
*/
private
String
stringResult
;
/**
* btye类型的result
*/
private
byte
[]
byteResult
;
public
Header
[]
getResponseHeaders
()
{
return
responseHeaders
;
}
public
void
setResponseHeaders
(
Header
[]
responseHeaders
)
{
this
.
responseHeaders
=
responseHeaders
;
}
public
byte
[]
getByteResult
()
{
if
(
byteResult
!=
null
)
{
return
byteResult
;
}
if
(
stringResult
!=
null
)
{
return
stringResult
.
getBytes
();
}
return
null
;
}
public
void
setByteResult
(
byte
[]
byteResult
)
{
this
.
byteResult
=
byteResult
;
}
public
String
getStringResult
()
throws
UnsupportedEncodingException
{
if
(
stringResult
!=
null
)
{
return
stringResult
;
}
if
(
byteResult
!=
null
)
{
return
new
String
(
byteResult
,
AlipayConfig
.
input_charset
);
}
return
null
;
}
public
void
setStringResult
(
String
stringResult
)
{
this
.
stringResult
=
stringResult
;
}
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/alipay/util/httpClient/HttpResultType.java
0 → 100755
View file @
d53783a9
/*
* Alipay.com Inc.
* Copyright (c) 2004-2005 All Rights Reserved.
*/
package
org.xxpay.service.channel.alipay.util.httpClient
;
/* *
*类名:HttpResultType
*功能:表示Http返回的结果字符方式
*详细:表示Http返回的结果字符方式
*版本:3.3
*日期:2012-08-17
*说明:
*以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
*该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
*/
public
enum
HttpResultType
{
/**
* 字符串方式
*/
STRING
,
/**
* 字节数组方式
*/
BYTES
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/tencent/Main.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.tencent
;
public
class
Main
{
/*public static void main(String[] args) {
try {
//--------------------------------------------------------------------
//温馨提示,第一次使用该SDK时请到com.tencent.common.Configure类里面进行配置
//--------------------------------------------------------------------
//--------------------------------------------------------------------
//PART One:基础组件测试
//--------------------------------------------------------------------
//1)https请求可用性测试
//HTTPSPostRquestWithCert.test();
//2)测试项目用到的XStream组件,本项目利用这个组件将Java对象转换成XML数据Post给API
//XStreamTest.test();
//--------------------------------------------------------------------
//PART Two:基础服务测试
//--------------------------------------------------------------------
//1)测试被扫支付API
//PayServiceTest.test();
//2)测试被扫订单查询API
//PayQueryServiceTest.test();
//3)测试撤销API
//温馨提示,测试支付API成功扣到钱之后,可以通过调用PayQueryServiceTest.test(),将支付成功返回的transaction_id和out_trade_no数据贴进去,完成撤销工作,把钱退回来 ^_^v
//ReverseServiceTest.test();
//4)测试退款申请API
//RefundServiceTest.test();
//5)测试退款查询API
//RefundQueryServiceTest.test();
//6)测试对账单API
//DownloadBillServiceTest.test();
//本地通过xml进行API数据模拟的时候,先按需手动修改xml各个节点的值,然后通过以下方法对这个新的xml数据进行签名得到一串合法的签名,最后把这串签名放到这个xml里面的sign字段里,这样进行模拟的时候就可以通过签名验证了
// Util.log(Signature.getSignFromResponseString(Util.getLocalXMLString("/test/com/tencent/business/refundqueryserviceresponsedata/refundquerysuccess2.xml")));
//Util.log(new Date().getTime());
//Util.log(System.currentTimeMillis());
} catch (Exception e){
Util.log(e.getMessage());
}
}*/
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/tencent/WXPay.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.tencent
;
import
org.xxpay.service.channel.tencent.protocol.downloadbill_protocol.DownloadBillReqData
;
import
org.xxpay.service.channel.tencent.protocol.pay_protocol.ScanPayReqData
;
import
org.xxpay.service.channel.tencent.protocol.pay_query_protocol.ScanPayQueryReqData
;
import
org.xxpay.service.channel.tencent.protocol.refund_protocol.RefundReqData
;
import
org.xxpay.service.channel.tencent.protocol.refund_query_protocol.RefundQueryReqData
;
import
org.xxpay.service.channel.tencent.protocol.reverse_protocol.ReverseReqData
;
import
org.xxpay.service.channel.tencent.service.*
;
/**
* SDK总入口
*/
public
class
WXPay
{
/**
* 初始化SDK依赖的几个关键配置
* @param key 签名算法需要用到的秘钥
* @param appID 公众账号ID
* @param mchID 商户ID
* @param sdbMchID 子商户ID,受理模式必填
* @param certLocalPath HTTP证书在服务器中的路径,用来加载证书用
* @param certPassword HTTP证书的密码,默认等于MCHID
*/
public
static
void
initSDKConfiguration
(
String
key
,
String
appID
,
String
mchID
,
String
sdbMchID
,
String
certLocalPath
,
String
certPassword
){
/* Configure.setKey(key);
Configure.setAppID(appID);
Configure.setMchID(mchID);
Configure.setSubMchID(sdbMchID);
Configure.setCertLocalPath(certLocalPath);
Configure.setCertPassword(certPassword);*/
}
/**
* 请求支付服务
* @param scanPayReqData 这个数据对象里面包含了API要求提交的各种数据字段
* @return API返回的数据
* @throws Exception
*/
public
static
String
requestScanPayService
(
ScanPayReqData
scanPayReqData
)
throws
Exception
{
return
new
ScanPayService
().
request
(
scanPayReqData
);
}
/**
* 请求支付查询服务
* @param scanPayQueryReqData 这个数据对象里面包含了API要求提交的各种数据字段
* @return API返回的XML数据
* @throws Exception
*/
public
static
String
requestScanPayQueryService
(
ScanPayQueryReqData
scanPayQueryReqData
)
throws
Exception
{
return
new
ScanPayQueryService
().
request
(
scanPayQueryReqData
);
}
/**
* 请求退款服务
* @param refundReqData 这个数据对象里面包含了API要求提交的各种数据字段
* @return API返回的XML数据
* @throws Exception
*/
public
static
String
requestRefundService
(
RefundReqData
refundReqData
)
throws
Exception
{
return
new
RefundService
().
request
(
refundReqData
);
}
/**
* 请求退款查询服务
* @param refundQueryReqData 这个数据对象里面包含了API要求提交的各种数据字段
* @return API返回的XML数据
* @throws Exception
*/
public
static
String
requestRefundQueryService
(
RefundQueryReqData
refundQueryReqData
)
throws
Exception
{
return
new
RefundQueryService
().
request
(
refundQueryReqData
);
}
/**
* 请求撤销服务
* @param reverseReqData 这个数据对象里面包含了API要求提交的各种数据字段
* @return API返回的XML数据
* @throws Exception
*/
public
static
String
requestReverseService
(
ReverseReqData
reverseReqData
)
throws
Exception
{
return
new
ReverseService
().
request
(
reverseReqData
);
}
/**
* 请求对账单下载服务
* @param downloadBillReqData 这个数据对象里面包含了API要求提交的各种数据字段
* @return API返回的XML数据
* @throws Exception
*/
public
static
String
requestDownloadBillService
(
DownloadBillReqData
downloadBillReqData
)
throws
Exception
{
return
new
DownloadBillService
().
request
(
downloadBillReqData
);
}
/*
*/
/**
* 直接执行被扫支付业务逻辑(包含最佳实践流程)
* @param scanPayReqData 这个数据对象里面包含了API要求提交的各种数据字段
* @param resultListener 商户需要自己监听被扫支付业务逻辑可能触发的各种分支事件,并做好合理的响应处理
* @throws Exception
*//*
public static void doScanPayBusiness(ScanPayReqData scanPayReqData, ScanPayBusiness.ResultListener resultListener) throws Exception {
//new ScanPayBusiness().run(scanPayReqData, resultListener);
}
*/
/**
* 调用退款业务逻辑
* @param refundReqData 这个数据对象里面包含了API要求提交的各种数据字段
* @param resultListener 业务逻辑可能走到的结果分支,需要商户处理
* @throws Exception
*//*
public static void doRefundBusiness(RefundReqData refundReqData, RefundBusiness.ResultListener resultListener) throws Exception {
//new RefundBusiness().run(refundReqData,resultListener);
}
*/
/**
* 运行退款查询的业务逻辑
* @param refundQueryReqData 这个数据对象里面包含了API要求提交的各种数据字段
* @param resultListener 商户需要自己监听被扫支付业务逻辑可能触发的各种分支事件,并做好合理的响应处理
* @throws Exception
*//*
public static void doRefundQueryBusiness(RefundQueryReqData refundQueryReqData, RefundQueryBusiness.ResultListener resultListener) throws Exception {
//new RefundQueryBusiness().run(refundQueryReqData,resultListener);
}
*/
/**
* 请求对账单下载服务
* @param downloadBillReqData 这个数据对象里面包含了API要求提交的各种数据字段
* @param resultListener 商户需要自己监听被扫支付业务逻辑可能触发的各种分支事件,并做好合理的响应处理
* @return API返回的XML数据
* @throws Exception
*//*
public static void doDownloadBillBusiness(DownloadBillReqData downloadBillReqData, DownloadBillBusiness.ResultListener resultListener) throws Exception {
//new DownloadBillBusiness().run(downloadBillReqData,resultListener);
}
*/
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/tencent/bridge/IBridge.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.tencent.bridge
;
/**
* User: rizenguo
* Date: 2014/12/1
* Time: 17:11
*/
public
interface
IBridge
{
/**
* 获取auth_code,这个是扫码终端设备从用户手机上扫取到的支付授权号,这个号是跟用户用来支付的银行卡绑定的,有效期是1分钟
* @return 授权码
*/
public
String
getAuthCode
();
/**
* 获取out_trade_no,这个是商户系统内自己可以用来唯一标识该笔订单的字符串,可以包含字母和数字,不超过32位
* @return 订单号
*/
public
String
getOutTradeNo
();
/**
* 获取body:要支付的商品的描述信息,用户会在支付成功页面里看到这个信息
* @return 描述信息
*/
public
String
getBody
();
/**
* 获取attach:支付订单里面可以填的附加数据,API会将提交的这个附加数据原样返回,有助于商户自己可以注明该笔消费的具体内容,方便后续的运营和记录
* @return 附加数据
*/
public
String
getAttach
();
/**
* 获取订单总额
* @return 订单总额
*/
public
int
getTotalFee
();
/**
* 获取device_info:商户自己定义的扫码支付终端设备号,方便追溯这笔交易发生在哪台终端设备上
* @return 支付终端设备号
*/
public
String
getDeviceInfo
();
/**
* 获取机器的ip地址
* @return 机器设备的ip地址
*/
public
String
getUserIp
();
/**
* 获取spBillCreateIP:订单生成的机器IP
* @return 订单生成的机器IP
*/
public
String
getSpBillCreateIP
();
/**
* 获取time_start:订单生成时间
* @return 订单生成时间
*/
public
String
getTimeStart
();
/**
* 获取time_end:订单生成时间
* @return 订单失效时间
*/
public
String
getTimeExpire
();
/**
* 获取goods_tag:商品标记,微信平台配置的商品标记,用于优惠券或者满减使用
* @return 商品标记
*/
public
String
getGoodsTag
();
/**
* 获取transaction_id:微信平台支付成功时给分配的唯一交易号,一般只要有这个tracnsacion_id,后续的查询、撤销、退款都建议优先用这个,而不是商户自己的那个out_trade_no
* @return 微信平台官方分配的交易号
*/
public
String
getTransactionID
();
/**
* 获取out_refund_no:商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔
* @return 商户系统内部的退款单号
*/
public
String
getOutRefundNo
();
/**
* 获取refund_fee:获取本次退款请求所要退的具体金额,这个金额不能比这个订单的total_fee(总金额)还大
* @return 本次退款请求所要退的具体金额
*/
public
int
getRefundFee
();
/**
* 获取refund_id:微信平台退款成功时给分配的唯一退款号,一般只要有这个refund_id,后续的查询建议优先用这个
* @return 微信平台官方分配的退款号
*/
public
String
getRefundID
();
/**
* 获取bill_date:获取对账单API需要的日期,格式是yyyyMMdd
* @return 要查询对账单的日期
*/
public
String
getBillDate
();
/**
* 获取bill_type:获取对账单API需要的数据类型,这些类型在DownloadBillService里面有定义
* @return 要查询对账单的类型
*/
public
String
getBillType
();
/**
* 获取操作员的ID,默认等于商户号
* @return 返回操作员的ID
*/
public
String
getOpUserID
();
/**
* 获取退款货币类型,符合ISO 4217标准的三位字母代码,默认为CNY(人民币)
* @return 获取退款货币类型
*/
public
String
getRefundFeeType
();
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/tencent/common/Configure.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.tencent.common
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONObject
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.cloud.context.config.annotation.RefreshScope
;
import
org.springframework.stereotype.Component
;
import
org.springframework.stereotype.Service
;
import
org.xxpay.common.constant.PayConstant
;
import
org.xxpay.common.util.IPUtility
;
import
org.xxpay.common.util.MyLog
;
import
org.xxpay.common.util.PropertiesFileUtil
;
import
java.util.Date
;
import
java.util.Map
;
/**
* User: rizenguo
* Date: 2014/10/29
* Time: 14:40
* 这里放置各种配置数据
*/
@RefreshScope
@Service
public
class
Configure
{
private
static
final
MyLog
_log
=
MyLog
.
getLog
(
Configure
.
class
);
public
Configure
init
(
String
configParam
)
{
JSONObject
paramObj
=
JSON
.
parseObject
(
configParam
);
this
.
setMchID
(
paramObj
.
getString
(
"mchId"
));
this
.
setAppID
(
paramObj
.
getString
(
"appId"
));
this
.
setCertLocalPath
(
Configure
.
class
.
getClassLoader
().
getResource
(
paramObj
.
getString
(
"certLocalPath"
)).
getPath
());
this
.
setCertPassword
(
paramObj
.
getString
(
"certPassword"
));
this
.
setKey
(
paramObj
.
getString
(
"key"
));
this
.
setIp
(
IPUtility
.
getLocalIP
());
return
this
;
}
// 这个就是自己要保管好的私有Key了(切记只能放在自己的后台代码里,不能放在任何可能被看到源代码的客户端程序中)
// 每次自己Post数据给API的时候都要用这个key来对所有字段进行签名,生成的签名会放在Sign这个字段,API收到Post数据的时候也会用同样的签名算法对Post过来的数据进行签名和验证
// 收到API的返回的时候也要用这个key来对返回的数据算下签名,跟API的Sign数据进行比较,如果值不一致,有可能数据被第三方给篡改
private
String
key
;
//微信分配的公众号ID(开通公众号之后可以获取到)
private
String
appID
;
private
String
mchID
;
//HTTPS证书的本地路径
// private static String certLocalPath = "/Users/dingzhiwei/java/tmp/wx.crt.p12";
private
String
certLocalPath
;
//HTTPS证书密码,默认密码等于商户号MCHID
private
String
certPassword
;
//是否使用异步线程的方式来上报API测速,默认为异步模式
private
static
boolean
useThreadToDoReport
=
true
;
//配置描述
private
String
desc
;
//机器IP
private
String
ip
;
//以下是几个API的路径:
//1)被扫支付API
public
static
String
PAY_API
=
"https://api.mch.weixin.qq.com/pay/micropay"
;
//2)被扫支付查询API
public
static
String
ORDER_QUERY_API
=
"https://api.mch.weixin.qq.com/pay/orderquery"
;
//3)退款API
public
static
String
REFUND_API
=
"https://api.mch.weixin.qq.com/secapi/pay/refund"
;
//4)退款查询API
public
static
String
REFUND_QUERY_API
=
"https://api.mch.weixin.qq.com/pay/refundquery"
;
//5)撤销API
public
static
String
REVERSE_API
=
"https://api.mch.weixin.qq.com/secapi/pay/reverse"
;
//6)下载对账单API
public
static
String
DOWNLOAD_BILL_API
=
"https://api.mch.weixin.qq.com/pay/downloadbill"
;
//7) 统计上报API
public
static
String
REPORT_API
=
"https://api.mch.weixin.qq.com/payitil/report"
;
//8) 统一下单API
public
static
String
UNIFIED_ORDER_API
=
"https://api.mch.weixin.qq.com/pay/unifiedorder"
;
//9) 发送现金红包API
public
static
String
SEND_REDPACK_API
=
"https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack"
;
//10) 查询现金红包API
public
static
String
QUERY_REDPACK_API
=
"https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo"
;
//9) 企业付款API
public
static
String
TRANSFERS_API
=
"https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"
;
//10) 查询企业付款API
public
static
String
GET_TRANSFERS_API
=
"https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo"
;
@Value
(
"${wx.notify_url}"
)
private
String
notify_url
;
// 配置加载时间
private
Long
loadTime
=
new
Date
().
getTime
();
public
static
boolean
isUseThreadToDoReport
()
{
return
useThreadToDoReport
;
}
public
static
void
setUseThreadToDoReport
(
boolean
useThreadToDoReport
)
{
Configure
.
useThreadToDoReport
=
useThreadToDoReport
;
}
public
static
String
HttpsRequestClassName
=
"org.xxpay.service.channel.tencent.common.HttpsRequest"
;
public
static
void
setHttpsRequestClassName
(
String
name
){
HttpsRequestClassName
=
name
;
}
public
String
getAppID
()
{
return
appID
;
}
public
void
setAppID
(
String
appID
)
{
this
.
appID
=
appID
;
}
public
String
getCertLocalPath
()
{
return
certLocalPath
;
}
public
void
setCertLocalPath
(
String
certLocalPath
)
{
this
.
certLocalPath
=
certLocalPath
;
}
public
String
getCertPassword
()
{
return
certPassword
;
}
public
void
setCertPassword
(
String
certPassword
)
{
this
.
certPassword
=
certPassword
;
}
public
String
getIp
()
{
return
ip
;
}
public
void
setIp
(
String
ip
)
{
this
.
ip
=
ip
;
}
public
String
getKey
()
{
return
key
;
}
public
void
setKey
(
String
key
)
{
this
.
key
=
key
;
}
public
String
getMchID
()
{
return
mchID
;
}
public
void
setMchID
(
String
mchID
)
{
this
.
mchID
=
mchID
;
}
public
String
getDesc
()
{
return
desc
;
}
public
String
getNotify_url
()
{
return
notify_url
;
}
public
void
setNotify_url
(
String
notify_url
)
{
this
.
notify_url
=
notify_url
;
}
public
void
setDesc
(
String
desc
)
{
this
.
desc
=
desc
;
}
public
Long
getLoadTime
()
{
return
loadTime
;
}
public
void
setLoadTime
(
Long
loadTime
)
{
this
.
loadTime
=
loadTime
;
}
@Override
public
String
toString
()
{
return
"Configure{"
+
"key='"
+
key
+
'\''
+
", appID='"
+
appID
+
'\''
+
", certLocalPath='"
+
certLocalPath
+
'\''
+
", certPassword='"
+
certPassword
+
'\''
+
", desc='"
+
desc
+
'\''
+
", ip='"
+
ip
+
'\''
+
", loadTime="
+
loadTime
+
'}'
;
}
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/tencent/common/HttpsRequest.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.tencent.common
;
import
com.thoughtworks.xstream.XStream
;
import
com.thoughtworks.xstream.io.xml.DomDriver
;
import
com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder
;
import
org.xxpay.service.channel.tencent.service.IServiceRequest
;
import
org.apache.http.HttpEntity
;
import
org.apache.http.HttpResponse
;
import
org.apache.http.client.config.RequestConfig
;
import
org.apache.http.client.methods.HttpPost
;
import
org.apache.http.conn.ConnectTimeoutException
;
import
org.apache.http.conn.ConnectionPoolTimeoutException
;
import
org.apache.http.conn.ssl.SSLConnectionSocketFactory
;
import
org.apache.http.conn.ssl.SSLContexts
;
import
org.apache.http.entity.StringEntity
;
import
org.apache.http.impl.client.CloseableHttpClient
;
import
org.apache.http.impl.client.HttpClients
;
import
org.apache.http.util.EntityUtils
;
import
org.slf4j.LoggerFactory
;
import
javax.net.ssl.SSLContext
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.IOException
;
import
java.net.SocketTimeoutException
;
import
java.security.*
;
import
java.security.cert.CertificateException
;
/**
* User: rizenguo
* Date: 2014/10/29
* Time: 14:36
*/
public
class
HttpsRequest
implements
IServiceRequest
{
public
interface
ResultListener
{
public
void
onConnectionPoolTimeoutError
();
}
private
static
Log
log
=
new
Log
(
LoggerFactory
.
getLogger
(
HttpsRequest
.
class
));
//表示请求器是否已经做了初始化工作
private
boolean
hasInit
=
false
;
//连接超时时间,默认10秒
private
int
socketTimeout
=
10000
;
//传输超时时间,默认30秒
private
int
connectTimeout
=
30000
;
//请求器的配置
private
RequestConfig
requestConfig
;
//HTTP请求器
private
CloseableHttpClient
httpClient
;
private
String
crtPath
;
private
String
crtPwd
;
public
HttpsRequest
()
throws
UnrecoverableKeyException
,
KeyManagementException
,
NoSuchAlgorithmException
,
KeyStoreException
,
IOException
{
//init();
}
public
void
init
()
throws
IOException
,
KeyStoreException
,
UnrecoverableKeyException
,
NoSuchAlgorithmException
,
KeyManagementException
{
KeyStore
keyStore
=
KeyStore
.
getInstance
(
"PKCS12"
);
FileInputStream
instream
=
new
FileInputStream
(
new
File
(
crtPath
));
//加载本地的证书进行https加密传输
try
{
keyStore
.
load
(
instream
,
crtPwd
.
toCharArray
());
//设置证书密码
}
catch
(
CertificateException
e
)
{
e
.
printStackTrace
();
}
catch
(
NoSuchAlgorithmException
e
)
{
e
.
printStackTrace
();
}
finally
{
instream
.
close
();
}
// Trust own CA and all self-signed certs
SSLContext
sslcontext
=
SSLContexts
.
custom
()
.
loadKeyMaterial
(
keyStore
,
crtPwd
.
toCharArray
())
.
build
();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory
sslsf
=
new
SSLConnectionSocketFactory
(
sslcontext
,
new
String
[]{
"TLSv1"
},
null
,
SSLConnectionSocketFactory
.
BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
);
httpClient
=
HttpClients
.
custom
()
.
setSSLSocketFactory
(
sslsf
)
.
build
();
//根据默认超时限制初始化requestConfig
requestConfig
=
RequestConfig
.
custom
().
setSocketTimeout
(
socketTimeout
).
setConnectTimeout
(
connectTimeout
).
build
();
hasInit
=
true
;
}
/**
* 通过Https往API post xml数据
*
* @param url API地址
* @param xmlObj 要提交的XML数据对象
* @return API回包的实际数据
* @throws IOException
* @throws KeyStoreException
* @throws UnrecoverableKeyException
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
*/
public
String
sendPost
(
String
url
,
Object
xmlObj
)
throws
IOException
,
KeyStoreException
,
UnrecoverableKeyException
,
NoSuchAlgorithmException
,
KeyManagementException
{
if
(!
hasInit
)
{
init
();
}
String
result
=
null
;
HttpPost
httpPost
=
new
HttpPost
(
url
);
//解决XStream对出现双下划线的bug
XStream
xStreamForRequestPostData
=
new
XStream
(
new
DomDriver
(
"UTF-8"
,
new
XmlFriendlyNameCoder
(
"-_"
,
"_"
)));
//将要提交给API的数据对象转换成XML格式数据Post给API
String
postDataXML
=
xStreamForRequestPostData
.
toXML
(
xmlObj
);
Util
.
log
(
"API,POST过去的数据是:"
);
Util
.
log
(
postDataXML
);
//得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
StringEntity
postEntity
=
new
StringEntity
(
postDataXML
,
"UTF-8"
);
httpPost
.
addHeader
(
"Content-Type"
,
"text/xml"
);
httpPost
.
setEntity
(
postEntity
);
//设置请求器的配置
httpPost
.
setConfig
(
requestConfig
);
Util
.
log
(
"executing request"
+
httpPost
.
getRequestLine
());
try
{
HttpResponse
response
=
httpClient
.
execute
(
httpPost
);
HttpEntity
entity
=
response
.
getEntity
();
result
=
EntityUtils
.
toString
(
entity
,
"UTF-8"
);
}
catch
(
ConnectionPoolTimeoutException
e
)
{
log
.
e
(
"http get throw ConnectionPoolTimeoutException(wait time out)"
);
}
catch
(
ConnectTimeoutException
e
)
{
log
.
e
(
"http get throw ConnectTimeoutException"
);
}
catch
(
SocketTimeoutException
e
)
{
log
.
e
(
"http get throw SocketTimeoutException"
);
}
catch
(
Exception
e
)
{
log
.
e
(
"http get throw Exception"
);
}
finally
{
httpPost
.
abort
();
}
return
result
;
}
/**
* 设置连接超时时间
*
* @param socketTimeout 连接时长,默认10秒
*/
public
void
setSocketTimeout
(
int
socketTimeout
)
{
socketTimeout
=
socketTimeout
;
resetRequestConfig
();
}
/**
* 设置传输超时时间
*
* @param connectTimeout 传输时长,默认30秒
*/
public
void
setConnectTimeout
(
int
connectTimeout
)
{
connectTimeout
=
connectTimeout
;
resetRequestConfig
();
}
private
void
resetRequestConfig
(){
requestConfig
=
RequestConfig
.
custom
().
setSocketTimeout
(
socketTimeout
).
setConnectTimeout
(
connectTimeout
).
build
();
}
/**
* 允许商户自己做更高级更复杂的请求器配置
*
* @param requestConfig 设置HttpsRequest的请求器配置
*/
public
void
setRequestConfig
(
RequestConfig
requestConfig
)
{
requestConfig
=
requestConfig
;
}
public
void
setCrt
(
Configure
configure
)
{
this
.
crtPath
=
configure
.
getCertLocalPath
();
this
.
crtPwd
=
configure
.
getCertPassword
();
}
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/tencent/common/Log.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.tencent.common
;
import
org.slf4j.Logger
;
/**
* User: rizenguo
* Date: 2014/11/12
* Time: 14:32
*/
public
class
Log
{
public
static
final
String
LOG_TYPE_TRACE
=
"logTypeTrace"
;
public
static
final
String
LOG_TYPE_DEBUG
=
"logTypeDebug"
;
public
static
final
String
LOG_TYPE_INFO
=
"logTypeInfo"
;
public
static
final
String
LOG_TYPE_WARN
=
"logTypeWarn"
;
public
static
final
String
LOG_TYPE_ERROR
=
"logTypeError"
;
//打印日志
private
Logger
logger
;
public
Log
(
Logger
log
){
logger
=
log
;
}
public
void
t
(
String
s
){
logger
.
trace
(
s
);
}
public
void
d
(
String
s
){
logger
.
debug
(
s
);
}
public
void
i
(
String
s
){
logger
.
info
(
s
);
}
public
void
w
(
String
s
){
logger
.
warn
(
s
);
}
public
void
e
(
String
s
){
logger
.
error
(
s
);
}
public
void
log
(
String
type
,
String
s
){
if
(
type
.
equals
(
Log
.
LOG_TYPE_TRACE
)){
t
(
s
);
}
else
if
(
type
.
equals
(
Log
.
LOG_TYPE_DEBUG
)){
d
(
s
);
}
else
if
(
type
.
equals
(
Log
.
LOG_TYPE_INFO
)){
i
(
s
);
}
else
if
(
type
.
equals
(
Log
.
LOG_TYPE_WARN
)){
w
(
s
);
}
else
if
(
type
.
equals
(
Log
.
LOG_TYPE_ERROR
)){
e
(
s
);
}
}
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/tencent/common/MD5.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.tencent.common
;
import
java.security.MessageDigest
;
/**
* User: rizenguo
* Date: 2014/10/23
* Time: 15:43
*/
public
class
MD5
{
private
final
static
String
[]
hexDigits
=
{
"0"
,
"1"
,
"2"
,
"3"
,
"4"
,
"5"
,
"6"
,
"7"
,
"8"
,
"9"
,
"a"
,
"b"
,
"c"
,
"d"
,
"e"
,
"f"
};
/**
* 转换字节数组为16进制字串
* @param b 字节数组
* @return 16进制字串
*/
public
static
String
byteArrayToHexString
(
byte
[]
b
)
{
StringBuilder
resultSb
=
new
StringBuilder
();
for
(
byte
aB
:
b
)
{
resultSb
.
append
(
byteToHexString
(
aB
));
}
return
resultSb
.
toString
();
}
/**
* 转换byte到16进制
* @param b 要转换的byte
* @return 16进制格式
*/
private
static
String
byteToHexString
(
byte
b
)
{
int
n
=
b
;
if
(
n
<
0
)
{
n
=
256
+
n
;
}
int
d1
=
n
/
16
;
int
d2
=
n
%
16
;
return
hexDigits
[
d1
]
+
hexDigits
[
d2
];
}
/**
* MD5编码
* @param origin 原始字符串
* @return 经过MD5加密之后的结果
*/
public
static
String
MD5Encode
(
String
origin
)
{
String
resultString
=
null
;
try
{
resultString
=
origin
;
MessageDigest
md
=
MessageDigest
.
getInstance
(
"MD5"
);
resultString
=
byteArrayToHexString
(
md
.
digest
(
resultString
.
getBytes
()));
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
return
resultString
;
}
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/tencent/common/RandomStringGenerator.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.tencent.common
;
import
java.util.Random
;
/**
* User: rizenguo
* Date: 2014/10/29
* Time: 14:18
*/
public
class
RandomStringGenerator
{
/**
* 获取一定长度的随机字符串
* @param length 指定字符串长度
* @return 一定长度的字符串
*/
public
static
String
getRandomStringByLength
(
int
length
)
{
String
base
=
"abcdefghijklmnopqrstuvwxyz0123456789"
;
Random
random
=
new
Random
();
StringBuffer
sb
=
new
StringBuffer
();
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
int
number
=
random
.
nextInt
(
base
.
length
());
sb
.
append
(
base
.
charAt
(
number
));
}
return
sb
.
toString
();
}
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/tencent/common/Signature.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.tencent.common
;
import
org.xml.sax.SAXException
;
import
javax.xml.parsers.ParserConfigurationException
;
import
java.io.IOException
;
import
java.lang.reflect.Field
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Map
;
/**
* User: rizenguo
* Date: 2014/10/29
* Time: 15:23
*/
public
class
Signature
{
/**
* 签名算法
* @param o 要参与签名的数据对象
* @return 签名
* @throws IllegalAccessException
*/
public
static
String
getSign
(
Object
o
,
String
key
)
throws
IllegalAccessException
{
ArrayList
<
String
>
list
=
new
ArrayList
<
String
>();
Class
cls
=
o
.
getClass
();
Field
[]
fields
=
cls
.
getDeclaredFields
();
for
(
Field
f
:
fields
)
{
f
.
setAccessible
(
true
);
if
(
f
.
get
(
o
)
!=
null
&&
f
.
get
(
o
)
!=
""
)
{
list
.
add
(
f
.
getName
()
+
"="
+
f
.
get
(
o
)
+
"&"
);
}
}
int
size
=
list
.
size
();
String
[]
arrayToSort
=
list
.
toArray
(
new
String
[
size
]);
Arrays
.
sort
(
arrayToSort
,
String
.
CASE_INSENSITIVE_ORDER
);
StringBuilder
sb
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
sb
.
append
(
arrayToSort
[
i
]);
}
String
result
=
sb
.
toString
();
result
+=
"key="
+
key
;
Util
.
log
(
"Sign Before MD5:"
+
result
);
result
=
MD5
.
MD5Encode
(
result
).
toUpperCase
();
Util
.
log
(
"Sign Result:"
+
result
);
return
result
;
}
public
static
String
getSign
(
Map
<
String
,
Object
>
map
,
String
key
){
ArrayList
<
String
>
list
=
new
ArrayList
<
String
>();
for
(
Map
.
Entry
<
String
,
Object
>
entry:
map
.
entrySet
()){
if
(!
""
.
equals
(
entry
.
getValue
())){
list
.
add
(
entry
.
getKey
()
+
"="
+
entry
.
getValue
()
+
"&"
);
}
}
int
size
=
list
.
size
();
String
[]
arrayToSort
=
list
.
toArray
(
new
String
[
size
]);
Arrays
.
sort
(
arrayToSort
,
String
.
CASE_INSENSITIVE_ORDER
);
StringBuilder
sb
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
sb
.
append
(
arrayToSort
[
i
]);
}
String
result
=
sb
.
toString
();
result
+=
"key="
+
key
;
//Util.log("Sign Before MD5:" + result);
result
=
MD5
.
MD5Encode
(
result
).
toUpperCase
();
//Util.log("Sign Result:" + result);
return
result
;
}
/**
* 从API返回的XML数据里面重新计算一次签名
* @param responseString API返回的XML数据
* @return 新鲜出炉的签名
* @throws ParserConfigurationException
* @throws IOException
* @throws SAXException
*/
public
static
String
getSignFromResponseString
(
String
responseString
,
String
key
)
throws
IOException
,
SAXException
,
ParserConfigurationException
{
Map
<
String
,
Object
>
map
=
XMLParser
.
getMapFromXML
(
responseString
);
//清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
map
.
put
(
"sign"
,
""
);
//将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
return
Signature
.
getSign
(
map
,
key
);
}
/**
* 检验API返回的数据里面的签名是否合法,避免数据在传输的过程中被第三方篡改
* @param responseString API返回的XML数据字符串
* @return API签名是否合法
* @throws ParserConfigurationException
* @throws IOException
* @throws SAXException
*/
public
static
boolean
checkIsSignValidFromResponseString
(
String
responseString
,
String
key
)
throws
ParserConfigurationException
,
IOException
,
SAXException
{
Map
<
String
,
Object
>
map
=
XMLParser
.
getMapFromXML
(
responseString
);
Util
.
log
(
map
.
toString
());
String
signFromAPIResponse
=
map
.
get
(
"sign"
).
toString
();
if
(
signFromAPIResponse
==
""
||
signFromAPIResponse
==
null
){
Util
.
log
(
"API返回的数据签名数据不存在,有可能被第三方篡改!!!"
);
return
false
;
}
Util
.
log
(
"服务器回包里面的签名是:"
+
signFromAPIResponse
);
//清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
map
.
put
(
"sign"
,
""
);
//将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
String
signForAPIResponse
=
Signature
.
getSign
(
map
,
key
);
if
(!
signForAPIResponse
.
equals
(
signFromAPIResponse
)){
//签名验不过,表示这个API返回的数据有可能已经被篡改了
Util
.
log
(
"API返回的数据签名验证不通过,有可能被第三方篡改!!!"
);
return
false
;
}
Util
.
log
(
"恭喜,API返回的数据签名验证通过!!!"
);
return
true
;
}
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/tencent/common/Util.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.tencent.common
;
import
com.thoughtworks.xstream.XStream
;
import
com.thoughtworks.xstream.io.xml.DomDriver
;
import
com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder
;
import
org.slf4j.LoggerFactory
;
import
java.io.ByteArrayInputStream
;
import
java.io.ByteArrayOutputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.lang.reflect.Field
;
import
java.util.Map
;
/**
* User: rizenguo
* Date: 2014/10/23
* Time: 14:59
*/
public
class
Util
{
//打log用
private
static
Log
logger
=
new
Log
(
LoggerFactory
.
getLogger
(
Util
.
class
));
/**
* 通过反射的方式遍历对象的属性和属性值,方便调试
*
* @param o 要遍历的对象
* @throws Exception
*/
public
static
void
reflect
(
Object
o
)
throws
Exception
{
Class
cls
=
o
.
getClass
();
Field
[]
fields
=
cls
.
getDeclaredFields
();
for
(
int
i
=
0
;
i
<
fields
.
length
;
i
++)
{
Field
f
=
fields
[
i
];
f
.
setAccessible
(
true
);
Util
.
log
(
f
.
getName
()
+
" -> "
+
f
.
get
(
o
));
}
}
public
static
byte
[]
readInput
(
InputStream
in
)
throws
IOException
{
ByteArrayOutputStream
out
=
new
ByteArrayOutputStream
();
int
len
=
0
;
byte
[]
buffer
=
new
byte
[
1024
];
while
((
len
=
in
.
read
(
buffer
))
>
0
)
{
out
.
write
(
buffer
,
0
,
len
);
}
out
.
close
();
in
.
close
();
return
out
.
toByteArray
();
}
public
static
String
inputStreamToString
(
InputStream
is
)
throws
IOException
{
ByteArrayOutputStream
baos
=
new
ByteArrayOutputStream
();
int
i
;
while
((
i
=
is
.
read
())
!=
-
1
)
{
baos
.
write
(
i
);
}
return
baos
.
toString
();
}
public
static
InputStream
getStringStream
(
String
sInputString
)
{
ByteArrayInputStream
tInputStringStream
=
null
;
if
(
sInputString
!=
null
&&
!
sInputString
.
trim
().
equals
(
""
))
{
tInputStringStream
=
new
ByteArrayInputStream
(
sInputString
.
getBytes
());
}
return
tInputStringStream
;
}
public
static
Object
getObjectFromXML
(
String
xml
,
Class
tClass
)
{
//将从API返回的XML数据映射到Java对象
XStream
xStreamForResponseData
=
new
XStream
();
xStreamForResponseData
.
alias
(
"xml"
,
tClass
);
xStreamForResponseData
.
ignoreUnknownElements
();
//暂时忽略掉一些新增的字段
return
xStreamForResponseData
.
fromXML
(
xml
);
}
public
static
String
getStringFromMap
(
Map
<
String
,
Object
>
map
,
String
key
,
String
defaultValue
)
{
if
(
key
==
""
||
key
==
null
)
{
return
defaultValue
;
}
String
result
=
(
String
)
map
.
get
(
key
);
if
(
result
==
null
)
{
return
defaultValue
;
}
else
{
return
result
;
}
}
public
static
int
getIntFromMap
(
Map
<
String
,
Object
>
map
,
String
key
)
{
if
(
key
==
""
||
key
==
null
)
{
return
0
;
}
if
(
map
.
get
(
key
)
==
null
)
{
return
0
;
}
return
Integer
.
parseInt
((
String
)
map
.
get
(
key
));
}
/**
* 打log接口
* @param log 要打印的log字符串
* @return 返回log
*/
public
static
String
log
(
Object
log
){
logger
.
i
(
log
.
toString
());
//System.out.println(log);
return
log
.
toString
();
}
/**
* 读取本地的xml数据,一般用来自测用
* @param localPath 本地xml文件路径
* @return 读到的xml字符串
*/
public
static
String
getLocalXMLString
(
String
localPath
)
throws
IOException
{
return
Util
.
inputStreamToString
(
Util
.
class
.
getResourceAsStream
(
localPath
));
}
public
static
String
objectToXML
(
Object
o
){
//解决XStream对出现双下划线的bug
XStream
xStreamForRequestPostData
=
new
XStream
(
new
DomDriver
(
"UTF-8"
,
new
XmlFriendlyNameCoder
(
"-_"
,
"_"
)));
//将要提交给API的数据对象转换成XML格式数据Post给API
return
xStreamForRequestPostData
.
toXML
(
o
);
}
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/tencent/common/XMLParser.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.tencent.common
;
import
org.xxpay.service.channel.tencent.protocol.refund_query_protocol.RefundOrderData
;
import
org.w3c.dom.Document
;
import
org.w3c.dom.Element
;
import
org.w3c.dom.Node
;
import
org.w3c.dom.NodeList
;
import
org.xml.sax.SAXException
;
import
javax.xml.parsers.DocumentBuilder
;
import
javax.xml.parsers.DocumentBuilderFactory
;
import
javax.xml.parsers.ParserConfigurationException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
/**
* User: rizenguo
* Date: 2014/11/1
* Time: 14:06
*/
public
class
XMLParser
{
/**
* 从RefunQueryResponseString里面解析出退款订单数据
* @param refundQueryResponseString RefundQuery API返回的数据
* @return 因为订单数据有可能是多个,所以返回一个列表
*/
public
static
List
<
RefundOrderData
>
getRefundOrderList
(
String
refundQueryResponseString
)
throws
IOException
,
SAXException
,
ParserConfigurationException
{
List
list
=
new
ArrayList
();
Map
<
String
,
Object
>
map
=
XMLParser
.
getMapFromXML
(
refundQueryResponseString
);
int
count
=
Integer
.
parseInt
((
String
)
map
.
get
(
"refund_count"
));
Util
.
log
(
"count:"
+
count
);
if
(
count
<
1
){
return
list
;
}
RefundOrderData
refundOrderData
;
for
(
int
i
=
0
;
i
<
count
;
i
++){
refundOrderData
=
new
RefundOrderData
();
refundOrderData
.
setOutRefundNo
(
Util
.
getStringFromMap
(
map
,
"out_refund_no_"
+
i
,
""
));
refundOrderData
.
setRefundID
(
Util
.
getStringFromMap
(
map
,
"refund_id_"
+
i
,
""
));
refundOrderData
.
setRefundChannel
(
Util
.
getStringFromMap
(
map
,
"refund_channel_"
+
i
,
""
));
refundOrderData
.
setRefundFee
(
Util
.
getIntFromMap
(
map
,
"refund_fee_"
+
i
));
refundOrderData
.
setCouponRefundFee
(
Util
.
getIntFromMap
(
map
,
"coupon_refund_fee_"
+
i
));
refundOrderData
.
setRefundStatus
(
Util
.
getStringFromMap
(
map
,
"refund_status_"
+
i
,
""
));
list
.
add
(
refundOrderData
);
}
return
list
;
}
public
static
Map
<
String
,
Object
>
getMapFromXML
(
String
xmlString
)
throws
ParserConfigurationException
,
IOException
,
SAXException
{
//这里用Dom的方式解析回包的最主要目的是防止API新增回包字段
DocumentBuilderFactory
factory
=
DocumentBuilderFactory
.
newInstance
();
DocumentBuilder
builder
=
factory
.
newDocumentBuilder
();
InputStream
is
=
Util
.
getStringStream
(
xmlString
);
Document
document
=
builder
.
parse
(
is
);
//获取到document里面的全部结点
NodeList
allNodes
=
document
.
getFirstChild
().
getChildNodes
();
Node
node
;
Map
<
String
,
Object
>
map
=
new
HashMap
<
String
,
Object
>();
int
i
=
0
;
while
(
i
<
allNodes
.
getLength
())
{
node
=
allNodes
.
item
(
i
);
if
(
node
instanceof
Element
){
map
.
put
(
node
.
getNodeName
(),
node
.
getTextContent
());
}
i
++;
}
return
map
;
}
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/tencent/common/report/ReportRunable.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.tencent.common.report
;
import
org.xxpay.service.channel.tencent.common.report.service.ReportService
;
import
java.io.IOException
;
import
java.security.KeyManagementException
;
import
java.security.KeyStoreException
;
import
java.security.NoSuchAlgorithmException
;
import
java.security.UnrecoverableKeyException
;
/**
* User: rizenguo
* Date: 2014/12/3
* Time: 16:34
*/
public
class
ReportRunable
implements
Runnable
{
private
ReportService
reportService
;
ReportRunable
(
ReportService
rs
){
reportService
=
rs
;
}
@Override
public
void
run
()
{
try
{
reportService
.
request
();
}
catch
(
UnrecoverableKeyException
e
)
{
e
.
printStackTrace
();
}
catch
(
KeyManagementException
e
)
{
e
.
printStackTrace
();
}
catch
(
NoSuchAlgorithmException
e
)
{
e
.
printStackTrace
();
}
catch
(
KeyStoreException
e
)
{
e
.
printStackTrace
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/tencent/common/report/Reporter.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.tencent.common.report
;
import
org.xxpay.service.channel.tencent.common.report.protocol.ReportReqData
;
import
org.xxpay.service.channel.tencent.common.report.service.ReportService
;
/**
* User: rizenguo
* Date: 2014/12/3
* Time: 11:42
*/
public
class
Reporter
{
private
ReportRunable
r
;
private
Thread
t
;
private
ReportService
rs
;
/**
* 请求统计上报API
* @param reportReqData 这个数据对象里面包含了API要求提交的各种数据字段
*/
public
Reporter
(
ReportReqData
reportReqData
){
rs
=
new
ReportService
(
reportReqData
);
}
public
void
run
(){
r
=
new
ReportRunable
(
rs
);
t
=
new
Thread
(
r
);
t
.
setDaemon
(
true
);
//后台线程
t
.
start
();
}
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/tencent/common/report/ReporterFactory.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.tencent.common.report
;
import
org.xxpay.service.channel.tencent.common.report.protocol.ReportReqData
;
/**
* User: rizenguo
* Date: 2014/12/3
* Time: 17:44
*/
public
class
ReporterFactory
{
/**
* 请求统计上报API
* @param reportReqData 这个数据对象里面包含了API要求提交的各种数据字段
* @return 返回一个Reporter
*/
public
static
Reporter
getReporter
(
ReportReqData
reportReqData
){
return
new
Reporter
(
reportReqData
);
}
}
xxpay4spring-cloud/xxpay-service/src/main/java/org/xxpay/service/channel/tencent/common/report/protocol/ReportReqData.java
0 → 100755
View file @
d53783a9
package
org.xxpay.service.channel.tencent.common.report.protocol
;
import
org.xxpay.service.channel.tencent.common.Configure
;
import
org.xxpay.service.channel.tencent.common.RandomStringGenerator
;
import
org.xxpay.service.channel.tencent.common.Signature
;
import
java.lang.reflect.Field
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* User: rizenguo
* Date: 2014/11/12
* Time: 17:05
*/
public
class
ReportReqData
{
//每个字段具体的意思请查看API文档
private
String
appid
;
private
String
mch_id
;
private
String
sub_mch_id
;
private
String
device_info
;
private
String
nonce_str
;
private
String
sign
;
//上报对应的接口的完整URL,类似:https://api.mch.weixin.qq.com/pay/unifiedorder
private
String
interface_url
;
//接口耗时情况,单位为毫秒
private
int
execute_time_cost
;
//发起接口调用时的机器IP
private
String
user_ip
;
//上报该统计请求时的系统时间,格式为yyyyMMddHHmmss
private
String
time
;
//以下是API接口返回的对应数据
private
String
return_code
;
private
String
return_msg
;
private
String
result_code
;
private
String
err_code
;
private
String
err_code_des
;
private
String
out_trade_no
;
/**
* 请求统计上报API
* @param deviceInfo 微信支付分配的终端设备号,商户自定义
* @param interfaceUrl 上报对应的接口的完整URL,类似: https://api.mch.weixin.qq.com/pay/unifiedorder
* @param executeTimeCost 接口耗时情况,单位为毫秒
* @param returnCode API返回的对应字段
* @param returnMsg API返回的对应字段
* @param resultCode API返回的对应字段
* @param errCode API返回的对应字段
* @param errCodeDes API返回的对应字段
* @param outTradeNo API返回的对应字段
* @param userIp 发起接口调用时的机器IP
*/
public
ReportReqData
(
Configure
configure
,
String
deviceInfo
,
String
interfaceUrl
,
int
executeTimeCost
,
String
returnCode
,
String
returnMsg
,
String
resultCode
,
String
errCode
,
String
errCodeDes
,
String
outTradeNo
,
String
userIp
){
//微信分配的公众号ID(开通公众号之后可以获取到)
setAppid
(
configure
.
getAppID
());
//微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
setMch_id
(
configure
.
getMchID
());
//商户系统自己生成的唯一的订单号
setOut_trade_no
(
outTradeNo
);
setDevice_info
(
deviceInfo
);
setInterface_url
(
interfaceUrl
);
setExecute_time_cost
(
executeTimeCost
);
setReturn_code
(
returnCode
);
setReturn_msg
(
returnMsg
);
setResult_code
(
resultCode
);
setErr_code
(
errCode
);
setErr_code_des
(
errCodeDes
);
setUser_ip
(
userIp
);
setTime
(
getTime
());
//随机字符串,不长于32 位
setNonce_str
(
RandomStringGenerator
.
getRandomStringByLength
(
32
));
//根据API给的签名规则进行签名
String
sign
=
Signature
.
getSign
(
toMap
(),
configure
.
getKey
());
setSign
(
sign
);
//把签名数据设置到Sign这个属性中
}
public
String
getAppid
()
{
return
appid
;
}
public
void
setAppid
(
String
appid
)
{
this
.
appid
=
appid
;
}
public
String
getMch_id
()
{
return
mch_id
;
}
public
void
setMch_id
(
String
mch_id
)
{
this
.
mch_id
=
mch_id
;
}
public
String
getDevice_info
()
{
return
device_info
;
}
public
void
setDevice_info
(
String
device_info
)
{
this
.
device_info
=
device_info
;
}
public
String
getNonce_str
()
{
return
nonce_str
;
}
public
void
setNonce_str
(
String
nonce_str
)
{
this
.
nonce_str
=
nonce_str
;
}
public
String
getSign
()
{
return
sign
;
}
public
void
setSign
(
String
sign
)
{
this
.
sign
=
sign
;
}
public
String
getInterface_url
()
{
return
interface_url
;
}
public
void
setInterface_url
(
String
interface_url
)
{
this
.
interface_url
=
interface_url
;
}
public
int
getExecute_time_cost
()
{
return
execute_time_cost
;
}
public
void
setExecute_time_cost
(
int
execute_time
)
{
this
.
execute_time_cost
=
execute_time
;
}
public
String
getReturn_code
()
{
return
return_code
;
}
public
void
setReturn_code
(
String
return_code
)
{
this
.
return_code
=
return_code
;
}
public
String
getReturn_msg
()
{
return
return_msg
;
}
public
void
setReturn_msg
(
String
return_msg
)
{
this
.
return_msg
=
return_msg
;
}
public
String
getResult_code
()
{
return
result_code
;
}
public
void
setResult_code
(
String
result_code
)
{
this
.
result_code
=
result_code
;
}
public
String
getErr_code
()
{
return
err_code
;
}
public
void
setErr_code
(
String
err_code
)
{
this
.
err_code
=
err_code
;
}
public
String
getErr_code_des
()
{
return
err_code_des
;
}
public
void
setErr_code_des
(
String
err_code_des
)
{
this
.
err_code_des
=
err_code_des
;
}
public
String
getOut_trade_no
()
{
return
out_trade_no
;
}
public
void
setOut_trade_no
(
String
out_trade_no
)
{
this
.
out_trade_no
=
out_trade_no
;
}
public
String
getUser_ip
()
{
return
user_ip
;
}
public
void
setUser_ip
(
String
user_ip
)
{
this
.
user_ip
=
user_ip
;
}
public
String
getTime
()
{
return
time
;
}
public
void
setTime
(
String
time
)
{
this
.
time
=
time
;
}
public
Map
<
String
,
Object
>
toMap
(){
Map
<
String
,
Object
>
map
=
new
HashMap
<
String
,
Object
>();
Field
[]
fields
=
this
.
getClass
().
getDeclaredFields
();
for
(
Field
field
:
fields
)
{
Object
obj
;
try
{
obj
=
field
.
get
(
this
);
if
(
obj
!=
null
){
map
.
put
(
field
.
getName
(),
obj
);
}
}
catch
(
IllegalArgumentException
e
)
{
e
.
printStackTrace
();
}
catch
(
IllegalAccessException
e
)
{
e
.
printStackTrace
();
}
}
return
map
;
}
}
Prev
1
…
16
17
18
19
20
21
22
23
24
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment