Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
B
baa-pay-server
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
贺超
baa-pay-server
Commits
aae49d8f
Commit
aae49d8f
authored
Sep 13, 2021
by
Administrator
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/master'
parents
54476527
e003ed79
Changes
23
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
2247 additions
and
40 deletions
+2247
-40
pom.xml
baa-pay-core/pom.xml
+5
-1
Acquirer.java
...ore/src/main/java/cn/quant/baa/pay/acquirer/Acquirer.java
+9
-3
AcquirerProperties.java
...in/java/cn/quant/baa/pay/acquirer/AcquirerProperties.java
+31
-0
MerchantAcquirer.java
...main/java/cn/quant/baa/pay/acquirer/MerchantAcquirer.java
+19
-6
AlipayMerchantAcquirer.java
...quant/baa/pay/acquirer/alipay/AlipayMerchantAcquirer.java
+535
-0
WeiXinMerchantAcquirer.java
...quant/baa/pay/acquirer/weixin/WeiXinMerchantAcquirer.java
+346
-1
ServerConfiguration.java
...ain/java/cn/quant/baa/pay/config/ServerConfiguration.java
+5
-4
AccessCode.java
...-core/src/main/java/cn/quant/baa/pay/dict/AccessCode.java
+5
-0
PayAccountEntity.java
...in/java/cn/quant/baa/pay/jpa/entity/PayAccountEntity.java
+22
-1
PayFeatureEntity.java
...in/java/cn/quant/baa/pay/jpa/entity/PayFeatureEntity.java
+11
-0
PayHistoryRepository.java
...cn/quant/baa/pay/jpa/repository/PayHistoryRepository.java
+2
-0
CheckPayRequestData.java
.../java/cn/quant/baa/pay/model/web/CheckPayRequestData.java
+46
-0
CheckRefundRequestData.java
...va/cn/quant/baa/pay/model/web/CheckRefundRequestData.java
+62
-0
CloseRequestData.java
...ain/java/cn/quant/baa/pay/model/web/CloseRequestData.java
+46
-0
RefundRequestData.java
...in/java/cn/quant/baa/pay/model/web/RefundRequestData.java
+90
-0
pom.xml
baa-pay-server/pom.xml
+21
-16
PayTestController.java
...rc/main/java/cn/quant/baa/pay/rest/PayTestController.java
+99
-0
TransactionController.java
...ain/java/cn/quant/baa/pay/rest/TransactionController.java
+54
-3
TransactionService.java
...ain/java/cn/quant/baa/pay/service/TransactionService.java
+23
-5
checkPay.html
...pay-server/src/main/resources/templates/pay/checkPay.html
+185
-0
checkRefund.html
...-server/src/main/resources/templates/pay/checkRefund.html
+188
-0
h5.html
baa-pay-server/src/main/resources/templates/pay/h5.html
+267
-0
index.html
baa-pay-server/src/main/resources/templates/pay/index.html
+176
-0
No files found.
baa-pay-core/pom.xml
View file @
aae49d8f
...
@@ -129,7 +129,11 @@
...
@@ -129,7 +129,11 @@
<groupId>
com.fasterxml.jackson.datatype
</groupId>
<groupId>
com.fasterxml.jackson.datatype
</groupId>
<artifactId>
jackson-datatype-hibernate5
</artifactId>
<artifactId>
jackson-datatype-hibernate5
</artifactId>
</dependency>
</dependency>
<dependency>
<groupId>
org.bouncycastle
</groupId>
<artifactId>
bcmail-jdk15
</artifactId>
<version>
1.45
</version>
</dependency>
<!--cache-->
<!--cache-->
<dependency>
<dependency>
<groupId>
com.github.ben-manes.caffeine
</groupId>
<groupId>
com.github.ben-manes.caffeine
</groupId>
...
...
baa-pay-core/src/main/java/cn/quant/baa/pay/acquirer/Acquirer.java
View file @
aae49d8f
package
cn
.
quant
.
baa
.
pay
.
acquirer
;
package
cn
.
quant
.
baa
.
pay
.
acquirer
;
import
cn.quant.baa.pay.jpa.entity.PayHistoryEntity
;
import
cn.quant.baa.pay.model.web.*
;
import
com.fasterxml.jackson.databind.JsonNode
;
/**
/**
* Created by Administrator on 2021/9/1 0001.
* Created by Administrator on 2021/9/1 0001.
*/
*/
public
interface
Acquirer
{
public
interface
Acquirer
{
Object
code
();
Object
code
();
void
pay
();
JsonNode
pay
(
PayRequestData
payRequestData
,
PayHistoryEntity
payHistoryEntity
);
void
refund
();
JsonNode
refund
(
RefundRequestData
refundRequestData
);
void
check
();
JsonNode
checkPay
(
CheckPayRequestData
checkPayRequestData
);
JsonNode
checkRefund
(
CheckRefundRequestData
checkRefundRequestData
);
JsonNode
close
(
CloseRequestData
closeRequestData
);
}
}
baa-pay-core/src/main/java/cn/quant/baa/pay/acquirer/AcquirerProperties.java
View file @
aae49d8f
...
@@ -42,6 +42,12 @@ public class AcquirerProperties implements Serializable{
...
@@ -42,6 +42,12 @@ public class AcquirerProperties implements Serializable{
private
String
payCertKey
;
private
String
payCertKey
;
private
String
payRootCertNo
;
private
String
payRootCertKey
;
private
String
productCode
;
//feature
//feature
private
AccessCode
accessCode
;
private
AccessCode
accessCode
;
...
@@ -119,6 +125,30 @@ public class AcquirerProperties implements Serializable{
...
@@ -119,6 +125,30 @@ public class AcquirerProperties implements Serializable{
this
.
name
=
name
;
this
.
name
=
name
;
}
}
public
String
getPayRootCertNo
()
{
return
payRootCertNo
;
}
public
void
setPayRootCertNo
(
String
payRootCertNo
)
{
this
.
payRootCertNo
=
payRootCertNo
;
}
public
String
getPayRootCertKey
()
{
return
payRootCertKey
;
}
public
void
setPayRootCertKey
(
String
payRootCertKey
)
{
this
.
payRootCertKey
=
payRootCertKey
;
}
public
String
getProductCode
()
{
return
productCode
;
}
public
void
setProductCode
(
String
productCode
)
{
this
.
productCode
=
productCode
;
}
public
String
getSecretKey
()
{
public
String
getSecretKey
()
{
return
secretKey
;
return
secretKey
;
}
}
...
@@ -315,6 +345,7 @@ public class AcquirerProperties implements Serializable{
...
@@ -315,6 +345,7 @@ public class AcquirerProperties implements Serializable{
sb
.
append
(
", secretType='"
).
append
(
secretType
).
append
(
'\''
);
sb
.
append
(
", secretType='"
).
append
(
secretType
).
append
(
'\''
);
sb
.
append
(
", signType='"
).
append
(
signType
).
append
(
'\''
);
sb
.
append
(
", signType='"
).
append
(
signType
).
append
(
'\''
);
sb
.
append
(
", payCertNo='"
).
append
(
payCertNo
).
append
(
'\''
);
sb
.
append
(
", payCertNo='"
).
append
(
payCertNo
).
append
(
'\''
);
sb
.
append
(
", payRootCertNo='"
).
append
(
payRootCertNo
).
append
(
'\''
);
sb
.
append
(
", accessCode="
).
append
(
accessCode
);
sb
.
append
(
", accessCode="
).
append
(
accessCode
);
sb
.
append
(
", accessType="
).
append
(
accessType
);
sb
.
append
(
", accessType="
).
append
(
accessType
);
sb
.
append
(
", accessMethod='"
).
append
(
accessMethod
).
append
(
'\''
);
sb
.
append
(
", accessMethod='"
).
append
(
accessMethod
).
append
(
'\''
);
...
...
baa-pay-core/src/main/java/cn/quant/baa/pay/acquirer/MerchantAcquirer.java
View file @
aae49d8f
package
cn
.
quant
.
baa
.
pay
.
acquirer
;
package
cn
.
quant
.
baa
.
pay
.
acquirer
;
import
cn.quant.baa.pay.jpa.entity.PayHistoryEntity
;
import
cn.quant.baa.pay.model.web.*
;
import
cn.quant.spring.NotSupportedException
;
import
cn.quant.spring.NotSupportedException
;
import
cn.quant.spring.security.Base64Cipher
;
import
cn.quant.spring.security.Base64Cipher
;
import
cn.quant.spring.security.CharacterCipher
;
import
cn.quant.spring.security.CharacterCipher
;
import
cn.quant.spring.util.RandomSequencer
;
import
cn.quant.spring.util.RandomSequencer
;
import
com.fasterxml.jackson.databind.JsonNode
;
import
javax.crypto.Cipher
;
import
javax.crypto.Cipher
;
import
javax.crypto.spec.GCMParameterSpec
;
import
javax.crypto.spec.GCMParameterSpec
;
...
@@ -62,17 +65,27 @@ public class MerchantAcquirer implements Acquirer {
...
@@ -62,17 +65,27 @@ public class MerchantAcquirer implements Acquirer {
}
}
@Override
@Override
public
void
pay
(
)
{
public
JsonNode
pay
(
PayRequestData
payRequestData
,
PayHistoryEntity
payHistoryEntity
)
{
throw
new
NotSupportedException
(
);
return
acquirers
.
get
(
payRequestData
.
getChanId
()).
pay
(
payRequestData
,
payHistoryEntity
);
}
}
@Override
@Override
public
void
refund
(
)
{
public
JsonNode
refund
(
RefundRequestData
refundRequestData
)
{
throw
new
NotSupportedException
(
);
return
acquirers
.
get
(
refundRequestData
.
getChanId
()).
refund
(
refundRequestData
);
}
}
@Override
@Override
public
void
check
()
{
public
JsonNode
checkPay
(
CheckPayRequestData
checkPayRequestData
)
{
throw
new
NotSupportedException
();
return
acquirers
.
get
(
checkPayRequestData
.
getChanId
()).
checkPay
(
checkPayRequestData
);
}
@Override
public
JsonNode
checkRefund
(
CheckRefundRequestData
checkRefundRequestData
)
{
return
acquirers
.
get
(
checkRefundRequestData
.
getChanId
()).
checkRefund
(
checkRefundRequestData
);
}
@Override
public
JsonNode
close
(
CloseRequestData
closeRequestData
)
{
return
acquirers
.
get
(
closeRequestData
.
getChanId
()).
close
(
closeRequestData
);
}
}
}
}
baa-pay-core/src/main/java/cn/quant/baa/pay/acquirer/alipay/AlipayMerchantAcquirer.java
0 → 100644
View file @
aae49d8f
package
cn
.
quant
.
baa
.
pay
.
acquirer
.
alipay
;
import
cn.quant.baa.pay.acquirer.AcquirerProperties
;
import
cn.quant.baa.pay.acquirer.MerchantAcquirer
;
import
cn.quant.baa.pay.jpa.entity.PayHistoryEntity
;
import
cn.quant.baa.pay.model.web.*
;
import
com.fasterxml.jackson.core.JsonProcessingException
;
import
com.fasterxml.jackson.core.type.TypeReference
;
import
com.fasterxml.jackson.databind.JsonNode
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.fasterxml.jackson.databind.node.ObjectNode
;
import
org.bouncycastle.jce.provider.BouncyCastleProvider
;
import
org.springframework.util.LinkedMultiValueMap
;
import
org.springframework.util.MultiValueMap
;
import
org.springframework.web.reactive.function.BodyInserters
;
import
org.springframework.web.reactive.function.client.ClientResponse
;
import
org.springframework.web.reactive.function.client.WebClient
;
import
org.springframework.web.util.UriUtils
;
import
reactor.core.publisher.Mono
;
import
java.io.ByteArrayInputStream
;
import
java.io.IOException
;
import
java.math.BigInteger
;
import
java.net.URI
;
import
java.security.*
;
import
java.security.cert.*
;
import
java.security.cert.Certificate
;
import
java.security.spec.InvalidKeySpecException
;
import
java.security.spec.PKCS8EncodedKeySpec
;
import
java.security.spec.X509EncodedKeySpec
;
import
java.text.DateFormat
;
import
java.text.SimpleDateFormat
;
import
java.util.*
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
/**
* Created by Administrator on 2021/8/31 0031.
*/
public
class
AlipayMerchantAcquirer
extends
MerchantAcquirer
{
private
WebClient
webClient
;
private
String
signType
=
"RSA2"
;
private
String
charset
=
"utf-8"
;
private
static
BouncyCastleProvider
provider
;
static
{
provider
=
new
BouncyCastleProvider
();
Security
.
addProvider
(
provider
);
}
/**
* 商户私钥
*/
PrivateKey
privateKey
;
/**
* 支付宝公钥
*/
X509Certificate
payPublicKey
;
/**
* 应用公钥
*/
X509Certificate
payCertKey
;
/**
* 支付宝根证书
*/
X509Certificate
[]
payRootCertKey
;
ObjectMapper
objectMapper
=
new
ObjectMapper
();
/**
* 支付初始化
* 1. 初始化私钥
* 2. 初始化平台证书
* 3. 初始化webClient
*
* @param properties
* @return
* @throws Exception
*/
@Override
public
MerchantAcquirer
init
(
AcquirerProperties
properties
)
throws
Exception
{
// super.init(properties);
this
.
properties
=
properties
;
privateKey
=
getPrivateKey
(
properties
.
getPrivateKey
());
payPublicKey
=
loadCertificate
(
properties
.
getPayPublicKey
());
payCertKey
=
loadCertificate
(
properties
.
getPayCertKey
());
payRootCertKey
=
loadCertificates
(
properties
.
getPayRootCertKey
());
this
.
webClient
=
WebClient
.
builder
()
.
baseUrl
(
properties
.
getDomain
())
.
defaultHeader
(
"Accept"
,
"application/json"
)
.
defaultHeader
(
"User-Agent"
,
"QuantGroup PayCenter Java Api"
)
.
defaultHeader
(
"Content-Type"
,
"application/x-www-form-urlencoded;charset="
+
charset
)
.
build
();
return
this
;
}
@Override
public
Object
code
()
{
return
this
.
properties
.
getMchChanId
().
toString
();
}
@Override
public
JsonNode
pay
(
PayRequestData
payRequestData
,
PayHistoryEntity
payHistoryEntity
)
{
ObjectNode
bodyNode
=
objectMapper
.
createObjectNode
();
bodyNode
.
put
(
"out_trade_no"
,
payRequestData
.
getOutTradeNo
());
bodyNode
.
put
(
"total_amount"
,
payRequestData
.
getAmount
());
bodyNode
.
put
(
"subject"
,
payRequestData
.
getSubject
());
bodyNode
.
put
(
"body"
,
payRequestData
.
getSubject
());
bodyNode
.
put
(
"product_code"
,
properties
.
getProductCode
());
switch
(
properties
.
getAccessCode
())
{
case
APP:
return
doAppExecute
(
bodyNode
);
case
H5:
case
WEB:
return
doWebExecute
(
bodyNode
);
default
:
}
return
doExecute
(
bodyNode
);
}
@Override
public
JsonNode
checkPay
(
CheckPayRequestData
checkPayRequestData
)
{
// String outTradeNo = "11111111218";
ObjectNode
bodyNode
=
objectMapper
.
createObjectNode
();
bodyNode
.
put
(
"out_trade_no"
,
checkPayRequestData
.
getOutTradeNo
());
return
doExecute
(
bodyNode
);
}
@Override
public
JsonNode
checkRefund
(
CheckRefundRequestData
checkRefundRequestData
)
{
ObjectNode
bodyNode
=
objectMapper
.
createObjectNode
();
bodyNode
.
put
(
"out_trade_no"
,
checkRefundRequestData
.
getOutTradeNo
());
bodyNode
.
put
(
"out_request_no"
,
checkRefundRequestData
.
getOutRefundNo
());
return
doExecute
(
bodyNode
);
}
@Override
public
JsonNode
close
(
CloseRequestData
closeRequestData
)
{
ObjectNode
bodyNode
=
objectMapper
.
createObjectNode
();
bodyNode
.
put
(
"out_trade_no"
,
closeRequestData
.
getOutTradeNo
());
return
doExecute
(
bodyNode
);
}
@Override
public
JsonNode
refund
(
RefundRequestData
refundRequestData
)
{
ObjectNode
bodyNode
=
objectMapper
.
createObjectNode
();
bodyNode
.
put
(
"out_trade_no"
,
refundRequestData
.
getOutTradeNo
());
bodyNode
.
put
(
"refund_amount"
,
refundRequestData
.
getRefundAmount
());
bodyNode
.
put
(
"refund_reason"
,
refundRequestData
.
getRefundReason
());
bodyNode
.
put
(
"out_request_no"
,
refundRequestData
.
getOutRefundNo
());
return
doExecute
(
bodyNode
);
}
/**
* App支付发起请求
*
* @param bodyNode
* @return
*/
private
JsonNode
doAppExecute
(
ObjectNode
bodyNode
)
{
ObjectNode
params
=
buildParams
(
bodyNode
);
TreeMap
<
String
,
String
>
sortedParams
=
getSortedMap
(
params
);
ObjectNode
body
=
objectMapper
.
createObjectNode
();
body
.
put
(
"data"
,
buildQuery
(
sortedParams
));
return
body
;
}
/**
* web支付发起请求
* alipay.trade.wap.pay
* alipay.trade.page.pay
*
* @param bodyNode
* @return
*/
private
JsonNode
doWebExecute
(
ObjectNode
bodyNode
)
{
ObjectNode
params
=
buildParams
(
bodyNode
);
TreeMap
<
String
,
String
>
sortedParams
=
getSortedMap
(
params
);
String
url
=
String
.
format
(
"%s%s?%s"
,
properties
.
getDomain
(),
properties
.
getPayAccess
(),
buildQuery
(
sortedParams
));
ObjectNode
body
=
objectMapper
.
createObjectNode
();
body
.
put
(
"data"
,
url
);
return
body
;
}
/**
* 发起请求
*
* @param bodyNode
* @return
*/
private
JsonNode
doExecute
(
ObjectNode
bodyNode
)
{
ObjectNode
params
=
buildParams
(
bodyNode
);
params
.
remove
(
"biz_content"
);
Map
<
String
,
String
>
sortedParams
=
objectMapper
.
convertValue
(
params
,
new
TypeReference
<
Map
<
String
,
String
>>(){});
URI
uri
=
URI
.
create
(
String
.
format
(
"%s%s?%s"
,
properties
.
getDomain
(),
properties
.
getPayAccess
(),
buildQuery
(
sortedParams
)));
MultiValueMap
<
String
,
String
>
formData
=
new
LinkedMultiValueMap
<>();
try
{
formData
.
add
(
"biz_content"
,
objectMapper
.
writeValueAsString
(
bodyNode
));
}
catch
(
JsonProcessingException
e
)
{
e
.
printStackTrace
();
}
Mono
<
ClientResponse
>
mono
=
webClient
.
post
()
.
uri
(
uri
)
.
body
(
BodyInserters
.
fromFormData
(
formData
))
.
exchange
();
ClientResponse
response
=
mono
.
block
();
JsonNode
bodyJsonNode
=
objectMapper
.
createObjectNode
();
if
(
response
!=
null
)
{
Mono
<
String
>
resultMono
=
response
.
bodyToMono
(
String
.
class
);
String
bodyRes
=
resultMono
.
block
();
Pattern
pattern
=
Pattern
.
compile
(
"[a-zA-Z_0-9]*_response"
);
//处理支付宝不同的返回格式,统一为response
Matcher
matcher
=
pattern
.
matcher
(
bodyRes
);
String
body
=
matcher
.
replaceAll
(
"response"
);
try
{
bodyJsonNode
=
objectMapper
.
readTree
(
body
);
}
catch
(
JsonProcessingException
e
)
{
e
.
printStackTrace
();
}
if
(
response
.
statusCode
().
value
()
>=
200
&&
response
.
statusCode
().
value
()
<
300
)
{
//支付宝公钥号
String
certSN
=
bodyJsonNode
.
get
(
"alipay_cert_sn"
).
asText
();
if
(!
getPublicKeyCertSN
().
equals
(
certSN
))
{
// TODO: 证书可能过期了,需要处理支付宝公钥过期的情况
throw
new
RuntimeException
(
"支付宝公钥过期"
);
}
//支付宝签名
String
signature
=
bodyJsonNode
.
get
(
"sign"
).
asText
();
//签名信息
//这里的斜杠替换是因为json解析之后自动去掉了转义符/,签名的时候需要再给加上
String
signText
=
bodyJsonNode
.
get
(
"response"
).
toString
().
replace
(
"/"
,
"\\/"
);
if
(
verify
(
signText
,
signature
))
{
return
bodyJsonNode
;
}
// TODO: 签名校验失败,做异常处理
throw
new
RuntimeException
(
"签名校验失败"
);
}
else
{
// TODO: 返回异常,做异常处理
throw
new
RuntimeException
(
"返回异常,做异常处理"
);
}
}
return
bodyJsonNode
;
}
public
ObjectNode
buildParams
(
ObjectNode
bizContent
)
{
ObjectNode
paramNode
=
objectMapper
.
createObjectNode
();
paramNode
.
put
(
"method"
,
properties
.
getAccessMethod
());
// paramNode.put("method", "alipay.trade.query");
paramNode
.
put
(
"version"
,
properties
.
getVersion
());
paramNode
.
put
(
"app_id"
,
properties
.
getPayAcctId
());
paramNode
.
put
(
"sign_type"
,
signType
);
paramNode
.
put
(
"notify_url"
,
bizContent
.
get
(
"notify_url"
));
paramNode
.
put
(
"return_url"
,
bizContent
.
get
(
"return_url"
));
paramNode
.
put
(
"charset"
,
charset
);
paramNode
.
put
(
"app_cert_sn"
,
properties
.
getPayCertNo
());
paramNode
.
put
(
"alipay_root_cert_sn"
,
properties
.
getPayRootCertNo
());
bizContent
.
remove
(
"notify_url"
);
bizContent
.
remove
(
"return_url"
);
Long
timestamp
=
System
.
currentTimeMillis
();
DateFormat
df
=
new
SimpleDateFormat
(
"yyyy-MM-dd HH:mm:ss"
);
df
.
setTimeZone
(
TimeZone
.
getTimeZone
(
"GMT+8"
));
paramNode
.
put
(
"timestamp"
,
df
.
format
(
new
Date
(
timestamp
)));
paramNode
.
put
(
"format"
,
"json"
);
// paramNode.put("auth_token", "");
try
{
paramNode
.
put
(
"biz_content"
,
objectMapper
.
writeValueAsString
(
bizContent
));
}
catch
(
JsonProcessingException
e
)
{
e
.
printStackTrace
();
}
TreeMap
<
String
,
String
>
sortedParams
=
getSortedMap
(
paramNode
);
String
signContent
=
getSignContent
(
sortedParams
);
paramNode
.
put
(
"sign"
,
sign
(
signContent
));
return
paramNode
;
}
public
String
buildQuery
(
Map
<
String
,
String
>
params
)
{
if
(
params
==
null
||
params
.
isEmpty
())
{
return
null
;
}
StringBuilder
query
=
new
StringBuilder
();
Set
<
Map
.
Entry
<
String
,
String
>>
entries
=
params
.
entrySet
();
boolean
hasParam
=
false
;
for
(
Map
.
Entry
<
String
,
String
>
entry
:
entries
)
{
String
name
=
entry
.
getKey
();
String
value
=
entry
.
getValue
();
// 忽略参数名或参数值为空的参数
if
(
areNotEmpty
(
name
,
value
))
{
if
(
hasParam
)
{
query
.
append
(
"&"
);
}
else
{
hasParam
=
true
;
}
query
.
append
(
name
).
append
(
"="
).
append
(
UriUtils
.
encode
(
value
,
charset
));
}
}
return
query
.
toString
();
}
public
TreeMap
<
String
,
String
>
getSortedMap
(
ObjectNode
paramNode
)
{
return
objectMapper
.
convertValue
(
paramNode
,
new
TypeReference
<
TreeMap
<
String
,
String
>>(){});
}
/**
* @param sortedParams
* @return
*/
public
String
getSignContent
(
TreeMap
<
String
,
String
>
sortedParams
)
{
StringBuilder
content
=
new
StringBuilder
();
List
<
String
>
keys
=
new
ArrayList
<
String
>(
sortedParams
.
keySet
());
Collections
.
sort
(
keys
);
int
index
=
0
;
for
(
String
key
:
keys
)
{
String
value
=
sortedParams
.
get
(
key
);
if
(
areNotEmpty
(
key
,
value
))
{
content
.
append
(
index
==
0
?
""
:
"&"
).
append
(
key
).
append
(
"="
).
append
(
value
);
index
++;
}
}
return
content
.
toString
();
}
/**
* 检查指定的字符串是否为空。
* <ul>
* <li>SysUtils.isEmpty(null) = true</li>
* <li>SysUtils.isEmpty("") = true</li>
* <li>SysUtils.isEmpty(" ") = true</li>
* <li>SysUtils.isEmpty("abc") = false</li>
* </ul>
*
* @param value 待检查的字符串
* @return true/false
*/
public
static
boolean
isEmpty
(
String
value
)
{
int
strLen
;
if
(
value
==
null
||
(
strLen
=
value
.
length
())
==
0
)
{
return
true
;
}
for
(
int
i
=
0
;
i
<
strLen
;
i
++)
{
if
((
Character
.
isWhitespace
(
value
.
charAt
(
i
))
==
false
))
{
return
false
;
}
}
return
true
;
}
/**
* 检查指定的字符串列表是否不为空。
*/
public
static
boolean
areNotEmpty
(
String
...
values
)
{
boolean
result
=
true
;
if
(
values
==
null
||
values
.
length
==
0
)
{
result
=
false
;
}
else
{
for
(
String
value
:
values
)
{
result
&=
!
isEmpty
(
value
);
}
}
return
result
;
}
/**
* 签名
*
* @param signText 需要签名的字符串
* @return
*/
public
String
sign
(
String
signText
)
{
try
{
Signature
sign
=
Signature
.
getInstance
(
properties
.
getSignType
());
sign
.
initSign
(
this
.
privateKey
);
sign
.
update
(
signText
.
getBytes
());
return
Base64
.
getEncoder
().
encodeToString
(
sign
.
sign
());
}
catch
(
NoSuchAlgorithmException
e
)
{
throw
new
RuntimeException
(
"当前Java环境不支持SHA256withRSA"
,
e
);
}
catch
(
SignatureException
e
)
{
throw
new
RuntimeException
(
"签名计算失败"
,
e
);
}
catch
(
InvalidKeyException
e
)
{
throw
new
RuntimeException
(
"无效的私钥"
,
e
);
}
}
/**
* 获取证书。
*
* @param certString 证书内容
* @return X509证书
*/
public
X509Certificate
[]
loadCertificates
(
String
certString
)
{
try
{
ByteArrayInputStream
fis
=
new
ByteArrayInputStream
(
certString
.
getBytes
());
CertificateFactory
cf
=
CertificateFactory
.
getInstance
(
"X509"
,
provider
);
Collection
<?
extends
Certificate
>
certs
=
cf
.
generateCertificates
(
fis
);
return
(
X509Certificate
[])
certs
.
toArray
(
new
X509Certificate
[
certs
.
size
()]);
}
catch
(
CertificateExpiredException
var3
)
{
throw
new
RuntimeException
(
"证书已过期"
,
var3
);
}
catch
(
CertificateNotYetValidException
var4
)
{
throw
new
RuntimeException
(
"证书尚未生效"
,
var4
);
}
catch
(
CertificateException
var5
)
{
throw
new
RuntimeException
(
"无效的证书"
,
var5
);
}
}
/**
* 获取证书。
*
* @param certString 证书内容
* @return X509证书
*/
public
X509Certificate
loadCertificate
(
String
certString
)
{
try
{
ByteArrayInputStream
fis
=
new
ByteArrayInputStream
(
certString
.
getBytes
());
CertificateFactory
cf
=
CertificateFactory
.
getInstance
(
"X509"
);
X509Certificate
cert
=
(
X509Certificate
)
cf
.
generateCertificate
(
fis
);
cert
.
checkValidity
();
return
cert
;
}
catch
(
CertificateExpiredException
var3
)
{
throw
new
RuntimeException
(
"证书已过期"
,
var3
);
}
catch
(
CertificateNotYetValidException
var4
)
{
throw
new
RuntimeException
(
"证书尚未生效"
,
var4
);
}
catch
(
CertificateException
var5
)
{
throw
new
RuntimeException
(
"无效的证书"
,
var5
);
}
}
/**
* RSA验签名检查
*
* @param content 待签名数据
* @param signature 签名值
* @return 布尔值
*/
public
boolean
verify
(
String
content
,
String
signature
)
{
try
{
Signature
sign
=
Signature
.
getInstance
(
properties
.
getSignType
());
sign
.
initVerify
(
payPublicKey
);
sign
.
update
(
content
.
getBytes
());
return
sign
.
verify
(
Base64
.
getDecoder
().
decode
(
signature
));
}
catch
(
NoSuchAlgorithmException
e
)
{
throw
new
RuntimeException
(
"当前Java环境不支持SHA256withRSA"
,
e
);
}
catch
(
SignatureException
e
)
{
throw
new
RuntimeException
(
"签名验证过程发生了错误"
,
e
);
}
catch
(
InvalidKeyException
e
)
{
throw
new
RuntimeException
(
"无效的证书"
,
e
);
}
}
/**
* 获取私钥。
*
* @param certString 私钥文件内容(required)
* @return 私钥对象
*/
public
PrivateKey
getPrivateKey
(
String
certString
)
{
try
{
String
privateKey
=
certString
.
replace
(
"-----BEGIN PRIVATE KEY-----"
,
""
)
.
replace
(
"-----END PRIVATE KEY-----"
,
""
)
.
replaceAll
(
"\\s+"
,
""
);
KeyFactory
kf
=
KeyFactory
.
getInstance
(
"RSA"
);
return
kf
.
generatePrivate
(
new
PKCS8EncodedKeySpec
(
Base64
.
getDecoder
().
decode
(
privateKey
)));
}
catch
(
NoSuchAlgorithmException
e
)
{
throw
new
RuntimeException
(
"当前Java环境不支持RSA"
,
e
);
}
catch
(
InvalidKeySpecException
e
)
{
throw
new
RuntimeException
(
"无效的密钥格式"
);
}
}
/**
* 获取公钥。
*
* @param certString 公钥文件内容(required)
* @return 私钥对象
*/
public
static
PublicKey
getPublicKey
(
String
certString
)
throws
IOException
{
try
{
String
publicKey
=
certString
.
replace
(
"-----BEGIN PUBLIC KEY-----"
,
""
)
.
replace
(
"-----END PUBLIC KEY-----"
,
""
)
.
replaceAll
(
"\\s+"
,
""
);
KeyFactory
kf
=
KeyFactory
.
getInstance
(
"RSA"
);
return
kf
.
generatePublic
(
new
X509EncodedKeySpec
(
Base64
.
getDecoder
().
decode
(
publicKey
)));
}
catch
(
NoSuchAlgorithmException
e
)
{
throw
new
RuntimeException
(
"当前Java环境不支持RSA"
,
e
);
}
catch
(
InvalidKeySpecException
e
)
{
throw
new
RuntimeException
(
"无效的密钥格式"
);
}
}
/**
* 获取支付宝私钥证书号
* @return
*/
public
String
getPublicKeyCertSN
()
{
try
{
MessageDigest
md
=
MessageDigest
.
getInstance
(
"MD5"
);
md
.
update
((
payPublicKey
.
getIssuerX500Principal
().
getName
()
+
payPublicKey
.
getSerialNumber
()).
getBytes
());
String
certSN
=
new
BigInteger
(
1
,
md
.
digest
()).
toString
(
16
);
//BigInteger会把0省略掉,需补全至32位
certSN
=
fillMD5
(
certSN
);
return
certSN
;
}
catch
(
NoSuchAlgorithmException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
private
String
fillMD5
(
String
md5
)
{
return
md5
.
length
()
==
32
?
md5
:
fillMD5
(
"0"
+
md5
);
}
}
\ No newline at end of file
baa-pay-core/src/main/java/cn/quant/baa/pay/acquirer/weixin/WeiXinMerchantAcquirer.java
View file @
aae49d8f
...
@@ -2,15 +2,81 @@ package cn.quant.baa.pay.acquirer.weixin;
...
@@ -2,15 +2,81 @@ package cn.quant.baa.pay.acquirer.weixin;
import
cn.quant.baa.pay.acquirer.AcquirerProperties
;
import
cn.quant.baa.pay.acquirer.AcquirerProperties
;
import
cn.quant.baa.pay.acquirer.MerchantAcquirer
;
import
cn.quant.baa.pay.acquirer.MerchantAcquirer
;
import
cn.quant.baa.pay.jpa.entity.PayHistoryEntity
;
import
cn.quant.baa.pay.model.web.*
;
import
com.fasterxml.jackson.core.JsonProcessingException
;
import
com.fasterxml.jackson.databind.JsonNode
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.fasterxml.jackson.databind.node.ObjectNode
;
import
org.springframework.http.HttpMethod
;
import
org.springframework.http.MediaType
;
import
org.springframework.web.reactive.function.client.ClientResponse
;
import
org.springframework.web.reactive.function.client.WebClient
;
import
org.springframework.web.util.UriComponentsBuilder
;
import
reactor.core.publisher.Mono
;
import
java.io.ByteArrayInputStream
;
import
java.io.IOException
;
import
java.math.BigDecimal
;
import
java.math.BigInteger
;
import
java.security.*
;
import
java.security.cert.*
;
import
java.security.spec.InvalidKeySpecException
;
import
java.security.spec.PKCS8EncodedKeySpec
;
import
java.security.spec.X509EncodedKeySpec
;
import
java.util.*
;
/**
/**
* Created by Administrator on 2021/8/31 0031.
* Created by Administrator on 2021/8/31 0031.
*/
*/
public
class
WeiXinMerchantAcquirer
extends
MerchantAcquirer
{
public
class
WeiXinMerchantAcquirer
extends
MerchantAcquirer
{
private
WebClient
webClient
;
/**
* 微信签名格式定义
*/
String
TOKEN_PATTERN
=
"mchid=\"%s\",nonce_str=\"%s\",timestamp=\"%d\",serial_no=\"%s\",signature=\"%s\""
;
/**
* 微信签名前缀
*/
String
SCHEMA
=
"WECHATPAY2-SHA256-RSA2048 "
;
/**
* 商户私钥
*/
PrivateKey
privateKey
;
/**
* 平台证书
*/
X509Certificate
payCerKey
;
ObjectMapper
objectMapper
=
new
ObjectMapper
();
/**
* 支付初始化
* 1. 初始化私钥
* 2. 初始化平台证书
* 3. 初始化webClient
*
* @param properties
* @return
* @throws Exception
*/
@Override
@Override
public
MerchantAcquirer
init
(
AcquirerProperties
properties
)
throws
Exception
{
public
MerchantAcquirer
init
(
AcquirerProperties
properties
)
throws
Exception
{
super
.
init
(
properties
);
super
.
init
(
properties
);
privateKey
=
getPrivateKey
(
properties
.
getPrivateKey
());
payCerKey
=
loadCertificate
(
properties
.
getPayCertKey
());
this
.
webClient
=
WebClient
.
builder
().
baseUrl
(
properties
.
getDomain
())
.
defaultHeader
(
"Accept"
,
"application/json"
)
.
defaultHeader
(
"User-Agent"
,
"QuantGroup PayCenter Java Api"
)
.
build
();
return
this
;
return
this
;
}
}
...
@@ -18,4 +84,283 @@ public class WeiXinMerchantAcquirer extends MerchantAcquirer {
...
@@ -18,4 +84,283 @@ public class WeiXinMerchantAcquirer extends MerchantAcquirer {
public
Object
code
()
{
public
Object
code
()
{
return
this
.
properties
.
getMchChanId
().
toString
();
return
this
.
properties
.
getMchChanId
().
toString
();
}
}
}
@Override
public
JsonNode
pay
(
PayRequestData
payRequestData
,
PayHistoryEntity
payHistoryEntity
)
{
ObjectNode
bodyNode
=
objectMapper
.
createObjectNode
();
// 转换金额为分
BigInteger
amount
=
new
BigDecimal
(
payRequestData
.
getAmount
()).
multiply
(
new
BigDecimal
(
100
)).
toBigInteger
();
bodyNode
.
put
(
"mchid"
,
properties
.
getPayAcctId
())
.
put
(
"appid"
,
properties
.
getPayAppId
())
.
put
(
"attach"
,
payRequestData
.
getAttach
())
.
put
(
"description"
,
payRequestData
.
getSubject
())
.
put
(
"notify_url"
,
payRequestData
.
getNotifyUrl
())
.
put
(
"out_trade_no"
,
payRequestData
.
getOutTradeNo
());
bodyNode
.
putObject
(
"amount"
)
.
put
(
"total"
,
amount
);
ObjectNode
sceneInfo
=
objectMapper
.
createObjectNode
()
.
put
(
"payer_client_ip"
,
"127.0.0.1"
);
switch
(
properties
.
getAccessCode
())
{
case
H5:
sceneInfo
.
putObject
(
"h5_info"
).
put
(
"type"
,
"Wap"
);
break
;
case
JS:
bodyNode
.
putObject
(
"payer"
)
.
put
(
"openid"
,
"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"
);
break
;
case
APP:
default
:
}
bodyNode
.
set
(
"scene_info"
,
sceneInfo
);
String
payAccess
=
properties
.
getPayAccess
();
return
doExecute
(
payAccess
,
bodyNode
);
}
@Override
public
JsonNode
checkPay
(
CheckPayRequestData
checkPayRequestData
)
{
ObjectNode
bodyNode
=
objectMapper
.
createObjectNode
();
bodyNode
.
put
(
"mchid"
,
properties
.
getPayAcctId
());
String
payAccess
=
properties
.
getPayAccess
().
replace
(
"{out_trade_no}"
,
checkPayRequestData
.
getOutTradeNo
());
return
doExecute
(
payAccess
,
bodyNode
);
}
@Override
public
JsonNode
checkRefund
(
CheckRefundRequestData
checkRefundRequestData
)
{
String
payAccess
=
properties
.
getPayAccess
().
replace
(
"{out_refund_no}"
,
checkRefundRequestData
.
getOutRefundNo
());
return
doExecute
(
payAccess
,
null
);
}
@Override
public
JsonNode
close
(
CloseRequestData
closeRequestData
)
{
ObjectNode
bodyNode
=
objectMapper
.
createObjectNode
();
bodyNode
.
put
(
"mchid"
,
properties
.
getPayAcctId
());
String
payAccess
=
properties
.
getPayAccess
().
replace
(
"{out_trade_no}"
,
closeRequestData
.
getOutTradeNo
());
return
doExecute
(
payAccess
,
bodyNode
);
}
@Override
public
JsonNode
refund
(
RefundRequestData
refundRequestData
)
{
// 转换金额为分
BigInteger
amount
=
new
BigDecimal
(
refundRequestData
.
getRefundAmount
()).
multiply
(
new
BigDecimal
(
100
)).
toBigInteger
();
ObjectNode
bodyNode
=
objectMapper
.
createObjectNode
();
bodyNode
.
put
(
"out_trade_no"
,
refundRequestData
.
getOutTradeNo
());
bodyNode
.
put
(
"out_refund_no"
,
refundRequestData
.
getOutRefundNo
());
bodyNode
.
put
(
"reason"
,
refundRequestData
.
getRefundReason
());
// bodyNode.put("notify_url", "");
bodyNode
.
putObject
(
"amount"
)
.
put
(
"refund"
,
amount
)
.
put
(
"total"
,
amount
)
.
put
(
"currency"
,
"CNY"
);
String
payAccess
=
properties
.
getPayAccess
();
return
doExecute
(
payAccess
,
bodyNode
);
}
/**
*
* @param payAccess
* @param bodyNode
* @return
*/
private
JsonNode
doExecute
(
String
payAccess
,
ObjectNode
bodyNode
)
{
String
method
=
properties
.
getAccessMethod
();
UriComponentsBuilder
uriComponentsBuilder
=
UriComponentsBuilder
.
fromUriString
(
payAccess
);
String
requestBody
=
""
;
// 处理GET请求
if
(
HttpMethod
.
GET
.
name
().
equals
(
method
))
{
if
(
null
!=
bodyNode
)
{
bodyNode
.
fields
().
forEachRemaining
((
entry
)
->
{
uriComponentsBuilder
.
queryParam
(
entry
.
getKey
(),
entry
.
getValue
().
asText
());
});
}
}
else
{
// 非GET请求的时候处理requestBody
try
{
if
(
null
!=
bodyNode
)
{
requestBody
=
objectMapper
.
writeValueAsString
(
bodyNode
);
}
}
catch
(
JsonProcessingException
e
)
{
e
.
printStackTrace
();
}
}
String
uri
=
uriComponentsBuilder
.
build
().
toString
();
long
timestamp
=
System
.
currentTimeMillis
()
/
1000
;
String
nonceStr
=
UUID
.
randomUUID
().
toString
().
replace
(
"-"
,
""
);
// 代签名字符串
String
signText
=
joining
(
"\n"
,
method
,
uri
,
String
.
valueOf
(
timestamp
),
nonceStr
,
requestBody
);
String
sign
=
sign
(
signText
);
String
token
=
String
.
format
(
TOKEN_PATTERN
,
properties
.
getPayAcctId
(),
nonceStr
,
timestamp
,
properties
.
getPayCertNo
(),
sign
);
Mono
<
ClientResponse
>
mono
=
webClient
.
method
(
HttpMethod
.
resolve
(
method
))
.
uri
(
uri
)
.
header
(
"Authorization"
,
SCHEMA
.
concat
(
token
))
.
contentType
(
MediaType
.
APPLICATION_JSON
)
.
bodyValue
(
requestBody
)
.
exchange
();
ClientResponse
response
=
mono
.
block
();
JsonNode
bodyJsonNode
=
objectMapper
.
createObjectNode
();
if
(
response
!=
null
)
{
Mono
<
String
>
resultMono
=
response
.
bodyToMono
(
String
.
class
);
String
body
=
resultMono
.
block
();
if
(
null
==
body
)
{
body
=
""
;
}
try
{
bodyJsonNode
=
objectMapper
.
readTree
(
body
);
}
catch
(
JsonProcessingException
e
)
{
e
.
printStackTrace
();
}
if
(
response
.
statusCode
().
value
()
>=
200
&&
response
.
statusCode
().
value
()
<
300
)
{
//Request-ID
String
requestId
=
response
.
headers
().
asHttpHeaders
().
getFirst
(
"Request-ID"
);
//当前使用的微信平台证书序列号
String
serial
=
response
.
headers
().
asHttpHeaders
().
getFirst
(
"Wechatpay-Serial"
);
//微信服务器的时间戳
String
wxTimestamp
=
response
.
headers
().
asHttpHeaders
().
getFirst
(
"Wechatpay-Timestamp"
);
//微信服务器提供的随机串
String
nonce
=
response
.
headers
().
asHttpHeaders
().
getFirst
(
"Wechatpay-Nonce"
);
//微信平台签名
String
signature
=
response
.
headers
().
asHttpHeaders
().
getFirst
(
"Wechatpay-Signature"
);
//签名信息
String
wsSignText
=
joining
(
"\n"
,
wxTimestamp
,
nonce
,
body
);
if
(
verify
(
wsSignText
,
signature
))
{
return
bodyJsonNode
;
}
// TODO: 签名校验失败,做异常处理
throw
new
RuntimeException
(
"签名校验失败"
);
}
else
{
return
bodyJsonNode
;
// TODO: 返回异常,做异常处理
// throw new RuntimeException("返回异常,做异常处理");
}
}
return
bodyJsonNode
;
}
/**
* 签名
*
* @param signText 需要签名的字符串
* @return
*/
public
String
sign
(
String
signText
)
{
try
{
Signature
sign
=
Signature
.
getInstance
(
properties
.
getSignType
());
sign
.
initSign
(
this
.
privateKey
);
sign
.
update
(
signText
.
getBytes
());
return
Base64
.
getEncoder
().
encodeToString
(
sign
.
sign
());
}
catch
(
NoSuchAlgorithmException
e
)
{
throw
new
RuntimeException
(
"当前Java环境不支持SHA256withRSA"
,
e
);
}
catch
(
SignatureException
e
)
{
throw
new
RuntimeException
(
"签名计算失败"
,
e
);
}
catch
(
InvalidKeyException
e
)
{
throw
new
RuntimeException
(
"无效的私钥"
,
e
);
}
}
/**
* 获取证书。
*
* @param certString 证书内容
* @return X509证书
*/
public
X509Certificate
loadCertificate
(
String
certString
)
{
try
{
ByteArrayInputStream
fis
=
new
ByteArrayInputStream
(
certString
.
getBytes
());
CertificateFactory
cf
=
CertificateFactory
.
getInstance
(
"X509"
);
X509Certificate
cert
=
(
X509Certificate
)
cf
.
generateCertificate
(
fis
);
cert
.
checkValidity
();
return
cert
;
}
catch
(
CertificateExpiredException
var3
)
{
throw
new
RuntimeException
(
"证书已过期"
,
var3
);
}
catch
(
CertificateNotYetValidException
var4
)
{
throw
new
RuntimeException
(
"证书尚未生效"
,
var4
);
}
catch
(
CertificateException
var5
)
{
throw
new
RuntimeException
(
"无效的证书"
,
var5
);
}
}
/**
* RSA验签名检查
*
* @param content 待签名数据
* @param signature 签名值
* @return 布尔值
*/
public
boolean
verify
(
String
content
,
String
signature
)
{
try
{
Signature
sign
=
Signature
.
getInstance
(
properties
.
getSignType
());
sign
.
initVerify
(
payCerKey
);
sign
.
update
(
content
.
getBytes
());
return
sign
.
verify
(
Base64
.
getDecoder
().
decode
(
signature
));
}
catch
(
NoSuchAlgorithmException
e
)
{
throw
new
RuntimeException
(
"当前Java环境不支持SHA256withRSA"
,
e
);
}
catch
(
SignatureException
e
)
{
throw
new
RuntimeException
(
"签名验证过程发生了错误"
,
e
);
}
catch
(
InvalidKeyException
e
)
{
throw
new
RuntimeException
(
"无效的证书"
,
e
);
}
}
/**
* 获取私钥。
*
* @param certString 私钥文件内容(required)
* @return 私钥对象
*/
public
PrivateKey
getPrivateKey
(
String
certString
)
{
try
{
String
privateKey
=
certString
.
replace
(
"-----BEGIN PRIVATE KEY-----"
,
""
)
.
replace
(
"-----END PRIVATE KEY-----"
,
""
)
.
replaceAll
(
"\\s+"
,
""
);
KeyFactory
kf
=
KeyFactory
.
getInstance
(
"RSA"
);
return
kf
.
generatePrivate
(
new
PKCS8EncodedKeySpec
(
Base64
.
getDecoder
().
decode
(
privateKey
)));
}
catch
(
NoSuchAlgorithmException
e
)
{
throw
new
RuntimeException
(
"当前Java环境不支持RSA"
,
e
);
}
catch
(
InvalidKeySpecException
e
)
{
throw
new
RuntimeException
(
"无效的密钥格式"
);
}
}
/**
* 获取公钥。
*
* @param certString 公钥文件内容(required)
* @return 私钥对象
*/
public
static
PublicKey
getPublicKey
(
String
certString
)
throws
IOException
{
try
{
String
publicKey
=
certString
.
replace
(
"-----BEGIN PUBLIC KEY-----"
,
""
)
.
replace
(
"-----END PUBLIC KEY-----"
,
""
)
.
replaceAll
(
"\\s+"
,
""
);
KeyFactory
kf
=
KeyFactory
.
getInstance
(
"RSA"
);
return
kf
.
generatePublic
(
new
X509EncodedKeySpec
(
Base64
.
getDecoder
().
decode
(
publicKey
)));
}
catch
(
NoSuchAlgorithmException
e
)
{
throw
new
RuntimeException
(
"当前Java环境不支持RSA"
,
e
);
}
catch
(
InvalidKeySpecException
e
)
{
throw
new
RuntimeException
(
"无效的密钥格式"
);
}
}
/**
* 字符串数组拼接为字符串
*
* @param separator 分隔符
* @param str 字符数组
* @return 字符串
*/
public
String
joining
(
String
separator
,
String
...
str
)
{
StringBuilder
builder
=
new
StringBuilder
();
for
(
String
s
:
str
)
{
builder
.
append
(
s
).
append
(
separator
);
}
return
builder
.
toString
();
}
}
\ No newline at end of file
baa-pay-core/src/main/java/cn/quant/baa/pay/config/ServerConfiguration.java
View file @
aae49d8f
...
@@ -4,6 +4,7 @@ import cn.quant.baa.pay.acquirer.AcquirerConfiguration;
...
@@ -4,6 +4,7 @@ import cn.quant.baa.pay.acquirer.AcquirerConfiguration;
import
cn.quant.baa.pay.acquirer.AcquirerConfigurer
;
import
cn.quant.baa.pay.acquirer.AcquirerConfigurer
;
import
cn.quant.baa.pay.acquirer.AcquirerProperties
;
import
cn.quant.baa.pay.acquirer.AcquirerProperties
;
import
cn.quant.baa.pay.acquirer.MerchantAcquirer
;
import
cn.quant.baa.pay.acquirer.MerchantAcquirer
;
import
cn.quant.baa.pay.acquirer.alipay.AlipayMerchantAcquirer
;
import
cn.quant.baa.pay.acquirer.weixin.WeiXinMerchantAcquirer
;
import
cn.quant.baa.pay.acquirer.weixin.WeiXinMerchantAcquirer
;
import
cn.quant.baa.pay.jpa.entity.*
;
import
cn.quant.baa.pay.jpa.entity.*
;
import
cn.quant.baa.pay.jpa.repository.*
;
import
cn.quant.baa.pay.jpa.repository.*
;
...
@@ -12,10 +13,6 @@ import org.springframework.beans.factory.annotation.Autowired;
...
@@ -12,10 +13,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Configuration
;
import
javax.crypto.NoSuchPaddingException
;
import
java.security.InvalidAlgorithmParameterException
;
import
java.security.InvalidKeyException
;
import
java.security.NoSuchAlgorithmException
;
import
java.util.Collection
;
import
java.util.Collection
;
import
java.util.List
;
import
java.util.List
;
...
@@ -90,6 +87,10 @@ public class ServerConfiguration {
...
@@ -90,6 +87,10 @@ public class ServerConfiguration {
WeiXinMerchantAcquirer
acquirer
=
new
WeiXinMerchantAcquirer
();
WeiXinMerchantAcquirer
acquirer
=
new
WeiXinMerchantAcquirer
();
acquirer
.
init
(
property
);
acquirer
.
init
(
property
);
merchantAcquirer
.
register
(
acquirer
);
merchantAcquirer
.
register
(
acquirer
);
}
else
if
(
"ALIP"
.
equals
(
property
.
getPayChanCode
()))
{
AlipayMerchantAcquirer
acquirer
=
new
AlipayMerchantAcquirer
();
acquirer
.
init
(
property
);
merchantAcquirer
.
register
(
acquirer
);
}
}
}
}
return
merchantAcquirer
;
return
merchantAcquirer
;
...
...
baa-pay-core/src/main/java/cn/quant/baa/pay/dict/AccessCode.java
View file @
aae49d8f
...
@@ -5,6 +5,11 @@ package cn.quant.baa.pay.dict;
...
@@ -5,6 +5,11 @@ package cn.quant.baa.pay.dict;
*/
*/
public
enum
AccessCode
{
public
enum
AccessCode
{
REFUND
(
"退款"
),
CHKRFD
(
"退款查询"
),
CHKPAY
(
"支付查询"
),
CLOSE
(
"关闭订单"
),
WEB
(
"电脑网站支付"
),
APP
(
"应用支付"
),
APP
(
"应用支付"
),
H5
(
"H5页支付"
),
H5
(
"H5页支付"
),
JS
(
"网页、小程序支付"
);
JS
(
"网页、小程序支付"
);
...
...
baa-pay-core/src/main/java/cn/quant/baa/pay/jpa/entity/PayAccountEntity.java
View file @
aae49d8f
...
@@ -44,13 +44,18 @@ public class PayAccountEntity extends OptimisticEntity implements Serializable {
...
@@ -44,13 +44,18 @@ public class PayAccountEntity extends OptimisticEntity implements Serializable {
@Column
(
name
=
"PAY_PUBLIC_KEY"
,
nullable
=
false
,
length
=
255
)
@Column
(
name
=
"PAY_PUBLIC_KEY"
,
nullable
=
false
,
length
=
255
)
private
String
payPublicKey
;
private
String
payPublicKey
;
@Column
(
name
=
"PAY_CERT_NO"
,
nullable
=
true
,
length
=
64
)
@Column
(
name
=
"PAY_CERT_NO"
,
nullable
=
true
,
length
=
64
)
private
String
payCertNo
;
private
String
payCertNo
;
@Column
(
name
=
"PAY_CERT_KEY"
,
nullable
=
true
,
length
=
2000
)
@Column
(
name
=
"PAY_CERT_KEY"
,
nullable
=
true
,
length
=
2000
)
private
String
payCertKey
;
private
String
payCertKey
;
@Column
(
name
=
"PAY_ROOT_CERT_NO"
,
nullable
=
true
,
length
=
64
)
private
String
payRootCertNo
;
@Column
(
name
=
"PAY_ROOT_CERT_KEY"
,
nullable
=
true
,
length
=
4000
)
private
String
payRootCertKey
;
public
PayAccountIds
getIds
()
{
public
PayAccountIds
getIds
()
{
return
ids
;
return
ids
;
}
}
...
@@ -139,6 +144,22 @@ public class PayAccountEntity extends OptimisticEntity implements Serializable {
...
@@ -139,6 +144,22 @@ public class PayAccountEntity extends OptimisticEntity implements Serializable {
this
.
payCertKey
=
payCertKey
;
this
.
payCertKey
=
payCertKey
;
}
}
public
String
getPayRootCertNo
()
{
return
payRootCertNo
;
}
public
void
setPayRootCertNo
(
String
payRootCertNo
)
{
this
.
payRootCertNo
=
payRootCertNo
;
}
public
String
getPayRootCertKey
()
{
return
payRootCertKey
;
}
public
void
setPayRootCertKey
(
String
payRootCertKey
)
{
this
.
payRootCertKey
=
payRootCertKey
;
}
@Override
@Override
public
String
persistenceKey
()
{
public
String
persistenceKey
()
{
return
ids
.
persistenceKey
();
return
ids
.
persistenceKey
();
...
...
baa-pay-core/src/main/java/cn/quant/baa/pay/jpa/entity/PayFeatureEntity.java
View file @
aae49d8f
...
@@ -32,6 +32,9 @@ public class PayFeatureEntity extends DescriptionEntity implements Serializable
...
@@ -32,6 +32,9 @@ public class PayFeatureEntity extends DescriptionEntity implements Serializable
@Column
(
name
=
"PAY_ACCESS"
,
nullable
=
false
,
length
=
255
)
@Column
(
name
=
"PAY_ACCESS"
,
nullable
=
false
,
length
=
255
)
private
String
payAccess
;
private
String
payAccess
;
@Column
(
name
=
"PRODUCT_CODE"
,
nullable
=
false
,
length
=
255
)
private
String
productCode
;
@Column
(
name
=
"REFUND_ACCESS"
,
nullable
=
false
,
length
=
255
)
@Column
(
name
=
"REFUND_ACCESS"
,
nullable
=
false
,
length
=
255
)
private
String
refundAccess
;
private
String
refundAccess
;
...
@@ -78,6 +81,14 @@ public class PayFeatureEntity extends DescriptionEntity implements Serializable
...
@@ -78,6 +81,14 @@ public class PayFeatureEntity extends DescriptionEntity implements Serializable
this
.
payAccess
=
payAccess
;
this
.
payAccess
=
payAccess
;
}
}
public
String
getProductCode
()
{
return
productCode
;
}
public
void
setProductCode
(
String
productCode
)
{
this
.
productCode
=
productCode
;
}
public
String
getRefundAccess
()
{
public
String
getRefundAccess
()
{
return
refundAccess
;
return
refundAccess
;
}
}
...
...
baa-pay-core/src/main/java/cn/quant/baa/pay/jpa/repository/PayHistoryRepository.java
View file @
aae49d8f
...
@@ -14,4 +14,6 @@ import org.springframework.stereotype.Repository;
...
@@ -14,4 +14,6 @@ import org.springframework.stereotype.Repository;
@Repository
@Repository
public
interface
PayHistoryRepository
extends
JpaRepository
<
PayHistoryEntity
,
PayHistoryIds
>
{
public
interface
PayHistoryRepository
extends
JpaRepository
<
PayHistoryEntity
,
PayHistoryIds
>
{
// @Query("")
// int counAAAt(PayHistoryIds ids);
}
}
baa-pay-core/src/main/java/cn/quant/baa/pay/model/web/CheckPayRequestData.java
0 → 100644
View file @
aae49d8f
package
cn
.
quant
.
baa
.
pay
.
model
.
web
;
import
javax.validation.constraints.NotNull
;
import
javax.validation.constraints.Size
;
import
java.io.Serializable
;
/**
* Created with IntelliJ IDEA.
* Author: Lipeng Liu
* Date: 2021/9/7
* Time: 下午4:31
* Description: No Description
*/
public
class
CheckPayRequestData
implements
Serializable
{
private
static
final
long
serialVersionUID
=
-
2386424808660622542L
;
/**
* 支付通道ID
*/
@NotNull
(
message
=
"ILLEGAL_REQ_CHAN_ID"
)
private
String
chanId
;
/**
* 商户订单号
*/
@Size
(
min
=
6
,
max
=
64
,
message
=
"ILLEGAL_REQ_OUT_TRADE_NO"
)
@NotNull
(
message
=
"ILLEGAL_REQ_OUT_TRADE_NO"
)
private
String
outTradeNo
;
public
String
getChanId
()
{
return
chanId
;
}
public
void
setChanId
(
String
chanId
)
{
this
.
chanId
=
chanId
;
}
public
String
getOutTradeNo
()
{
return
outTradeNo
;
}
public
void
setOutTradeNo
(
String
outTradeNo
)
{
this
.
outTradeNo
=
outTradeNo
;
}
}
baa-pay-core/src/main/java/cn/quant/baa/pay/model/web/CheckRefundRequestData.java
0 → 100644
View file @
aae49d8f
package
cn
.
quant
.
baa
.
pay
.
model
.
web
;
import
javax.validation.constraints.NotNull
;
import
javax.validation.constraints.Size
;
import
java.io.Serializable
;
/**
* Created with IntelliJ IDEA.
* Author: Lipeng Liu
* Date: 2021/9/8
* Time: 上午11:05
* Description: No Description
*/
public
class
CheckRefundRequestData
implements
Serializable
{
private
static
final
long
serialVersionUID
=
4652001398076281697L
;
/**
* 支付通道ID
*/
@NotNull
(
message
=
"ILLEGAL_REQ_CHAN_ID"
)
private
String
chanId
;
/**
* 退款订单号
*/
@Size
(
min
=
6
,
max
=
64
,
message
=
"ILLEGAL_REQ_OUT_REFUND_NO"
)
@NotNull
(
message
=
"ILLEGAL_REQ_OUT_REFUND_NO"
)
private
String
outRefundNo
;
/**
* 商户订单号
*/
@Size
(
min
=
6
,
max
=
64
,
message
=
"ILLEGAL_REQ_OUT_TRADE_NO"
)
@NotNull
(
message
=
"ILLEGAL_REQ_OUT_TRADE_NO"
)
private
String
outTradeNo
;
public
String
getChanId
()
{
return
chanId
;
}
public
void
setChanId
(
String
chanId
)
{
this
.
chanId
=
chanId
;
}
public
String
getOutRefundNo
()
{
return
outRefundNo
;
}
public
void
setOutRefundNo
(
String
outRefundNo
)
{
this
.
outRefundNo
=
outRefundNo
;
}
public
String
getOutTradeNo
()
{
return
outTradeNo
;
}
public
void
setOutTradeNo
(
String
outTradeNo
)
{
this
.
outTradeNo
=
outTradeNo
;
}
}
baa-pay-core/src/main/java/cn/quant/baa/pay/model/web/CloseRequestData.java
0 → 100644
View file @
aae49d8f
package
cn
.
quant
.
baa
.
pay
.
model
.
web
;
import
javax.validation.constraints.NotNull
;
import
javax.validation.constraints.Size
;
import
java.io.Serializable
;
/**
* Created with IntelliJ IDEA.
* Author: Lipeng Liu
* Date: 2021/9/8
* Time: 上午11:28
* Description: No Description
*/
public
class
CloseRequestData
implements
Serializable
{
private
static
final
long
serialVersionUID
=
8489060627679269541L
;
/**
* 支付通道ID
*/
@NotNull
(
message
=
"ILLEGAL_REQ_CHAN_ID"
)
private
String
chanId
;
/**
* 商户订单号
*/
@Size
(
min
=
6
,
max
=
64
,
message
=
"ILLEGAL_REQ_OUT_TRADE_NO"
)
@NotNull
(
message
=
"ILLEGAL_REQ_OUT_TRADE_NO"
)
private
String
outTradeNo
;
public
String
getChanId
()
{
return
chanId
;
}
public
void
setChanId
(
String
chanId
)
{
this
.
chanId
=
chanId
;
}
public
String
getOutTradeNo
()
{
return
outTradeNo
;
}
public
void
setOutTradeNo
(
String
outTradeNo
)
{
this
.
outTradeNo
=
outTradeNo
;
}
}
baa-pay-core/src/main/java/cn/quant/baa/pay/model/web/RefundRequestData.java
0 → 100644
View file @
aae49d8f
package
cn
.
quant
.
baa
.
pay
.
model
.
web
;
import
javax.validation.constraints.NotNull
;
import
javax.validation.constraints.Size
;
import
java.io.Serializable
;
/**
* Created with IntelliJ IDEA.
* Author: Lipeng Liu
* Date: 2021/9/8
* Time: 上午11:30
* Description: No Description
*/
public
class
RefundRequestData
implements
Serializable
{
private
static
final
long
serialVersionUID
=
-
3619831737213449288L
;
/**
* 支付通道ID
*/
@NotNull
(
message
=
"ILLEGAL_REQ_CHAN_ID"
)
private
String
chanId
;
/**
* 退款订单号
*/
@Size
(
min
=
6
,
max
=
64
,
message
=
"ILLEGAL_REQ_OUT_REFUND_NO"
)
@NotNull
(
message
=
"ILLEGAL_REQ_OUT_REFUND_NO"
)
private
String
outRefundNo
;
/**
* 商户订单号
*/
@Size
(
min
=
6
,
max
=
64
,
message
=
"ILLEGAL_REQ_OUT_TRADE_NO"
)
@NotNull
(
message
=
"ILLEGAL_REQ_OUT_TRADE_NO"
)
private
String
outTradeNo
;
/**
* 退款原因
*/
@NotNull
(
message
=
"ILLEGAL_REQ_REFUND_REASON"
)
private
String
refundReason
;
/**
* 退款金额
*/
@NotNull
(
message
=
"ILLEGAL_REQ_REFUND_AMOUNT"
)
private
String
refundAmount
;
public
String
getChanId
()
{
return
chanId
;
}
public
void
setChanId
(
String
chanId
)
{
this
.
chanId
=
chanId
;
}
public
String
getOutRefundNo
()
{
return
outRefundNo
;
}
public
void
setOutRefundNo
(
String
outRefundNo
)
{
this
.
outRefundNo
=
outRefundNo
;
}
public
String
getOutTradeNo
()
{
return
outTradeNo
;
}
public
void
setOutTradeNo
(
String
outTradeNo
)
{
this
.
outTradeNo
=
outTradeNo
;
}
public
String
getRefundReason
()
{
return
refundReason
;
}
public
void
setRefundReason
(
String
refundReason
)
{
this
.
refundReason
=
refundReason
;
}
public
String
getRefundAmount
()
{
return
refundAmount
;
}
public
void
setRefundAmount
(
String
refundAmount
)
{
this
.
refundAmount
=
refundAmount
;
}
}
baa-pay-server/pom.xml
View file @
aae49d8f
...
@@ -67,6 +67,10 @@
...
@@ -67,6 +67,10 @@
<artifactId>
junit
</artifactId>
<artifactId>
junit
</artifactId>
<scope>
test
</scope>
<scope>
test
</scope>
</dependency>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-thymeleaf
</artifactId>
</dependency>
</dependencies>
</dependencies>
<build>
<build>
...
@@ -81,6 +85,7 @@
...
@@ -81,6 +85,7 @@
<include>
**/*.xml
</include>
<include>
**/*.xml
</include>
<include>
**/*.properties
</include>
<include>
**/*.properties
</include>
<include>
**/*.txt
</include>
<include>
**/*.txt
</include>
<include>
**/*.html
</include>
</includes>
</includes>
</resource>
</resource>
<resource>
<resource>
...
@@ -125,22 +130,22 @@
...
@@ -125,22 +130,22 @@
</configuration>
</configuration>
</plugin>
</plugin>
<!--<plugin>-->
<!--<plugin>-->
<!--<artifactId>maven-assembly-plugin</artifactId>-->
<!--<artifactId>maven-assembly-plugin</artifactId>-->
<!--<configuration>-->
<!--<configuration>-->
<!--<appendAssemblyId>false</appendAssemblyId>-->
<!--<appendAssemblyId>false</appendAssemblyId>-->
<!--<descriptors>-->
<!--<descriptors>-->
<!--<descriptor>src/assembly/assembly.xml</descriptor>-->
<!--<descriptor>src/assembly/assembly.xml</descriptor>-->
<!--</descriptors>-->
<!--</descriptors>-->
<!--</configuration>-->
<!--</configuration>-->
<!--<executions>-->
<!--<executions>-->
<!--<execution>-->
<!--<execution>-->
<!--<id>make-assembly</id>-->
<!--<id>make-assembly</id>-->
<!--<phase>package</phase>-->
<!--<phase>package</phase>-->
<!--<goals>-->
<!--<goals>-->
<!--<goal>single</goal>-->
<!--<goal>single</goal>-->
<!--</goals>-->
<!--</goals>-->
<!--</execution>-->
<!--</execution>-->
<!--</executions>-->
<!--</executions>-->
<!--</plugin>-->
<!--</plugin>-->
<plugin>
<plugin>
<groupId>
org.apache.maven.plugins
</groupId>
<groupId>
org.apache.maven.plugins
</groupId>
...
...
baa-pay-server/src/main/java/cn/quant/baa/pay/rest/PayTestController.java
0 → 100644
View file @
aae49d8f
package
cn
.
quant
.
baa
.
pay
.
rest
;
import
cn.quant.baa.pay.annotation.BusinessMapping
;
import
cn.quant.baa.pay.context.TransactionSession
;
import
cn.quant.baa.pay.model.BusinessRequest
;
import
cn.quant.baa.pay.model.web.CheckPayRequestData
;
import
cn.quant.baa.pay.model.web.CheckRefundRequestData
;
import
cn.quant.baa.pay.model.web.PayRequestData
;
import
cn.quant.baa.pay.service.TransactionService
;
import
com.fasterxml.jackson.core.JsonProcessingException
;
import
com.fasterxml.jackson.databind.DeserializationFeature
;
import
com.fasterxml.jackson.databind.JsonNode
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.fasterxml.jackson.databind.PropertyNamingStrategy
;
import
com.fasterxml.jackson.databind.json.JsonMapper
;
import
com.fasterxml.jackson.databind.node.ObjectNode
;
import
org.json.JSONObject
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Controller
;
import
org.springframework.ui.Model
;
import
org.springframework.web.bind.annotation.*
;
import
javax.servlet.http.HttpServletRequest
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* Created with IntelliJ IDEA.
* Author: Lipeng Liu
* Date: 2021/9/9
* Time: 上午9:51
* Description: No Description
*/
@Controller
//@RestController
@RequestMapping
(
"pay"
)
public
class
PayTestController
{
ObjectMapper
objectMapper
=
new
ObjectMapper
();
@Autowired
private
TransactionService
transactionService
;
@GetMapping
(
""
)
public
String
getPay
(
Model
model
)
{
return
"pay/index"
;
}
@RequestMapping
(
"h5"
)
public
String
getH5
(
Model
model
)
{
return
"pay/h5"
;
}
@RequestMapping
(
"checkPay"
)
public
String
checkPay
(
CheckPayRequestData
data
,
Model
model
,
HttpServletRequest
servletRequest
)
{
String
res
=
""
;
if
(
servletRequest
.
getMethod
().
equals
(
"POST"
))
{
res
=
transactionService
.
checkPay
(
data
).
toString
();
}
model
.
addAttribute
(
"res"
,
res
);
return
"pay/checkPay"
;
}
@RequestMapping
(
"checkRefund"
)
public
String
checkRefund
(
CheckRefundRequestData
data
,
Model
model
,
HttpServletRequest
servletRequest
)
{
String
res
=
""
;
if
(
servletRequest
.
getMethod
().
equals
(
"POST"
))
{
res
=
transactionService
.
checkRefund
(
data
).
toString
();
}
model
.
addAttribute
(
"res"
,
res
);
return
"pay/checkRefund"
;
}
@PostMapping
(
"goPay"
)
@BusinessMapping
(
session
=
1
)
@ResponseBody
public
JsonNode
goPay
(
@RequestBody
(
required
=
false
)
BusinessRequest
<
PayRequestData
>
requestData
)
{
PayRequestData
data
=
requestData
.
getData
();
String
str
=
"{\"subject\":\"测试订单1\",\"mchId\":\"wx2f44c7fe7b08458d\",\"chanId\":\"75772285618946307\",\"outTradeNo\":\"11111111223\",\"originalAmount\":\"110.00\",\"amount\":0.01,\"discounts\":\"10.00\",\"notifyUrl\":\"http://127.0.0.1:8080/notifyUrl\",\"buyerId\":\"777777\",\"attach\":\"AAAA-BBBB-1111-2222\",\"creditAmount\":\"10.00\",\"cashAmount\":\"10\",\"goodsDetail\":[{\"goodsNo\":\"123123\",\"goodsId\":\"11111\",\"goodsName\":\"商品1\",\"quantity\":2,\"price\":\"10.00\",\"discounts\":\"2.5\",\"amount\":\"17.5\",\"attach\":\"---\",\"creditAmount\":123,\"cashAmount\":123}]}"
;
try
{
objectMapper
.
configure
(
DeserializationFeature
.
FAIL_ON_UNKNOWN_PROPERTIES
,
false
);
PayRequestData
payRequestData
=
objectMapper
.
readValue
(
str
,
PayRequestData
.
class
);
String
[]
temp
=
data
.
getChanId
().
split
(
"_"
);
payRequestData
.
setChanId
(
temp
[
0
]);
payRequestData
.
setMchId
(
temp
[
1
]);
payRequestData
.
setOutTradeNo
(
data
.
getOutTradeNo
());
payRequestData
.
setSubject
(
data
.
getSubject
());
payRequestData
.
setAmount
(
data
.
getAmount
());
payRequestData
.
setNotifyUrl
(
"http://127.0.0.1:8080/notifyUrl"
);
JsonNode
res
=
transactionService
.
pay
(
payRequestData
);
return
res
;
}
catch
(
JsonProcessingException
e
)
{
e
.
printStackTrace
();
}
return
objectMapper
.
createObjectNode
();
}
}
\ No newline at end of file
baa-pay-server/src/main/java/cn/quant/baa/pay/rest/TransactionController.java
View file @
aae49d8f
...
@@ -3,8 +3,9 @@ package cn.quant.baa.pay.rest;
...
@@ -3,8 +3,9 @@ package cn.quant.baa.pay.rest;
import
cn.quant.baa.pay.annotation.BusinessMapping
;
import
cn.quant.baa.pay.annotation.BusinessMapping
;
import
cn.quant.baa.pay.jpa.entity.PayHistoryEntity
;
import
cn.quant.baa.pay.jpa.entity.PayHistoryEntity
;
import
cn.quant.baa.pay.model.BusinessRequest
;
import
cn.quant.baa.pay.model.BusinessRequest
;
import
cn.quant.baa.pay.model.web.
PayRequestData
;
import
cn.quant.baa.pay.model.web.
*
;
import
cn.quant.baa.pay.service.TransactionService
;
import
cn.quant.baa.pay.service.TransactionService
;
import
com.fasterxml.jackson.databind.JsonNode
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.bind.annotation.*
;
...
@@ -22,11 +23,61 @@ public class TransactionController extends BusinessController {
...
@@ -22,11 +23,61 @@ public class TransactionController extends BusinessController {
@ResponseBody
@ResponseBody
@BusinessMapping
(
session
=
1
)
@BusinessMapping
(
session
=
1
)
@PostMapping
(
"/pay"
)
@PostMapping
(
"/pay"
)
public
void
pay
(
@RequestBody
BusinessRequest
<
PayRequestData
>
request
)
{
public
JsonNode
pay
(
@RequestBody
BusinessRequest
<
PayRequestData
>
request
)
{
PayRequestData
data
=
request
.
getData
();
PayRequestData
data
=
request
.
getData
();
transactionService
.
pay
(
data
);
JsonNode
res
=
transactionService
.
pay
(
data
);
System
.
currentTimeMillis
();
System
.
currentTimeMillis
();
return
res
;
}
}
@ResponseBody
@BusinessMapping
(
session
=
1
)
@PostMapping
(
"/checkPay"
)
public
JsonNode
checkPay
(
@RequestBody
BusinessRequest
<
CheckPayRequestData
>
request
)
{
CheckPayRequestData
data
=
request
.
getData
();
JsonNode
res
=
transactionService
.
checkPay
(
data
);
System
.
currentTimeMillis
();
return
res
;
}
@ResponseBody
@BusinessMapping
(
session
=
1
)
@PostMapping
(
"/checkRefund"
)
public
JsonNode
checkRefund
(
@RequestBody
BusinessRequest
<
CheckRefundRequestData
>
request
)
{
CheckRefundRequestData
data
=
request
.
getData
();
JsonNode
res
=
transactionService
.
checkRefund
(
data
);
System
.
currentTimeMillis
();
return
res
;
}
@ResponseBody
@BusinessMapping
(
session
=
1
)
@PostMapping
(
"/close"
)
public
JsonNode
close
(
@RequestBody
BusinessRequest
<
CloseRequestData
>
request
)
{
CloseRequestData
data
=
request
.
getData
();
JsonNode
res
=
transactionService
.
close
(
data
);
System
.
currentTimeMillis
();
return
res
;
}
@ResponseBody
@BusinessMapping
(
session
=
1
)
@PostMapping
(
"/refund"
)
public
JsonNode
refund
(
@RequestBody
BusinessRequest
<
RefundRequestData
>
request
)
{
RefundRequestData
data
=
request
.
getData
();
JsonNode
res
=
transactionService
.
refund
(
data
);
System
.
currentTimeMillis
();
return
res
;
}
}
}
baa-pay-server/src/main/java/cn/quant/baa/pay/service/TransactionService.java
View file @
aae49d8f
...
@@ -5,10 +5,10 @@ import cn.quant.baa.pay.acquirer.AcquirerConfiguration;
...
@@ -5,10 +5,10 @@ import cn.quant.baa.pay.acquirer.AcquirerConfiguration;
import
cn.quant.baa.pay.acquirer.MerchantAcquirer
;
import
cn.quant.baa.pay.acquirer.MerchantAcquirer
;
import
cn.quant.baa.pay.context.TransactionSession
;
import
cn.quant.baa.pay.context.TransactionSession
;
import
cn.quant.baa.pay.jpa.entity.*
;
import
cn.quant.baa.pay.jpa.entity.*
;
import
cn.quant.baa.pay.model.web.*
;
import
cn.quant.baa.pay.util.AssertUtils
;
import
cn.quant.baa.pay.util.AssertUtils
;
import
cn.quant.baa.pay.model.web.GoodsDetail
;
import
cn.quant.baa.pay.acquirer.AcquirerProperties
;
import
cn.quant.baa.pay.acquirer.AcquirerProperties
;
import
c
n.quant.baa.pay.model.web.PayRequestData
;
import
c
om.fasterxml.jackson.databind.JsonNode
;
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
...
@@ -105,15 +105,33 @@ public class TransactionService extends BusinessService {
...
@@ -105,15 +105,33 @@ public class TransactionService extends BusinessService {
@Transactional
(
propagation
=
Propagation
.
NOT_SUPPORTED
)
@Transactional
(
propagation
=
Propagation
.
NOT_SUPPORTED
)
public
void
pay
(
PayRequestData
data
)
{
public
JsonNode
pay
(
PayRequestData
data
)
{
TransactionSession
session
=
payHistory
(
data
);
TransactionSession
session
=
payHistory
(
data
);
session
.
getProperty
(
PayHistoryEntity
.
class
,
PayHistoryEntity
.
class
);
PayHistoryEntity
payHistoryEntity
=
session
.
getProperty
(
PayHistoryEntity
.
class
,
PayHistoryEntity
.
class
);
System
.
currentTimeMillis
();
System
.
currentTimeMillis
();
// acquirer.pay(history, data);
return
acquirer
.
pay
(
data
,
payHistoryEntity
);
}
@Transactional
(
propagation
=
Propagation
.
NOT_SUPPORTED
)
public
JsonNode
checkPay
(
CheckPayRequestData
data
)
{
return
acquirer
.
checkPay
(
data
);
}
@Transactional
(
propagation
=
Propagation
.
NOT_SUPPORTED
)
public
JsonNode
checkRefund
(
CheckRefundRequestData
data
)
{
return
acquirer
.
checkRefund
(
data
);
}
@Transactional
(
propagation
=
Propagation
.
NOT_SUPPORTED
)
public
JsonNode
close
(
CloseRequestData
data
)
{
return
acquirer
.
close
(
data
);
}
@Transactional
(
propagation
=
Propagation
.
NOT_SUPPORTED
)
public
JsonNode
refund
(
RefundRequestData
data
)
{
return
acquirer
.
refund
(
data
);
}
}
}
}
baa-pay-server/src/main/resources/templates/pay/checkPay.html
0 → 100644
View file @
aae49d8f
<!DOCTYPE html>
<html
xmlns:th=
"http://www.thymeleaf.org"
lang=
"CN"
>
<head>
<title>
交易查询
</title>
<meta
http-equiv=
"Content-Type"
content=
"text/html; charset=utf-8"
>
<style>
*
{
margin
:
0
;
padding
:
0
;
}
ul
,
ol
{
list-style
:
none
;
}
body
{
font-family
:
"Helvetica Neue"
,
Helvetica
,
Arial
,
"Lucida Grande"
,
sans-serif
;
}
.hidden
{
display
:
none
;
}
.new-btn-login-sp
{
padding
:
1px
;
display
:
inline-block
;
width
:
75%
;
}
.new-btn-login
{
background-color
:
#02aaf1
;
color
:
#FFFFFF
;
font-weight
:
bold
;
border
:
none
;
width
:
100%
;
height
:
30px
;
border-radius
:
5px
;
font-size
:
16px
;
}
#main
{
width
:
100%
;
margin
:
0
auto
;
font-size
:
14px
;
}
.red-star
{
color
:
#f00
;
width
:
10px
;
display
:
inline-block
;
}
.null-star
{
color
:
#fff
;
}
.content
{
margin-top
:
5px
;
}
.content
dt
{
width
:
100px
;
display
:
inline-block
;
float
:
left
;
margin-left
:
20px
;
color
:
#666
;
font-size
:
13px
;
margin-top
:
8px
;
}
.content
dd
{
margin-left
:
120px
;
margin-bottom
:
5px
;
}
.content
dd
input
,
select
{
width
:
85%
;
height
:
28px
;
border
:
0
;
-webkit-border-radius
:
0
;
-webkit-appearance
:
none
;
}
#foot
{
margin-top
:
10px
;
position
:
absolute
;
bottom
:
15px
;
width
:
100%
;
}
.foot-ul
{
width
:
100%
;
}
.foot-ul
li
{
width
:
100%
;
text-align
:
center
;
color
:
#666
;
}
.note-help
{
color
:
#999999
;
font-size
:
12px
;
line-height
:
130%
;
margin-top
:
5px
;
width
:
100%
;
display
:
block
;
}
#btn-dd
{
margin
:
20px
;
text-align
:
center
;
}
.foot-ul
{
width
:
100%
;
}
.one_line
{
display
:
block
;
height
:
1px
;
border
:
0
;
border-top
:
1px
solid
#eeeeee
;
width
:
100%
;
margin-left
:
20px
;
}
.am-header
{
display
:
-webkit-box
;
display
:
-ms-flexbox
;
display
:
box
;
width
:
100%
;
position
:
relative
;
padding
:
7px
0
;
-webkit-box-sizing
:
border-box
;
-ms-box-sizing
:
border-box
;
box-sizing
:
border-box
;
background
:
#1D222D
;
height
:
50px
;
text-align
:
center
;
-webkit-box-pack
:
center
;
-ms-flex-pack
:
center
;
box-pack
:
center
;
-webkit-box-align
:
center
;
-ms-flex-align
:
center
;
box-align
:
center
;
}
.am-header
h1
{
-webkit-box-flex
:
1
;
-ms-flex
:
1
;
box-flex
:
1
;
line-height
:
18px
;
text-align
:
center
;
font-size
:
18px
;
font-weight
:
300
;
color
:
#fff
;
}
</style>
</head>
<body
text=
#000000
bgColor=
"#ffffff"
leftMargin=
0
topMargin=
4
>
<header
class=
"am-header"
>
<h1>
交易查询
</h1>
</header>
<div
id=
"main"
>
<form
name=
alipayment
action=
''
method=
post
>
<div
id=
"body"
style=
"clear:left"
>
<dl
class=
"content"
>
<dt>
支付方式
:
</dt>
<dd>
<select
name=
"chanId"
>
<option
value=
"75772285618946310"
>
微信
</option>
<option
value=
"75772285618946309"
>
支付宝
</option>
</select>
</dd>
<hr
class=
"one_line"
>
<dt>
商户订单号
:
</dt>
<dd>
<input
id=
"WIDout_trade_no"
name=
"outTradeNo"
value=
"11111111218"
/>
</dd>
<hr
class=
"one_line"
>
<dt></dt>
<dd>
<span
style=
"line-height: 28px; color:red;"
>
[[${res}]]
</span>
</dd>
<dd
id=
"btn-dd"
>
<span
class=
"new-btn-login-sp"
>
<button
class=
"new-btn-login"
type=
"submit"
style=
"text-align:center;"
>
确 认
</button>
</span>
<span
class=
"note-help"
>
如果您点击“确认”按钮,即表示您同意该次的执行操作。
</span>
</dd>
</dl>
</div>
</form>
<div
id=
"foot"
>
<ul
class=
"foot-ul"
>
<li>
QUANTGROUP.CN
</li>
</ul>
</div>
</div>
</body>
\ No newline at end of file
baa-pay-server/src/main/resources/templates/pay/checkRefund.html
0 → 100644
View file @
aae49d8f
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<title>
退款查询
</title>
<meta
http-equiv=
"Content-Type"
content=
"text/html; charset=utf-8"
>
<style>
*
{
margin
:
0
;
padding
:
0
;
}
ul
,
ol
{
list-style
:
none
;
}
body
{
font-family
:
"Helvetica Neue"
,
Helvetica
,
Arial
,
"Lucida Grande"
,
sans-serif
;
}
.hidden
{
display
:
none
;
}
.new-btn-login-sp
{
padding
:
1px
;
display
:
inline-block
;
width
:
75%
;
}
.new-btn-login
{
background-color
:
#02aaf1
;
color
:
#FFFFFF
;
font-weight
:
bold
;
border
:
none
;
width
:
100%
;
height
:
30px
;
border-radius
:
5px
;
font-size
:
16px
;
}
#main
{
width
:
100%
;
margin
:
0
auto
;
font-size
:
14px
;
}
.red-star
{
color
:
#f00
;
width
:
10px
;
display
:
inline-block
;
}
.null-star
{
color
:
#fff
;
}
.content
{
margin-top
:
5px
;
}
.content
dt
{
width
:
100px
;
display
:
inline-block
;
float
:
left
;
margin-left
:
20px
;
color
:
#666
;
font-size
:
13px
;
margin-top
:
8px
;
}
.content
dd
{
margin-left
:
120px
;
margin-bottom
:
5px
;
}
.content
dd
input
,
select
{
width
:
85%
;
height
:
28px
;
border
:
0
;
-webkit-border-radius
:
0
;
-webkit-appearance
:
none
;
}
#foot
{
margin-top
:
10px
;
position
:
absolute
;
bottom
:
15px
;
width
:
100%
;
}
.foot-ul
{
width
:
100%
;
}
.foot-ul
li
{
width
:
100%
;
text-align
:
center
;
color
:
#666
;
}
.note-help
{
color
:
#999999
;
font-size
:
12px
;
line-height
:
130%
;
margin-top
:
5px
;
width
:
100%
;
display
:
block
;
}
#btn-dd
{
margin
:
20px
;
text-align
:
center
;
}
.foot-ul
{
width
:
100%
;
}
.one_line
{
display
:
block
;
height
:
1px
;
border
:
0
;
border-top
:
1px
solid
#eeeeee
;
width
:
100%
;
margin-left
:
20px
;
}
.am-header
{
display
:
-webkit-box
;
display
:
-ms-flexbox
;
display
:
box
;
width
:
100%
;
position
:
relative
;
padding
:
7px
0
;
-webkit-box-sizing
:
border-box
;
-ms-box-sizing
:
border-box
;
box-sizing
:
border-box
;
background
:
#1D222D
;
height
:
50px
;
text-align
:
center
;
-webkit-box-pack
:
center
;
-ms-flex-pack
:
center
;
box-pack
:
center
;
-webkit-box-align
:
center
;
-ms-flex-align
:
center
;
box-align
:
center
;
}
.am-header
h1
{
-webkit-box-flex
:
1
;
-ms-flex
:
1
;
box-flex
:
1
;
line-height
:
18px
;
text-align
:
center
;
font-size
:
18px
;
font-weight
:
300
;
color
:
#fff
;
}
</style>
</head>
<body
text=
#000000
bgColor=
"#ffffff"
leftMargin=
0
topMargin=
4
>
<header
class=
"am-header"
>
<h1>
交易退款查询
</h1>
</header>
<div
id=
"main"
>
<form
name=
alipayment
action=
''
method=
post
>
<div
id=
"body"
style=
"clear:left"
>
<dl
class=
"content"
>
<dt>
支付方式
:
</dt>
<dd>
<select
name=
"chanId"
>
<option
value=
"75772285618946311"
>
支付宝
</option>
<option
value=
"75772285618946312"
>
微信
</option>
</select>
</dd>
<hr
class=
"one_line"
>
<dt>
退款请求号:
</dt>
<dd>
<input
id=
"WIDout_request_no"
name=
"outRefundNo"
value=
"11111111218"
/>
</dd>
<dt>
商户订单号:
</dt>
<dd>
<input
id=
"WIDout_trade_no"
name=
"outTradeNo"
value=
"11111111218"
/>
</dd>
<hr
class=
"one_line"
>
<dt></dt>
<dd>
<span
style=
"line-height: 28px; color:red;"
>
[[${res}]]
</span>
</dd>
<dd
id=
"btn-dd"
>
<span
class=
"new-btn-login-sp"
>
<button
class=
"new-btn-login"
type=
"submit"
style=
"text-align:center;"
>
确 认
</button>
</span>
<span
class=
"note-help"
>
如果您点击“确认”按钮,即表示您同意该次的执行操作。
</span>
</dd>
</dl>
</div>
</form>
<div
id=
"foot"
>
<ul
class=
"foot-ul"
>
<li>
QUANTGROUP.CN
</li>
</ul>
</div>
</div>
</body>
\ No newline at end of file
baa-pay-server/src/main/resources/templates/pay/h5.html
0 → 100644
View file @
aae49d8f
<!DOCTYPE html>
<html
xmlns:th=
"http://www.thymeleaf.org"
lang=
"CN"
>
<head>
<title>
手机网站支付接口
</title>
<meta
http-equiv=
"Content-Type"
content=
"text/html; charset=utf-8"
>
<script
src=
"https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"
></script>
<script
src=
"https://cdn.bootcdn.net/ajax/libs/jquery.serializeJSON/3.2.1/jquery.serializejson.min.js"
></script>
<!-- <meta http-equiv="refresh" content="url=[[${payUrl}]]">-->
<style>
*
{
margin
:
0
;
padding
:
0
;
}
ul
,
ol
{
list-style
:
none
;
}
body
{
font-family
:
"Helvetica Neue"
,
Helvetica
,
Arial
,
"Lucida Grande"
,
sans-serif
;
}
.hidden
{
display
:
none
;
}
.new-btn-login-sp
{
padding
:
1px
;
display
:
inline-block
;
width
:
75%
;
}
.new-btn-login
{
background-color
:
#02aaf1
;
color
:
#FFFFFF
;
font-weight
:
bold
;
border
:
none
;
width
:
100%
;
height
:
30px
;
border-radius
:
5px
;
font-size
:
16px
;
}
#main
{
width
:
100%
;
margin
:
0
auto
;
font-size
:
14px
;
}
.red-star
{
color
:
#f00
;
width
:
10px
;
display
:
inline-block
;
}
.null-star
{
color
:
#fff
;
}
.content
{
margin-top
:
5px
;
}
.content
dt
{
width
:
100px
;
display
:
inline-block
;
float
:
left
;
margin-left
:
20px
;
color
:
#666
;
font-size
:
13px
;
margin-top
:
8px
;
}
.content
dd
{
margin-left
:
120px
;
margin-bottom
:
5px
;
}
.content
dd
input
,
.content
dd
select
{
width
:
85%
;
height
:
28px
;
border
:
0
;
-webkit-border-radius
:
0
;
-webkit-appearance
:
none
;
}
#foot
{
margin-top
:
10px
;
position
:
absolute
;
bottom
:
15px
;
width
:
100%
;
}
.foot-ul
{
width
:
100%
;
}
.foot-ul
li
{
width
:
100%
;
text-align
:
center
;
color
:
#666
;
}
.note-help
{
color
:
#999999
;
font-size
:
12px
;
line-height
:
130%
;
margin-top
:
5px
;
width
:
100%
;
display
:
block
;
}
#btn-dd
{
margin
:
20px
;
text-align
:
center
;
}
.foot-ul
{
width
:
100%
;
}
.one_line
{
display
:
block
;
height
:
1px
;
border
:
0
;
border-top
:
1px
solid
#eeeeee
;
width
:
100%
;
margin-left
:
20px
;
}
.am-header
{
display
:
-webkit-box
;
display
:
-ms-flexbox
;
display
:
box
;
width
:
100%
;
position
:
relative
;
padding
:
7px
0
;
-webkit-box-sizing
:
border-box
;
-ms-box-sizing
:
border-box
;
box-sizing
:
border-box
;
background
:
#1D222D
;
height
:
50px
;
text-align
:
center
;
-webkit-box-pack
:
center
;
-ms-flex-pack
:
center
;
box-pack
:
center
;
-webkit-box-align
:
center
;
-ms-flex-align
:
center
;
box-align
:
center
;
}
.am-header
h1
{
-webkit-box-flex
:
1
;
-ms-flex
:
1
;
box-flex
:
1
;
line-height
:
18px
;
text-align
:
center
;
font-size
:
18px
;
font-weight
:
300
;
color
:
#fff
;
}
</style>
</head>
<body
text=
#000000
bgColor=
"#ffffff"
leftMargin=
0
topMargin=
4
>
<header
class=
"am-header"
>
<h1>
手机网站支付接口
</h1>
</header>
<div
id=
"main"
>
<form
name=
payment
action=
''
method=
post
target=
"_blank"
enctype=
"application/x-www-form-urlencoded"
th:object=
"${requestData}"
>
<div
id=
"body"
style=
"clear:left"
>
<dl
class=
"content"
>
<dt>
支付方式
:
</dt>
<dd>
<select
name=
"data[chan_id]"
>
<option
value=
"75772285618946307_wx2f44c7fe7b08458d"
>
微信
</option>
<option
value=
"75772285618946317_wxd678efh567hg6787"
>
支付宝
</option>
</select>
</dd>
<hr
class=
"one_line"
>
<dt>
商户订单号
:
</dt>
<dd>
<input
id=
"outTradeNo"
name=
"data[out_trade_no]"
/>
</dd>
<hr
class=
"one_line"
>
<dt>
订单名称
:
</dt>
<dd>
<input
id=
"subject"
name=
"data[subject]"
/>
</dd>
<hr
class=
"one_line"
>
<dt>
付款金额
:
</dt>
<dd>
<input
id=
"amount"
name=
"data[amount]"
/>
</dd>
<hr
class=
"one_line"
>
<dt>
商品描述:
</dt>
<dd>
<input
id=
"body"
name=
"data[body]"
/>
</dd>
<hr
class=
"one_line"
>
<dt></dt>
<dd
id=
"btn-dd"
>
<span
class=
"new-btn-login-sp"
>
<button
class=
"new-btn-login"
type=
"button"
style=
"text-align:center;"
>
确 认
</button>
</span>
<span
class=
"note-help"
>
如果您点击“确认”按钮,即表示您同意该次的执行操作。
</span>
</dd>
</dl>
</div>
</form>
<div
id=
"foot"
>
<ul
class=
"foot-ul"
>
<li>
QUANTGROUP.CN
</li>
</ul>
</div>
</div>
</body>
<script
language=
"javascript"
>
$
(
"
.new-btn-login
"
).
click
(
function
()
{
$
.
ajax
({
type
:
"
post
"
,
url
:
'
/pay/goPay
'
,
async
:
false
,
// 使用同步方式
// 1 需要使用JSON.stringify 否则格式为 a=2&b=3&now=14...
// 2 需要强制类型转换,否则格式为 {"a":"2","b":"3"}
data
:
JSON
.
stringify
(
$
(
'
form
'
).
serializeJSON
()),
contentType
:
"
application/json; charset=utf-8
"
,
dataType
:
"
json
"
,
success
:
function
(
data
)
{
if
(
data
.
hasOwnProperty
(
"
h5_url
"
))
{
window
.
location
.
href
=
data
.
h5_url
;
}
if
(
data
.
hasOwnProperty
(
"
data
"
))
{
window
.
location
.
href
=
data
.
data
;
}
}
// 注意不要在此行增加逗号
});
});
function
GetDateNow
()
{
var
vNow
=
new
Date
();
var
sNow
=
""
;
sNow
+=
String
(
vNow
.
getFullYear
());
sNow
+=
String
(
vNow
.
getMonth
()
+
1
);
sNow
+=
String
(
vNow
.
getDate
());
sNow
+=
String
(
vNow
.
getHours
());
sNow
+=
String
(
vNow
.
getMinutes
());
sNow
+=
String
(
vNow
.
getSeconds
());
sNow
+=
String
(
vNow
.
getMilliseconds
());
document
.
getElementById
(
"
outTradeNo
"
).
value
=
sNow
;
document
.
getElementById
(
"
subject
"
).
value
=
"
测试
"
;
document
.
getElementById
(
"
amount
"
).
value
=
"
0.01
"
;
document
.
getElementById
(
"
body
"
).
value
=
"
购买测试商品0.01元
"
;
}
GetDateNow
();
</script>
</html>
\ No newline at end of file
baa-pay-server/src/main/resources/templates/pay/index.html
0 → 100644
View file @
aae49d8f
<!DOCTYPE html>
<html
xmlns:th=
"http://www.thymeleaf.org"
lang=
"CN"
>
<head>
<title>
支付中心API
</title>
<meta
http-equiv=
"Content-Type"
content=
"text/html; charset=utf-8"
>
<style>
*
{
margin
:
0
;
padding
:
0
;
}
ul
,
ol
{
list-style
:
none
;
}
body
{
font-family
:
"Helvetica Neue"
,
Helvetica
,
Arial
,
"Lucida Grande"
,
sans-serif
;
}
.hidden
{
display
:
none
;
}
.new-btn-login-sp
{
padding
:
1px
;
display
:
inline-block
;
width
:
75%
;
}
.new-btn-login
{
background-color
:
#02aaf1
;
color
:
#FFFFFF
;
font-weight
:
bold
;
border
:
none
;
width
:
100%
;
height
:
30px
;
border-radius
:
5px
;
font-size
:
16px
;
}
#main
{
width
:
100%
;
margin
:
0
auto
;
font-size
:
14px
;
}
.red-star
{
color
:
#f00
;
width
:
10px
;
display
:
inline-block
;
}
.null-star
{
color
:
#fff
;
}
.content
{
margin-top
:
5px
;
}
.content
dt
{
width
:
100px
;
display
:
inline-block
;
float
:
left
;
margin-left
:
20px
;
color
:
#666
;
font-size
:
13px
;
margin-top
:
8px
;
}
.content
dd
{
margin-left
:
120px
;
margin-bottom
:
5px
;
}
.content
dd
input
{
width
:
85%
;
height
:
28px
;
border
:
0
;
-webkit-border-radius
:
0
;
-webkit-appearance
:
none
;
}
#foot
{
margin-top
:
10px
;
position
:
absolute
;
bottom
:
15px
;
width
:
100%
;
}
.foot-ul
{
width
:
100%
;
}
.foot-ul
li
{
width
:
100%
;
text-align
:
center
;
color
:
#666
;
}
.note-help
{
color
:
#999999
;
font-size
:
12px
;
line-height
:
130%
;
margin-top
:
5px
;
width
:
100%
;
display
:
block
;
}
.btn-dd
{
margin
:
20px
;
text-align
:
center
;
}
.foot-ul
{
width
:
100%
;
}
.one_line
{
display
:
block
;
height
:
1px
;
border
:
0
;
border-top
:
1px
solid
#eeeeee
;
width
:
100%
;
margin-left
:
20px
;
}
.am-header
{
display
:
-webkit-box
;
display
:
-ms-flexbox
;
display
:
box
;
width
:
100%
;
position
:
relative
;
padding
:
7px
0
;
-webkit-box-sizing
:
border-box
;
-ms-box-sizing
:
border-box
;
box-sizing
:
border-box
;
background
:
#1D222D
;
height
:
50px
;
text-align
:
center
;
-webkit-box-pack
:
center
;
-ms-flex-pack
:
center
;
box-pack
:
center
;
-webkit-box-align
:
center
;
-ms-flex-align
:
center
;
box-align
:
center
;
}
.am-header
h1
{
-webkit-box-flex
:
1
;
-ms-flex
:
1
;
box-flex
:
1
;
line-height
:
18px
;
text-align
:
center
;
font-size
:
18px
;
font-weight
:
300
;
color
:
#fff
;
}
</style>
</head>
<body
text=
#000000
bgColor=
"#ffffff"
leftMargin=
0
topMargin=
4
>
<header
class=
"am-header"
>
<h1>
支付中心接口
</h1>
</header>
<div
id=
"main"
>
<div
id=
"body"
style=
"clear:left"
>
<dl
class=
"content"
>
<dt></dt>
<dd
class=
"btn-dd"
>
<span
class=
"new-btn-login-sp"
>
<button
class=
"new-btn-login"
style=
"text-align:center;"
onclick=
"window.open('/pay/h5')"
>
手机网站支付
</button>
</span>
</dd>
<dt></dt>
<dd
class=
"btn-dd"
>
<span
class=
"new-btn-login-sp"
>
<button
class=
"new-btn-login"
style=
"text-align:center;"
onclick=
"window.open('/pay/checkPay')"
>
订单查询
</button>
</span>
</dd>
<dt></dt>
<dd
class=
"btn-dd"
>
<span
class=
"new-btn-login-sp"
>
<button
class=
"new-btn-login"
style=
"text-align:center;"
onclick=
"window.open('/pay/checkRefund')"
>
退款查询
</button>
</span>
</dd>
</dl>
</div>
<div
id=
"foot"
>
<ul
class=
"foot-ul"
>
<li>
QUANTGROUP.CN
</li>
</ul>
</div>
</div>
</body>
</html>
\ No newline at end of file
Write
Preview
Markdown
is supported
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