Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
提交反馈
为 GitLab 提交贡献
登录
切换导航
I
ibzpay
项目
项目
详情
动态
版本
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
ibiz4jteam
ibzpay
提交
b6bd4bcd
提交
b6bd4bcd
编写于
8月 30, 2020
作者:
zhouweidong
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
引入支付宝、微信支付
上级
3866b7e4
变更
14
展开全部
显示空白字符变更
内嵌
并排
正在显示
14 个修改的文件
包含
2140 行增加
和
0 行删除
+2140
-0
DevBootSecurityConfig.java
...rc/main/java/cn/ibizlab/config/DevBootSecurityConfig.java
+2
-0
pom.xml
ibzpay-core/pom.xml
+6
-0
PayCoreService.java
...va/cn/ibizlab/core/extensions/service/PayCoreService.java
+272
-0
IWXPayDomain.java
.../ibizlab/core/extensions/service/wechat/IWXPayDomain.java
+42
-0
WXPay.java
...java/cn/ibizlab/core/extensions/service/wechat/WXPay.java
+689
-0
WXPayConfig.java
...n/ibizlab/core/extensions/service/wechat/WXPayConfig.java
+103
-0
WXPayConstants.java
...bizlab/core/extensions/service/wechat/WXPayConstants.java
+59
-0
WXPayReport.java
...n/ibizlab/core/extensions/service/wechat/WXPayReport.java
+265
-0
WXPayRequest.java
.../ibizlab/core/extensions/service/wechat/WXPayRequest.java
+258
-0
WXPayUtil.java
.../cn/ibizlab/core/extensions/service/wechat/WXPayUtil.java
+295
-0
WXPayXmlUtil.java
.../ibizlab/core/extensions/service/wechat/WXPayXmlUtil.java
+30
-0
WechatPayConfig.java
...izlab/core/extensions/service/wechat/WechatPayConfig.java
+65
-0
apiSecurityConfig.java
...rc/main/java/cn/ibizlab/api/config/apiSecurityConfig.java
+2
-0
PayCoreResource.java
.../java/cn/ibizlab/api/rest/extensions/PayCoreResource.java
+52
-0
未找到文件。
ibzpay-boot/src/main/java/cn/ibizlab/config/DevBootSecurityConfig.java
浏览文件 @
b6bd4bcd
...
...
@@ -114,6 +114,8 @@ public class DevBootSecurityConfig extends WebSecurityConfigurerAdapter {
.
antMatchers
(
"/"
+
downloadpath
+
"/**"
).
permitAll
()
.
antMatchers
(
"/"
+
uploadpath
).
permitAll
()
.
antMatchers
(
"/"
+
previewpath
+
"/**"
).
permitAll
()
//开放支付接口
.
antMatchers
(
"/trade/pagepay"
).
permitAll
()
.
anyRequest
().
authenticated
()
// 防止iframe 造成跨域
.
and
().
headers
().
frameOptions
().
disable
();
...
...
ibzpay-core/pom.xml
浏览文件 @
b6bd4bcd
...
...
@@ -98,6 +98,12 @@
<artifactId>
jobs-spring-boot-starter
</artifactId>
</dependency>
<!--支付宝开放平台sdk -->
<dependency>
<groupId>
com.alipay.sdk
</groupId>
<artifactId>
alipay-sdk-java
</artifactId>
<version>
4.10.90.ALL
</version>
</dependency>
</dependencies>
...
...
ibzpay-core/src/main/java/cn/ibizlab/core/extensions/service/PayCoreService.java
0 → 100644
浏览文件 @
b6bd4bcd
package
cn
.
ibizlab
.
core
.
extensions
.
service
;
import
cn.ibizlab.core.extensions.service.wechat.WXPay
;
import
cn.ibizlab.core.extensions.service.wechat.WechatPayConfig
;
import
cn.ibizlab.core.pay.domain.PayOpenAccess
;
import
cn.ibizlab.core.pay.domain.PayTrade
;
import
cn.ibizlab.core.pay.service.IPayOpenAccessService
;
import
cn.ibizlab.util.errors.BadRequestAlertException
;
import
com.alipay.api.AlipayClient
;
import
com.alipay.api.DefaultAlipayClient
;
import
com.alipay.api.request.*
;
import
com.alipay.api.response.*
;
import
lombok.SneakyThrows
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
org.springframework.util.ObjectUtils
;
import
org.springframework.util.StringUtils
;
import
java.util.*
;
@Service
@Slf4j
public
class
PayCoreService
{
@Autowired
IPayOpenAccessService
openAccessService
;
//支付宝沙箱环境
private
final
String
aliPayUrl
=
"https://openapi.alipaydev.com/gateway.do"
;
private
final
String
format
=
"json"
;
private
final
String
charset
=
"UTF-8"
;
private
final
String
signType
=
"RSA2"
;
private
static
Map
<
String
,
AlipayClient
>
aliPayClientMap
=
Collections
.
synchronizedMap
(
new
HashMap
<>());
/**
* 支付宝网页支付
* @param trade
* @return
*/
@SneakyThrows
public
String
pagePay
(
PayTrade
trade
){
PayOpenAccess
openAccess
=
getOpenAccess
(
trade
);
AlipayClient
alipayClient
=
getAliPayClient
(
openAccess
);
AlipayTradePagePayRequest
request
=
new
AlipayTradePagePayRequest
();
request
.
setBizContent
(
"{\"out_trade_no\":\""
+
trade
.
getOutTradeNo
()
+
"\","
+
"\"total_amount\":\""
+
trade
.
getTotalAmount
()
+
"\","
+
"\"subject\":\""
+
trade
.
getSubject
()
+
"\","
+
"\"return_url\":\""
+
openAccess
.
getRedirectUri
()
+
"}"
);
AlipayTradePagePayResponse
response
=
alipayClient
.
pageExecute
(
request
);
if
(
response
.
isSuccess
())
{
log
.
info
(
"调用成功"
);
}
else
{
log
.
error
(
"调用失败"
);
}
return
response
.
getBody
();
}
/**
* 预创建订单,生成支付二维码
* @param trade
* @return
*/
public
boolean
preCreate
(
PayTrade
trade
){
PayOpenAccess
openAccess
=
getOpenAccess
(
trade
);
switch
(
openAccess
.
getOpenType
()){
case
"aliyun"
:
aliPayPreCreate
(
openAccess
,
trade
);
break
;
case
"wechat"
:
wechatPreCreate
(
openAccess
,
trade
);
break
;
}
return
true
;
}
/**
* 查询订单
* @param trade
* @return
*/
public
boolean
query
(
PayTrade
trade
){
PayOpenAccess
openAccess
=
getOpenAccess
(
trade
);
switch
(
openAccess
.
getOpenType
()){
case
"aliyun"
:
aliPayQuery
(
openAccess
,
trade
);
break
;
case
"wechat"
:
wechatPayQuery
(
openAccess
,
trade
);
break
;
}
return
true
;
}
/**
* 取消订单
* @param trade
* @return
*/
public
boolean
cancel
(
PayTrade
trade
){
PayOpenAccess
openAccess
=
getOpenAccess
(
trade
);
switch
(
openAccess
.
getOpenType
()){
case
"aliyun"
:
aliPayCancel
(
openAccess
,
trade
);
break
;
case
"wechat"
:
wechatPayCancel
(
openAccess
,
trade
);
break
;
}
return
true
;
}
/**
* 交易预创建,生成正扫二维码
* @param trade
*/
@SneakyThrows
private
String
aliPayPreCreate
(
PayOpenAccess
openAccess
,
PayTrade
trade
){
AlipayClient
alipayClient
=
getAliPayClient
(
openAccess
);
AlipayTradePrecreateRequest
request
=
new
AlipayTradePrecreateRequest
();
request
.
setBizContent
(
"{"
+
"\"out_trade_no\":\""
+
trade
.
getOutTradeNo
()+
"\","
+
"\"subject\":\""
+
trade
.
getSubject
()+
"\","
+
"\"total_amount\":"
+
trade
.
getTotalAmount
()+
","
+
" }"
);
AlipayTradePrecreateResponse
response
=
alipayClient
.
execute
(
request
);
if
(
response
.
isSuccess
()){
System
.
out
.
println
(
"调用成功"
);
}
else
{
System
.
out
.
println
(
"调用失败"
);
}
return
response
.
getQrCode
();
}
/**
* 交易查询
* @param trade
*/
@SneakyThrows
private
String
aliPayQuery
(
PayOpenAccess
openAccess
,
PayTrade
trade
){
AlipayClient
alipayClient
=
getAliPayClient
(
openAccess
);
AlipayTradeQueryRequest
request
=
new
AlipayTradeQueryRequest
();
request
.
setBizContent
(
"{"
+
"\"out_trade_no\":\""
+
trade
.
getOutTradeNo
()+
"\","
+
" }"
);
AlipayTradeQueryResponse
response
=
alipayClient
.
execute
(
request
);
if
(
response
.
isSuccess
()){
System
.
out
.
println
(
"调用成功"
);
}
else
{
System
.
out
.
println
(
"调用失败"
);
}
return
response
.
getBody
();
}
/**
* 撤销交易
* @param trade
*/
@SneakyThrows
private
String
aliPayCancel
(
PayOpenAccess
openAccess
,
PayTrade
trade
)
{
AlipayClient
alipayClient
=
getAliPayClient
(
openAccess
);
AlipayTradeCancelRequest
request
=
new
AlipayTradeCancelRequest
();
request
.
setBizContent
(
"{"
+
"\"out_trade_no\":\""
+
trade
.
getOutTradeNo
()+
"\","
+
" }"
);
AlipayTradeCancelResponse
response
=
alipayClient
.
execute
(
request
);
if
(
response
.
isSuccess
()){
System
.
out
.
println
(
"调用成功"
);
}
else
{
System
.
out
.
println
(
"调用失败"
);
}
return
response
.
getOutTradeNo
();
}
/**
* 微信预创建订单
* @param trade
*/
@SneakyThrows
private
void
wechatPreCreate
(
PayOpenAccess
openAccess
,
PayTrade
trade
)
{
WechatPayConfig
config
=
getWechatPayConfig
(
openAccess
);
WXPay
wxpay
=
new
WXPay
(
config
);
Map
<
String
,
String
>
data
=
new
HashMap
<
String
,
String
>();
data
.
put
(
"body"
,
trade
.
getSubject
());
data
.
put
(
"out_trade_no"
,
trade
.
getOutTradeNo
());
// data.put("device_info", "");
data
.
put
(
"fee_type"
,
"CNY"
);
data
.
put
(
"total_fee"
,
trade
.
getTotalAmount
());
// data.put("spbill_create_ip", "123.12.12.123");
data
.
put
(
"notify_url"
,
openAccess
.
getRedirectUri
());
data
.
put
(
"trade_type"
,
"NATIVE"
);
// 此处指定为扫码支付
// data.put("product_id", "12");
Map
<
String
,
String
>
resp
=
wxpay
.
unifiedOrder
(
data
);
System
.
out
.
println
(
resp
);
}
/**
* 微信:订单查询
* @param trade
*/
@SneakyThrows
private
void
wechatPayQuery
(
PayOpenAccess
openAccess
,
PayTrade
trade
)
{
WechatPayConfig
config
=
getWechatPayConfig
(
openAccess
);
WXPay
wxpay
=
new
WXPay
(
config
);
Map
<
String
,
String
>
data
=
new
HashMap
<
String
,
String
>();
data
.
put
(
"out_trade_no"
,
trade
.
getOutTradeNo
());
Map
<
String
,
String
>
resp
=
wxpay
.
orderQuery
(
data
);
System
.
out
.
println
(
resp
);
}
/**
* 微信:取消订单
* @param trade
*/
@SneakyThrows
private
void
wechatPayCancel
(
PayOpenAccess
openAccess
,
PayTrade
trade
)
{
WechatPayConfig
config
=
getWechatPayConfig
(
openAccess
);
WXPay
wxpay
=
new
WXPay
(
config
);
Map
<
String
,
String
>
data
=
new
HashMap
<
String
,
String
>();
data
.
put
(
"out_trade_no"
,
trade
.
getOutTradeNo
());
Map
<
String
,
String
>
resp
=
wxpay
.
closeOrder
(
data
);
System
.
out
.
println
(
resp
);
}
/**
* 获取开放平台信息
* @param trade
* @return
*/
private
PayOpenAccess
getOpenAccess
(
PayTrade
trade
){
PayOpenAccess
openAccess
=
null
;
String
accessId
=
trade
.
getAccessId
();
if
(!
StringUtils
.
isEmpty
(
accessId
))
openAccess
=
openAccessService
.
getById
(
accessId
);
if
(
ObjectUtils
.
isEmpty
(
openAccess
))
throw
new
BadRequestAlertException
(
"支付失败,未能获取到开放平台"
,
"PayCoreService"
,
"pagePay"
);
return
openAccess
;
}
/**
* 获取阿里支付客户端对象
* @param openAccess
* @return
*/
private
synchronized
AlipayClient
getAliPayClient
(
PayOpenAccess
openAccess
){
String
appId
=
openAccess
.
getAccessKey
();
if
(
aliPayClientMap
.
get
(
appId
)!=
null
){
return
aliPayClientMap
.
get
(
appId
);
}
AlipayClient
alipayClient
=
new
DefaultAlipayClient
(
aliPayUrl
,
openAccess
.
getAccessKey
(),
openAccess
.
getSecretKey
(),
format
,
charset
,
openAccess
.
getAccessToken
(),
signType
);
aliPayClientMap
.
put
(
appId
,
alipayClient
);
return
alipayClient
;
}
/**
* 获取微信应用配置
* @param openAccess
* @return
*/
private
WechatPayConfig
getWechatPayConfig
(
PayOpenAccess
openAccess
)
{
WechatPayConfig
config
=
new
WechatPayConfig
();
config
.
setAppID
(
openAccess
.
getAccessKey
());
config
.
setKey
(
openAccess
.
getAccessKey
());
config
.
setMchID
(
openAccess
.
getRegionId
());
config
.
setWXPayDomain
(
null
);
return
config
;
}
}
ibzpay-core/src/main/java/cn/ibizlab/core/extensions/service/wechat/IWXPayDomain.java
0 → 100644
浏览文件 @
b6bd4bcd
package
cn
.
ibizlab
.
core
.
extensions
.
service
.
wechat
;
/**
* 域名管理,实现主备域名自动切换
*/
public
abstract
interface
IWXPayDomain
{
/**
* 上报域名网络状况
* @param domain 域名。 比如:api.mch.weixin.qq.com
* @param elapsedTimeMillis 耗时
* @param ex 网络请求中出现的异常。
* null表示没有异常
* ConnectTimeoutException,表示建立网络连接异常
* UnknownHostException, 表示dns解析异常
*/
abstract
void
report
(
final
String
domain
,
long
elapsedTimeMillis
,
final
Exception
ex
);
/**
* 获取域名
* @param config 配置
* @return 域名
*/
abstract
DomainInfo
getDomain
(
final
WXPayConfig
config
);
static
class
DomainInfo
{
public
String
domain
;
//域名
public
boolean
primaryDomain
;
//该域名是否为主域名。例如:api.mch.weixin.qq.com为主域名
public
DomainInfo
(
String
domain
,
boolean
primaryDomain
)
{
this
.
domain
=
domain
;
this
.
primaryDomain
=
primaryDomain
;
}
@Override
public
String
toString
()
{
return
"DomainInfo{"
+
"domain='"
+
domain
+
'\''
+
", primaryDomain="
+
primaryDomain
+
'}'
;
}
}
}
\ No newline at end of file
ibzpay-core/src/main/java/cn/ibizlab/core/extensions/service/wechat/WXPay.java
0 → 100644
浏览文件 @
b6bd4bcd
此差异已折叠。
点击以展开。
ibzpay-core/src/main/java/cn/ibizlab/core/extensions/service/wechat/WXPayConfig.java
0 → 100644
浏览文件 @
b6bd4bcd
package
cn
.
ibizlab
.
core
.
extensions
.
service
.
wechat
;
import
java.io.InputStream
;
public
abstract
class
WXPayConfig
{
/**
* 获取 App ID
*
* @return App ID
*/
abstract
String
getAppID
();
/**
* 获取 Mch ID
*
* @return Mch ID
*/
abstract
String
getMchID
();
/**
* 获取 API 密钥
*
* @return API密钥
*/
abstract
String
getKey
();
/**
* 获取商户证书内容
*
* @return 商户证书内容
*/
abstract
InputStream
getCertStream
();
/**
* HTTP(S) 连接超时时间,单位毫秒
*
* @return
*/
public
int
getHttpConnectTimeoutMs
()
{
return
6
*
1000
;
}
/**
* HTTP(S) 读数据超时时间,单位毫秒
*
* @return
*/
public
int
getHttpReadTimeoutMs
()
{
return
8
*
1000
;
}
/**
* 获取WXPayDomain, 用于多域名容灾自动切换
* @return
*/
abstract
IWXPayDomain
getWXPayDomain
();
/**
* 是否自动上报。
* 若要关闭自动上报,子类中实现该函数返回 false 即可。
*
* @return
*/
public
boolean
shouldAutoReport
()
{
return
true
;
}
/**
* 进行健康上报的线程的数量
*
* @return
*/
public
int
getReportWorkerNum
()
{
return
6
;
}
/**
* 健康上报缓存消息的最大数量。会有线程去独立上报
* 粗略计算:加入一条消息200B,10000消息占用空间 2000 KB,约为2MB,可以接受
*
* @return
*/
public
int
getReportQueueMaxSize
()
{
return
10000
;
}
/**
* 批量上报,一次最多上报多个数据
*
* @return
*/
public
int
getReportBatchSize
()
{
return
10
;
}
}
ibzpay-core/src/main/java/cn/ibizlab/core/extensions/service/wechat/WXPayConstants.java
0 → 100644
浏览文件 @
b6bd4bcd
package
cn
.
ibizlab
.
core
.
extensions
.
service
.
wechat
;
import
org.apache.http.client.HttpClient
;
/**
* 常量
*/
public
class
WXPayConstants
{
public
enum
SignType
{
MD5
,
HMACSHA256
}
public
static
final
String
DOMAIN_API
=
"api.mch.weixin.qq.com"
;
public
static
final
String
DOMAIN_API2
=
"api2.mch.weixin.qq.com"
;
public
static
final
String
DOMAIN_APIHK
=
"apihk.mch.weixin.qq.com"
;
public
static
final
String
DOMAIN_APIUS
=
"apius.mch.weixin.qq.com"
;
public
static
final
String
FAIL
=
"FAIL"
;
public
static
final
String
SUCCESS
=
"SUCCESS"
;
public
static
final
String
HMACSHA256
=
"HMAC-SHA256"
;
public
static
final
String
MD5
=
"MD5"
;
public
static
final
String
FIELD_SIGN
=
"sign"
;
public
static
final
String
FIELD_SIGN_TYPE
=
"sign_type"
;
public
static
final
String
WXPAYSDK_VERSION
=
"WXPaySDK/3.0.9"
;
public
static
final
String
USER_AGENT
=
WXPAYSDK_VERSION
+
" ("
+
System
.
getProperty
(
"os.arch"
)
+
" "
+
System
.
getProperty
(
"os.name"
)
+
" "
+
System
.
getProperty
(
"os.version"
)
+
") Java/"
+
System
.
getProperty
(
"java.version"
)
+
" HttpClient/"
+
HttpClient
.
class
.
getPackage
().
getImplementationVersion
();
public
static
final
String
MICROPAY_URL_SUFFIX
=
"/pay/micropay"
;
public
static
final
String
UNIFIEDORDER_URL_SUFFIX
=
"/pay/unifiedorder"
;
public
static
final
String
ORDERQUERY_URL_SUFFIX
=
"/pay/orderquery"
;
public
static
final
String
REVERSE_URL_SUFFIX
=
"/secapi/pay/reverse"
;
public
static
final
String
CLOSEORDER_URL_SUFFIX
=
"/pay/closeorder"
;
public
static
final
String
REFUND_URL_SUFFIX
=
"/secapi/pay/refund"
;
public
static
final
String
REFUNDQUERY_URL_SUFFIX
=
"/pay/refundquery"
;
public
static
final
String
DOWNLOADBILL_URL_SUFFIX
=
"/pay/downloadbill"
;
public
static
final
String
REPORT_URL_SUFFIX
=
"/payitil/report"
;
public
static
final
String
SHORTURL_URL_SUFFIX
=
"/tools/shorturl"
;
public
static
final
String
AUTHCODETOOPENID_URL_SUFFIX
=
"/tools/authcodetoopenid"
;
// sandbox
public
static
final
String
SANDBOX_MICROPAY_URL_SUFFIX
=
"/sandboxnew/pay/micropay"
;
public
static
final
String
SANDBOX_UNIFIEDORDER_URL_SUFFIX
=
"/sandboxnew/pay/unifiedorder"
;
public
static
final
String
SANDBOX_ORDERQUERY_URL_SUFFIX
=
"/sandboxnew/pay/orderquery"
;
public
static
final
String
SANDBOX_REVERSE_URL_SUFFIX
=
"/sandboxnew/secapi/pay/reverse"
;
public
static
final
String
SANDBOX_CLOSEORDER_URL_SUFFIX
=
"/sandboxnew/pay/closeorder"
;
public
static
final
String
SANDBOX_REFUND_URL_SUFFIX
=
"/sandboxnew/secapi/pay/refund"
;
public
static
final
String
SANDBOX_REFUNDQUERY_URL_SUFFIX
=
"/sandboxnew/pay/refundquery"
;
public
static
final
String
SANDBOX_DOWNLOADBILL_URL_SUFFIX
=
"/sandboxnew/pay/downloadbill"
;
public
static
final
String
SANDBOX_REPORT_URL_SUFFIX
=
"/sandboxnew/payitil/report"
;
public
static
final
String
SANDBOX_SHORTURL_URL_SUFFIX
=
"/sandboxnew/tools/shorturl"
;
public
static
final
String
SANDBOX_AUTHCODETOOPENID_URL_SUFFIX
=
"/sandboxnew/tools/authcodetoopenid"
;
}
ibzpay-core/src/main/java/cn/ibizlab/core/extensions/service/wechat/WXPayReport.java
0 → 100644
浏览文件 @
b6bd4bcd
此差异已折叠。
点击以展开。
ibzpay-core/src/main/java/cn/ibizlab/core/extensions/service/wechat/WXPayRequest.java
0 → 100644
浏览文件 @
b6bd4bcd
此差异已折叠。
点击以展开。
ibzpay-core/src/main/java/cn/ibizlab/core/extensions/service/wechat/WXPayUtil.java
0 → 100644
浏览文件 @
b6bd4bcd
package
cn
.
ibizlab
.
core
.
extensions
.
service
.
wechat
;
import
cn.ibizlab.core.extensions.service.wechat.WXPayConstants.SignType
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.w3c.dom.Node
;
import
org.w3c.dom.NodeList
;
import
javax.crypto.Mac
;
import
javax.crypto.spec.SecretKeySpec
;
import
javax.xml.parsers.DocumentBuilder
;
import
javax.xml.transform.OutputKeys
;
import
javax.xml.transform.Transformer
;
import
javax.xml.transform.TransformerFactory
;
import
javax.xml.transform.dom.DOMSource
;
import
javax.xml.transform.stream.StreamResult
;
import
java.io.ByteArrayInputStream
;
import
java.io.InputStream
;
import
java.io.StringWriter
;
import
java.security.MessageDigest
;
import
java.security.SecureRandom
;
import
java.util.*
;
public
class
WXPayUtil
{
private
static
final
String
SYMBOLS
=
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
;
private
static
final
Random
RANDOM
=
new
SecureRandom
();
/**
* XML格式字符串转换为Map
*
* @param strXML XML字符串
* @return XML数据转换后的Map
* @throws Exception
*/
public
static
Map
<
String
,
String
>
xmlToMap
(
String
strXML
)
throws
Exception
{
try
{
Map
<
String
,
String
>
data
=
new
HashMap
<
String
,
String
>();
DocumentBuilder
documentBuilder
=
WXPayXmlUtil
.
newDocumentBuilder
();
InputStream
stream
=
new
ByteArrayInputStream
(
strXML
.
getBytes
(
"UTF-8"
));
org
.
w3c
.
dom
.
Document
doc
=
documentBuilder
.
parse
(
stream
);
doc
.
getDocumentElement
().
normalize
();
NodeList
nodeList
=
doc
.
getDocumentElement
().
getChildNodes
();
for
(
int
idx
=
0
;
idx
<
nodeList
.
getLength
();
++
idx
)
{
Node
node
=
nodeList
.
item
(
idx
);
if
(
node
.
getNodeType
()
==
Node
.
ELEMENT_NODE
)
{
org
.
w3c
.
dom
.
Element
element
=
(
org
.
w3c
.
dom
.
Element
)
node
;
data
.
put
(
element
.
getNodeName
(),
element
.
getTextContent
());
}
}
try
{
stream
.
close
();
}
catch
(
Exception
ex
)
{
// do nothing
}
return
data
;
}
catch
(
Exception
ex
)
{
WXPayUtil
.
getLogger
().
warn
(
"Invalid XML, can not convert to map. Error message: {}. XML content: {}"
,
ex
.
getMessage
(),
strXML
);
throw
ex
;
}
}
/**
* 将Map转换为XML格式的字符串
*
* @param data Map类型数据
* @return XML格式的字符串
* @throws Exception
*/
public
static
String
mapToXml
(
Map
<
String
,
String
>
data
)
throws
Exception
{
org
.
w3c
.
dom
.
Document
document
=
WXPayXmlUtil
.
newDocument
();
org
.
w3c
.
dom
.
Element
root
=
document
.
createElement
(
"xml"
);
document
.
appendChild
(
root
);
for
(
String
key:
data
.
keySet
())
{
String
value
=
data
.
get
(
key
);
if
(
value
==
null
)
{
value
=
""
;
}
value
=
value
.
trim
();
org
.
w3c
.
dom
.
Element
filed
=
document
.
createElement
(
key
);
filed
.
appendChild
(
document
.
createTextNode
(
value
));
root
.
appendChild
(
filed
);
}
TransformerFactory
tf
=
TransformerFactory
.
newInstance
();
Transformer
transformer
=
tf
.
newTransformer
();
DOMSource
source
=
new
DOMSource
(
document
);
transformer
.
setOutputProperty
(
OutputKeys
.
ENCODING
,
"UTF-8"
);
transformer
.
setOutputProperty
(
OutputKeys
.
INDENT
,
"yes"
);
StringWriter
writer
=
new
StringWriter
();
StreamResult
result
=
new
StreamResult
(
writer
);
transformer
.
transform
(
source
,
result
);
String
output
=
writer
.
getBuffer
().
toString
();
//.replaceAll("\n|\r", "");
try
{
writer
.
close
();
}
catch
(
Exception
ex
)
{
}
return
output
;
}
/**
* 生成带有 sign 的 XML 格式字符串
*
* @param data Map类型数据
* @param key API密钥
* @return 含有sign字段的XML
*/
public
static
String
generateSignedXml
(
final
Map
<
String
,
String
>
data
,
String
key
)
throws
Exception
{
return
generateSignedXml
(
data
,
key
,
SignType
.
MD5
);
}
/**
* 生成带有 sign 的 XML 格式字符串
*
* @param data Map类型数据
* @param key API密钥
* @param signType 签名类型
* @return 含有sign字段的XML
*/
public
static
String
generateSignedXml
(
final
Map
<
String
,
String
>
data
,
String
key
,
SignType
signType
)
throws
Exception
{
String
sign
=
generateSignature
(
data
,
key
,
signType
);
data
.
put
(
WXPayConstants
.
FIELD_SIGN
,
sign
);
return
mapToXml
(
data
);
}
/**
* 判断签名是否正确
*
* @param xmlStr XML格式数据
* @param key API密钥
* @return 签名是否正确
* @throws Exception
*/
public
static
boolean
isSignatureValid
(
String
xmlStr
,
String
key
)
throws
Exception
{
Map
<
String
,
String
>
data
=
xmlToMap
(
xmlStr
);
if
(!
data
.
containsKey
(
WXPayConstants
.
FIELD_SIGN
)
)
{
return
false
;
}
String
sign
=
data
.
get
(
WXPayConstants
.
FIELD_SIGN
);
return
generateSignature
(
data
,
key
).
equals
(
sign
);
}
/**
* 判断签名是否正确,必须包含sign字段,否则返回false。使用MD5签名。
*
* @param data Map类型数据
* @param key API密钥
* @return 签名是否正确
* @throws Exception
*/
public
static
boolean
isSignatureValid
(
Map
<
String
,
String
>
data
,
String
key
)
throws
Exception
{
return
isSignatureValid
(
data
,
key
,
SignType
.
MD5
);
}
/**
* 判断签名是否正确,必须包含sign字段,否则返回false。
*
* @param data Map类型数据
* @param key API密钥
* @param signType 签名方式
* @return 签名是否正确
* @throws Exception
*/
public
static
boolean
isSignatureValid
(
Map
<
String
,
String
>
data
,
String
key
,
SignType
signType
)
throws
Exception
{
if
(!
data
.
containsKey
(
WXPayConstants
.
FIELD_SIGN
)
)
{
return
false
;
}
String
sign
=
data
.
get
(
WXPayConstants
.
FIELD_SIGN
);
return
generateSignature
(
data
,
key
,
signType
).
equals
(
sign
);
}
/**
* 生成签名
*
* @param data 待签名数据
* @param key API密钥
* @return 签名
*/
public
static
String
generateSignature
(
final
Map
<
String
,
String
>
data
,
String
key
)
throws
Exception
{
return
generateSignature
(
data
,
key
,
SignType
.
MD5
);
}
/**
* 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
*
* @param data 待签名数据
* @param key API密钥
* @param signType 签名方式
* @return 签名
*/
public
static
String
generateSignature
(
final
Map
<
String
,
String
>
data
,
String
key
,
SignType
signType
)
throws
Exception
{
Set
<
String
>
keySet
=
data
.
keySet
();
String
[]
keyArray
=
keySet
.
toArray
(
new
String
[
keySet
.
size
()]);
Arrays
.
sort
(
keyArray
);
StringBuilder
sb
=
new
StringBuilder
();
for
(
String
k
:
keyArray
)
{
if
(
k
.
equals
(
WXPayConstants
.
FIELD_SIGN
))
{
continue
;
}
if
(
data
.
get
(
k
).
trim
().
length
()
>
0
)
// 参数值为空,则不参与签名
sb
.
append
(
k
).
append
(
"="
).
append
(
data
.
get
(
k
).
trim
()).
append
(
"&"
);
}
sb
.
append
(
"key="
).
append
(
key
);
if
(
SignType
.
MD5
.
equals
(
signType
))
{
return
MD5
(
sb
.
toString
()).
toUpperCase
();
}
else
if
(
SignType
.
HMACSHA256
.
equals
(
signType
))
{
return
HMACSHA256
(
sb
.
toString
(),
key
);
}
else
{
throw
new
Exception
(
String
.
format
(
"Invalid sign_type: %s"
,
signType
));
}
}
/**
* 获取随机字符串 Nonce Str
*
* @return String 随机字符串
*/
public
static
String
generateNonceStr
()
{
char
[]
nonceChars
=
new
char
[
32
];
for
(
int
index
=
0
;
index
<
nonceChars
.
length
;
++
index
)
{
nonceChars
[
index
]
=
SYMBOLS
.
charAt
(
RANDOM
.
nextInt
(
SYMBOLS
.
length
()));
}
return
new
String
(
nonceChars
);
}
/**
* 生成 MD5
*
* @param data 待处理数据
* @return MD5结果
*/
public
static
String
MD5
(
String
data
)
throws
Exception
{
MessageDigest
md
=
MessageDigest
.
getInstance
(
"MD5"
);
byte
[]
array
=
md
.
digest
(
data
.
getBytes
(
"UTF-8"
));
StringBuilder
sb
=
new
StringBuilder
();
for
(
byte
item
:
array
)
{
sb
.
append
(
Integer
.
toHexString
((
item
&
0xFF
)
|
0x100
).
substring
(
1
,
3
));
}
return
sb
.
toString
().
toUpperCase
();
}
/**
* 生成 HMACSHA256
* @param data 待处理数据
* @param key 密钥
* @return 加密结果
* @throws Exception
*/
public
static
String
HMACSHA256
(
String
data
,
String
key
)
throws
Exception
{
Mac
sha256_HMAC
=
Mac
.
getInstance
(
"HmacSHA256"
);
SecretKeySpec
secret_key
=
new
SecretKeySpec
(
key
.
getBytes
(
"UTF-8"
),
"HmacSHA256"
);
sha256_HMAC
.
init
(
secret_key
);
byte
[]
array
=
sha256_HMAC
.
doFinal
(
data
.
getBytes
(
"UTF-8"
));
StringBuilder
sb
=
new
StringBuilder
();
for
(
byte
item
:
array
)
{
sb
.
append
(
Integer
.
toHexString
((
item
&
0xFF
)
|
0x100
).
substring
(
1
,
3
));
}
return
sb
.
toString
().
toUpperCase
();
}
/**
* 日志
* @return
*/
public
static
Logger
getLogger
()
{
Logger
logger
=
LoggerFactory
.
getLogger
(
"wxpay java sdk"
);
return
logger
;
}
/**
* 获取当前时间戳,单位秒
* @return
*/
public
static
long
getCurrentTimestamp
()
{
return
System
.
currentTimeMillis
()/
1000
;
}
/**
* 获取当前时间戳,单位毫秒
* @return
*/
public
static
long
getCurrentTimestampMs
()
{
return
System
.
currentTimeMillis
();
}
}
ibzpay-core/src/main/java/cn/ibizlab/core/extensions/service/wechat/WXPayXmlUtil.java
0 → 100644
浏览文件 @
b6bd4bcd
package
cn
.
ibizlab
.
core
.
extensions
.
service
.
wechat
;
import
org.w3c.dom.Document
;
import
javax.xml.XMLConstants
;
import
javax.xml.parsers.DocumentBuilder
;
import
javax.xml.parsers.DocumentBuilderFactory
;
import
javax.xml.parsers.ParserConfigurationException
;
/**
* 2018/7/3
*/
public
final
class
WXPayXmlUtil
{
public
static
DocumentBuilder
newDocumentBuilder
()
throws
ParserConfigurationException
{
DocumentBuilderFactory
documentBuilderFactory
=
DocumentBuilderFactory
.
newInstance
();
documentBuilderFactory
.
setFeature
(
"http://apache.org/xml/features/disallow-doctype-decl"
,
true
);
documentBuilderFactory
.
setFeature
(
"http://xml.org/sax/features/external-general-entities"
,
false
);
documentBuilderFactory
.
setFeature
(
"http://xml.org/sax/features/external-parameter-entities"
,
false
);
documentBuilderFactory
.
setFeature
(
"http://apache.org/xml/features/nonvalidating/load-external-dtd"
,
false
);
documentBuilderFactory
.
setFeature
(
XMLConstants
.
FEATURE_SECURE_PROCESSING
,
true
);
documentBuilderFactory
.
setXIncludeAware
(
false
);
documentBuilderFactory
.
setExpandEntityReferences
(
false
);
return
documentBuilderFactory
.
newDocumentBuilder
();
}
public
static
Document
newDocument
()
throws
ParserConfigurationException
{
return
newDocumentBuilder
().
newDocument
();
}
}
ibzpay-core/src/main/java/cn/ibizlab/core/extensions/service/wechat/WechatPayConfig.java
0 → 100644
浏览文件 @
b6bd4bcd
package
cn
.
ibizlab
.
core
.
extensions
.
service
.
wechat
;
import
lombok.Data
;
import
java.io.ByteArrayInputStream
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.InputStream
;
@Data
public
class
WechatPayConfig
extends
WXPayConfig
{
private
byte
[]
certData
;
private
String
appID
;
private
String
mchID
;
private
String
key
;
private
InputStream
certStream
;
private
IWXPayDomain
WXPayDomain
;
// public WechatPayConfig() throws Exception {
// String certPath = "/path/to/apiclient_cert.p12";
// File file = new File(certPath);
// InputStream certStream = new FileInputStream(file);
// this.certData = new byte[(int) file.length()];
// certStream.read(this.certData);
// certStream.close();
// }
//
// public String getAppID() {
// return "wx8888888888888888";
// }
//
// public String getMchID() {
// return "12888888";
// }
//
// public String getKey() {
// return "88888888888888888888888888888888";
// }
// public InputStream getCertStream() {
// ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
// return certBis;
// }
// public int getHttpConnectTimeoutMs() {
// return 8000;
// }
//
// public int getHttpReadTimeoutMs() {
// return 10000;
// }
// @Override
// IWXPayDomain getWXPayDomain() {
// return null;
// }
}
\ No newline at end of file
ibzpay-provider/ibzpay-provider-api/src/main/java/cn/ibizlab/api/config/apiSecurityConfig.java
浏览文件 @
b6bd4bcd
...
...
@@ -119,6 +119,8 @@ public class apiSecurityConfig extends WebSecurityConfigurerAdapter {
.
antMatchers
(
"/"
+
downloadpath
+
"/**"
).
permitAll
()
.
antMatchers
(
"/"
+
uploadpath
).
permitAll
()
.
antMatchers
(
"/"
+
previewpath
+
"/**"
).
permitAll
()
//开放支付接口
.
antMatchers
(
"/trade/pagepay"
).
permitAll
()
// 所有请求都需要认证
.
anyRequest
().
authenticated
()
// 防止iframe 造成跨域
...
...
ibzpay-provider/ibzpay-provider-api/src/main/java/cn/ibizlab/api/rest/extensions/PayCoreResource.java
0 → 100644
浏览文件 @
b6bd4bcd
package
cn
.
ibizlab
.
api
.
rest
.
extensions
;
import
cn.ibizlab.api.dto.PayTradeDTO
;
import
cn.ibizlab.api.mapping.PayTradeMapping
;
import
cn.ibizlab.core.extensions.service.PayCoreService
;
import
io.swagger.annotations.ApiOperation
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.context.annotation.Lazy
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMethod
;
import
org.springframework.web.bind.annotation.RestController
;
@RestController
public
class
PayCoreResource
{
@Autowired
@Lazy
PayCoreService
payCoreService
;
@Autowired
@Lazy
PayTradeMapping
payTradeMapping
;
@ApiOperation
(
value
=
"预下单获取二维码"
,
tags
=
{
"获取二维码"
},
notes
=
"预下单获取二维码"
)
@RequestMapping
(
method
=
RequestMethod
.
POST
,
value
=
"/trade/precreate"
)
public
ResponseEntity
<
Boolean
>
preCreate
(
@Validated
@RequestBody
PayTradeDTO
dto
){
return
ResponseEntity
.
status
(
HttpStatus
.
OK
).
body
(
payCoreService
.
preCreate
(
payTradeMapping
.
toDomain
(
dto
)));
}
@ApiOperation
(
value
=
"查询订单"
,
tags
=
{
"查询订单"
},
notes
=
"查询订单"
)
@RequestMapping
(
method
=
RequestMethod
.
POST
,
value
=
"/trade/query"
)
public
ResponseEntity
<
Boolean
>
query
(
@Validated
@RequestBody
PayTradeDTO
dto
){
return
ResponseEntity
.
status
(
HttpStatus
.
OK
).
body
(
payCoreService
.
query
(
payTradeMapping
.
toDomain
(
dto
)));
}
@ApiOperation
(
value
=
"取消订单"
,
tags
=
{
"取消订单"
},
notes
=
"取消订单"
)
@RequestMapping
(
method
=
RequestMethod
.
POST
,
value
=
"/trade/cancel"
)
public
ResponseEntity
<
Boolean
>
cancel
(
@Validated
@RequestBody
PayTradeDTO
dto
){
return
ResponseEntity
.
status
(
HttpStatus
.
OK
).
body
(
payCoreService
.
cancel
(
payTradeMapping
.
toDomain
(
dto
)));
}
@ApiOperation
(
value
=
"网页支付"
,
tags
=
{
"网页支付"
},
notes
=
"网页支付"
)
@RequestMapping
(
method
=
RequestMethod
.
POST
,
value
=
"/trade/pagepay"
)
public
ResponseEntity
<
String
>
pagePay
(
@Validated
@RequestBody
PayTradeDTO
dto
){
return
ResponseEntity
.
status
(
HttpStatus
.
OK
).
body
(
payCoreService
.
pagePay
(
payTradeMapping
.
toDomain
(
dto
)));
}
}
编辑
预览
Markdown
格式
0%
请重试
or
添加新附件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
先完成此消息的编辑!
取消
想要评论请
注册
或
登录