Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
H
hls-support-rlwx
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
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
rl
hls-support-rlwx
Commits
7b2af1cc
Commit
7b2af1cc
authored
Apr 21, 2022
by
胡建龙
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
20220415 未整理接口
parent
95a9ed4a
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
359 additions
and
8 deletions
+359
-8
pom.xml
core/pom.xml
+1
-0
HclcCmbPolyController.java
.../main/java/com/cmb/controllers/HclcCmbPolyController.java
+37
-0
HclcCmbPolyService.java
core/src/main/java/com/cmb/service/HclcCmbPolyService.java
+5
-0
HclcCmbPolyServiceImpl.java
...ain/java/com/cmb/service/impl/HclcCmbPolyServiceImpl.java
+207
-4
GenerateUtil.java
core/src/main/java/com/cmb/util/GenerateUtil.java
+90
-0
Pojo.java
core/src/main/java/com/cmb/util/Pojo.java
+5
-0
SignatureUtil.java
core/src/main/java/com/cmb/util/SignatureUtil.java
+14
-4
No files found.
core/pom.xml
View file @
7b2af1cc
...
...
@@ -264,6 +264,7 @@
<groupId>
org.bouncycastle
</groupId>
<artifactId>
bcprov-jdk15on
</artifactId>
<version>
1.65.01
</version>
<!-- <version>1.47</version>-->
<scope>
system
</scope>
<systemPath>
${project.basedir}/src/main/webapp/WEB-INF/lib/bcprov-jdk15on-1.65.01.jar
...
...
core/src/main/java/com/cmb/controllers/HclcCmbPolyController.java
View file @
7b2af1cc
...
...
@@ -22,6 +22,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import
org.springframework.web.bind.annotation.ResponseBody
;
import
javax.servlet.http.HttpServletRequest
;
import
java.util.Map
;
/*
* 〈〉
...
...
@@ -53,4 +54,40 @@ public class HclcCmbPolyController extends BaseController {
return
jsonResult
;
}
/**
* 主动请求订单状态结果
* @param request
* @param params
* @return
*/
@ResponseBody
@RequestMapping
(
"/cmb/poly/query/order/status"
)
public
JSONObject
queryOrderStatus
(
HttpServletRequest
request
,
@RequestBody
(
required
=
true
)
JSONObject
params
)
{
JSONObject
jsonResult
=
new
JSONObject
();
IRequest
iRequest
=
createRequestContext
(
request
);
jsonResult
=
hclcCmbPolyService
.
queryOrderStatus
(
iRequest
,
params
);
return
jsonResult
;
}
/**
* 暴露出去的回调地址,被动获取订单状态结果
* @param request
* @param params
* @return
*/
@ResponseBody
@RequestMapping
(
"/cmb/poly/order/notify"
)
public
Map
<
String
,
String
>
orderStatusNotify
(
HttpServletRequest
request
,
@RequestBody
(
required
=
true
)
JSONObject
params
)
{
IRequest
iRequest
=
createRequestContext
(
request
);
return
hclcCmbPolyService
.
orderNotify
(
iRequest
,
params
);
}
//订单关闭 4.7.1
}
\ No newline at end of file
core/src/main/java/com/cmb/service/HclcCmbPolyService.java
View file @
7b2af1cc
...
...
@@ -3,9 +3,14 @@ package com.cmb.service;
import
com.alibaba.fastjson.JSONObject
;
import
com.hand.hap.core.IRequest
;
import
java.util.Map
;
public
interface
HclcCmbPolyService
{
JSONObject
getQrcode
(
IRequest
iRequest
,
JSONObject
params
);
JSONObject
queryOrderStatus
(
IRequest
iRequest
,
JSONObject
params
);
Map
orderNotify
(
IRequest
iRequest
,
JSONObject
params
);
}
core/src/main/java/com/cmb/service/impl/HclcCmbPolyServiceImpl.java
View file @
7b2af1cc
...
...
@@ -2,10 +2,7 @@ package com.cmb.service.impl;
import
com.alibaba.fastjson.JSONObject
;
import
com.cmb.service.HclcCmbPolyService
;
import
com.cmb.util.MD5Utils
;
import
com.cmb.util.SM2Util
;
import
com.cmb.util.SignatureUtil
;
import
com.cmb.util.Utils
;
import
com.cmb.util.*
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.hand.hap.core.IRequest
;
import
org.springframework.beans.factory.annotation.Value
;
...
...
@@ -14,10 +11,14 @@ import org.springframework.stereotype.Service;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.TreeMap
;
import
java.util.stream.Collectors
;
@Service
public
class
HclcCmbPolyServiceImpl
implements
HclcCmbPolyService
{
private
static
final
String
url
=
"https://api.cmburl.cn:8065/polypay/v1.0/mchorders/qrcodeapply"
;
//UAT
//需要补充域名加端口==================================================================
private
static
final
String
notifyUrl
=
"/cmb/poly/order/notify"
;
//uat环境商户国密私钥
public
static
final
String
privateKey
=
"D5F2AFA24E6BA9071B54A8C9AD735F9A1DE9C4657FA386C09B592694BC118B38"
;
//uat环境招行国密公钥
...
...
@@ -39,6 +40,33 @@ public class HclcCmbPolyServiceImpl implements HclcCmbPolyService {
@Override
public
JSONObject
getQrcode
(
IRequest
iRequest
,
JSONObject
params
)
{
/*
版本号 version String(5) 是 固定为0.0.1
编码方式 encoding String(20) 是 固定为UTF-8
签名 sign String(1024) 是
签名方法 signMethod String(2) 是 02:SM2
商户号 merId String(32) 是 商户在招行完成商户进件后分配的招行商户号
商户订单号 orderId String(32) 是 商户端生成,要求此订单号在整个商户下唯一
收银员 userId String(32) 是 招行系统生成的收银员,每个收银员均会对应到一个门店。若商户无门店、收银员概念则上送默认的虚拟收银员即可。
终端号 termId String(8) 否 原则是可以通过交易上送的终端编号准确定位商户每一个门店内每一台收银设备,建议按“门店编号+收银机编号”或“设备编号”组成8位终端编号在交易中上送
支付有效时间 payValidTime String(10) 否 二维码的有效时长,单位为秒,若商户上送,则以商户上送值为准,否则使用默认有效时长1200秒
交易通知地址 notifyUrl String(256) 是 支付结果将送到本通知
交易金额 txnAmt String(13) 是 单位为分
交易币种 currencyCode String(3) 否 默认156,目前只支持人民币(156)
商品描述 body String(128) 否 用于展示支付宝账单详情中的“商品说明”和微信账单详情中的“商品”字段,若不上送则默认显示商户简称。
商户保留域 mchReserved String(128) 否 用于传输商户自定义数据,在支付结果查询和支付结果通知时原样返回(不上送则不返回此字段)
交易场景 tradeScene String(13) 是 OFFLINE:线下
ONLINE:线上
INSURANCE:保险
CHARITY:公益
PAYMENT: 缴费
SCHOOL:校园
商户门店号 mchStoreId String(32) 否 商户门店号
终端信息 terminalInfo String(6000) 否 商户侧受理终端信息,字段说明详见终端信息terminalInfo。
*/
JSONObject
result
=
new
JSONObject
();
Map
<
String
,
String
>
requestPublicParams
=
JSONObject
.
parseObject
(
params
.
toJSONString
(),
Map
.
class
);
...
...
@@ -109,6 +137,8 @@ public class HclcCmbPolyServiceImpl implements HclcCmbPolyService {
}
}
private
String
signMethod
(
Map
paramsMap
){
Map
<
String
,
String
>
requestPublicParams
=
new
TreeMap
<>();
String
requestStr
=
null
;
...
...
@@ -117,6 +147,7 @@ public class HclcCmbPolyServiceImpl implements HclcCmbPolyService {
requestPublicParams
.
put
(
"version"
,
version
);
//版本号,固定为0.0.1(必传字段)
requestPublicParams
.
put
(
"encoding"
,
encoding
);
//编码方式,固定为UTF-8(必传)
requestPublicParams
.
put
(
"signMethod"
,
signMethod
);
//签名方法,固定为02,表示签名方式为国密(必传)
requestPublicParams
.
put
(
"notifyUrl"
,
notifyUrl
);
// //业务要素
// Map<String, String> requestTransactionParams = new HashMap<>();
// requestTransactionParams.put("body", "聚合支付测试"); //商户号(必传)
...
...
@@ -173,4 +204,176 @@ public class HclcCmbPolyServiceImpl implements HclcCmbPolyService {
return
false
;
}
}
@Override
public
JSONObject
queryOrderStatus
(
IRequest
iRequest
,
JSONObject
params
)
{
JSONObject
result
=
new
JSONObject
();
final
String
url
=
"https://api.cmburl.cn:8065/polypay/v1.0/mchorders/orderquery"
;
//初始化请求报文
//实体类为商户传过来的一些参数,会封装作为biz_content部分
Pojo
pojo
=
new
Pojo
();
String
requestString
=
GenerateUtil
.
initRequestParam
(
pojo
);
try
{
ObjectMapper
objectMapper
=
new
ObjectMapper
();
Map
<
String
,
String
>
requestMap
=
objectMapper
.
readValue
(
requestString
,
Map
.
class
);
long
currentTimeMills
=
System
.
currentTimeMillis
()
/
1000
;
//对请求报文进行加密
Map
<
String
,
String
>
apiEncMap
=
new
HashMap
<>();
apiEncMap
.
put
(
"appid"
,
appId
);
apiEncMap
.
put
(
"secret"
,
appSecret
);
apiEncMap
.
put
(
"sign"
,
requestMap
.
get
(
"sign"
));
apiEncMap
.
put
(
"timestamp"
,
""
+
currentTimeMills
);
//MD5加密
String
MD5Content
=
SignatureUtil
.
getSignContent
(
apiEncMap
);
String
apiEncString
=
MD5Utils
.
getMD5Content
(
MD5Content
).
toLowerCase
();
//组请求报文头
Map
<
String
,
String
>
requstHeader
=
new
HashMap
<>();
requstHeader
.
put
(
"appid"
,
appId
);
requstHeader
.
put
(
"timestamp"
,
""
+
currentTimeMills
);
requstHeader
.
put
(
"apisign"
,
apiEncString
);
//发送http请求
Map
<
String
,
String
>
responseMap
=
Utils
.
postForEntity
(
url
,
requestString
,
requstHeader
);
//处理响应报文
GenerateUtil
.
handleResponse
(
responseMap
);
}
catch
(
Exception
ex
)
{
ex
.
printStackTrace
();
}
return
result
;
}
@Override
public
Map
<
String
,
String
>
orderNotify
(
IRequest
iRequest
,
JSONObject
params
)
{
/*
版本号 version String(5) 是 固定为0.0.1
编码方式 encoding String(20) 是 固定为UTF-8
签名 sign String(1024) 是
签名方法 signMethod String(2) 是 02:SM2
商户号 merId String(32) 是 商户在招行完成商户进件后分配的招行商户号
商户订单号 orderId String(32) 是 支付交易的商户订单号
平台订单号 cmbOrderId String(32) 是 招行生成的订单号
收银员 userId String(32) 否 支付交易的收银员信息,若有,则返回
交易金额 txnAmt String(13) 是 单位为分
优惠金额 dscAmt String(13) 是 单位为分
银联优惠信息 couponInfo String(500) 否 银联通道且有优惠活动时出现,字段说明详见2.6优惠信息字段说明
订单原始金额 orderOrigAmt String(13) 否 单位为分,请求上送orderOrigAmt则对应返回该内容
订单优惠金额 orderCouponAmt String(13) 否 单位为分,请求上送orderCouponAmt则对应返回该内容
优惠券信息 promotionDetail String 否 微信、支付宝优惠券信息,规则见2.6优惠信息字段说明
交易币种 currencyCode String(3) 是 目前只支持人民币(156)
支付方式 payType String(2) 是 目前支持:支付宝/微信/银联
ZF:支付宝
WX:微信
YL:银联
用户标识 openId String(128) 否 支付宝支付:用户在支付宝系统的唯一标识
微信支付:商户上送sub_appid时返回用户在sub_appid下的sub_openid
付款银行 payBank String(32) 否 支付宝支付:
ALIPAYACCOUNT 支付宝账户
PCREDIT 蚂蚁花呗
DEBIT_CARD 借记卡
CREDIT_CARD 信用卡
MIXED_CARD 借贷合一卡 等
微信支付:CMB_CREDIT 等
第三方订单号 thirdOrderId String(64) 否 支付宝、微信侧的订单号
支付宝账户 buyerLogonId String(64) 否 支付宝支付的交易返回,如:koh***@sandbox.com
订单发送时间 txnTime String(14) 是 支付订单生成的时间,格式为yyyyMMddHHmmss
订单完成日期 endDate String(8) 否 第三方系统返回的交易完成日期,此日期仅在交易成功是返回,不保证是实际清算日期,格式为yyyyMMdd
订单完成时间 endTime String(6) 否 第三方系统返回的交易完成时间,此时间仅在交易成功是返回,格式为HHmmss
支付宝和微信通道的成功交易返回此字段
银联通道的交易无论成功与否,均不返回此字段
商户保留域 mchReserved String(128) 否 若原交易有上送此字段,则返回此字段
*/
JSONObject
result
=
new
JSONObject
();
System
.
out
.
println
(
params
);
String
requestBodyString
=
params
.
toJSONString
();
Map
<
String
,
String
>
respData
=
new
HashMap
<>();
/*
版本号 version String(5) 是 固定为0.0.1
编码方式 encoding String(20) 是 固定为UTF-8
签名 sign String(1024) 是
签名方法 signMethod String(2) 是 02:SM2
返回码 returnCode String(7) 是 SUCCESS/FAIL,SUCCESS表示商户接收通知成功并校验成功
以下字段仅在returnCode为SUCCESS时返回
响应码 respCode String(10) 是 商户返回的业务错误码,成功为SUCCESS,失败为FAIL
应答信息 respMsg String(256) 否 请求处理失败的详细描述信息
*/
//设置响应数据
respData
.
put
(
"version"
,
"0.0.1"
);
//版本号,固定为0.0.1(必传)
respData
.
put
(
"encoding"
,
"UTF-8"
);
//编码方式,固定为UTF-8(必传)
respData
.
put
(
"signMethod"
,
"02"
);
//签名方法,固定为02,国密
try
{
respData
.
put
(
"returnCode"
,
"SUCCESS"
);
//SUCCESS表示商户接收通知成功并校验成功
//非空校验
if
(
requestBodyString
==
null
||
""
.
equals
(
requestBodyString
.
trim
()))
{
respData
.
put
(
"returnCode"
,
"FAIL"
);
return
respData
;
}
Map
<
String
,
String
>
requestBodyMap
=
str2Map
(
requestBodyString
);
Map
<
String
,
String
>
resultMap
=
requestBodyMap
.
entrySet
().
stream
().
collect
(
Collectors
.
toMap
(
e
->
SignatureUtil
.
decode
(
e
.
getKey
()),
e
->
SignatureUtil
.
decode
(
e
.
getValue
())));
if
(
resultMap
==
null
)
{
respData
.
put
(
"returnCode"
,
"FAIL"
);
return
respData
;
}
String
sign
=
resultMap
.
remove
(
"sign"
);
//对待加签内容进行排序拼接
String
contentStr
=
SignatureUtil
.
getSignContent
(
resultMap
);
//验证签名-使用招行公钥进行验签
boolean
flag
=
SM2Util
.
sm2Check
(
contentStr
,
sign
,
publicKey
);
if
(!
flag
)
{
//验签失败
System
.
out
.
println
(
"验签失败"
);
respData
.
put
(
"returnCode"
,
"FAIL"
);
return
respData
;
}
System
.
out
.
println
(
"验签成功"
);
//......(处理自身业务逻辑)
//......
//......
respData
.
put
(
"respCode"
,
"SUCCESS"
);
//业务错误码,成功为SUCCESS,失败为FAIL
/*如果处理自身业务逻辑发生错误,返回
respData.put("respCode","FAIL");
respData.put("respMsg","error_msg");
*/
//对待加签内容进行排序拼接
String
signContent
=
SignatureUtil
.
getSignContent
(
respData
);
//加签-使用商户私钥加签
respData
.
put
(
"sign"
,
SM2Util
.
sm2Sign
(
signContent
,
privateKey
));
System
.
out
.
println
(
"加签成功"
);
return
respData
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
respData
.
put
(
"returnCode"
,
"FAIL"
);
return
respData
;
}
}
private
Map
<
String
,
String
>
str2Map
(
String
str
)
{
Map
<
String
,
String
>
result
=
new
HashMap
<>();
String
[]
results
=
str
.
split
(
"&"
);
if
(
results
!=
null
&&
results
.
length
>
0
)
{
for
(
int
var
=
0
;
var
<
results
.
length
;
++
var
)
{
String
pair
=
results
[
var
];
String
[]
kv
=
pair
.
split
(
"="
,
2
);
if
(
kv
!=
null
&&
kv
.
length
==
2
)
{
result
.
put
(
kv
[
0
],
kv
[
1
]);
}
}
}
return
result
;
}
}
core/src/main/java/com/cmb/util/GenerateUtil.java
0 → 100644
View file @
7b2af1cc
package
com
.
cmb
.
util
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
org.apache.log4j.Logger
;
import
org.springframework.beans.factory.annotation.Value
;
import
java.util.HashMap
;
import
java.util.Map
;
//构造请求报文工具类
public
class
GenerateUtil
{
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
GenerateUtil
.
class
);
@Value
(
"${cmb.version}"
)
private
static
String
version
;
@Value
(
"${cmb.encoding}"
)
private
static
String
encoding
;
@Value
(
"${cmb.signMethod}"
)
private
static
String
signMethod
;
public
static
final
String
privateKey
=
"D5F2AFA24E6BA9071B54A8C9AD735F9A1DE9C4657FA386C09B592694BC118B38"
;
public
static
final
String
publicKey
=
"MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE6Q+fktsnY9OFP+LpSR5Udbxf5zHCFO0PmOKlFNTxDIGl8jsPbbB/9ET23NV+acSz4FEkzD74sW2iiNVHRLiKHg=="
;
public
static
String
initRequestParam
(
Pojo
pojo
){
//设置公共请求参数
Map
<
String
,
String
>
resultPublicParam
=
new
HashMap
<>();
resultPublicParam
.
put
(
"version"
,
version
);
resultPublicParam
.
put
(
"encoding"
,
encoding
);
resultPublicParam
.
put
(
"sign_method"
,
signMethod
);
//初始化业务请求参数
try
{
ObjectMapper
objectMapper
=
new
ObjectMapper
();
String
bizContent
=
objectMapper
.
writeValueAsString
(
pojo
);
System
.
out
.
println
(
bizContent
);
resultPublicParam
.
put
(
"biz_content"
,
bizContent
);
//对待加签内容进行排序拼接
String
signStr
=
SignatureUtil
.
getSignContent
(
resultPublicParam
);
//加签
String
sign
=
SM2Util
.
sm2Sign
(
signStr
,
privateKey
);
resultPublicParam
.
put
(
"sign"
,
sign
);
String
requestStr
=
objectMapper
.
writeValueAsString
(
resultPublicParam
);
LOGGER
.
info
(
"加签后的报文内容:"
+
requestStr
);
return
requestStr
;
}
catch
(
Exception
ex
){
ex
.
printStackTrace
();
return
null
;
}
}
/**
* 处理响应报文
* @param responseMap
* @return
*/
public
static
void
handleResponse
(
Map
<
String
,
String
>
responseMap
){
if
(
null
==
responseMap
){
LOGGER
.
equals
(
"响应的内容为空"
);
return
;
}
try
{
ObjectMapper
objectMapper
=
new
ObjectMapper
();
LOGGER
.
info
(
"收到响应的内容为:"
+
objectMapper
.
writeValueAsString
(
responseMap
));
//验签
String
sign
=
responseMap
.
remove
(
"sign"
);
//生成验签字符串
String
signStr
=
SignatureUtil
.
getSignContent
(
responseMap
);
boolean
flag
=
SM2Util
.
sm2Check
(
signStr
,
sign
,
publicKey
);
if
(
flag
){
LOGGER
.
info
(
"验签成功!"
);
}
else
{
LOGGER
.
error
(
"验签失败!"
);
}
return
;
}
catch
(
Exception
ex
){
LOGGER
.
equals
(
"系统异常"
);
return
;
}
}
}
core/src/main/java/com/cmb/util/Pojo.java
0 → 100644
View file @
7b2af1cc
package
com
.
cmb
.
util
;
public
class
Pojo
{
public
Pojo
(){}
}
core/src/main/java/com/cmb/util/SignatureUtil.java
View file @
7b2af1cc
...
...
@@ -5,10 +5,8 @@ package com.cmb.util;
import
org.apache.commons.codec.binary.Base64
;
import
java.io.ByteArrayInputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStreamReader
;
import
java.io.*
;
import
java.net.URLDecoder
;
import
java.nio.charset.Charset
;
import
java.security.KeyFactory
;
import
java.security.PrivateKey
;
...
...
@@ -87,6 +85,18 @@ public class SignatureUtil {
return
content
.
toString
();
}
public
static
String
decode
(
String
str
)
{
String
result
=
null
;
if
(
str
!=
null
)
{
try
{
result
=
URLDecoder
.
decode
(
str
,
"UTF-8"
);
}
catch
(
UnsupportedEncodingException
var4
)
{
throw
new
RuntimeException
(
var4
);
}
}
return
result
;
}
public
static
boolean
rsaCheck
(
String
content
,
String
sign
,
String
publicKey
,
String
charset
)
throws
Exception
{
try
{
PublicKey
pubKey
=
getPublicKeyFromX509
(
"RSA"
,
new
ByteArrayInputStream
(
publicKey
.
getBytes
()));
...
...
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