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
82f0a880
Commit
82f0a880
authored
Sep 03, 2021
by
刘李鹏
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
微信支付示例完成
parent
3972936f
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
283 additions
and
12 deletions
+283
-12
Acquirer.java
...ore/src/main/java/cn/quant/baa/pay/acquirer/Acquirer.java
+6
-1
MerchantAcquirer.java
...main/java/cn/quant/baa/pay/acquirer/MerchantAcquirer.java
+10
-2
WeiXinMerchantAcquirer.java
...quant/baa/pay/acquirer/weixin/WeiXinMerchantAcquirer.java
+257
-1
PayHistoryRepository.java
...cn/quant/baa/pay/jpa/repository/PayHistoryRepository.java
+2
-0
TransactionService.java
...ain/java/cn/quant/baa/pay/service/TransactionService.java
+4
-6
TransactionController.java
...ain/java/cn/quant/baa/pay/rest/TransactionController.java
+4
-2
No files found.
baa-pay-core/src/main/java/cn/quant/baa/pay/acquirer/Acquirer.java
View file @
82f0a880
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.PayRequestData
;
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
();
void
refund
();
void
check
();
void
check
();
void
close
();
}
}
baa-pay-core/src/main/java/cn/quant/baa/pay/acquirer/MerchantAcquirer.java
View file @
82f0a880
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.PayRequestData
;
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,8 +65,8 @@ public class MerchantAcquirer implements Acquirer {
...
@@ -62,8 +65,8 @@ 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
...
@@ -75,4 +78,9 @@ public class MerchantAcquirer implements Acquirer {
...
@@ -75,4 +78,9 @@ public class MerchantAcquirer implements Acquirer {
public
void
check
()
{
public
void
check
()
{
throw
new
NotSupportedException
();
throw
new
NotSupportedException
();
}
}
@Override
public
void
close
()
{
}
}
}
baa-pay-core/src/main/java/cn/quant/baa/pay/acquirer/weixin/WeiXinMerchantAcquirer.java
View file @
82f0a880
...
@@ -2,15 +2,75 @@ package cn.quant.baa.pay.acquirer.weixin;
...
@@ -2,15 +2,75 @@ 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.PayRequestData
;
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.MediaType
;
import
org.springframework.web.reactive.function.client.ClientResponse
;
import
org.springframework.web.reactive.function.client.WebClient
;
import
reactor.core.publisher.Mono
;
import
java.io.ByteArrayInputStream
;
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.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
;
/**
* 支付初始化
* 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 +78,200 @@ public class WeiXinMerchantAcquirer extends MerchantAcquirer {
...
@@ -18,4 +78,200 @@ 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
)
{
String
outTradeNo
=
UUID
.
randomUUID
().
toString
().
replace
(
"-"
,
""
);
ObjectMapper
objectMapper
=
new
ObjectMapper
();
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
requestBody
=
bodyNode
.
toString
();
return
doExecute
(
requestBody
);
}
/**
* 发起请求
*
* @param requestBody
* @return
*/
private
JsonNode
doExecute
(
String
requestBody
)
{
long
timestamp
=
System
.
currentTimeMillis
()
/
1000
;
String
nonceStr
=
UUID
.
randomUUID
().
toString
().
replace
(
"-"
,
""
);
String
signText
=
joining
(
"\n"
,
"POST"
,
properties
.
getPayAccess
(),
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
.
post
()
.
uri
(
properties
.
getPayAccess
())
.
header
(
"Authorization"
,
SCHEMA
.
concat
(
token
))
.
contentType
(
MediaType
.
APPLICATION_JSON
)
.
bodyValue
(
requestBody
).
exchange
();
ClientResponse
response
=
mono
.
block
();
ObjectMapper
objectMapper
=
new
ObjectMapper
();
JsonNode
bodyJsonNode
=
objectMapper
.
createObjectNode
();
if
(
response
!=
null
)
{
Mono
<
String
>
resultMono
=
response
.
bodyToMono
(
String
.
class
);
String
body
=
resultMono
.
block
();
try
{
bodyJsonNode
=
objectMapper
.
readTree
(
body
);
}
catch
(
JsonProcessingException
e
)
{
e
.
printStackTrace
();
}
if
(
response
.
statusCode
().
value
()
>=
200
&&
response
.
statusCode
().
value
()
<
300
)
{
//当前使用的微信平台证书序列号
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
,
resultMono
.
block
());
if
(
verify
(
wsSignText
,
signature
))
{
return
bodyJsonNode
;
}
// TODO: 签名校验失败,做异常处理
// throw new Exception("签名校验失败");
}
else
{
// TODO: 微信返回异常,做异常处理
// throw new Exception("微信返回异常,做异常处理");
}
}
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 separator 分隔符
* @param str 字符数组
* @return 字符串
*/
public
String
joining
(
String
separator
,
String
...
str
)
{
StringBuilder
builder
=
new
StringBuilder
();
for
(
String
s
:
str
)
{
if
(
s
==
null
||
s
.
length
()
==
0
)
{
continue
;
}
builder
.
append
(
s
).
append
(
separator
);
}
return
builder
.
toString
();
}
}
}
\ No newline at end of file
baa-pay-core/src/main/java/cn/quant/baa/pay/jpa/repository/PayHistoryRepository.java
View file @
82f0a880
...
@@ -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/service/TransactionService.java
View file @
82f0a880
...
@@ -9,6 +9,7 @@ import cn.quant.baa.pay.util.AssertUtils;
...
@@ -9,6 +9,7 @@ import cn.quant.baa.pay.util.AssertUtils;
import
cn.quant.baa.pay.model.web.GoodsDetail
;
import
cn.quant.baa.pay.model.web.GoodsDetail
;
import
cn.quant.baa.pay.acquirer.AcquirerProperties
;
import
cn.quant.baa.pay.acquirer.AcquirerProperties
;
import
cn.quant.baa.pay.model.web.PayRequestData
;
import
cn.quant.baa.pay.model.web.PayRequestData
;
import
com.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 +106,12 @@ public class TransactionService extends BusinessService {
...
@@ -105,15 +106,12 @@ 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
);
}
}
}
}
baa-pay-server/src/main/java/cn/quant/baa/pay/rest/TransactionController.java
View file @
82f0a880
...
@@ -5,6 +5,7 @@ import cn.quant.baa.pay.jpa.entity.PayHistoryEntity;
...
@@ -5,6 +5,7 @@ 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.PayRequestData
;
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,12 @@ public class TransactionController extends BusinessController {
...
@@ -22,11 +23,12 @@ 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
;
}
}
}
}
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