Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
customer-service
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
Packages
Packages
Container Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
SuperHive
back-end
customer-service
Commits
4f9a20eb
Commit
4f9a20eb
authored
Jun 04, 2020
by
huangcb
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
增加货主支付功能
parent
802de6d9
Changes
40
Show whitespace changes
Inline
Side-by-side
Showing
40 changed files
with
6329 additions
and
119 deletions
+6329
-119
pom.xml
pom.xml
+1
-2
ApplicationLoadRunner.java
...ight/customer/common/component/ApplicationLoadRunner.java
+19
-2
ErrorMessageComponent.java
...ight/customer/common/component/ErrorMessageComponent.java
+3
-0
SDKConstants.java
...m/esv/freight/customer/common/constants/SDKConstants.java
+378
-0
RestLogFilter.java
...com/esv/freight/customer/common/filter/RestLogFilter.java
+3
-54
AppUnionPayOrderReq.java
...esv/freight/customer/common/pojo/AppUnionPayOrderReq.java
+43
-0
AppUnionPayOrderRes.java
...esv/freight/customer/common/pojo/AppUnionPayOrderRes.java
+35
-0
AcpService.java
.../com/esv/freight/customer/common/unionpay/AcpService.java
+702
-0
BaseHttpSSLSocketFactory.java
...ht/customer/common/unionpay/BaseHttpSSLSocketFactory.java
+107
-0
CertUtil.java
...va/com/esv/freight/customer/common/unionpay/CertUtil.java
+755
-0
DemoBase.java
...va/com/esv/freight/customer/common/unionpay/DemoBase.java
+218
-0
HttpClient.java
.../com/esv/freight/customer/common/unionpay/HttpClient.java
+294
-0
SDKConfig.java
...a/com/esv/freight/customer/common/unionpay/SDKConfig.java
+952
-0
SDKUtil.java
...ava/com/esv/freight/customer/common/unionpay/SDKUtil.java
+816
-0
SecureUtil.java
.../com/esv/freight/customer/common/unionpay/SecureUtil.java
+528
-0
UnionPayComponent.java
...v/freight/customer/common/unionpay/UnionPayComponent.java
+202
-0
MapUtils.java
...n/java/com/esv/freight/customer/common/util/MapUtils.java
+37
-0
ReqUtils.java
...n/java/com/esv/freight/customer/common/util/ReqUtils.java
+66
-0
ResUtils.java
...n/java/com/esv/freight/customer/common/util/ResUtils.java
+57
-0
ServletConfig.java
...n/java/com/esv/freight/customer/config/ServletConfig.java
+42
-0
FreightBillService.java
...va/com/esv/freight/customer/feign/FreightBillService.java
+28
-0
PayConstants.java
...ava/com/esv/freight/customer/module/pay/PayConstants.java
+36
-0
PayController.java
...freight/customer/module/pay/controller/PayController.java
+98
-0
CustomerUnionpayOrderDao.java
...ght/customer/module/pay/dao/CustomerUnionpayOrderDao.java
+28
-0
CustomerUnionpayOrderEntity.java
...stomer/module/pay/entity/CustomerUnionpayOrderEntity.java
+21
-20
CustomerPayOrderForm.java
...reight/customer/module/pay/form/CustomerPayOrderForm.java
+49
-0
UnionPayOrderQueryForm.java
...ight/customer/module/pay/form/UnionPayOrderQueryForm.java
+36
-0
GoodsOwnerPayOrderService.java
...ustomer/module/pay/service/GoodsOwnerPayOrderService.java
+0
-16
UnionpayOrderService.java
...ght/customer/module/pay/service/UnionpayOrderService.java
+73
-0
GoodsOwnerPayOrderServiceImpl.java
...odule/pay/service/impl/GoodsOwnerPayOrderServiceImpl.java
+0
-14
UnionpayOrderServiceImpl.java
...mer/module/pay/service/impl/UnionpayOrderServiceImpl.java
+191
-0
AppFrontRcvServlet.java
...v/freight/customer/module/servlet/AppFrontRcvServlet.java
+64
-0
UnionpayBackRcvServlet.java
...eight/customer/module/servlet/UnionpayBackRcvServlet.java
+102
-0
acp_sdk.properties
src/main/resources/acp_sdk.properties
+68
-0
acp_sdk_dev.properties
src/main/resources/acp_sdk_dev.properties
+68
-0
application-dev.yml
src/main/resources/application-dev.yml
+13
-2
application-test.yml
src/main/resources/application-test.yml
+13
-2
CustomerUnionpayOrderDao.xml
src/main/resources/mapper/pay/CustomerUnionpayOrderDao.xml
+13
-7
UnionPayComponentTest.java
...eight/customer/common/unionpay/UnionPayComponentTest.java
+46
-0
PayControllerTest.java
...ght/customer/module/pay/controller/PayControllerTest.java
+124
-0
No files found.
pom.xml
View file @
4f9a20eb
...
...
@@ -181,8 +181,7 @@
<directory>
src/main/resources
</directory>
<excludes>
<exclude>
*.yml
</exclude>
<exclude>
application*.properties
</exclude>
<exclude>
bootstrap.properties
</exclude>
<exclude>
*.properties
</exclude>
<exclude>
logback-spring.xml
</exclude>
</excludes>
<filtering>
true
</filtering>
...
...
src/main/java/com/esv/freight/customer/common/component/ApplicationLoadRunner.java
View file @
4f9a20eb
...
...
@@ -23,11 +23,28 @@ public class ApplicationLoadRunner implements ApplicationRunner {
@Value
(
"${spring.application.name}"
)
private
String
applicationName
;
@Value
(
"${spring.profiles.active}"
)
private
String
profilesActive
;
@Value
(
"${unionpay.acp-sdk.properties.path}"
)
private
String
acpSdkPropertiesPath
;
@Override
public
void
run
(
ApplicationArguments
var
)
{
log
.
info
(
"-------------------- [{}]初始化完成 --------------------"
,
applicationName
);
// 从classpath加载acp_sdk.properties文件
// 初始化银联配置文件
initUnionpayProperties
();
}
/**
* 初始化银联配置文件
**/
private
void
initUnionpayProperties
()
{
if
(
"dev"
.
equals
(
profilesActive
))
{
SDKConfig
.
getConfig
().
loadPropertiesFromSrc
();
}
else
{
SDKConfig
.
getConfig
().
loadPropertiesFromPath
(
acpSdkPropertiesPath
);
}
}
}
src/main/java/com/esv/freight/customer/common/component/ErrorMessageComponent.java
View file @
4f9a20eb
...
...
@@ -322,4 +322,7 @@ public class ErrorMessageComponent {
@Value
(
"${error-message.contract.online.get-by-number.1001}"
)
private
String
contractOnlineGetByNumber1001
;
@Value
(
"${error-message.pay.customer.order.create.1001}"
)
private
String
payCustomerOrderCreate1001
;
}
src/main/java/com/esv/freight/customer/common/constants/SDKConstants.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
common
.
constants
;
/**
* @description: 银联支付:acpsdk常量类
* @project: freight-customer-service
* @name: com.esv.freight.customer.common.constants.SDKConstants
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/05/30 14:12
* @version:1.0
*/
public
class
SDKConstants
{
public
final
static
String
COLUMN_DEFAULT
=
"-"
;
public
final
static
String
KEY_DELIMITER
=
"#"
;
/** memeber variable: blank. */
public
static
final
String
BLANK
=
""
;
/** member variabel: space. */
public
static
final
String
SPACE
=
" "
;
/** memeber variable: unline. */
public
static
final
String
UNLINE
=
"_"
;
/** memeber varibale: star. */
public
static
final
String
STAR
=
"*"
;
/** memeber variable: line. */
public
static
final
String
LINE
=
"-"
;
/** memeber variable: add. */
public
static
final
String
ADD
=
"+"
;
/** memeber variable: colon. */
public
final
static
String
COLON
=
"|"
;
/** memeber variable: point. */
public
final
static
String
POINT
=
"."
;
/** memeber variable: comma. */
public
final
static
String
COMMA
=
","
;
/** memeber variable: slash. */
public
final
static
String
SLASH
=
"/"
;
/** memeber variable: div. */
public
final
static
String
DIV
=
"/"
;
/** memeber variable: left . */
public
final
static
String
LB
=
"("
;
/** memeber variable: right. */
public
final
static
String
RB
=
")"
;
/** memeber variable: rmb. */
public
final
static
String
CUR_RMB
=
"RMB"
;
/** memeber variable: .page size */
public
static
final
int
PAGE_SIZE
=
10
;
/** memeber variable: String ONE. */
public
static
final
String
ONE
=
"1"
;
/** memeber variable: String ZERO. */
public
static
final
String
ZERO
=
"0"
;
/** memeber variable: number six. */
public
static
final
int
NUM_SIX
=
6
;
/** memeber variable: equal mark. */
public
static
final
String
EQUAL
=
"="
;
/** memeber variable: operation ne. */
public
static
final
String
NE
=
"!="
;
/** memeber variable: operation le. */
public
static
final
String
LE
=
"<="
;
/** memeber variable: operation ge. */
public
static
final
String
GE
=
">="
;
/** memeber variable: operation lt. */
public
static
final
String
LT
=
"<"
;
/** memeber variable: operation gt. */
public
static
final
String
GT
=
">"
;
/** memeber variable: list separator. */
public
static
final
String
SEP
=
"./"
;
/** memeber variable: Y. */
public
static
final
String
Y
=
"Y"
;
/** memeber variable: AMPERSAND. */
public
static
final
String
AMPERSAND
=
"&"
;
/** memeber variable: SQL_LIKE_TAG. */
public
static
final
String
SQL_LIKE_TAG
=
"%"
;
/** memeber variable: @. */
public
static
final
String
MAIL
=
"@"
;
/** memeber variable: number zero. */
public
static
final
int
NZERO
=
0
;
public
static
final
String
LEFT_BRACE
=
"{"
;
public
static
final
String
RIGHT_BRACE
=
"}"
;
/** memeber variable: string true. */
public
static
final
String
TRUE_STRING
=
"true"
;
/** memeber variable: string false. */
public
static
final
String
FALSE_STRING
=
"false"
;
/** memeber variable: forward success. */
public
static
final
String
SUCCESS
=
"success"
;
/** memeber variable: forward fail. */
public
static
final
String
FAIL
=
"fail"
;
/** memeber variable: global forward success. */
public
static
final
String
GLOBAL_SUCCESS
=
"$success"
;
/** memeber variable: global forward fail. */
public
static
final
String
GLOBAL_FAIL
=
"$fail"
;
public
static
final
String
UTF_8_ENCODING
=
"UTF-8"
;
public
static
final
String
GBK_ENCODING
=
"GBK"
;
public
static
final
String
CONTENT_TYPE
=
"Content-type"
;
public
static
final
String
APP_XML_TYPE
=
"application/xml;charset=utf-8"
;
public
static
final
String
APP_FORM_TYPE
=
"application/x-www-form-urlencoded;charset="
;
public
static
final
String
VERSION_1_0_0
=
"1.0.0"
;
public
static
final
String
VERSION_5_0_0
=
"5.0.0"
;
public
static
final
String
VERSION_5_0_1
=
"5.0.1"
;
public
static
final
String
VERSION_5_1_0
=
"5.1.0"
;
public
static
final
String
SIGNMETHOD_RSA
=
"01"
;
public
static
final
String
SIGNMETHOD_SHA256
=
"11"
;
public
static
final
String
SIGNMETHOD_SM3
=
"12"
;
public
static
final
String
UNIONPAY_CNNAME
=
"中国银联股份有限公司"
;
public
static
final
String
CERTTYPE_01
=
"01"
;
// 敏感信息加密公钥
public
static
final
String
CERTTYPE_02
=
"02"
;
// 磁道加密公钥
/******************************************** 5.0报文接口定义 ********************************************/
/** 版本号. */
public
static
final
String
param_version
=
"version"
;
/** 证书ID. */
public
static
final
String
param_certId
=
"certId"
;
/** 签名. */
public
static
final
String
param_signature
=
"signature"
;
/** 签名方法. */
public
static
final
String
param_signMethod
=
"signMethod"
;
/** 编码方式. */
public
static
final
String
param_encoding
=
"encoding"
;
/** 交易类型. */
public
static
final
String
param_txnType
=
"txnType"
;
/** 交易子类. */
public
static
final
String
param_txnSubType
=
"txnSubType"
;
/** 业务类型. */
public
static
final
String
param_bizType
=
"bizType"
;
/** 前台通知地址 . */
public
static
final
String
param_frontUrl
=
"frontUrl"
;
/** 后台通知地址. */
public
static
final
String
param_backUrl
=
"backUrl"
;
/** 接入类型. */
public
static
final
String
param_accessType
=
"accessType"
;
/** 收单机构代码. */
public
static
final
String
param_acqInsCode
=
"acqInsCode"
;
/** 商户类别. */
public
static
final
String
param_merCatCode
=
"merCatCode"
;
/** 商户类型. */
public
static
final
String
param_merType
=
"merType"
;
/** 商户代码. */
public
static
final
String
param_merId
=
"merId"
;
/** 商户名称. */
public
static
final
String
param_merName
=
"merName"
;
/** 商户简称. */
public
static
final
String
param_merAbbr
=
"merAbbr"
;
/** 二级商户代码. */
public
static
final
String
param_subMerId
=
"subMerId"
;
/** 二级商户名称. */
public
static
final
String
param_subMerName
=
"subMerName"
;
/** 二级商户简称. */
public
static
final
String
param_subMerAbbr
=
"subMerAbbr"
;
/** Cupsecure 商户代码. */
public
static
final
String
param_csMerId
=
"csMerId"
;
/** 商户订单号. */
public
static
final
String
param_orderId
=
"orderId"
;
/** 交易时间. */
public
static
final
String
param_txnTime
=
"txnTime"
;
/** 发送时间. */
public
static
final
String
param_txnSendTime
=
"txnSendTime"
;
/** 订单超时时间间隔. */
public
static
final
String
param_orderTimeoutInterval
=
"orderTimeoutInterval"
;
/** 支付超时时间. */
public
static
final
String
param_payTimeoutTime
=
"payTimeoutTime"
;
/** 默认支付方式. */
public
static
final
String
param_defaultPayType
=
"defaultPayType"
;
/** 支持支付方式. */
public
static
final
String
param_supPayType
=
"supPayType"
;
/** 支付方式. */
public
static
final
String
param_payType
=
"payType"
;
/** 自定义支付方式. */
public
static
final
String
param_customPayType
=
"customPayType"
;
/** 物流标识. */
public
static
final
String
param_shippingFlag
=
"shippingFlag"
;
/** 收货地址-国家. */
public
static
final
String
param_shippingCountryCode
=
"shippingCountryCode"
;
/** 收货地址-省. */
public
static
final
String
param_shippingProvinceCode
=
"shippingProvinceCode"
;
/** 收货地址-市. */
public
static
final
String
param_shippingCityCode
=
"shippingCityCode"
;
/** 收货地址-地区. */
public
static
final
String
param_shippingDistrictCode
=
"shippingDistrictCode"
;
/** 收货地址-详细. */
public
static
final
String
param_shippingStreet
=
"shippingStreet"
;
/** 商品总类. */
public
static
final
String
param_commodityCategory
=
"commodityCategory"
;
/** 商品名称. */
public
static
final
String
param_commodityName
=
"commodityName"
;
/** 商品URL. */
public
static
final
String
param_commodityUrl
=
"commodityUrl"
;
/** 商品单价. */
public
static
final
String
param_commodityUnitPrice
=
"commodityUnitPrice"
;
/** 商品数量. */
public
static
final
String
param_commodityQty
=
"commodityQty"
;
/** 是否预授权. */
public
static
final
String
param_isPreAuth
=
"isPreAuth"
;
/** 币种. */
public
static
final
String
param_currencyCode
=
"currencyCode"
;
/** 账户类型. */
public
static
final
String
param_accType
=
"accType"
;
/** 账号. */
public
static
final
String
param_accNo
=
"accNo"
;
/** 支付卡类型. */
public
static
final
String
param_payCardType
=
"payCardType"
;
/** 发卡机构代码. */
public
static
final
String
param_issInsCode
=
"issInsCode"
;
/** 持卡人信息. */
public
static
final
String
param_customerInfo
=
"customerInfo"
;
/** 交易金额. */
public
static
final
String
param_txnAmt
=
"txnAmt"
;
/** 余额. */
public
static
final
String
param_balance
=
"balance"
;
/** 地区代码. */
public
static
final
String
param_districtCode
=
"districtCode"
;
/** 附加地区代码. */
public
static
final
String
param_additionalDistrictCode
=
"additionalDistrictCode"
;
/** 账单类型. */
public
static
final
String
param_billType
=
"billType"
;
/** 账单号码. */
public
static
final
String
param_billNo
=
"billNo"
;
/** 账单月份. */
public
static
final
String
param_billMonth
=
"billMonth"
;
/** 账单查询要素. */
public
static
final
String
param_billQueryInfo
=
"billQueryInfo"
;
/** 账单详情. */
public
static
final
String
param_billDetailInfo
=
"billDetailInfo"
;
/** 账单金额. */
public
static
final
String
param_billAmt
=
"billAmt"
;
/** 账单金额符号. */
public
static
final
String
param_billAmtSign
=
"billAmtSign"
;
/** 绑定标识号. */
public
static
final
String
param_bindId
=
"bindId"
;
/** 风险级别. */
public
static
final
String
param_riskLevel
=
"riskLevel"
;
/** 绑定信息条数. */
public
static
final
String
param_bindInfoQty
=
"bindInfoQty"
;
/** 绑定信息集. */
public
static
final
String
param_bindInfoList
=
"bindInfoList"
;
/** 批次号. */
public
static
final
String
param_batchNo
=
"batchNo"
;
/** 总笔数. */
public
static
final
String
param_totalQty
=
"totalQty"
;
/** 总金额. */
public
static
final
String
param_totalAmt
=
"totalAmt"
;
/** 文件类型. */
public
static
final
String
param_fileType
=
"fileType"
;
/** 文件名称. */
public
static
final
String
param_fileName
=
"fileName"
;
/** 批量文件内容. */
public
static
final
String
param_fileContent
=
"fileContent"
;
/** 商户摘要. */
public
static
final
String
param_merNote
=
"merNote"
;
/** 商户自定义域. */
// public static final String param_merReserved = "merReserved";//接口变更删除
/** 请求方保留域. */
public
static
final
String
param_reqReserved
=
"reqReserved"
;
// 新增接口
/** 保留域. */
public
static
final
String
param_reserved
=
"reserved"
;
/** 终端号. */
public
static
final
String
param_termId
=
"termId"
;
/** 终端类型. */
public
static
final
String
param_termType
=
"termType"
;
/** 交互模式. */
public
static
final
String
param_interactMode
=
"interactMode"
;
/** 发卡机构识别模式. */
// public static final String param_recognitionMode = "recognitionMode";
public
static
final
String
param_issuerIdentifyMode
=
"issuerIdentifyMode"
;
// 接口名称变更
/** 商户端用户号. */
public
static
final
String
param_merUserId
=
"merUserId"
;
/** 持卡人IP. */
public
static
final
String
param_customerIp
=
"customerIp"
;
/** 查询流水号. */
public
static
final
String
param_queryId
=
"queryId"
;
/** 原交易查询流水号. */
public
static
final
String
param_origQryId
=
"origQryId"
;
/** 系统跟踪号. */
public
static
final
String
param_traceNo
=
"traceNo"
;
/** 交易传输时间. */
public
static
final
String
param_traceTime
=
"traceTime"
;
/** 清算日期. */
public
static
final
String
param_settleDate
=
"settleDate"
;
/** 清算币种. */
public
static
final
String
param_settleCurrencyCode
=
"settleCurrencyCode"
;
/** 清算金额. */
public
static
final
String
param_settleAmt
=
"settleAmt"
;
/** 清算汇率. */
public
static
final
String
param_exchangeRate
=
"exchangeRate"
;
/** 兑换日期. */
public
static
final
String
param_exchangeDate
=
"exchangeDate"
;
/** 响应时间. */
public
static
final
String
param_respTime
=
"respTime"
;
/** 原交易应答码. */
public
static
final
String
param_origRespCode
=
"origRespCode"
;
/** 原交易应答信息. */
public
static
final
String
param_origRespMsg
=
"origRespMsg"
;
/** 应答码. */
public
static
final
String
param_respCode
=
"respCode"
;
/** 应答码信息. */
public
static
final
String
param_respMsg
=
"respMsg"
;
// 新增四个报文字段merUserRegDt merUserEmail checkFlag activateStatus
/** 商户端用户注册时间. */
public
static
final
String
param_merUserRegDt
=
"merUserRegDt"
;
/** 商户端用户注册邮箱. */
public
static
final
String
param_merUserEmail
=
"merUserEmail"
;
/** 验证标识. */
public
static
final
String
param_checkFlag
=
"checkFlag"
;
/** 开通状态. */
public
static
final
String
param_activateStatus
=
"activateStatus"
;
/** 加密证书ID. */
public
static
final
String
param_encryptCertId
=
"encryptCertId"
;
/** 用户MAC、IMEI串号、SSID. */
public
static
final
String
param_userMac
=
"userMac"
;
/** 关联交易. */
// public static final String param_relationTxnType = "relationTxnType";
/** 短信类型 */
public
static
final
String
param_smsType
=
"smsType"
;
/** 风控信息域 */
public
static
final
String
param_riskCtrlInfo
=
"riskCtrlInfo"
;
/** IC卡交易信息域 */
public
static
final
String
param_ICTransData
=
"ICTransData"
;
/** VPC交易信息域 */
public
static
final
String
param_VPCTransData
=
"VPCTransData"
;
/** 安全类型 */
public
static
final
String
param_securityType
=
"securityType"
;
/** 银联订单号 */
public
static
final
String
param_tn
=
"tn"
;
/** 分期付款手续费率 */
public
static
final
String
param_instalRate
=
"instalRate"
;
/** 分期付款手续费率 */
public
static
final
String
param_mchntFeeSubsidy
=
"mchntFeeSubsidy"
;
/** 签名公钥证书 */
public
static
final
String
param_signPubKeyCert
=
"signPubKeyCert"
;
/** 加密公钥证书 */
public
static
final
String
param_encryptPubKeyCert
=
"encryptPubKeyCert"
;
/** 证书类型 */
public
static
final
String
param_certType
=
"certType"
;
}
src/main/java/com/esv/freight/customer/common/filter/RestLogFilter.java
View file @
4f9a20eb
...
...
@@ -10,11 +10,9 @@ import lombok.extern.slf4j.Slf4j;
import
javax.servlet.*
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.
*
;
import
java.
nio.charset.Charset
;
import
java.io.
IOException
;
import
java.
io.UnsupportedEncodingException
;
import
java.util.Enumeration
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* @description: Rest请求日志Filter
...
...
@@ -55,55 +53,6 @@ public class RestLogFilter implements Filter {
this
.
logRes
(
requestWrapper
,
responseWrapper
);
}
/**
* 获取请求返回体
**/
private
String
getPostBodyStr
(
HttpServletRequest
request
)
{
String
bodyStr
=
null
;
StringBuilder
sb
=
new
StringBuilder
();
InputStream
inputStream
=
null
;
BufferedReader
reader
=
null
;
try
{
inputStream
=
request
.
getInputStream
();
reader
=
new
BufferedReader
(
new
InputStreamReader
(
inputStream
,
Charset
.
forName
(
CommonConstants
.
DEFAULT_CHARACTER_ENCODING
)));
String
line
=
""
;
while
((
line
=
reader
.
readLine
())
!=
null
)
{
sb
.
append
(
line
);
}
if
(
0
==
sb
.
length
())
{
Map
<
String
,
String
>
bodyMap
=
new
HashMap
<>();
Map
<
String
,
String
[]>
parameterMap
=
request
.
getParameterMap
();
for
(
Map
.
Entry
<
String
,
String
[]>
entry
:
parameterMap
.
entrySet
())
{
for
(
String
value
:
entry
.
getValue
())
{
bodyMap
.
put
(
entry
.
getKey
(),
value
);
}
}
bodyStr
=
bodyMap
.
toString
();
}
else
{
bodyStr
=
sb
.
toString
();
}
}
catch
(
IOException
e
)
{
log
.
error
(
"解析post参数时发生错误:{}"
,
e
.
getMessage
(),
e
);
}
finally
{
if
(
inputStream
!=
null
)
{
try
{
inputStream
.
close
();
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
}
if
(
reader
!=
null
)
{
try
{
reader
.
close
();
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
}
}
return
bodyStr
;
}
/**
* 日志输出请求体
**/
...
...
@@ -122,7 +71,7 @@ public class RestLogFilter implements Filter {
}
reqBody
=
reqBody
.
replaceFirst
(
"&"
,
""
);
}
else
if
(
CommonConstants
.
HTTP_REQUEST_METHOD_POST
.
equalsIgnoreCase
(
method
))
{
reqBody
=
this
.
getPostBodyStr
(
requestWrapper
);
reqBody
=
ReqUtils
.
getPostBody
(
requestWrapper
);
}
// 请求体日志截取
...
...
src/main/java/com/esv/freight/customer/common/pojo/AppUnionPayOrderReq.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
common
.
pojo
;
import
lombok.Data
;
import
org.apache.commons.lang3.builder.ToStringBuilder
;
import
org.apache.commons.lang3.builder.ToStringStyle
;
/**
* @description: 银联APP终端创建支付订单请求参数
* @project: freight-customer-service
* @name: com.esv.freight.customer.common.pojo.AppUnionPayOrder
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/05/30 13:48
* @version:1.0
*/
@Data
public
class
AppUnionPayOrderReq
{
/**
* 商户代码(网络货运平台在支付平台的商户号)
*/
private
String
merId
;
/**
* 账单号
*/
private
String
billId
;
/**
* 账单描述
*/
private
String
billDesc
;
/**
* 交易金额(单位为分)
*/
private
Long
txnAmt
;
/**
* 请求支付平台订单发送时间
*/
private
String
txnTime
;
@Override
public
String
toString
()
{
return
ToStringBuilder
.
reflectionToString
(
this
,
ToStringStyle
.
JSON_STYLE
);
}
}
src/main/java/com/esv/freight/customer/common/pojo/AppUnionPayOrderRes.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
common
.
pojo
;
import
lombok.Data
;
import
org.apache.commons.lang3.builder.ToStringBuilder
;
import
org.apache.commons.lang3.builder.ToStringStyle
;
/**
* @description: 银联APP终端创建支付订单返回参数
* @project: freight-customer-service
* @name: com.esv.freight.customer.common.pojo.AppUnionPayOrder
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/05/30 13:48
* @version:1.0
*/
@Data
public
class
AppUnionPayOrderRes
{
/**
* 银联受理订单号
*/
private
String
tn
;
/**
* 请求参数
*/
private
String
reqMessage
;
/**
* 返回参数
*/
private
String
rspMessage
;
@Override
public
String
toString
()
{
return
ToStringBuilder
.
reflectionToString
(
this
,
ToStringStyle
.
JSON_STYLE
);
}
}
src/main/java/com/esv/freight/customer/common/unionpay/AcpService.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
common
.
unionpay
;
import
com.esv.freight.customer.common.constants.SDKConstants
;
import
lombok.extern.slf4j.Slf4j
;
import
java.io.*
;
import
java.util.HashMap
;
import
java.util.Iterator
;
import
java.util.Map
;
import
java.util.Map.Entry
;
import
java.util.Set
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
import
static
java
.
util
.
regex
.
Pattern
.
compile
;
/**
* @description: acpsdk接口服务类,接入商户集成请可以直接参考使用本类中的方法
* @project: freight-customer-service
* @name: com.esv.freight.customer.common.unionpay.AcpService
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/05/30 14:41
* @version:1.0
*/
@Slf4j
public
class
AcpService
{
/**
* 请求报文签名(使用配置文件中配置的私钥证书或者对称密钥签名)<br>
* 功能:对请求报文进行签名,并计算赋值certid,signature字段并返回<br>
*
* @param reqData 请求报文map<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return 签名后的map对象<br>
*/
public
static
Map
<
String
,
String
>
sign
(
Map
<
String
,
String
>
reqData
,
String
encoding
)
{
reqData
=
SDKUtil
.
filterBlank
(
reqData
);
SDKUtil
.
sign
(
reqData
,
encoding
);
return
reqData
;
}
/**
* 同signByCertInfo<br>
*
* @param reqData
* @param certPath
* @param certPwd
* @param encoding
* @return
* @deprecated
*/
public
static
Map
<
String
,
String
>
sign
(
Map
<
String
,
String
>
reqData
,
String
certPath
,
String
certPwd
,
String
encoding
)
{
reqData
=
SDKUtil
.
filterBlank
(
reqData
);
SDKUtil
.
signByCertInfo
(
reqData
,
certPath
,
certPwd
,
encoding
);
return
reqData
;
}
/**
* 多证书签名(通过传入私钥证书路径和密码签名)<br>
* 功能:如果有多个商户号接入银联,每个商户号对应不同的证书可以使用此方法:传入私钥证书和密码(并且在acp_sdk.properties中 配置 acpsdk.singleMode=false)<br>
*
* @param reqData 请求报文map<br>
* @param certPath 签名私钥文件(带路径)<br>
* @param certPwd 签名私钥密码<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return 签名后的map对象<br>
*/
public
static
Map
<
String
,
String
>
signByCertInfo
(
Map
<
String
,
String
>
reqData
,
String
certPath
,
String
certPwd
,
String
encoding
)
{
reqData
=
SDKUtil
.
filterBlank
(
reqData
);
SDKUtil
.
signByCertInfo
(
reqData
,
certPath
,
certPwd
,
encoding
);
return
reqData
;
}
/**
* 多密钥签名(通过传入密钥签名)<br>
* 功能:如果有多个商户号接入银联,每个商户号对应不同的证书可以使用此方法:传入私钥证书和密码(并且在acp_sdk.properties中 配置 acpsdk.singleMode=false)<br>
*
* @param reqData 请求报文map<br>
* @param secureKey 签名对称密钥<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return 签名后的map对象<br>
*/
public
static
Map
<
String
,
String
>
signBySecureKey
(
Map
<
String
,
String
>
reqData
,
String
secureKey
,
String
encoding
)
{
reqData
=
SDKUtil
.
filterBlank
(
reqData
);
SDKUtil
.
signBySecureKey
(
reqData
,
secureKey
,
encoding
);
return
reqData
;
}
/**
* 验证签名(SHA-1摘要算法)<br>
*
* @param rspData 返回报文数据<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return true 通过 false 未通过<br>
*/
public
static
boolean
validate
(
Map
<
String
,
String
>
rspData
,
String
encoding
)
{
return
SDKUtil
.
validate
(
rspData
,
encoding
);
}
/**
* 多密钥验签(通过传入密钥签名)<br>
*
* @param rspData 返回报文数据<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return true 通过 false 未通过<br>
*/
public
static
boolean
validateBySecureKey
(
Map
<
String
,
String
>
rspData
,
String
secureKey
,
String
encoding
)
{
return
SDKUtil
.
validateBySecureKey
(
rspData
,
secureKey
,
encoding
);
}
/**
* @param jsonData json格式数据,例如:{"sign" : "J6rPLClQ64szrdXCOtV1ccOMzUmpiOKllp9cseBuRqJ71pBKPPkZ1FallzW18gyP7CvKh1RxfNNJ66AyXNMFJi1OSOsteAAFjF5GZp0Xsfm3LeHaN3j/N7p86k3B1GrSPvSnSw1LqnYuIBmebBkC1OD0Qi7qaYUJosyA1E8Ld8oGRZT5RR2gLGBoiAVraDiz9sci5zwQcLtmfpT5KFk/eTy4+W9SsC0M/2sVj43R9ePENlEvF8UpmZBqakyg5FO8+JMBz3kZ4fwnutI5pWPdYIWdVrloBpOa+N4pzhVRKD4eWJ0CoiD+joMS7+C0aPIEymYFLBNYQCjM0KV7N726LA==", "data" : "pay_result=success&tn=201602141008032671528&cert_id=68759585097"}
* @return 是否成功
* @deprecated 5.1.0开发包已删除此方法,请直接参考5.1.0开发包中的VerifyAppData.java验签。
* 对控件支付成功返回的结果信息中data域进行验签(控件端获取的应答信息)<br>
*/
public
static
boolean
validateAppResponse
(
String
jsonData
,
String
encoding
)
{
log
.
info
(
"控件应答信息验签处理开始:["
+
jsonData
+
"]"
);
if
(
SDKUtil
.
isEmpty
(
encoding
))
{
encoding
=
"UTF-8"
;
}
Pattern
p
=
compile
(
"\\s*\"sign\"\\s*:\\s*\"([^\"]*)\"\\s*"
);
Matcher
m
=
p
.
matcher
(
jsonData
);
if
(!
m
.
find
())
{
return
false
;
}
String
sign
=
m
.
group
(
1
);
p
=
compile
(
"\\s*\"data\"\\s*:\\s*\"([^\"]*)\"\\s*"
);
m
=
p
.
matcher
(
jsonData
);
if
(!
m
.
find
())
{
return
false
;
}
String
data
=
m
.
group
(
1
);
p
=
compile
(
"cert_id=(\\d*)"
);
m
=
p
.
matcher
(
jsonData
);
if
(!
m
.
find
())
{
return
false
;
}
String
certId
=
m
.
group
(
1
);
try
{
// 验证签名需要用银联发给商户的公钥证书.
return
SecureUtil
.
validateSignBySoft
(
CertUtil
.
getValidatePublicKey
(
certId
),
SecureUtil
.
base64Decode
(
sign
.
getBytes
(
encoding
)),
SecureUtil
.
sha1X16
(
data
,
encoding
));
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
return
false
;
}
/**
* 功能:后台交易提交请求报文并接收同步应答报文<br>
*
* @param reqData 请求报文<br>
* @param reqUrl 请求地址<br>
* @param encoding<br>
* @return 应答http 200返回true ,其他false<br>
*/
public
static
Map
<
String
,
String
>
post
(
Map
<
String
,
String
>
reqData
,
String
reqUrl
,
String
encoding
)
{
Map
<
String
,
String
>
rspData
=
new
HashMap
<>(
32
);
log
.
info
(
"请求银联地址:"
+
reqUrl
);
//发送后台请求数据
HttpClient
hc
=
new
HttpClient
(
reqUrl
,
5000
,
5000
);
//连接超时时间,读超时时间(可自行判断,修改)
try
{
int
status
=
hc
.
send
(
reqData
,
encoding
);
if
(
200
==
status
)
{
String
resultString
=
hc
.
getResult
();
if
(
null
!=
resultString
&&
!
""
.
equals
(
resultString
))
{
// 将返回结果转换为map
Map
<
String
,
String
>
tmpRspData
=
SDKUtil
.
convertResultStringToMap
(
resultString
);
rspData
.
putAll
(
tmpRspData
);
}
}
else
{
log
.
info
(
"返回http状态码["
+
status
+
"],请检查请求报文或者请求地址是否正确"
);
}
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
return
rspData
;
}
/**
* 功能:http Get方法 便民缴费产品中使用<br>
*
* @param reqUrl 请求地址<br>
* @param encoding<br>
* @return
*/
public
static
String
get
(
String
reqUrl
,
String
encoding
)
{
log
.
info
(
"请求银联地址:"
+
reqUrl
);
//发送后台请求数据
HttpClient
hc
=
new
HttpClient
(
reqUrl
,
5000
,
5000
);
try
{
int
status
=
hc
.
sendGet
(
encoding
);
if
(
200
==
status
)
{
String
resultString
=
hc
.
getResult
();
if
(
null
!=
resultString
&&
!
""
.
equals
(
resultString
))
{
return
resultString
;
}
}
else
{
log
.
info
(
"返回http状态码["
+
status
+
"],请检查请求报文或者请求地址是否正确"
);
}
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
return
null
;
}
/**
* 功能:前台交易构造HTTP POST自动提交表单<br>
*
* @param reqUrl 表单提交地址<br>
* @param hiddens 以MAP形式存储的表单键值<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return 构造好的HTTP POST交易表单<br>
*/
public
static
String
createAutoFormHtml
(
String
reqUrl
,
Map
<
String
,
String
>
hiddens
,
String
encoding
)
{
StringBuffer
sf
=
new
StringBuffer
();
sf
.
append
(
"<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset="
+
encoding
+
"\"/></head><body>"
);
sf
.
append
(
"<form id = \"pay_form\" action=\""
+
reqUrl
+
"\" method=\"post\">"
);
if
(
null
!=
hiddens
&&
0
!=
hiddens
.
size
())
{
Set
<
Entry
<
String
,
String
>>
set
=
hiddens
.
entrySet
();
Iterator
<
Entry
<
String
,
String
>>
it
=
set
.
iterator
();
while
(
it
.
hasNext
())
{
Entry
<
String
,
String
>
ey
=
it
.
next
();
String
key
=
ey
.
getKey
();
String
value
=
ey
.
getValue
();
sf
.
append
(
"<input type=\"hidden\" name=\""
+
key
+
"\" id=\""
+
key
+
"\" value=\""
+
value
+
"\"/>"
);
}
}
sf
.
append
(
"</form>"
);
sf
.
append
(
"</body>"
);
sf
.
append
(
"<script type=\"text/javascript\">"
);
sf
.
append
(
"document.all.pay_form.submit();"
);
sf
.
append
(
"</script>"
);
sf
.
append
(
"</html>"
);
return
sf
.
toString
();
}
/**
* 功能:将批量文件内容使用DEFLATE压缩算法压缩,Base64编码生成字符串并返回<br>
* 适用到的交易:批量代付,批量代收,批量退货<br>
*
* @param filePath 批量文件-全路径文件名<br>
* @return
*/
public
static
String
enCodeFileContent
(
String
filePath
,
String
encoding
)
{
String
baseFileContent
=
""
;
File
file
=
new
File
(
filePath
);
if
(!
file
.
exists
())
{
try
{
file
.
createNewFile
();
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
}
InputStream
in
=
null
;
try
{
in
=
new
FileInputStream
(
file
);
int
fl
=
in
.
available
();
if
(
null
!=
in
)
{
byte
[]
s
=
new
byte
[
fl
];
in
.
read
(
s
,
0
,
fl
);
// 压缩编码.
baseFileContent
=
new
String
(
SecureUtil
.
base64Encode
(
SDKUtil
.
deflater
(
s
)),
encoding
);
}
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
finally
{
if
(
null
!=
in
)
{
try
{
in
.
close
();
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
}
}
return
baseFileContent
;
}
/**
* 功能:解析交易返回的fileContent字符串并落地 ( 解base64,解DEFLATE压缩并落地)<br>
* 适用到的交易:对账文件下载,批量交易状态查询<br>
*
* @param resData 返回报文map<br>
* @param fileDirectory 落地的文件目录(绝对路径)
* @param encoding 上送请求报文域encoding字段的值<br>
*/
public
static
String
deCodeFileContent
(
Map
<
String
,
String
>
resData
,
String
fileDirectory
,
String
encoding
)
{
// 解析返回文件
String
filePath
=
null
;
String
fileContent
=
resData
.
get
(
SDKConstants
.
param_fileContent
);
if
(
null
!=
fileContent
&&
!
""
.
equals
(
fileContent
))
{
FileOutputStream
out
=
null
;
try
{
byte
[]
fileArray
=
SDKUtil
.
inflater
(
SecureUtil
.
base64Decode
(
fileContent
.
getBytes
(
encoding
)));
if
(
SDKUtil
.
isEmpty
(
resData
.
get
(
"fileName"
)))
{
filePath
=
fileDirectory
+
File
.
separator
+
resData
.
get
(
"merId"
)
+
"_"
+
resData
.
get
(
"batchNo"
)
+
"_"
+
resData
.
get
(
"txnTime"
)
+
".txt"
;
}
else
{
filePath
=
fileDirectory
+
File
.
separator
+
resData
.
get
(
"fileName"
);
}
File
file
=
new
File
(
filePath
);
if
(
file
.
exists
())
{
file
.
delete
();
}
file
.
createNewFile
();
out
=
new
FileOutputStream
(
file
);
out
.
write
(
fileArray
,
0
,
fileArray
.
length
);
out
.
flush
();
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
finally
{
try
{
out
.
close
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
}
return
filePath
;
}
/**
* 功能:将结果文件内容 转换成明文字符串:解base64,解压缩<br>
* 适用到的交易:批量交易状态查询<br>
*
* @param fileContent 批量交易状态查询返回的文件内容<br>
* @return 内容明文<br>
*/
public
static
String
getFileContent
(
String
fileContent
,
String
encoding
)
{
String
fc
=
""
;
try
{
fc
=
new
String
(
SDKUtil
.
inflater
(
SecureUtil
.
base64Decode
(
fileContent
.
getBytes
())),
encoding
);
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
return
fc
;
}
/**
* 功能:持卡人信息域customerInfo构造<br>
* 说明:不勾选对敏感信息加密权限使用旧的构造customerInfo域方式,不对敏感信息进行加密(对 phoneNo,cvn2, expired不加密),但如果送pin的话则加密<br>
*
* @param customerInfoMap 信息域请求参数 key送域名value送值,必送<br>
* 例如:customerInfoMap.put("certifTp", "01"); //证件类型<br>
* customerInfoMap.put("certifId", "341126197709218366"); //证件号码<br>
* customerInfoMap.put("customerNm", "互联网"); //姓名<br>
* customerInfoMap.put("phoneNo", "13552535506"); //手机号<br>
* customerInfoMap.put("smsCode", "123456"); //短信验证码<br>
* customerInfoMap.put("pin", "111111"); //密码(加密)<br>
* customerInfoMap.put("cvn2", "123"); //卡背面的cvn2三位数字(不加密)<br>
* customerInfoMap.put("expired", "1711"); //有效期 年在前月在后(不加密)<br>
* @param accNo customerInfoMap送了密码那么卡号必送,如果customerInfoMap未送密码pin,此字段可以不送<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return base64后的持卡人信息域字段<br>
*/
public
static
String
getCustomerInfo
(
Map
<
String
,
String
>
customerInfoMap
,
String
accNo
,
String
encoding
)
{
if
(
customerInfoMap
.
isEmpty
())
{
return
"{}"
;
}
StringBuffer
sf
=
new
StringBuffer
(
"{"
);
for
(
Iterator
<
String
>
it
=
customerInfoMap
.
keySet
().
iterator
();
it
.
hasNext
();
)
{
String
key
=
it
.
next
();
String
value
=
customerInfoMap
.
get
(
key
);
if
(
key
.
equals
(
"pin"
))
{
if
(
null
==
accNo
||
""
.
equals
(
accNo
.
trim
()))
{
log
.
info
(
"送了密码(PIN),必须在getCustomerInfo参数中上传卡号"
);
throw
new
RuntimeException
(
"加密PIN没送卡号无法后续处理"
);
}
else
{
value
=
encryptPin
(
accNo
,
value
,
encoding
);
}
}
sf
.
append
(
key
).
append
(
SDKConstants
.
EQUAL
).
append
(
value
);
if
(
it
.
hasNext
())
{
sf
.
append
(
SDKConstants
.
AMPERSAND
);
}
}
String
customerInfo
=
sf
.
append
(
"}"
).
toString
();
log
.
info
(
"组装的customerInfo明文:"
+
customerInfo
);
try
{
return
new
String
(
SecureUtil
.
base64Encode
(
sf
.
toString
().
getBytes
(
encoding
)),
encoding
);
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
return
customerInfo
;
}
/**
* 功能:持卡人信息域customerInfo构造,勾选对敏感信息加密权限 适用新加密规范,对pin和phoneNo,cvn2,expired加密 <br>
* 适用到的交易: <br>
*
* @param customerInfoMap 信息域请求参数 key送域名value送值,必送 <br>
* 例如:customerInfoMap.put("certifTp", "01"); //证件类型 <br>
* customerInfoMap.put("certifId", "341126197709218366"); //证件号码 <br>
* customerInfoMap.put("customerNm", "互联网"); //姓名 <br>
* customerInfoMap.put("smsCode", "123456"); //短信验证码 <br>
* customerInfoMap.put("pin", "111111"); //密码(加密) <br>
* customerInfoMap.put("phoneNo", "13552535506"); //手机号(加密) <br>
* customerInfoMap.put("cvn2", "123"); //卡背面的cvn2三位数字(加密) <br>
* customerInfoMap.put("expired", "1711"); //有效期 年在前月在后(加密) <br>
* @param accNo customerInfoMap送了密码那么卡号必送,如果customerInfoMap未送密码PIN,此字段可以不送<br>
* @param encoding 上送请求报文域encoding字段的值
* @return base64后的持卡人信息域字段 <br>
*/
public
static
String
getCustomerInfoWithEncrypt
(
Map
<
String
,
String
>
customerInfoMap
,
String
accNo
,
String
encoding
)
{
if
(
customerInfoMap
.
isEmpty
())
{
return
"{}"
;
}
StringBuffer
sf
=
new
StringBuffer
(
"{"
);
//敏感信息加密域
StringBuffer
encryptedInfoSb
=
new
StringBuffer
(
""
);
for
(
Iterator
<
String
>
it
=
customerInfoMap
.
keySet
().
iterator
();
it
.
hasNext
();
)
{
String
key
=
it
.
next
();
String
value
=
customerInfoMap
.
get
(
key
);
if
(
key
.
equals
(
"phoneNo"
)
||
key
.
equals
(
"cvn2"
)
||
key
.
equals
(
"expired"
))
{
encryptedInfoSb
.
append
(
key
).
append
(
SDKConstants
.
EQUAL
).
append
(
value
).
append
(
SDKConstants
.
AMPERSAND
);
}
else
{
if
(
key
.
equals
(
"pin"
))
{
if
(
null
==
accNo
||
""
.
equals
(
accNo
.
trim
()))
{
log
.
info
(
"送了密码(PIN),必须在getCustomerInfoWithEncrypt参数中上传卡号"
);
throw
new
RuntimeException
(
"加密PIN没送卡号无法后续处理"
);
}
else
{
value
=
encryptPin
(
accNo
,
value
,
encoding
);
}
}
sf
.
append
(
key
).
append
(
SDKConstants
.
EQUAL
).
append
(
value
).
append
(
SDKConstants
.
AMPERSAND
);
}
}
if
(!
encryptedInfoSb
.
toString
().
equals
(
""
))
{
encryptedInfoSb
.
setLength
(
encryptedInfoSb
.
length
()
-
1
);
//去掉最后一个&符号
log
.
info
(
"组装的customerInfo encryptedInfo明文:"
+
encryptedInfoSb
.
toString
());
sf
.
append
(
"encryptedInfo"
).
append
(
SDKConstants
.
EQUAL
).
append
(
encryptData
(
encryptedInfoSb
.
toString
(),
encoding
));
}
else
{
sf
.
setLength
(
sf
.
length
()
-
1
);
}
String
customerInfo
=
sf
.
append
(
"}"
).
toString
();
log
.
info
(
"组装的customerInfo明文:"
+
customerInfo
);
try
{
return
new
String
(
SecureUtil
.
base64Encode
(
sf
.
toString
().
getBytes
(
encoding
)),
encoding
);
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
return
customerInfo
;
}
/**
* 解析返回报文(后台通知)中的customerInfo域:<br>
* 解base64,如果带敏感信息加密 encryptedInfo 则将其解密并将 encryptedInfo中的域放到customerInfoMap返回<br>
*
* @param customerInfo<br>
* @param encoding<br>
* @return
*/
public
static
Map
<
String
,
String
>
parseCustomerInfo
(
String
customerInfo
,
String
encoding
)
{
Map
<
String
,
String
>
customerInfoMap
=
null
;
try
{
byte
[]
b
=
SecureUtil
.
base64Decode
(
customerInfo
.
getBytes
(
encoding
));
String
customerInfoNoBase64
=
new
String
(
b
,
encoding
);
log
.
info
(
"解base64后===>"
+
customerInfoNoBase64
);
//去掉前后的{}
customerInfoNoBase64
=
customerInfoNoBase64
.
substring
(
1
,
customerInfoNoBase64
.
length
()
-
1
);
customerInfoMap
=
SDKUtil
.
parseQString
(
customerInfoNoBase64
);
if
(
customerInfoMap
.
containsKey
(
"encryptedInfo"
))
{
String
encInfoStr
=
customerInfoMap
.
get
(
"encryptedInfo"
);
customerInfoMap
.
remove
(
"encryptedInfo"
);
String
encryptedInfoStr
=
decryptData
(
encInfoStr
,
encoding
);
Map
<
String
,
String
>
encryptedInfoMap
=
SDKUtil
.
parseQString
(
encryptedInfoStr
);
customerInfoMap
.
putAll
(
encryptedInfoMap
);
}
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
return
customerInfoMap
;
}
/**
* 解析返回报文(后台通知)中的customerInfo域:<br>
* 解base64,如果带敏感信息加密 encryptedInfo 则将其解密并将 encryptedInfo中的域放到customerInfoMap返回<br>
*
* @param customerInfo<br>
* @param encoding<br>
* @return
*/
public
static
Map
<
String
,
String
>
parseCustomerInfo
(
String
customerInfo
,
String
certPath
,
String
certPwd
,
String
encoding
)
{
Map
<
String
,
String
>
customerInfoMap
=
null
;
try
{
byte
[]
b
=
SecureUtil
.
base64Decode
(
customerInfo
.
getBytes
(
encoding
));
String
customerInfoNoBase64
=
new
String
(
b
,
encoding
);
log
.
info
(
"解base64后===>"
+
customerInfoNoBase64
);
//去掉前后的{}
customerInfoNoBase64
=
customerInfoNoBase64
.
substring
(
1
,
customerInfoNoBase64
.
length
()
-
1
);
customerInfoMap
=
SDKUtil
.
parseQString
(
customerInfoNoBase64
);
if
(
customerInfoMap
.
containsKey
(
"encryptedInfo"
))
{
String
encInfoStr
=
customerInfoMap
.
get
(
"encryptedInfo"
);
customerInfoMap
.
remove
(
"encryptedInfo"
);
String
encryptedInfoStr
=
decryptData
(
encInfoStr
,
certPath
,
certPwd
,
encoding
);
Map
<
String
,
String
>
encryptedInfoMap
=
SDKUtil
.
parseQString
(
encryptedInfoStr
);
customerInfoMap
.
putAll
(
encryptedInfoMap
);
}
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
return
customerInfoMap
;
}
/**
* 密码加密并做base64<br>
*
* @param accNo 卡号<br>
* @param pin 密码<br>
* @param encoding<br>
* @return 加密的内容<br>
*/
public
static
String
encryptPin
(
String
accNo
,
String
pin
,
String
encoding
)
{
return
SecureUtil
.
encryptPin
(
accNo
,
pin
,
encoding
,
CertUtil
.
getEncryptCertPublicKey
());
}
/**
* 敏感信息加密并做base64(卡号,手机号,cvn2,有效期)<br>
*
* @param data 送 phoneNo,cvn2,有效期<br>
* @param encoding<br>
* @return 加密的密文<br>
*/
public
static
String
encryptData
(
String
data
,
String
encoding
)
{
return
SecureUtil
.
encryptData
(
data
,
encoding
,
CertUtil
.
getEncryptCertPublicKey
());
}
/**
* 敏感信息解密,使用配置文件acp_sdk.properties解密<br>
*
* @param base64EncryptedInfo 加密信息<br>
* @param encoding<br>
* @return 解密后的明文<br>
*/
public
static
String
decryptData
(
String
base64EncryptedInfo
,
String
encoding
)
{
return
SecureUtil
.
decryptData
(
base64EncryptedInfo
,
encoding
,
CertUtil
.
getSignCertPrivateKey
());
}
/**
* 敏感信息解密,通过传入的私钥解密<br>
*
* @param base64EncryptedInfo 加密信息<br>
* @param certPath 私钥文件(带全路径)<br>
* @param certPwd 私钥密码<br>
* @param encoding<br>
* @return
*/
public
static
String
decryptData
(
String
base64EncryptedInfo
,
String
certPath
,
String
certPwd
,
String
encoding
)
{
return
SecureUtil
.
decryptData
(
base64EncryptedInfo
,
encoding
,
CertUtil
.
getSignCertPrivateKeyByStoreMap
(
certPath
,
certPwd
));
}
/**
* 5.0.0加密磁道信息,5.1.0接口请勿使用<br>
*
* @param trackData 待加密磁道数据<br>
* @param encoding 编码格式<br>
* @return 加密的密文<br>
* @deprecated
*/
public
static
String
encryptTrack
(
String
trackData
,
String
encoding
)
{
return
SecureUtil
.
encryptData
(
trackData
,
encoding
,
CertUtil
.
getEncryptTrackPublicKey
());
}
/**
* 获取敏感信息加密证书的物理序列号<br>
*
* @return
*/
public
static
String
getEncryptCertId
()
{
return
CertUtil
.
getEncryptCertId
();
}
/**
* 对字符串做base64<br>
*
* @param rawStr<br>
* @param encoding<br>
* @throws IOException
* @return<br>
*/
public
static
String
base64Encode
(
String
rawStr
,
String
encoding
)
throws
IOException
{
byte
[]
rawByte
=
rawStr
.
getBytes
(
encoding
);
return
new
String
(
SecureUtil
.
base64Encode
(
rawByte
),
encoding
);
}
/**
* 对base64的字符串解base64<br>
*
* @param base64Str<br>
* @param encoding<br>
* @throws IOException
* @return<br>
*/
public
static
String
base64Decode
(
String
base64Str
,
String
encoding
)
throws
IOException
{
byte
[]
rawByte
=
base64Str
.
getBytes
(
encoding
);
return
new
String
(
SecureUtil
.
base64Decode
(
rawByte
),
encoding
);
}
/**
* 有卡交易信息域(cardTransData)构造<br>
* 所有子域需用“{}”包含,子域间以“&”符号链接。格式如下:{子域名1=值&子域名2=值&子域名3=值}<br>
* 说明:本示例仅供参考,开发时请根据接口文档中的报文要素组装<br>
*
* @param cardTransDataMap cardTransData的数据<br>
* @param requestData 必须包含merId、orderId、txnTime、txnAmt,磁道加密时需要使用<br>
* @param encoding 编码<br>
* @return
*/
public
static
String
getCardTransData
(
Map
<
String
,
String
>
cardTransDataMap
,
Map
<
String
,
String
>
requestData
,
String
encoding
)
{
{
StringBuffer
cardTransDataBuffer
=
new
StringBuffer
();
if
(
cardTransDataMap
.
containsKey
(
"track2Data"
))
{
StringBuffer
track2Buffer
=
new
StringBuffer
();
track2Buffer
.
append
(
requestData
.
get
(
"merId"
))
.
append
(
SDKConstants
.
COLON
).
append
(
requestData
.
get
(
"orderId"
))
.
append
(
SDKConstants
.
COLON
).
append
(
requestData
.
get
(
"txnTime"
))
.
append
(
SDKConstants
.
COLON
).
append
(
requestData
.
get
(
"txnAmt"
)
==
null
?
0
:
requestData
.
get
(
"txnAmt"
))
.
append
(
SDKConstants
.
COLON
).
append
(
cardTransDataMap
.
get
(
"track2Data"
));
cardTransDataMap
.
put
(
"track2Data"
,
AcpService
.
encryptData
(
track2Buffer
.
toString
(),
encoding
));
}
if
(
cardTransDataMap
.
containsKey
(
"track3Data"
))
{
StringBuffer
track3Buffer
=
new
StringBuffer
();
track3Buffer
.
append
(
requestData
.
get
(
"merId"
))
.
append
(
SDKConstants
.
COLON
).
append
(
requestData
.
get
(
"orderId"
))
.
append
(
SDKConstants
.
COLON
).
append
(
requestData
.
get
(
"txnTime"
))
.
append
(
SDKConstants
.
COLON
).
append
(
requestData
.
get
(
"txnAmt"
)
==
null
?
0
:
requestData
.
get
(
"txnAmt"
))
.
append
(
SDKConstants
.
COLON
).
append
(
cardTransDataMap
.
get
(
"track3Data"
));
cardTransDataMap
.
put
(
"track3Data"
,
AcpService
.
encryptData
(
track3Buffer
.
toString
(),
encoding
));
}
return
cardTransDataBuffer
.
append
(
SDKConstants
.
LEFT_BRACE
)
.
append
(
SDKUtil
.
coverMap2String
(
cardTransDataMap
))
.
append
(
SDKConstants
.
RIGHT_BRACE
).
toString
();
}
}
/**
* 获取应答报文中的加密公钥证书,并存储到本地,备份原始证书,并自动替换证书<br>
* 更新成功则返回1,无更新返回0,失败异常返回-1<br>
*
* @param resData 返回报文
* @param encoding
* @return
*/
public
static
int
updateEncryptCert
(
Map
<
String
,
String
>
resData
,
String
encoding
)
{
return
SDKUtil
.
getEncryptCert
(
resData
,
encoding
);
}
/**
* 获取
*
* @param number
* @return
*/
public
static
int
genLuhn
(
String
number
)
{
return
SecureUtil
.
genLuhn
(
number
);
}
}
src/main/java/com/esv/freight/customer/common/unionpay/BaseHttpSSLSocketFactory.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
common
.
unionpay
;
import
lombok.extern.slf4j.Slf4j
;
import
javax.net.ssl.*
;
import
java.io.IOException
;
import
java.net.InetAddress
;
import
java.net.Socket
;
import
java.net.UnknownHostException
;
import
java.security.cert.X509Certificate
;
/**
* @description: 忽略验证ssl证书
* @project: freight-customer-service
* @name: com.esv.freight.customer.common.unionpay.BaseHttpSSLSocketFactory
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/05/30 14:44
* @version:1.0
*/
@Slf4j
public
class
BaseHttpSSLSocketFactory
extends
SSLSocketFactory
{
private
SSLContext
getSSLContext
()
{
return
createEasySSLContext
();
}
@Override
public
Socket
createSocket
(
InetAddress
arg0
,
int
arg1
,
InetAddress
arg2
,
int
arg3
)
throws
IOException
{
return
getSSLContext
().
getSocketFactory
().
createSocket
(
arg0
,
arg1
,
arg2
,
arg3
);
}
@Override
public
Socket
createSocket
(
String
arg0
,
int
arg1
,
InetAddress
arg2
,
int
arg3
)
throws
IOException
,
UnknownHostException
{
return
getSSLContext
().
getSocketFactory
().
createSocket
(
arg0
,
arg1
,
arg2
,
arg3
);
}
@Override
public
Socket
createSocket
(
InetAddress
arg0
,
int
arg1
)
throws
IOException
{
return
getSSLContext
().
getSocketFactory
().
createSocket
(
arg0
,
arg1
);
}
@Override
public
Socket
createSocket
(
String
arg0
,
int
arg1
)
throws
IOException
,
UnknownHostException
{
return
getSSLContext
().
getSocketFactory
().
createSocket
(
arg0
,
arg1
);
}
@Override
public
String
[]
getSupportedCipherSuites
()
{
// TODO Auto-generated method stub
return
null
;
}
@Override
public
String
[]
getDefaultCipherSuites
()
{
// TODO Auto-generated method stub
return
null
;
}
@Override
public
Socket
createSocket
(
Socket
arg0
,
String
arg1
,
int
arg2
,
boolean
arg3
)
throws
IOException
{
return
getSSLContext
().
getSocketFactory
().
createSocket
(
arg0
,
arg1
,
arg2
,
arg3
);
}
private
SSLContext
createEasySSLContext
()
{
try
{
SSLContext
context
=
SSLContext
.
getInstance
(
"SSL"
);
context
.
init
(
null
,
new
TrustManager
[]{
MyX509TrustManager
.
manger
},
null
);
return
context
;
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
null
;
}
}
public
static
class
MyX509TrustManager
implements
X509TrustManager
{
static
MyX509TrustManager
manger
=
new
MyX509TrustManager
();
public
MyX509TrustManager
()
{
}
@Override
public
X509Certificate
[]
getAcceptedIssuers
()
{
return
null
;
}
@Override
public
void
checkClientTrusted
(
X509Certificate
[]
chain
,
String
authType
)
{
}
@Override
public
void
checkServerTrusted
(
X509Certificate
[]
chain
,
String
authType
)
{
}
}
/**
* 解决由于服务器证书问题导致HTTPS无法访问的情况 PS:HTTPS hostname wrong: should be <localhost>
*/
public
static
class
TrustAnyHostnameVerifier
implements
HostnameVerifier
{
@Override
public
boolean
verify
(
String
hostname
,
SSLSession
session
)
{
//直接返回true
return
true
;
}
}
}
src/main/java/com/esv/freight/customer/common/unionpay/CertUtil.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
common
.
unionpay
;
import
com.esv.freight.customer.common.constants.SDKConstants
;
import
lombok.extern.slf4j.Slf4j
;
import
java.io.*
;
import
java.math.BigInteger
;
import
java.security.*
;
import
java.security.cert.*
;
import
java.security.spec.RSAPublicKeySpec
;
import
java.util.*
;
import
java.util.concurrent.ConcurrentHashMap
;
/**
* @description: 银联支付:acpsdk证书工具类,主要用于对证书的加载和使用
* @project: freight-customer-service
* @name: com.esv.freight.customer.common.unionpay.CertUtil
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/05/30 14:20
* @version:1.0
*/
@Slf4j
public
class
CertUtil
{
/**
* 证书容器,存储对商户请求报文签名私钥证书.
*/
private
static
KeyStore
keyStore
=
null
;
/**
* 敏感信息加密公钥证书
*/
private
static
X509Certificate
encryptCert
=
null
;
/**
* 磁道加密公钥
*/
private
static
PublicKey
encryptTrackKey
=
null
;
/**
* 验证银联返回报文签名证书.
*/
private
static
X509Certificate
validateCert
=
null
;
/**
* 验签中级证书
*/
private
static
X509Certificate
middleCert
=
null
;
/**
* 验签根证书
*/
private
static
X509Certificate
rootCert
=
null
;
/**
* 验证银联返回报文签名的公钥证书存储Map.
*/
private
static
Map
<
String
,
X509Certificate
>
certMap
=
new
HashMap
<
String
,
X509Certificate
>();
/**
* 商户私钥存储Map
*/
private
final
static
Map
<
String
,
KeyStore
>
keyStoreMap
=
new
ConcurrentHashMap
<
String
,
KeyStore
>();
static
{
init
();
}
/**
* 初始化所有证书.
*/
private
static
void
init
()
{
try
{
addProvider
();
//向系统添加BC provider
initSignCert
();
//初始化签名私钥证书
initMiddleCert
();
//初始化验签证书的中级证书
initRootCert
();
//初始化验签证书的根证书
initEncryptCert
();
//初始化加密公钥
initTrackKey
();
//构建磁道加密公钥
initValidateCertFromDir
();
//初始化所有的验签证书
}
catch
(
Exception
e
)
{
log
.
error
(
"init失败。(如果是用对称密钥签名的可无视此异常。)"
,
e
);
}
}
/**
* 添加签名,验签,加密算法提供者
*/
private
static
void
addProvider
()
{
if
(
Security
.
getProvider
(
"BC"
)
==
null
)
{
log
.
info
(
"add BC provider"
);
Security
.
addProvider
(
new
org
.
bouncycastle
.
jce
.
provider
.
BouncyCastleProvider
());
}
else
{
Security
.
removeProvider
(
"BC"
);
//解决eclipse调试时tomcat自动重新加载时,BC存在不明原因异常的问题。
Security
.
addProvider
(
new
org
.
bouncycastle
.
jce
.
provider
.
BouncyCastleProvider
());
log
.
info
(
"re-add BC provider"
);
}
printSysInfo
();
}
/**
* 用配置文件acp_sdk.properties中配置的私钥路径和密码 加载签名证书
*/
private
static
void
initSignCert
()
{
if
(!
"01"
.
equals
(
SDKConfig
.
getConfig
().
getSignMethod
()))
{
log
.
info
(
"非rsa签名方式,不加载签名证书。"
);
return
;
}
if
(
SDKConfig
.
getConfig
().
getSignCertPath
()
==
null
||
SDKConfig
.
getConfig
().
getSignCertPwd
()
==
null
||
SDKConfig
.
getConfig
().
getSignCertType
()
==
null
)
{
log
.
error
(
"WARN: "
+
SDKConfig
.
SDK_SIGNCERT_PATH
+
"或"
+
SDKConfig
.
SDK_SIGNCERT_PWD
+
"或"
+
SDKConfig
.
SDK_SIGNCERT_TYPE
+
"为空。 停止加载签名证书。"
);
return
;
}
if
(
null
!=
keyStore
)
{
keyStore
=
null
;
}
try
{
keyStore
=
getKeyInfo
(
SDKConfig
.
getConfig
().
getSignCertPath
(),
SDKConfig
.
getConfig
().
getSignCertPwd
(),
SDKConfig
.
getConfig
().
getSignCertType
());
log
.
info
(
"InitSignCert Successful. CertId=["
+
getSignCertId
()
+
"]"
);
}
catch
(
IOException
e
)
{
log
.
error
(
"InitSignCert Error"
,
e
);
}
}
/**
* 用配置文件acp_sdk.properties配置路径 加载敏感信息加密证书
*/
private
static
void
initMiddleCert
()
{
log
.
info
(
"加载中级证书==>"
+
SDKConfig
.
getConfig
().
getMiddleCertPath
());
if
(!
SDKUtil
.
isEmpty
(
SDKConfig
.
getConfig
().
getMiddleCertPath
()))
{
middleCert
=
initCert
(
SDKConfig
.
getConfig
().
getMiddleCertPath
());
log
.
info
(
"Load MiddleCert Successful"
);
}
else
{
log
.
info
(
"WARN: acpsdk.middle.path is empty"
);
}
}
/**
* 用配置文件acp_sdk.properties配置路径 加载敏感信息加密证书
*/
private
static
void
initRootCert
()
{
log
.
info
(
"加载根证书==>"
+
SDKConfig
.
getConfig
().
getRootCertPath
());
if
(!
SDKUtil
.
isEmpty
(
SDKConfig
.
getConfig
().
getRootCertPath
()))
{
rootCert
=
initCert
(
SDKConfig
.
getConfig
().
getRootCertPath
());
log
.
info
(
"Load RootCert Successful"
);
}
else
{
log
.
info
(
"WARN: acpsdk.rootCert.path is empty"
);
}
}
/**
* 用配置文件acp_sdk.properties配置路径 加载银联公钥上级证书(中级证书)
*/
private
static
void
initEncryptCert
()
{
log
.
info
(
"加载敏感信息加密证书==>"
+
SDKConfig
.
getConfig
().
getEncryptCertPath
());
if
(!
SDKUtil
.
isEmpty
(
SDKConfig
.
getConfig
().
getEncryptCertPath
()))
{
encryptCert
=
initCert
(
SDKConfig
.
getConfig
().
getEncryptCertPath
());
log
.
info
(
"Load EncryptCert Successful"
);
}
else
{
log
.
info
(
"WARN: acpsdk.encryptCert.path is empty"
);
}
}
/**
* 用配置文件acp_sdk.properties配置路径 加载磁道公钥
*/
private
static
void
initTrackKey
()
{
if
(!
SDKUtil
.
isEmpty
(
SDKConfig
.
getConfig
().
getEncryptTrackKeyModulus
())
&&
!
SDKUtil
.
isEmpty
(
SDKConfig
.
getConfig
().
getEncryptTrackKeyExponent
()))
{
encryptTrackKey
=
getPublicKey
(
SDKConfig
.
getConfig
().
getEncryptTrackKeyModulus
(),
SDKConfig
.
getConfig
().
getEncryptTrackKeyExponent
());
log
.
info
(
"LoadEncryptTrackKey Successful"
);
}
else
{
log
.
info
(
"WARN: acpsdk.encryptTrackKey.modulus or acpsdk.encryptTrackKey.exponent is empty"
);
}
}
/**
* 用配置文件acp_sdk.properties配置路径 加载验证签名证书
*/
private
static
void
initValidateCertFromDir
()
{
if
(!
"01"
.
equals
(
SDKConfig
.
getConfig
().
getSignMethod
()))
{
log
.
info
(
"非rsa签名方式,不加载验签证书。"
);
return
;
}
certMap
.
clear
();
String
dir
=
SDKConfig
.
getConfig
().
getValidateCertDir
();
log
.
info
(
"加载验证签名证书目录==>"
+
dir
+
" 注:如果请求报文中version=5.1.0那么此验签证书目录使用不到,可以不需要设置(version=5.0.0必须设置)。"
);
if
(
SDKUtil
.
isEmpty
(
dir
))
{
log
.
warn
(
"WARN: acpsdk.validateCert.dir is empty"
);
return
;
}
CertificateFactory
cf
;
FileInputStream
in
=
null
;
try
{
cf
=
CertificateFactory
.
getInstance
(
"X.509"
,
"BC"
);
}
catch
(
NoSuchProviderException
e
)
{
log
.
error
(
"LoadVerifyCert Error: No BC Provider"
,
e
);
return
;
}
catch
(
CertificateException
e
)
{
log
.
error
(
"LoadVerifyCert Error"
,
e
);
return
;
}
File
fileDir
=
new
File
(
dir
);
File
[]
files
=
fileDir
.
listFiles
(
new
CerFilter
());
for
(
int
i
=
0
;
i
<
files
.
length
;
i
++)
{
File
file
=
files
[
i
];
try
{
in
=
new
FileInputStream
(
file
.
getAbsolutePath
());
validateCert
=
(
X509Certificate
)
cf
.
generateCertificate
(
in
);
if
(
validateCert
==
null
)
{
log
.
error
(
"Load verify cert error, "
+
file
.
getAbsolutePath
()
+
" has error cert content."
);
continue
;
}
certMap
.
put
(
validateCert
.
getSerialNumber
().
toString
(),
validateCert
);
// 打印证书加载信息,供测试阶段调试
log
.
info
(
"["
+
file
.
getAbsolutePath
()
+
"][CertId="
+
validateCert
.
getSerialNumber
().
toString
()
+
"]"
);
}
catch
(
CertificateException
e
)
{
log
.
error
(
"LoadVerifyCert Error"
,
e
);
}
catch
(
FileNotFoundException
e
)
{
log
.
error
(
"LoadVerifyCert Error File Not Found"
,
e
);
}
finally
{
if
(
null
!=
in
)
{
try
{
in
.
close
();
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
toString
());
}
}
}
}
log
.
info
(
"LoadVerifyCert Finish"
);
}
/**
* 用给定的路径和密码 加载签名证书,并保存到certKeyStoreMap
*
* @param certFilePath
* @param certPwd
*/
private
static
void
loadSignCert
(
String
certFilePath
,
String
certPwd
)
{
KeyStore
keyStore
=
null
;
try
{
keyStore
=
getKeyInfo
(
certFilePath
,
certPwd
,
"PKCS12"
);
keyStoreMap
.
put
(
certFilePath
,
keyStore
);
log
.
info
(
"LoadRsaCert Successful"
);
}
catch
(
IOException
e
)
{
log
.
error
(
"LoadRsaCert Error"
,
e
);
}
}
/**
* 通过证书路径初始化为公钥证书
*
* @param path
* @return
*/
private
static
X509Certificate
initCert
(
String
path
)
{
X509Certificate
encryptCertTemp
=
null
;
CertificateFactory
cf
=
null
;
FileInputStream
in
=
null
;
try
{
cf
=
CertificateFactory
.
getInstance
(
"X.509"
,
"BC"
);
in
=
new
FileInputStream
(
path
);
encryptCertTemp
=
(
X509Certificate
)
cf
.
generateCertificate
(
in
);
// 打印证书加载信息,供测试阶段调试
log
.
info
(
"["
+
path
+
"][CertId="
+
encryptCertTemp
.
getSerialNumber
().
toString
()
+
"]"
);
}
catch
(
CertificateException
e
)
{
log
.
error
(
"InitCert Error"
,
e
);
}
catch
(
FileNotFoundException
e
)
{
log
.
error
(
"InitCert Error File Not Found"
,
e
);
}
catch
(
NoSuchProviderException
e
)
{
log
.
error
(
"LoadVerifyCert Error No BC Provider"
,
e
);
}
finally
{
if
(
null
!=
in
)
{
try
{
in
.
close
();
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
toString
());
}
}
}
return
encryptCertTemp
;
}
/**
* 通过keyStore 获取私钥签名证书PrivateKey对象
*
* @return
*/
public
static
PrivateKey
getSignCertPrivateKey
()
{
try
{
Enumeration
<
String
>
aliasenum
=
keyStore
.
aliases
();
String
keyAlias
=
null
;
if
(
aliasenum
.
hasMoreElements
())
{
keyAlias
=
aliasenum
.
nextElement
();
}
PrivateKey
privateKey
=
(
PrivateKey
)
keyStore
.
getKey
(
keyAlias
,
SDKConfig
.
getConfig
().
getSignCertPwd
().
toCharArray
());
return
privateKey
;
}
catch
(
KeyStoreException
e
)
{
log
.
error
(
"getSignCertPrivateKey Error"
,
e
);
return
null
;
}
catch
(
UnrecoverableKeyException
e
)
{
log
.
error
(
"getSignCertPrivateKey Error"
,
e
);
return
null
;
}
catch
(
NoSuchAlgorithmException
e
)
{
log
.
error
(
"getSignCertPrivateKey Error"
,
e
);
return
null
;
}
}
/**
* 通过指定路径的私钥证书 获取PrivateKey对象
*
* @return
*/
public
static
PrivateKey
getSignCertPrivateKeyByStoreMap
(
String
certPath
,
String
certPwd
)
{
if
(!
keyStoreMap
.
containsKey
(
certPath
))
{
loadSignCert
(
certPath
,
certPwd
);
}
try
{
Enumeration
<
String
>
aliasenum
=
keyStoreMap
.
get
(
certPath
).
aliases
();
String
keyAlias
=
null
;
if
(
aliasenum
.
hasMoreElements
())
{
keyAlias
=
aliasenum
.
nextElement
();
}
PrivateKey
privateKey
=
(
PrivateKey
)
keyStoreMap
.
get
(
certPath
).
getKey
(
keyAlias
,
certPwd
.
toCharArray
());
return
privateKey
;
}
catch
(
KeyStoreException
e
)
{
log
.
error
(
"getSignCertPrivateKeyByStoreMap Error"
,
e
);
return
null
;
}
catch
(
UnrecoverableKeyException
e
)
{
log
.
error
(
"getSignCertPrivateKeyByStoreMap Error"
,
e
);
return
null
;
}
catch
(
NoSuchAlgorithmException
e
)
{
log
.
error
(
"getSignCertPrivateKeyByStoreMap Error"
,
e
);
return
null
;
}
}
/**
* 获取敏感信息加密证书PublicKey
*
* @return
*/
public
static
PublicKey
getEncryptCertPublicKey
()
{
if
(
null
==
encryptCert
)
{
String
path
=
SDKConfig
.
getConfig
().
getEncryptCertPath
();
if
(!
SDKUtil
.
isEmpty
(
path
))
{
encryptCert
=
initCert
(
path
);
return
encryptCert
.
getPublicKey
();
}
else
{
log
.
error
(
"acpsdk.encryptCert.path is empty"
);
return
null
;
}
}
else
{
return
encryptCert
.
getPublicKey
();
}
}
/**
* 重置敏感信息加密证书公钥
*/
public
static
void
resetEncryptCertPublicKey
()
{
encryptCert
=
null
;
}
/**
* 获取磁道加密证书PublicKey
*
* @return
*/
public
static
PublicKey
getEncryptTrackPublicKey
()
{
if
(
null
==
encryptTrackKey
)
{
initTrackKey
();
}
return
encryptTrackKey
;
}
/**
* 通过certId获取验签证书Map中对应证书PublicKey
*
* @param certId 证书物理序号
* @return 通过证书编号获取到的公钥
*/
public
static
PublicKey
getValidatePublicKey
(
String
certId
)
{
X509Certificate
cf
=
null
;
if
(
certMap
.
containsKey
(
certId
))
{
// 存在certId对应的证书对象
cf
=
certMap
.
get
(
certId
);
return
cf
.
getPublicKey
();
}
else
{
// 不存在则重新Load证书文件目录
initValidateCertFromDir
();
if
(
certMap
.
containsKey
(
certId
))
{
// 存在certId对应的证书对象
cf
=
certMap
.
get
(
certId
);
return
cf
.
getPublicKey
();
}
else
{
log
.
error
(
"缺少certId=["
+
certId
+
"]对应的验签证书."
);
return
null
;
}
}
}
/**
* 获取配置文件acp_sdk.properties中配置的签名私钥证书certId
*
* @return 证书的物理编号
*/
public
static
String
getSignCertId
()
{
try
{
Enumeration
<
String
>
aliasenum
=
keyStore
.
aliases
();
String
keyAlias
=
null
;
if
(
aliasenum
.
hasMoreElements
())
{
keyAlias
=
aliasenum
.
nextElement
();
}
X509Certificate
cert
=
(
X509Certificate
)
keyStore
.
getCertificate
(
keyAlias
);
return
cert
.
getSerialNumber
().
toString
();
}
catch
(
Exception
e
)
{
log
.
error
(
"getSignCertId Error"
,
e
);
return
null
;
}
}
/**
* 获取敏感信息加密证书的certId
*
* @return
*/
public
static
String
getEncryptCertId
()
{
if
(
null
==
encryptCert
)
{
String
path
=
SDKConfig
.
getConfig
().
getEncryptCertPath
();
if
(!
SDKUtil
.
isEmpty
(
path
))
{
encryptCert
=
initCert
(
path
);
return
encryptCert
.
getSerialNumber
().
toString
();
}
else
{
log
.
error
(
"acpsdk.encryptCert.path is empty"
);
return
null
;
}
}
else
{
return
encryptCert
.
getSerialNumber
().
toString
();
}
}
/**
* 将签名私钥证书文件读取为证书存储对象
*
* @param pfxkeyfile 证书文件名
* @param keypwd 证书密码
* @param type 证书类型
* @return 证书对象
* @throws IOException
*/
private
static
KeyStore
getKeyInfo
(
String
pfxkeyfile
,
String
keypwd
,
String
type
)
throws
IOException
{
log
.
info
(
"加载签名证书==>"
+
pfxkeyfile
);
FileInputStream
fis
=
null
;
try
{
KeyStore
ks
=
KeyStore
.
getInstance
(
type
,
"BC"
);
log
.
info
(
"Load RSA CertPath=["
+
pfxkeyfile
+
"],Pwd=["
+
keypwd
+
"],type=["
+
type
+
"]"
);
fis
=
new
FileInputStream
(
pfxkeyfile
);
char
[]
nPassword
;
nPassword
=
null
==
keypwd
||
""
.
equals
(
keypwd
.
trim
())
?
null
:
keypwd
.
toCharArray
();
if
(
null
!=
ks
)
{
ks
.
load
(
fis
,
nPassword
);
}
return
ks
;
}
catch
(
Exception
e
)
{
log
.
error
(
"getKeyInfo Error"
,
e
);
return
null
;
}
finally
{
if
(
null
!=
fis
)
{
fis
.
close
();
}
}
}
/**
* 通过签名私钥证书路径,密码获取私钥证书certId
*
* @param certPath
* @param certPwd
* @return
*/
public
static
String
getCertIdByKeyStoreMap
(
String
certPath
,
String
certPwd
)
{
if
(!
keyStoreMap
.
containsKey
(
certPath
))
{
// 缓存中未查询到,则加载RSA证书
loadSignCert
(
certPath
,
certPwd
);
}
return
getCertIdIdByStore
(
keyStoreMap
.
get
(
certPath
));
}
/**
* 通过keystore获取私钥证书的certId值
*
* @param keyStore
* @return
*/
private
static
String
getCertIdIdByStore
(
KeyStore
keyStore
)
{
Enumeration
<
String
>
aliasenum
=
null
;
try
{
aliasenum
=
keyStore
.
aliases
();
String
keyAlias
=
null
;
if
(
aliasenum
.
hasMoreElements
())
{
keyAlias
=
aliasenum
.
nextElement
();
}
X509Certificate
cert
=
(
X509Certificate
)
keyStore
.
getCertificate
(
keyAlias
);
return
cert
.
getSerialNumber
().
toString
();
}
catch
(
KeyStoreException
e
)
{
log
.
error
(
"getCertIdIdByStore Error"
,
e
);
return
null
;
}
}
/**
* 使用模和指数生成RSA公钥 注意:此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同
*
* @param modulus 模
* @param exponent 指数
* @return
*/
private
static
PublicKey
getPublicKey
(
String
modulus
,
String
exponent
)
{
try
{
BigInteger
b1
=
new
BigInteger
(
modulus
);
BigInteger
b2
=
new
BigInteger
(
exponent
);
KeyFactory
keyFactory
=
KeyFactory
.
getInstance
(
"RSA"
,
"BC"
);
RSAPublicKeySpec
keySpec
=
new
RSAPublicKeySpec
(
b1
,
b2
);
return
keyFactory
.
generatePublic
(
keySpec
);
}
catch
(
Exception
e
)
{
log
.
error
(
"构造RSA公钥失败:"
+
e
);
return
null
;
}
}
/**
* 将字符串转换为X509Certificate对象.
*
* @param x509CertString
* @return
*/
public
static
X509Certificate
genCertificateByStr
(
String
x509CertString
)
{
X509Certificate
x509Cert
=
null
;
try
{
CertificateFactory
cf
=
CertificateFactory
.
getInstance
(
"X.509"
,
"BC"
);
InputStream
tIn
=
new
ByteArrayInputStream
(
x509CertString
.
getBytes
(
"ISO-8859-1"
));
x509Cert
=
(
X509Certificate
)
cf
.
generateCertificate
(
tIn
);
}
catch
(
Exception
e
)
{
log
.
error
(
"gen certificate error"
,
e
);
}
return
x509Cert
;
}
/**
* 从配置文件acp_sdk.properties中获取验签公钥使用的中级证书
*
* @return
*/
public
static
X509Certificate
getMiddleCert
()
{
if
(
null
==
middleCert
)
{
String
path
=
SDKConfig
.
getConfig
().
getMiddleCertPath
();
if
(!
SDKUtil
.
isEmpty
(
path
))
{
initMiddleCert
();
}
else
{
log
.
error
(
SDKConfig
.
SDK_MIDDLECERT_PATH
+
" not set in "
+
SDKConfig
.
FILE_NAME
);
return
null
;
}
}
return
middleCert
;
}
/**
* 从配置文件acp_sdk.properties中获取验签公钥使用的根证书
*
* @return
*/
public
static
X509Certificate
getRootCert
()
{
if
(
null
==
rootCert
)
{
String
path
=
SDKConfig
.
getConfig
().
getRootCertPath
();
if
(!
SDKUtil
.
isEmpty
(
path
))
{
initRootCert
();
}
else
{
log
.
error
(
SDKConfig
.
SDK_ROOTCERT_PATH
+
" not set in "
+
SDKConfig
.
FILE_NAME
);
return
null
;
}
}
return
rootCert
;
}
/**
* 获取证书的CN
*
* @param aCert
* @return
*/
private
static
String
getIdentitiesFromCertficate
(
X509Certificate
aCert
)
{
String
tDN
=
aCert
.
getSubjectDN
().
toString
();
String
tPart
=
""
;
if
((
tDN
!=
null
))
{
String
tSplitStr
[]
=
tDN
.
substring
(
tDN
.
indexOf
(
"CN="
)).
split
(
"@"
);
if
(
tSplitStr
!=
null
&&
tSplitStr
.
length
>
2
&&
tSplitStr
[
2
]
!=
null
)
tPart
=
tSplitStr
[
2
];
}
return
tPart
;
}
/**
* 验证书链。
*
* @param cert
* @return
*/
private
static
boolean
verifyCertificateChain
(
X509Certificate
cert
)
{
if
(
null
==
cert
)
{
log
.
error
(
"cert must Not null"
);
return
false
;
}
X509Certificate
middleCert
=
CertUtil
.
getMiddleCert
();
if
(
null
==
middleCert
)
{
log
.
error
(
"middleCert must Not null"
);
return
false
;
}
X509Certificate
rootCert
=
CertUtil
.
getRootCert
();
if
(
null
==
rootCert
)
{
log
.
error
(
"rootCert or cert must Not null"
);
return
false
;
}
try
{
X509CertSelector
selector
=
new
X509CertSelector
();
selector
.
setCertificate
(
cert
);
Set
<
TrustAnchor
>
trustAnchors
=
new
HashSet
<
TrustAnchor
>();
trustAnchors
.
add
(
new
TrustAnchor
(
rootCert
,
null
));
PKIXBuilderParameters
pkixParams
=
new
PKIXBuilderParameters
(
trustAnchors
,
selector
);
Set
<
X509Certificate
>
intermediateCerts
=
new
HashSet
<
X509Certificate
>();
intermediateCerts
.
add
(
rootCert
);
intermediateCerts
.
add
(
middleCert
);
intermediateCerts
.
add
(
cert
);
pkixParams
.
setRevocationEnabled
(
false
);
CertStore
intermediateCertStore
=
CertStore
.
getInstance
(
"Collection"
,
new
CollectionCertStoreParameters
(
intermediateCerts
),
"BC"
);
pkixParams
.
addCertStore
(
intermediateCertStore
);
CertPathBuilder
builder
=
CertPathBuilder
.
getInstance
(
"PKIX"
,
"BC"
);
@SuppressWarnings
(
"unused"
)
PKIXCertPathBuilderResult
result
=
(
PKIXCertPathBuilderResult
)
builder
.
build
(
pkixParams
);
log
.
info
(
"verify certificate chain succeed."
);
return
true
;
}
catch
(
java
.
security
.
cert
.
CertPathBuilderException
e
)
{
log
.
error
(
"verify certificate chain fail."
,
e
);
}
catch
(
Exception
e
)
{
log
.
error
(
"verify certificate chain exception: "
,
e
);
}
return
false
;
}
/**
* 检查证书链
*
* @param cert 待验证的证书
* @return
*/
public
static
boolean
verifyCertificate
(
X509Certificate
cert
)
{
if
(
null
==
cert
)
{
log
.
error
(
"cert must Not null"
);
return
false
;
}
try
{
cert
.
checkValidity
();
//验证有效期
// cert.verify(middleCert.getPublicKey());
if
(!
verifyCertificateChain
(
cert
))
{
return
false
;
}
}
catch
(
Exception
e
)
{
log
.
error
(
"verifyCertificate fail"
,
e
);
return
false
;
}
if
(
SDKConfig
.
getConfig
().
isIfValidateCNName
())
{
// 验证公钥是否属于银联
if
(!
SDKConstants
.
UNIONPAY_CNNAME
.
equals
(
CertUtil
.
getIdentitiesFromCertficate
(
cert
)))
{
log
.
error
(
"cer owner is not CUP:"
+
CertUtil
.
getIdentitiesFromCertficate
(
cert
));
return
false
;
}
}
else
{
// 验证公钥是否属于银联
if
(!
SDKConstants
.
UNIONPAY_CNNAME
.
equals
(
CertUtil
.
getIdentitiesFromCertficate
(
cert
))
&&
!
"00040000:SIGN"
.
equals
(
CertUtil
.
getIdentitiesFromCertficate
(
cert
)))
{
log
.
error
(
"cer owner is not CUP:"
+
CertUtil
.
getIdentitiesFromCertficate
(
cert
));
return
false
;
}
}
return
true
;
}
/**
* 打印系统环境信息
*/
private
static
void
printSysInfo
()
{
if
(
log
.
isDebugEnabled
())
{
log
.
debug
(
"================= SYS INFO begin===================="
);
log
.
debug
(
"os_name:"
+
System
.
getProperty
(
"os.name"
));
log
.
debug
(
"os_arch:"
+
System
.
getProperty
(
"os.arch"
));
log
.
debug
(
"os_version:"
+
System
.
getProperty
(
"os.version"
));
log
.
debug
(
"java_vm_specification_version:"
+
System
.
getProperty
(
"java.vm.specification.version"
));
log
.
debug
(
"java_vm_specification_vendor:"
+
System
.
getProperty
(
"java.vm.specification.vendor"
));
log
.
debug
(
"java_vm_specification_name:"
+
System
.
getProperty
(
"java.vm.specification.name"
));
log
.
debug
(
"java_vm_version:"
+
System
.
getProperty
(
"java.vm.version"
));
log
.
debug
(
"java_vm_name:"
+
System
.
getProperty
(
"java.vm.name"
));
log
.
debug
(
"java.version:"
+
System
.
getProperty
(
"java.version"
));
log
.
debug
(
"java.vm.vendor=["
+
System
.
getProperty
(
"java.vm.vendor"
)
+
"]"
);
log
.
debug
(
"java.version=["
+
System
.
getProperty
(
"java.version"
)
+
"]"
);
printProviders
();
log
.
debug
(
"================= SYS INFO end====================="
);
}
}
/**
* 打jre中印算法提供者列表
*/
private
static
void
printProviders
()
{
log
.
debug
(
"Providers List:"
);
Provider
[]
providers
=
Security
.
getProviders
();
for
(
int
i
=
0
;
i
<
providers
.
length
;
i
++)
{
log
.
debug
(
i
+
1
+
"."
+
providers
[
i
].
getName
());
}
}
/**
* 证书文件过滤器
*/
static
class
CerFilter
implements
FilenameFilter
{
public
boolean
isCer
(
String
name
)
{
if
(
name
.
toLowerCase
().
endsWith
(
".cer"
))
{
return
true
;
}
else
{
return
false
;
}
}
@Override
public
boolean
accept
(
File
dir
,
String
name
)
{
return
isCer
(
name
);
}
}
}
src/main/java/com/esv/freight/customer/common/unionpay/DemoBase.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
common
.
unionpay
;
import
com.esv.freight.customer.common.constants.SDKConstants
;
import
lombok.extern.slf4j.Slf4j
;
import
java.io.*
;
import
java.text.SimpleDateFormat
;
import
java.util.*
;
import
java.util.Map.Entry
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipInputStream
;
/**
* @description: demo中用到的方法
* @project: freight-customer-service
* @name: com.esv.freight.customer.common.unionpay.DemoBase
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/05/30 14:38
* @version:1.0
*/
@Slf4j
public
class
DemoBase
{
//默认配置的是UTF-8
public
static
String
encoding
=
"UTF-8"
;
//全渠道固定值
public
static
String
version
=
SDKConfig
.
getConfig
().
getVersion
();
//后台服务对应的写法参照 FrontRcvResponse.java
public
static
String
frontUrl
=
SDKConfig
.
getConfig
().
getFrontUrl
();
//后台服务对应的写法参照 BackRcvResponse.java
public
static
String
backUrl
=
SDKConfig
.
getConfig
().
getBackUrl
();
//受理方和发卡方自选填写的域[O]--后台通知地址
// 商户发送交易时间 格式:yyyyMMddHHmmss
public
static
String
getCurrentTime
()
{
return
new
SimpleDateFormat
(
"yyyyMMddHHmmss"
).
format
(
new
Date
());
}
// AN8..40 商户订单号,不能含"-"或"_"
public
static
String
getOrderId
()
{
return
new
SimpleDateFormat
(
"yyyyMMddHHmmssSSS"
).
format
(
new
Date
());
}
/**
* 组装请求,返回报文字符串用于显示
*
* @param data
* @return
*/
public
static
String
genHtmlResult
(
Map
<
String
,
String
>
data
)
{
TreeMap
<
String
,
String
>
tree
=
new
TreeMap
<
String
,
String
>();
Iterator
<
Entry
<
String
,
String
>>
it
=
data
.
entrySet
().
iterator
();
while
(
it
.
hasNext
())
{
Entry
<
String
,
String
>
en
=
it
.
next
();
tree
.
put
(
en
.
getKey
(),
en
.
getValue
());
}
it
=
tree
.
entrySet
().
iterator
();
StringBuffer
sf
=
new
StringBuffer
();
while
(
it
.
hasNext
())
{
Entry
<
String
,
String
>
en
=
it
.
next
();
String
key
=
en
.
getKey
();
String
value
=
en
.
getValue
();
if
(
"respCode"
.
equals
(
key
))
{
sf
.
append
(
"<b>"
+
key
+
SDKConstants
.
EQUAL
+
value
+
"</br></b>"
);
}
else
{
sf
.
append
(
key
+
SDKConstants
.
EQUAL
+
value
+
"</br>"
);
}
}
return
sf
.
toString
();
}
/**
* 功能:解析全渠道商户对账文件中的ZM文件并以List<Map>方式返回
* 适用交易:对账文件下载后对文件的查看
*
* @param filePath ZM文件全路径
* @return 包含每一笔交易中 序列号 和 值 的map序列
*/
public
static
List
<
Map
>
parseZMFile
(
String
filePath
)
{
int
lengthArray
[]
=
{
3
,
11
,
11
,
6
,
10
,
19
,
12
,
4
,
2
,
21
,
2
,
32
,
2
,
6
,
10
,
13
,
13
,
4
,
15
,
2
,
2
,
6
,
2
,
4
,
32
,
1
,
21
,
15
,
1
,
15
,
32
,
13
,
13
,
8
,
32
,
13
,
13
,
12
,
2
,
1
,
32
,
98
};
return
parseFile
(
filePath
,
lengthArray
);
}
/**
* 功能:解析全渠道商户对账文件中的ZME文件并以List<Map>方式返回
* 适用交易:对账文件下载后对文件的查看
*
* @param filePath ZME文件全路径
* @return 包含每一笔交易中 序列号 和 值 的map序列
*/
public
static
List
<
Map
>
parseZMEFile
(
String
filePath
)
{
int
lengthArray
[]
=
{
3
,
11
,
11
,
6
,
10
,
19
,
12
,
4
,
2
,
2
,
6
,
10
,
4
,
12
,
13
,
13
,
15
,
15
,
1
,
12
,
2
,
135
};
return
parseFile
(
filePath
,
lengthArray
);
}
/**
* 功能:解析全渠道商户 ZM,ZME对账文件
*
* @param filePath
* @param lengthArray 参照《全渠道平台接入接口规范 第3部分 文件接口》 全渠道商户对账文件 6.1 ZM文件和6.2 ZME 文件 格式的类型长度组成int型数组
* @return
*/
private
static
List
<
Map
>
parseFile
(
String
filePath
,
int
lengthArray
[])
{
List
<
Map
>
ZmDataList
=
new
ArrayList
<
Map
>();
try
{
String
encoding
=
"gbk"
;
//文件是gbk编码
File
file
=
new
File
(
filePath
);
if
(
file
.
isFile
()
&&
file
.
exists
())
{
//判断文件是否存在
InputStreamReader
read
=
new
InputStreamReader
(
new
FileInputStream
(
file
),
"iso-8859-1"
);
BufferedReader
bufferedReader
=
new
BufferedReader
(
read
);
String
lineTxt
=
null
;
while
((
lineTxt
=
bufferedReader
.
readLine
())
!=
null
)
{
byte
[]
bs
=
lineTxt
.
getBytes
(
"iso-8859-1"
);
//解析的结果MAP,key为对账文件列序号,value为解析的值
Map
<
Integer
,
String
>
ZmDataMap
=
new
LinkedHashMap
<
Integer
,
String
>();
//左侧游标
int
leftIndex
=
0
;
//右侧游标
int
rightIndex
=
0
;
for
(
int
i
=
0
;
i
<
lengthArray
.
length
;
i
++)
{
rightIndex
=
leftIndex
+
lengthArray
[
i
];
String
filed
=
new
String
(
Arrays
.
copyOfRange
(
bs
,
leftIndex
,
rightIndex
),
encoding
);
leftIndex
=
rightIndex
+
1
;
ZmDataMap
.
put
(
i
,
filed
);
}
ZmDataList
.
add
(
ZmDataMap
);
}
read
.
close
();
}
else
{
System
.
out
.
println
(
"找不到指定的文件"
);
}
}
catch
(
Exception
e
)
{
System
.
out
.
println
(
"读取文件内容出错"
);
e
.
printStackTrace
();
}
return
ZmDataList
;
}
public
static
String
getFileContentTable
(
List
<
Map
>
dataList
,
String
file
)
{
StringBuffer
tableSb
=
new
StringBuffer
(
"对账文件的规范参考 https://open.unionpay.com/ajweb/help/file/ 产品接口规范->平台接口规范:文件接口</br> 文件【"
+
file
+
"】解析后内容如下:"
);
tableSb
.
append
(
"<table border=\"1\">"
);
if
(
dataList
.
size
()
>
0
)
{
Map
<
Integer
,
String
>
dataMapTmp
=
dataList
.
get
(
0
);
tableSb
.
append
(
"<tr>"
);
for
(
Iterator
<
Integer
>
it
=
dataMapTmp
.
keySet
().
iterator
();
it
.
hasNext
();
)
{
Integer
key
=
it
.
next
();
String
value
=
dataMapTmp
.
get
(
key
);
System
.
out
.
println
(
"序号:"
+
(
key
+
1
)
+
" 值: '"
+
value
+
"'"
);
tableSb
.
append
(
"<td>序号"
+
(
key
+
1
)
+
"</td>"
);
}
tableSb
.
append
(
"</tr>"
);
}
for
(
int
i
=
0
;
i
<
dataList
.
size
();
i
++)
{
System
.
out
.
println
(
"行数: "
+
(
i
+
1
));
Map
<
Integer
,
String
>
dataMapTmp
=
dataList
.
get
(
i
);
tableSb
.
append
(
"<tr>"
);
for
(
Iterator
<
Integer
>
it
=
dataMapTmp
.
keySet
().
iterator
();
it
.
hasNext
();
)
{
Integer
key
=
it
.
next
();
String
value
=
dataMapTmp
.
get
(
key
);
System
.
out
.
println
(
"序号:"
+
(
key
+
1
)
+
" 值: '"
+
value
+
"'"
);
tableSb
.
append
(
"<td>"
+
value
+
"</td>"
);
}
tableSb
.
append
(
"</tr>"
);
}
tableSb
.
append
(
"</table>"
);
return
tableSb
.
toString
();
}
public
static
List
<
String
>
unzip
(
String
zipFilePath
,
String
outPutDirectory
)
{
List
<
String
>
fileList
=
new
ArrayList
<
String
>();
try
{
ZipInputStream
zin
=
new
ZipInputStream
(
new
FileInputStream
(
zipFilePath
));
//输入源zip路径
BufferedInputStream
bin
=
new
BufferedInputStream
(
zin
);
BufferedOutputStream
bout
=
null
;
File
file
=
null
;
ZipEntry
entry
;
try
{
while
((
entry
=
zin
.
getNextEntry
())
!=
null
&&
!
entry
.
isDirectory
())
{
file
=
new
File
(
outPutDirectory
,
entry
.
getName
());
if
(!
file
.
exists
())
{
(
new
File
(
file
.
getParent
())).
mkdirs
();
}
bout
=
new
BufferedOutputStream
(
new
FileOutputStream
(
file
));
int
b
;
while
((
b
=
bin
.
read
())
!=
-
1
)
{
bout
.
write
(
b
);
}
bout
.
flush
();
fileList
.
add
(
file
.
getAbsolutePath
());
System
.
out
.
println
(
file
+
"解压成功"
);
}
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
finally
{
try
{
bin
.
close
();
zin
.
close
();
if
(
bout
!=
null
)
{
bout
.
close
();
}
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
}
catch
(
FileNotFoundException
e
)
{
e
.
printStackTrace
();
}
return
fileList
;
}
}
src/main/java/com/esv/freight/customer/common/unionpay/HttpClient.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
common
.
unionpay
;
import
com.esv.freight.customer.common.unionpay.BaseHttpSSLSocketFactory.TrustAnyHostnameVerifier
;
import
lombok.extern.slf4j.Slf4j
;
import
javax.net.ssl.HttpsURLConnection
;
import
java.io.*
;
import
java.net.*
;
import
java.util.Map
;
import
java.util.Map.Entry
;
/**
* @description: acpsdk发送后台http请求类
* @project: freight-customer-service
* @name: com.esv.freight.customer.common.unionpay.HttpClient
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/05/30 14:43
* @version:1.0
*/
@Slf4j
public
class
HttpClient
{
/**
* 目标地址
*/
private
URL
url
;
/**
* 通信连接超时时间
*/
private
int
connectionTimeout
;
/**
* 通信读超时时间
*/
private
int
readTimeOut
;
/**
* 通信结果
*/
private
String
result
;
/**
* 获取通信结果
*
* @return
*/
public
String
getResult
()
{
return
result
;
}
/**
* 设置通信结果
*
* @param result
*/
public
void
setResult
(
String
result
)
{
this
.
result
=
result
;
}
/**
* 构造函数
*
* @param url 目标地址
* @param connectionTimeout HTTP连接超时时间
* @param readTimeOut HTTP读写超时时间
*/
public
HttpClient
(
String
url
,
int
connectionTimeout
,
int
readTimeOut
)
{
try
{
this
.
url
=
new
URL
(
url
);
this
.
connectionTimeout
=
connectionTimeout
;
this
.
readTimeOut
=
readTimeOut
;
}
catch
(
MalformedURLException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
}
/**
* 发送信息到服务端
*
* @param data
* @param encoding
* @return
* @throws Exception
*/
public
int
send
(
Map
<
String
,
String
>
data
,
String
encoding
)
throws
Exception
{
try
{
HttpURLConnection
httpURLConnection
=
createConnection
(
encoding
);
if
(
null
==
httpURLConnection
)
{
throw
new
Exception
(
"Create httpURLConnection Failure"
);
}
String
sendData
=
this
.
getRequestParamString
(
data
,
encoding
);
log
.
info
(
"请求报文(对每个报文域的值均已做url编码):["
+
sendData
+
"]"
);
this
.
requestServer
(
httpURLConnection
,
sendData
,
encoding
);
this
.
result
=
this
.
response
(
httpURLConnection
,
encoding
);
log
.
info
(
"Response message:["
+
result
+
"]"
);
return
httpURLConnection
.
getResponseCode
();
}
catch
(
Exception
e
)
{
throw
e
;
}
}
/**
* 发送信息到服务端 GET方式
*
* @param encoding
* @return
* @throws Exception
*/
public
int
sendGet
(
String
encoding
)
throws
Exception
{
try
{
HttpURLConnection
httpURLConnection
=
createConnectionGet
(
encoding
);
if
(
null
==
httpURLConnection
)
{
throw
new
Exception
(
"创建联接失败"
);
}
this
.
result
=
this
.
response
(
httpURLConnection
,
encoding
);
log
.
info
(
"同步返回报文:["
+
result
+
"]"
);
return
httpURLConnection
.
getResponseCode
();
}
catch
(
Exception
e
)
{
throw
e
;
}
}
/**
* HTTP Post发送消息
*
* @param connection
* @param message
* @throws IOException
*/
private
void
requestServer
(
final
URLConnection
connection
,
String
message
,
String
encoder
)
throws
Exception
{
PrintStream
out
=
null
;
try
{
connection
.
connect
();
out
=
new
PrintStream
(
connection
.
getOutputStream
(),
false
,
encoder
);
out
.
print
(
message
);
out
.
flush
();
}
catch
(
Exception
e
)
{
throw
e
;
}
finally
{
if
(
null
!=
out
)
{
out
.
close
();
}
}
}
/**
* 显示Response消息
*
* @param connection
* @param encoding
* @return
* @throws URISyntaxException
* @throws IOException
*/
private
String
response
(
final
HttpURLConnection
connection
,
String
encoding
)
throws
URISyntaxException
,
IOException
,
Exception
{
InputStream
in
=
null
;
StringBuilder
sb
=
new
StringBuilder
(
1024
);
BufferedReader
br
=
null
;
try
{
if
(
200
==
connection
.
getResponseCode
())
{
in
=
connection
.
getInputStream
();
sb
.
append
(
new
String
(
read
(
in
),
encoding
));
}
else
{
in
=
connection
.
getErrorStream
();
sb
.
append
(
new
String
(
read
(
in
),
encoding
));
}
log
.
info
(
"HTTP Return Status-Code:["
+
connection
.
getResponseCode
()
+
"]"
);
return
sb
.
toString
();
}
catch
(
Exception
e
)
{
throw
e
;
}
finally
{
if
(
null
!=
br
)
{
br
.
close
();
}
if
(
null
!=
in
)
{
in
.
close
();
}
if
(
null
!=
connection
)
{
connection
.
disconnect
();
}
}
}
public
static
byte
[]
read
(
InputStream
in
)
throws
IOException
{
byte
[]
buf
=
new
byte
[
1024
];
int
length
=
0
;
ByteArrayOutputStream
bout
=
new
ByteArrayOutputStream
();
while
((
length
=
in
.
read
(
buf
,
0
,
buf
.
length
))
>
0
)
{
bout
.
write
(
buf
,
0
,
length
);
}
bout
.
flush
();
return
bout
.
toByteArray
();
}
/**
* 创建连接
*
* @return
* @throws ProtocolException
*/
private
HttpURLConnection
createConnection
(
String
encoding
)
throws
ProtocolException
{
HttpURLConnection
httpURLConnection
=
null
;
try
{
httpURLConnection
=
(
HttpURLConnection
)
url
.
openConnection
();
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
null
;
}
httpURLConnection
.
setConnectTimeout
(
this
.
connectionTimeout
);
// 连接超时时间
httpURLConnection
.
setReadTimeout
(
this
.
readTimeOut
);
// 读取结果超时时间
httpURLConnection
.
setDoInput
(
true
);
// 可读
httpURLConnection
.
setDoOutput
(
true
);
// 可写
httpURLConnection
.
setUseCaches
(
false
);
// 取消缓存
httpURLConnection
.
setRequestProperty
(
"Content-type"
,
"application/x-www-form-urlencoded;charset="
+
encoding
);
httpURLConnection
.
setRequestMethod
(
"POST"
);
if
(
"https"
.
equalsIgnoreCase
(
url
.
getProtocol
()))
{
HttpsURLConnection
husn
=
(
HttpsURLConnection
)
httpURLConnection
;
//是否验证https证书,测试环境请设置false,生产环境建议优先尝试true,不行再false
if
(!
SDKConfig
.
getConfig
().
isIfValidateRemoteCert
())
{
husn
.
setSSLSocketFactory
(
new
BaseHttpSSLSocketFactory
());
husn
.
setHostnameVerifier
(
new
TrustAnyHostnameVerifier
());
//解决由于服务器证书问题导致HTTPS无法访问的情况
}
return
husn
;
}
return
httpURLConnection
;
}
/**
* 创建连接
*
* @return
* @throws ProtocolException
*/
private
HttpURLConnection
createConnectionGet
(
String
encoding
)
throws
ProtocolException
{
HttpURLConnection
httpURLConnection
=
null
;
try
{
httpURLConnection
=
(
HttpURLConnection
)
url
.
openConnection
();
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
null
;
}
httpURLConnection
.
setConnectTimeout
(
this
.
connectionTimeout
);
// 连接超时时间
httpURLConnection
.
setReadTimeout
(
this
.
readTimeOut
);
// 读取结果超时时间
httpURLConnection
.
setUseCaches
(
false
);
// 取消缓存
httpURLConnection
.
setRequestProperty
(
"Content-type"
,
"application/x-www-form-urlencoded;charset="
+
encoding
);
httpURLConnection
.
setRequestMethod
(
"GET"
);
if
(
"https"
.
equalsIgnoreCase
(
url
.
getProtocol
()))
{
HttpsURLConnection
husn
=
(
HttpsURLConnection
)
httpURLConnection
;
//是否验证https证书,测试环境请设置false,生产环境建议优先尝试true,不行再false
if
(!
SDKConfig
.
getConfig
().
isIfValidateRemoteCert
())
{
husn
.
setSSLSocketFactory
(
new
BaseHttpSSLSocketFactory
());
husn
.
setHostnameVerifier
(
new
TrustAnyHostnameVerifier
());
//解决由于服务器证书问题导致HTTPS无法访问的情况
}
return
husn
;
}
return
httpURLConnection
;
}
/**
* 将Map存储的对象,转换为key=value&key=value的字符
*
* @param requestParam
* @param coder
* @return
*/
private
String
getRequestParamString
(
Map
<
String
,
String
>
requestParam
,
String
coder
)
{
if
(
null
==
coder
||
""
.
equals
(
coder
))
{
coder
=
"UTF-8"
;
}
StringBuffer
sf
=
new
StringBuffer
(
""
);
String
reqstr
=
""
;
if
(
null
!=
requestParam
&&
0
!=
requestParam
.
size
())
{
for
(
Entry
<
String
,
String
>
en
:
requestParam
.
entrySet
())
{
try
{
sf
.
append
(
en
.
getKey
()
+
"="
+
(
null
==
en
.
getValue
()
||
""
.
equals
(
en
.
getValue
())
?
""
:
URLEncoder
.
encode
(
en
.
getValue
(),
coder
))
+
"&"
);
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
""
;
}
}
reqstr
=
sf
.
substring
(
0
,
sf
.
length
()
-
1
);
}
log
.
info
(
"Request Message:["
+
reqstr
+
"]"
);
return
reqstr
;
}
}
src/main/java/com/esv/freight/customer/common/unionpay/SDKConfig.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
common
.
unionpay
;
import
com.esv.freight.customer.common.constants.SDKConstants
;
import
lombok.extern.slf4j.Slf4j
;
import
java.io.*
;
import
java.util.Properties
;
/**
* @description: acpsdk配置文件acp_sdk.properties配置信息类
* @project: freight-customer-service
* @name: com.esv.freight.customer.common.unionpay.SDKConfig
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/05/30 14:25
* @version:1.0
*/
@Slf4j
public
class
SDKConfig
{
public
static
final
String
FILE_NAME
=
"acp_sdk_dev.properties"
;
/**
* 前台请求URL.
*/
private
String
frontRequestUrl
;
/**
* 后台请求URL.
*/
private
String
backRequestUrl
;
/**
* 二维码统一下单请求URL.
*/
private
String
orderRequestUrl
;
/**
* 单笔查询
*/
private
String
singleQueryUrl
;
/**
* 批量查询
*/
private
String
batchQueryUrl
;
/**
* 批量交易
*/
private
String
batchTransUrl
;
/**
* 文件传输
*/
private
String
fileTransUrl
;
/**
* 签名证书路径.
*/
private
String
signCertPath
;
/**
* 签名证书密码.
*/
private
String
signCertPwd
;
/**
* 签名证书类型.
*/
private
String
signCertType
;
/**
* 加密公钥证书路径.
*/
private
String
encryptCertPath
;
/**
* 验证签名公钥证书目录.
*/
private
String
validateCertDir
;
/**
* 按照商户代码读取指定签名证书目录.
*/
private
String
signCertDir
;
/**
* 磁道加密证书路径.
*/
private
String
encryptTrackCertPath
;
/**
* 磁道加密公钥模数.
*/
private
String
encryptTrackKeyModulus
;
/**
* 磁道加密公钥指数.
*/
private
String
encryptTrackKeyExponent
;
/**
* 有卡交易.
*/
private
String
cardRequestUrl
;
/**
* app交易
*/
private
String
appRequestUrl
;
/**
* 证书使用模式(单证书/多证书)
*/
private
String
singleMode
;
/**
* 安全密钥(SHA256和SM3计算时使用)
*/
private
String
secureKey
;
/**
* 中级证书路径
*/
private
String
middleCertPath
;
/**
* 根证书路径
*/
private
String
rootCertPath
;
/**
* 是否验证验签证书CN,除了false都验
*/
private
boolean
ifValidateCNName
=
true
;
/**
* 是否验证https证书,默认都不验
*/
private
boolean
ifValidateRemoteCert
=
false
;
/**
* signMethod,没配按01吧
*/
private
String
signMethod
=
"01"
;
/**
* version,没配按5.0.0
*/
private
String
version
=
"5.0.0"
;
/**
* frontUrl
*/
private
String
frontUrl
;
/**
* backUrl
*/
private
String
backUrl
;
/**
* frontFailUrl
*/
private
String
frontFailUrl
;
/*缴费相关地址*/
private
String
jfFrontRequestUrl
;
private
String
jfBackRequestUrl
;
private
String
jfSingleQueryUrl
;
private
String
jfCardRequestUrl
;
private
String
jfAppRequestUrl
;
private
String
qrcBackTransUrl
;
private
String
qrcB2cIssBackTransUrl
;
private
String
qrcB2cMerBackTransUrl
;
//综合认证
private
String
zhrzFrontRequestUrl
;
private
String
zhrzBackRequestUrl
;
private
String
zhrzSingleQueryUrl
;
private
String
zhrzCardRequestUrl
;
private
String
zhrzAppRequestUrl
;
private
String
zhrzFaceRequestUrl
;
/**
* 配置文件中的前台URL常量.
*/
public
static
final
String
SDK_FRONT_URL
=
"acpsdk.frontTransUrl"
;
/**
* 配置文件中的后台URL常量.
*/
public
static
final
String
SDK_BACK_URL
=
"acpsdk.backTransUrl"
;
/**
* 配置文件中的统一下单URL常量.
*/
public
static
final
String
SDK_ORDER_URL
=
"acpsdk.orderTransUrl"
;
/**
* 配置文件中的单笔交易查询URL常量.
*/
public
static
final
String
SDK_SIGNQ_URL
=
"acpsdk.singleQueryUrl"
;
/**
* 配置文件中的批量交易查询URL常量.
*/
public
static
final
String
SDK_BATQ_URL
=
"acpsdk.batchQueryUrl"
;
/**
* 配置文件中的批量交易URL常量.
*/
public
static
final
String
SDK_BATTRANS_URL
=
"acpsdk.batchTransUrl"
;
/**
* 配置文件中的文件类交易URL常量.
*/
public
static
final
String
SDK_FILETRANS_URL
=
"acpsdk.fileTransUrl"
;
/**
* 配置文件中的有卡交易URL常量.
*/
public
static
final
String
SDK_CARD_URL
=
"acpsdk.cardTransUrl"
;
/**
* 配置文件中的app交易URL常量.
*/
public
static
final
String
SDK_APP_URL
=
"acpsdk.appTransUrl"
;
/**
* 以下缴费产品使用,其余产品用不到,无视即可
*/
// 前台请求地址
public
static
final
String
JF_SDK_FRONT_TRANS_URL
=
"acpsdk.jfFrontTransUrl"
;
// 后台请求地址
public
static
final
String
JF_SDK_BACK_TRANS_URL
=
"acpsdk.jfBackTransUrl"
;
// 单笔查询请求地址
public
static
final
String
JF_SDK_SINGLE_QUERY_URL
=
"acpsdk.jfSingleQueryUrl"
;
// 有卡交易地址
public
static
final
String
JF_SDK_CARD_TRANS_URL
=
"acpsdk.jfCardTransUrl"
;
// App交易地址
public
static
final
String
JF_SDK_APP_TRANS_URL
=
"acpsdk.jfAppTransUrl"
;
// 人到人
public
static
final
String
QRC_BACK_TRANS_URL
=
"acpsdk.qrcBackTransUrl"
;
// 人到人
public
static
final
String
QRC_B2C_ISS_BACK_TRANS_URL
=
"acpsdk.qrcB2cIssBackTransUrl"
;
// 人到人
public
static
final
String
QRC_B2C_MER_BACK_TRANS_URL
=
"acpsdk.qrcB2cMerBackTransUrl"
;
/**
* 以下综合认证产品使用,其余产品用不到,无视即可
*/
// 前台请求地址
public
static
final
String
ZHRZ_SDK_FRONT_TRANS_URL
=
"acpsdk.zhrzFrontTransUrl"
;
// 后台请求地址
public
static
final
String
ZHRZ_SDK_BACK_TRANS_URL
=
"acpsdk.zhrzBackTransUrl"
;
// 单笔查询请求地址
public
static
final
String
ZHRZ_SDK_SINGLE_QUERY_URL
=
"acpsdk.zhrzSingleQueryUrl"
;
// 有卡交易地址
public
static
final
String
ZHRZ_SDK_CARD_TRANS_URL
=
"acpsdk.zhrzCardTransUrl"
;
// App交易地址
public
static
final
String
ZHRZ_SDK_APP_TRANS_URL
=
"acpsdk.zhrzAppTransUrl"
;
// 图片识别交易地址
public
static
final
String
ZHRZ_SDK_FACE_TRANS_URL
=
"acpsdk.zhrzFaceTransUrl"
;
/**
* 配置文件中签名证书路径常量.
*/
public
static
final
String
SDK_SIGNCERT_PATH
=
"acpsdk.signCert.path"
;
/**
* 配置文件中签名证书密码常量.
*/
public
static
final
String
SDK_SIGNCERT_PWD
=
"acpsdk.signCert.pwd"
;
/**
* 配置文件中签名证书类型常量.
*/
public
static
final
String
SDK_SIGNCERT_TYPE
=
"acpsdk.signCert.type"
;
/**
* 配置文件中密码加密证书路径常量.
*/
public
static
final
String
SDK_ENCRYPTCERT_PATH
=
"acpsdk.encryptCert.path"
;
/**
* 配置文件中磁道加密证书路径常量.
*/
public
static
final
String
SDK_ENCRYPTTRACKCERT_PATH
=
"acpsdk.encryptTrackCert.path"
;
/**
* 配置文件中磁道加密公钥模数常量.
*/
public
static
final
String
SDK_ENCRYPTTRACKKEY_MODULUS
=
"acpsdk.encryptTrackKey.modulus"
;
/**
* 配置文件中磁道加密公钥指数常量.
*/
public
static
final
String
SDK_ENCRYPTTRACKKEY_EXPONENT
=
"acpsdk.encryptTrackKey.exponent"
;
/**
* 配置文件中验证签名证书目录常量.
*/
public
static
final
String
SDK_VALIDATECERT_DIR
=
"acpsdk.validateCert.dir"
;
/**
* 配置文件中是否加密cvn2常量.
*/
public
static
final
String
SDK_CVN_ENC
=
"acpsdk.cvn2.enc"
;
/**
* 配置文件中是否加密cvn2有效期常量.
*/
public
static
final
String
SDK_DATE_ENC
=
"acpsdk.date.enc"
;
/**
* 配置文件中是否加密卡号常量.
*/
public
static
final
String
SDK_PAN_ENC
=
"acpsdk.pan.enc"
;
/**
* 配置文件中证书使用模式
*/
public
static
final
String
SDK_SINGLEMODE
=
"acpsdk.singleMode"
;
/**
* 配置文件中安全密钥
*/
public
static
final
String
SDK_SECURITYKEY
=
"acpsdk.secureKey"
;
/**
* 配置文件中根证书路径常量
*/
public
static
final
String
SDK_ROOTCERT_PATH
=
"acpsdk.rootCert.path"
;
/**
* 配置文件中根证书路径常量
*/
public
static
final
String
SDK_MIDDLECERT_PATH
=
"acpsdk.middleCert.path"
;
/**
* 配置是否需要验证验签证书CN,除了false之外的值都当true处理
*/
public
static
final
String
SDK_IF_VALIDATE_CN_NAME
=
"acpsdk.ifValidateCNName"
;
/**
* 配置是否需要验证https证书,除了true之外的值都当false处理
*/
public
static
final
String
SDK_IF_VALIDATE_REMOTE_CERT
=
"acpsdk.ifValidateRemoteCert"
;
/**
* signmethod
*/
public
static
final
String
SDK_SIGN_METHOD
=
"acpsdk.signMethod"
;
/**
* version
*/
public
static
final
String
SDK_VERSION
=
"acpsdk.version"
;
/**
* 后台通知地址
*/
public
static
final
String
SDK_BACKURL
=
"acpsdk.backUrl"
;
/**
* 前台通知地址
*/
public
static
final
String
SDK_FRONTURL
=
"acpsdk.frontUrl"
;
/**
* 前台失败通知地址
*/
public
static
final
String
SDK_FRONT_FAIL_URL
=
"acpsdk.frontFailUrl"
;
/**
* 操作对象.
*/
private
static
SDKConfig
config
=
new
SDKConfig
();
/**
* 属性文件对象.
*/
private
Properties
properties
;
private
SDKConfig
()
{
super
();
}
/**
* 获取config对象.
*
* @return
*/
public
static
SDKConfig
getConfig
()
{
return
config
;
}
/**
* 从properties文件加载
*
* @param rootPath 包含文件名的目录.
*/
public
void
loadPropertiesFromPath
(
String
rootPath
)
{
if
(
rootPath
!=
null
&&
!
""
.
equals
(
rootPath
.
trim
()))
{
log
.
info
(
"从路径读取配置文件: "
+
rootPath
);
File
file
=
new
File
(
rootPath
);
InputStream
in
=
null
;
if
(
file
.
exists
())
{
try
{
in
=
new
FileInputStream
(
file
);
properties
=
new
Properties
();
properties
.
load
(
in
);
loadProperties
(
properties
);
}
catch
(
FileNotFoundException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
finally
{
if
(
null
!=
in
)
{
try
{
in
.
close
();
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
}
}
}
else
{
// 由于此时可能还没有完成LOG的加载,因此采用标准输出来打印日志信息
log
.
error
(
rootPath
+
FILE_NAME
+
"不存在,加载参数失败"
);
}
}
else
{
loadPropertiesFromSrc
();
}
}
/**
* 从classpath路径下加载配置参数
*/
public
void
loadPropertiesFromSrc
()
{
InputStream
in
=
null
;
try
{
log
.
info
(
"从classpath: "
+
SDKConfig
.
class
.
getClassLoader
().
getResource
(
""
).
getPath
()
+
" 获取属性文件"
+
FILE_NAME
);
in
=
SDKConfig
.
class
.
getClassLoader
().
getResourceAsStream
(
FILE_NAME
);
if
(
null
!=
in
)
{
properties
=
new
Properties
();
try
{
properties
.
load
(
in
);
}
catch
(
IOException
e
)
{
throw
e
;
}
}
else
{
log
.
error
(
FILE_NAME
+
"属性文件未能在classpath指定的目录下 "
+
SDKConfig
.
class
.
getClassLoader
().
getResource
(
""
).
getPath
()
+
" 找到!"
);
return
;
}
loadProperties
(
properties
);
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
finally
{
if
(
null
!=
in
)
{
try
{
in
.
close
();
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
}
}
}
/**
* 根据传入的 {Properties}对象设置配置参数
*
* @param pro
*/
public
void
loadProperties
(
Properties
pro
)
{
log
.
info
(
"开始从属性文件中加载配置项"
);
String
value
=
null
;
value
=
pro
.
getProperty
(
SDK_SIGNCERT_PATH
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
signCertPath
=
value
.
trim
();
log
.
info
(
"配置项:私钥签名证书路径==>"
+
SDK_SIGNCERT_PATH
+
"==>"
+
value
+
" 已加载"
);
}
value
=
pro
.
getProperty
(
SDK_SIGNCERT_PWD
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
signCertPwd
=
value
.
trim
();
log
.
info
(
"配置项:私钥签名证书密码==>"
+
SDK_SIGNCERT_PWD
+
" 已加载"
);
}
value
=
pro
.
getProperty
(
SDK_SIGNCERT_TYPE
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
signCertType
=
value
.
trim
();
log
.
info
(
"配置项:私钥签名证书类型==>"
+
SDK_SIGNCERT_TYPE
+
"==>"
+
value
+
" 已加载"
);
}
value
=
pro
.
getProperty
(
SDK_ENCRYPTCERT_PATH
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
encryptCertPath
=
value
.
trim
();
log
.
info
(
"配置项:敏感信息加密证书==>"
+
SDK_ENCRYPTCERT_PATH
+
"==>"
+
value
+
" 已加载"
);
}
value
=
pro
.
getProperty
(
SDK_VALIDATECERT_DIR
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
validateCertDir
=
value
.
trim
();
log
.
info
(
"配置项:验证签名证书路径(这里配置的是目录,不要指定到公钥文件)==>"
+
SDK_VALIDATECERT_DIR
+
"==>"
+
value
+
" 已加载"
);
}
value
=
pro
.
getProperty
(
SDK_FRONT_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
frontRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_BACK_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
backRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_ORDER_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
orderRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_BATQ_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
batchQueryUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_BATTRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
batchTransUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_FILETRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
fileTransUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_SIGNQ_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
singleQueryUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_CARD_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
cardRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_APP_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
appRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_ENCRYPTTRACKCERT_PATH
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
encryptTrackCertPath
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_SECURITYKEY
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
secureKey
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_ROOTCERT_PATH
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
rootCertPath
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_MIDDLECERT_PATH
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
middleCertPath
=
value
.
trim
();
}
/**缴费部分**/
value
=
pro
.
getProperty
(
JF_SDK_FRONT_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
jfFrontRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
JF_SDK_BACK_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
jfBackRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
JF_SDK_SINGLE_QUERY_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
jfSingleQueryUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
JF_SDK_CARD_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
jfCardRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
JF_SDK_APP_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
jfAppRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
QRC_BACK_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
qrcBackTransUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
QRC_B2C_ISS_BACK_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
qrcB2cIssBackTransUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
QRC_B2C_MER_BACK_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
qrcB2cMerBackTransUrl
=
value
.
trim
();
}
/**综合认证**/
value
=
pro
.
getProperty
(
ZHRZ_SDK_FRONT_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
zhrzFrontRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
ZHRZ_SDK_BACK_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
zhrzBackRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
ZHRZ_SDK_SINGLE_QUERY_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
zhrzSingleQueryUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
ZHRZ_SDK_CARD_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
zhrzCardRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
ZHRZ_SDK_APP_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
zhrzAppRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
ZHRZ_SDK_FACE_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
zhrzFaceRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_ENCRYPTTRACKKEY_EXPONENT
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
encryptTrackKeyExponent
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_ENCRYPTTRACKKEY_MODULUS
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
encryptTrackKeyModulus
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_IF_VALIDATE_CN_NAME
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
if
(
SDKConstants
.
FALSE_STRING
.
equals
(
value
.
trim
()))
{
this
.
ifValidateCNName
=
false
;
}
}
value
=
pro
.
getProperty
(
SDK_IF_VALIDATE_REMOTE_CERT
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
if
(
SDKConstants
.
TRUE_STRING
.
equals
(
value
.
trim
()))
{
this
.
ifValidateRemoteCert
=
true
;
}
}
value
=
pro
.
getProperty
(
SDK_SIGN_METHOD
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
signMethod
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_SIGN_METHOD
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
signMethod
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_VERSION
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
version
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_FRONTURL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
frontUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_BACKURL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
backUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_FRONT_FAIL_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
frontFailUrl
=
value
.
trim
();
}
}
public
String
getFrontRequestUrl
()
{
return
frontRequestUrl
;
}
public
void
setFrontRequestUrl
(
String
frontRequestUrl
)
{
this
.
frontRequestUrl
=
frontRequestUrl
;
}
public
String
getBackRequestUrl
()
{
return
backRequestUrl
;
}
public
void
setBackRequestUrl
(
String
backRequestUrl
)
{
this
.
backRequestUrl
=
backRequestUrl
;
}
public
String
getOrderRequestUrl
()
{
return
orderRequestUrl
;
}
public
void
setOrderRequestUrl
(
String
orderRequestUrl
)
{
this
.
orderRequestUrl
=
orderRequestUrl
;
}
public
String
getSignCertPath
()
{
return
signCertPath
;
}
public
void
setSignCertPath
(
String
signCertPath
)
{
this
.
signCertPath
=
signCertPath
;
}
public
String
getSignCertPwd
()
{
return
signCertPwd
;
}
public
void
setSignCertPwd
(
String
signCertPwd
)
{
this
.
signCertPwd
=
signCertPwd
;
}
public
String
getSignCertType
()
{
return
signCertType
;
}
public
void
setSignCertType
(
String
signCertType
)
{
this
.
signCertType
=
signCertType
;
}
public
String
getEncryptCertPath
()
{
return
encryptCertPath
;
}
public
void
setEncryptCertPath
(
String
encryptCertPath
)
{
this
.
encryptCertPath
=
encryptCertPath
;
}
public
String
getValidateCertDir
()
{
return
validateCertDir
;
}
public
void
setValidateCertDir
(
String
validateCertDir
)
{
this
.
validateCertDir
=
validateCertDir
;
}
public
String
getSingleQueryUrl
()
{
return
singleQueryUrl
;
}
public
void
setSingleQueryUrl
(
String
singleQueryUrl
)
{
this
.
singleQueryUrl
=
singleQueryUrl
;
}
public
String
getBatchQueryUrl
()
{
return
batchQueryUrl
;
}
public
void
setBatchQueryUrl
(
String
batchQueryUrl
)
{
this
.
batchQueryUrl
=
batchQueryUrl
;
}
public
String
getBatchTransUrl
()
{
return
batchTransUrl
;
}
public
void
setBatchTransUrl
(
String
batchTransUrl
)
{
this
.
batchTransUrl
=
batchTransUrl
;
}
public
String
getFileTransUrl
()
{
return
fileTransUrl
;
}
public
void
setFileTransUrl
(
String
fileTransUrl
)
{
this
.
fileTransUrl
=
fileTransUrl
;
}
public
String
getSignCertDir
()
{
return
signCertDir
;
}
public
void
setSignCertDir
(
String
signCertDir
)
{
this
.
signCertDir
=
signCertDir
;
}
public
Properties
getProperties
()
{
return
properties
;
}
public
void
setProperties
(
Properties
properties
)
{
this
.
properties
=
properties
;
}
public
String
getCardRequestUrl
()
{
return
cardRequestUrl
;
}
public
void
setCardRequestUrl
(
String
cardRequestUrl
)
{
this
.
cardRequestUrl
=
cardRequestUrl
;
}
public
String
getAppRequestUrl
()
{
return
appRequestUrl
;
}
public
void
setAppRequestUrl
(
String
appRequestUrl
)
{
this
.
appRequestUrl
=
appRequestUrl
;
}
public
String
getEncryptTrackCertPath
()
{
return
encryptTrackCertPath
;
}
public
void
setEncryptTrackCertPath
(
String
encryptTrackCertPath
)
{
this
.
encryptTrackCertPath
=
encryptTrackCertPath
;
}
public
String
getJfFrontRequestUrl
()
{
return
jfFrontRequestUrl
;
}
public
void
setJfFrontRequestUrl
(
String
jfFrontRequestUrl
)
{
this
.
jfFrontRequestUrl
=
jfFrontRequestUrl
;
}
public
String
getJfBackRequestUrl
()
{
return
jfBackRequestUrl
;
}
public
void
setJfBackRequestUrl
(
String
jfBackRequestUrl
)
{
this
.
jfBackRequestUrl
=
jfBackRequestUrl
;
}
public
String
getJfSingleQueryUrl
()
{
return
jfSingleQueryUrl
;
}
public
void
setJfSingleQueryUrl
(
String
jfSingleQueryUrl
)
{
this
.
jfSingleQueryUrl
=
jfSingleQueryUrl
;
}
public
String
getJfCardRequestUrl
()
{
return
jfCardRequestUrl
;
}
public
void
setJfCardRequestUrl
(
String
jfCardRequestUrl
)
{
this
.
jfCardRequestUrl
=
jfCardRequestUrl
;
}
public
String
getJfAppRequestUrl
()
{
return
jfAppRequestUrl
;
}
public
void
setJfAppRequestUrl
(
String
jfAppRequestUrl
)
{
this
.
jfAppRequestUrl
=
jfAppRequestUrl
;
}
public
String
getSingleMode
()
{
return
singleMode
;
}
public
void
setSingleMode
(
String
singleMode
)
{
this
.
singleMode
=
singleMode
;
}
public
String
getEncryptTrackKeyExponent
()
{
return
encryptTrackKeyExponent
;
}
public
void
setEncryptTrackKeyExponent
(
String
encryptTrackKeyExponent
)
{
this
.
encryptTrackKeyExponent
=
encryptTrackKeyExponent
;
}
public
String
getEncryptTrackKeyModulus
()
{
return
encryptTrackKeyModulus
;
}
public
void
setEncryptTrackKeyModulus
(
String
encryptTrackKeyModulus
)
{
this
.
encryptTrackKeyModulus
=
encryptTrackKeyModulus
;
}
public
String
getSecureKey
()
{
return
secureKey
;
}
public
void
setSecureKey
(
String
securityKey
)
{
this
.
secureKey
=
securityKey
;
}
public
String
getMiddleCertPath
()
{
return
middleCertPath
;
}
public
void
setMiddleCertPath
(
String
middleCertPath
)
{
this
.
middleCertPath
=
middleCertPath
;
}
public
boolean
isIfValidateCNName
()
{
return
ifValidateCNName
;
}
public
void
setIfValidateCNName
(
boolean
ifValidateCNName
)
{
this
.
ifValidateCNName
=
ifValidateCNName
;
}
public
boolean
isIfValidateRemoteCert
()
{
return
ifValidateRemoteCert
;
}
public
void
setIfValidateRemoteCert
(
boolean
ifValidateRemoteCert
)
{
this
.
ifValidateRemoteCert
=
ifValidateRemoteCert
;
}
public
String
getSignMethod
()
{
return
signMethod
;
}
public
void
setSignMethod
(
String
signMethod
)
{
this
.
signMethod
=
signMethod
;
}
public
String
getQrcBackTransUrl
()
{
return
qrcBackTransUrl
;
}
public
void
setQrcBackTransUrl
(
String
qrcBackTransUrl
)
{
this
.
qrcBackTransUrl
=
qrcBackTransUrl
;
}
public
String
getQrcB2cIssBackTransUrl
()
{
return
qrcB2cIssBackTransUrl
;
}
public
void
setQrcB2cIssBackTransUrl
(
String
qrcB2cIssBackTransUrl
)
{
this
.
qrcB2cIssBackTransUrl
=
qrcB2cIssBackTransUrl
;
}
public
String
getQrcB2cMerBackTransUrl
()
{
return
qrcB2cMerBackTransUrl
;
}
public
void
setQrcB2cMerBackTransUrl
(
String
qrcB2cMerBackTransUrl
)
{
this
.
qrcB2cMerBackTransUrl
=
qrcB2cMerBackTransUrl
;
}
public
String
getZhrzFrontRequestUrl
()
{
return
zhrzFrontRequestUrl
;
}
public
String
getZhrzBackRequestUrl
()
{
return
zhrzBackRequestUrl
;
}
public
String
getZhrzSingleQueryUrl
()
{
return
zhrzSingleQueryUrl
;
}
public
String
getZhrzCardRequestUrl
()
{
return
zhrzCardRequestUrl
;
}
public
String
getZhrzAppRequestUrl
()
{
return
zhrzAppRequestUrl
;
}
public
String
getZhrzFaceRequestUrl
()
{
return
zhrzFaceRequestUrl
;
}
public
String
getVersion
()
{
return
version
;
}
public
void
setVersion
(
String
version
)
{
this
.
version
=
version
;
}
public
String
getFrontUrl
()
{
return
frontUrl
;
}
public
void
setFrontUrl
(
String
frontUrl
)
{
this
.
frontUrl
=
frontUrl
;
}
public
String
getBackUrl
()
{
return
backUrl
;
}
public
void
setBackUrl
(
String
backUrl
)
{
this
.
backUrl
=
backUrl
;
}
public
String
getFrontFailUrl
()
{
return
frontFailUrl
;
}
public
String
getRootCertPath
()
{
return
rootCertPath
;
}
public
void
setRootCertPath
(
String
rootCertPath
)
{
this
.
rootCertPath
=
rootCertPath
;
}
}
src/main/java/com/esv/freight/customer/common/unionpay/SDKUtil.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
common
.
unionpay
;
import
com.esv.freight.customer.common.constants.SDKConstants
;
import
lombok.extern.slf4j.Slf4j
;
import
java.io.*
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.security.cert.X509Certificate
;
import
java.util.*
;
import
java.util.Map.Entry
;
import
java.util.zip.Deflater
;
import
java.util.zip.Inflater
;
/**
* @description: 银联支付:acpsdk工具类
* @project: freight-customer-service
* @name: com.esv.freight.customer.common.unionpay.SDKUtil
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/05/30 14:11
* @version:1.0
*/
@Slf4j
public
class
SDKUtil
{
/**
* 根据signMethod的值,提供三种计算签名的方法
*
* @param data 待签名数据Map键值对形式
* @param encoding 编码
* @return 签名是否成功
*/
public
static
boolean
sign
(
Map
<
String
,
String
>
data
,
String
encoding
)
{
if
(
isEmpty
(
encoding
))
{
encoding
=
"UTF-8"
;
}
String
signMethod
=
data
.
get
(
SDKConstants
.
param_signMethod
);
String
version
=
data
.
get
(
SDKConstants
.
param_version
);
if
(!
SDKConstants
.
VERSION_1_0_0
.
equals
(
version
)
&&
!
SDKConstants
.
VERSION_5_0_1
.
equals
(
version
)
&&
isEmpty
(
signMethod
))
{
log
.
error
(
"signMethod must Not null"
);
return
false
;
}
if
(
isEmpty
(
version
))
{
log
.
error
(
"version must Not null"
);
return
false
;
}
if
(
SDKConstants
.
SIGNMETHOD_RSA
.
equals
(
signMethod
)
||
SDKConstants
.
VERSION_1_0_0
.
equals
(
version
)
||
SDKConstants
.
VERSION_5_0_1
.
equals
(
version
))
{
if
(
SDKConstants
.
VERSION_5_0_0
.
equals
(
version
)
||
SDKConstants
.
VERSION_1_0_0
.
equals
(
version
)
||
SDKConstants
.
VERSION_5_0_1
.
equals
(
version
))
{
// 设置签名证书序列号
data
.
put
(
SDKConstants
.
param_certId
,
CertUtil
.
getSignCertId
());
// 将Map信息转换成key1=value1&key2=value2的形式
String
stringData
=
coverMap2String
(
data
);
log
.
info
(
"打印排序后待签名请求报文串(交易返回11验证签名失败时可以用来同正确的进行比对):["
+
stringData
+
"]"
);
byte
[]
byteSign
;
String
stringSign
;
try
{
// 通过SHA1进行摘要并转16进制
byte
[]
signDigest
=
SecureUtil
.
sha1X16
(
stringData
,
encoding
);
log
.
info
(
"打印摘要(交易返回11验证签名失败可以用来同正确的进行比对):["
+
new
String
(
signDigest
)
+
"]"
);
byteSign
=
SecureUtil
.
base64Encode
(
SecureUtil
.
signBySoft
(
CertUtil
.
getSignCertPrivateKey
(),
signDigest
));
stringSign
=
new
String
(
byteSign
);
// 设置签名域值
data
.
put
(
SDKConstants
.
param_signature
,
stringSign
);
return
true
;
}
catch
(
Exception
e
)
{
log
.
error
(
"Sign Error"
,
e
);
return
false
;
}
}
else
if
(
SDKConstants
.
VERSION_5_1_0
.
equals
(
version
))
{
// 设置签名证书序列号
data
.
put
(
SDKConstants
.
param_certId
,
CertUtil
.
getSignCertId
());
// 将Map信息转换成key1=value1&key2=value2的形式
String
stringData
=
coverMap2String
(
data
);
log
.
info
(
"打印待签名请求报文串(交易返回11验证签名失败时可以用来同正确的进行比对):["
+
stringData
+
"]"
);
byte
[]
byteSign
;
String
stringSign
;
try
{
// 通过SHA256进行摘要并转16进制
byte
[]
signDigest
=
SecureUtil
.
sha256X16
(
stringData
,
encoding
);
log
.
info
(
"打印摘要(交易返回11验证签名失败可以用来同正确的进行比对):["
+
new
String
(
signDigest
)
+
"]"
);
byteSign
=
SecureUtil
.
base64Encode
(
SecureUtil
.
signBySoft256
(
CertUtil
.
getSignCertPrivateKey
(),
signDigest
));
stringSign
=
new
String
(
byteSign
);
// 设置签名域值
data
.
put
(
SDKConstants
.
param_signature
,
stringSign
);
return
true
;
}
catch
(
Exception
e
)
{
log
.
error
(
"Sign Error"
,
e
);
return
false
;
}
}
}
else
if
(
SDKConstants
.
SIGNMETHOD_SHA256
.
equals
(
signMethod
))
{
return
signBySecureKey
(
data
,
SDKConfig
.
getConfig
().
getSecureKey
(),
encoding
);
}
else
if
(
SDKConstants
.
SIGNMETHOD_SM3
.
equals
(
signMethod
))
{
return
signBySecureKey
(
data
,
SDKConfig
.
getConfig
().
getSecureKey
(),
encoding
);
}
return
false
;
}
/**
* 通过传入的证书绝对路径和证书密码读取签名证书进行签名并返回签名值<br>
*
* @param data 待签名数据Map键值对形式
* @param secureKey
* @param encoding 编码
* @return 签名值
*/
public
static
boolean
signBySecureKey
(
Map
<
String
,
String
>
data
,
String
secureKey
,
String
encoding
)
{
if
(
isEmpty
(
encoding
))
{
encoding
=
"UTF-8"
;
}
if
(
isEmpty
(
secureKey
))
{
log
.
error
(
"secureKey is empty"
);
return
false
;
}
String
signMethod
=
data
.
get
(
SDKConstants
.
param_signMethod
);
if
(
isEmpty
(
signMethod
))
{
log
.
error
(
"signMethod must Not null"
);
return
false
;
}
if
(
SDKConstants
.
SIGNMETHOD_SHA256
.
equals
(
signMethod
))
{
// 将Map信息转换成key1=value1&key2=value2的形式
String
stringData
=
coverMap2String
(
data
);
log
.
info
(
"待签名请求报文串:["
+
stringData
+
"]"
);
String
strBeforeSha256
=
stringData
+
SDKConstants
.
AMPERSAND
+
SecureUtil
.
sha256X16Str
(
secureKey
,
encoding
);
String
strAfterSha256
=
SecureUtil
.
sha256X16Str
(
strBeforeSha256
,
encoding
);
// 设置签名域值
data
.
put
(
SDKConstants
.
param_signature
,
strAfterSha256
);
return
true
;
}
else
if
(
SDKConstants
.
SIGNMETHOD_SM3
.
equals
(
signMethod
))
{
String
stringData
=
coverMap2String
(
data
);
log
.
info
(
"待签名请求报文串:["
+
stringData
+
"]"
);
String
strBeforeSM3
=
stringData
+
SDKConstants
.
AMPERSAND
+
SecureUtil
.
sm3X16Str
(
secureKey
,
encoding
);
String
strAfterSM3
=
SecureUtil
.
sm3X16Str
(
strBeforeSM3
,
encoding
);
// 设置签名域值
data
.
put
(
SDKConstants
.
param_signature
,
strAfterSM3
);
return
true
;
}
return
false
;
}
/**
* 通过传入的签名密钥进行签名并返回签名值<br>
*
* @param data 待签名数据Map键值对形式
* @param encoding 编码
* @param certPath 证书绝对路径
* @param certPwd 证书密码
* @return 签名值
*/
public
static
boolean
signByCertInfo
(
Map
<
String
,
String
>
data
,
String
certPath
,
String
certPwd
,
String
encoding
)
{
if
(
isEmpty
(
encoding
))
{
encoding
=
"UTF-8"
;
}
if
(
isEmpty
(
certPath
)
||
isEmpty
(
certPwd
))
{
log
.
error
(
"CertPath or CertPwd is empty"
);
return
false
;
}
String
signMethod
=
data
.
get
(
SDKConstants
.
param_signMethod
);
String
version
=
data
.
get
(
SDKConstants
.
param_version
);
if
(!
SDKConstants
.
VERSION_1_0_0
.
equals
(
version
)
&&
!
SDKConstants
.
VERSION_5_0_1
.
equals
(
version
)
&&
isEmpty
(
signMethod
))
{
log
.
error
(
"signMethod must Not null"
);
return
false
;
}
if
(
isEmpty
(
version
))
{
log
.
error
(
"version must Not null"
);
return
false
;
}
if
(
SDKConstants
.
SIGNMETHOD_RSA
.
equals
(
signMethod
)
||
SDKConstants
.
VERSION_1_0_0
.
equals
(
version
)
||
SDKConstants
.
VERSION_5_0_1
.
equals
(
version
))
{
if
(
SDKConstants
.
VERSION_5_0_0
.
equals
(
version
)
||
SDKConstants
.
VERSION_1_0_0
.
equals
(
version
)
||
SDKConstants
.
VERSION_5_0_1
.
equals
(
version
))
{
// 设置签名证书序列号
data
.
put
(
SDKConstants
.
param_certId
,
CertUtil
.
getCertIdByKeyStoreMap
(
certPath
,
certPwd
));
// 将Map信息转换成key1=value1&key2=value2的形式
String
stringData
=
coverMap2String
(
data
);
log
.
info
(
"待签名请求报文串:["
+
stringData
+
"]"
);
byte
[]
byteSign
=
null
;
String
stringSign
=
null
;
try
{
// 通过SHA1进行摘要并转16进制
byte
[]
signDigest
=
SecureUtil
.
sha1X16
(
stringData
,
encoding
);
byteSign
=
SecureUtil
.
base64Encode
(
SecureUtil
.
signBySoft
(
CertUtil
.
getSignCertPrivateKeyByStoreMap
(
certPath
,
certPwd
),
signDigest
));
stringSign
=
new
String
(
byteSign
);
// 设置签名域值
data
.
put
(
SDKConstants
.
param_signature
,
stringSign
);
return
true
;
}
catch
(
Exception
e
)
{
log
.
error
(
"Sign Error"
,
e
);
return
false
;
}
}
else
if
(
SDKConstants
.
VERSION_5_1_0
.
equals
(
version
))
{
// 设置签名证书序列号
data
.
put
(
SDKConstants
.
param_certId
,
CertUtil
.
getCertIdByKeyStoreMap
(
certPath
,
certPwd
));
// 将Map信息转换成key1=value1&key2=value2的形式
String
stringData
=
coverMap2String
(
data
);
log
.
info
(
"待签名请求报文串:["
+
stringData
+
"]"
);
byte
[]
byteSign
;
String
stringSign
;
try
{
// 通过SHA256进行摘要并转16进制
byte
[]
signDigest
=
SecureUtil
.
sha256X16
(
stringData
,
encoding
);
byteSign
=
SecureUtil
.
base64Encode
(
SecureUtil
.
signBySoft256
(
CertUtil
.
getSignCertPrivateKeyByStoreMap
(
certPath
,
certPwd
),
signDigest
));
stringSign
=
new
String
(
byteSign
);
// 设置签名域值
data
.
put
(
SDKConstants
.
param_signature
,
stringSign
);
return
true
;
}
catch
(
Exception
e
)
{
log
.
error
(
"Sign Error"
,
e
);
return
false
;
}
}
}
return
false
;
}
/**
* 验证签名
*
* @param resData 返回报文数据
* @param encoding 编码格式
* @return
*/
public
static
boolean
validateBySecureKey
(
Map
<
String
,
String
>
resData
,
String
secureKey
,
String
encoding
)
{
log
.
info
(
"验签处理开始"
);
if
(
isEmpty
(
encoding
))
{
encoding
=
"UTF-8"
;
}
String
signMethod
=
resData
.
get
(
SDKConstants
.
param_signMethod
);
if
(
SDKConstants
.
SIGNMETHOD_SHA256
.
equals
(
signMethod
))
{
// 1.进行SHA256验证
String
stringSign
=
resData
.
get
(
SDKConstants
.
param_signature
);
log
.
info
(
"签名原文:["
+
stringSign
+
"]"
);
// 将Map信息转换成key1=value1&key2=value2的形式
String
stringData
=
coverMap2String
(
resData
);
log
.
info
(
"待验签返回报文串:["
+
stringData
+
"]"
);
String
strBeforeSha256
=
stringData
+
SDKConstants
.
AMPERSAND
+
SecureUtil
.
sha256X16Str
(
secureKey
,
encoding
);
String
strAfterSha256
=
SecureUtil
.
sha256X16Str
(
strBeforeSha256
,
encoding
);
return
stringSign
.
equals
(
strAfterSha256
);
}
else
if
(
SDKConstants
.
SIGNMETHOD_SM3
.
equals
(
signMethod
))
{
// 1.进行SM3验证
String
stringSign
=
resData
.
get
(
SDKConstants
.
param_signature
);
log
.
info
(
"签名原文:["
+
stringSign
+
"]"
);
// 将Map信息转换成key1=value1&key2=value2的形式
String
stringData
=
coverMap2String
(
resData
);
log
.
info
(
"待验签返回报文串:["
+
stringData
+
"]"
);
String
strBeforeSM3
=
stringData
+
SDKConstants
.
AMPERSAND
+
SecureUtil
.
sm3X16Str
(
secureKey
,
encoding
);
String
strAfterSM3
=
SecureUtil
.
sm3X16Str
(
strBeforeSM3
,
encoding
);
return
stringSign
.
equals
(
strAfterSM3
);
}
return
false
;
}
/**
* 验证签名
*
* @param resData 返回报文数据
* @param encoding 编码格式
* @return
*/
public
static
boolean
validate
(
Map
<
String
,
String
>
resData
,
String
encoding
)
{
log
.
info
(
"验签处理开始"
);
if
(
isEmpty
(
encoding
))
{
encoding
=
"UTF-8"
;
}
String
signMethod
=
resData
.
get
(
SDKConstants
.
param_signMethod
);
String
version
=
resData
.
get
(
SDKConstants
.
param_version
);
if
(
SDKConstants
.
SIGNMETHOD_RSA
.
equals
(
signMethod
)
||
SDKConstants
.
VERSION_1_0_0
.
equals
(
version
)
||
SDKConstants
.
VERSION_5_0_1
.
equals
(
version
))
{
// 获取返回报文的版本号
if
(
SDKConstants
.
VERSION_5_0_0
.
equals
(
version
)
||
SDKConstants
.
VERSION_1_0_0
.
equals
(
version
)
||
SDKConstants
.
VERSION_5_0_1
.
equals
(
version
))
{
String
stringSign
=
resData
.
get
(
SDKConstants
.
param_signature
);
log
.
info
(
"签名原文:["
+
stringSign
+
"]"
);
// 从返回报文中获取certId ,然后去证书静态Map中查询对应验签证书对象
String
certId
=
resData
.
get
(
SDKConstants
.
param_certId
);
log
.
info
(
"对返回报文串验签使用的验签公钥序列号:["
+
certId
+
"]"
);
// 将Map信息转换成key1=value1&key2=value2的形式
String
stringData
=
coverMap2String
(
resData
);
log
.
info
(
"待验签返回报文串:["
+
stringData
+
"]"
);
try
{
// 验证签名需要用银联发给商户的公钥证书.
return
SecureUtil
.
validateSignBySoft
(
CertUtil
.
getValidatePublicKey
(
certId
),
SecureUtil
.
base64Decode
(
stringSign
.
getBytes
(
encoding
)),
SecureUtil
.
sha1X16
(
stringData
,
encoding
));
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
}
else
if
(
SDKConstants
.
VERSION_5_1_0
.
equals
(
version
))
{
// 1.从返回报文中获取公钥信息转换成公钥对象
String
strCert
=
resData
.
get
(
SDKConstants
.
param_signPubKeyCert
);
// log.info("验签公钥证书:["+strCert+"]");
X509Certificate
x509Cert
=
CertUtil
.
genCertificateByStr
(
strCert
);
if
(
x509Cert
==
null
)
{
log
.
error
(
"convert signPubKeyCert failed"
);
return
false
;
}
// 2.验证证书链
if
(!
CertUtil
.
verifyCertificate
(
x509Cert
))
{
log
.
error
(
"验证公钥证书失败,证书信息:["
+
strCert
+
"]"
);
return
false
;
}
// 3.验签
String
stringSign
=
resData
.
get
(
SDKConstants
.
param_signature
);
log
.
info
(
"签名原文:["
+
stringSign
+
"]"
);
// 将Map信息转换成key1=value1&key2=value2的形式
String
stringData
=
coverMap2String
(
resData
);
log
.
info
(
"待验签返回报文串:["
+
stringData
+
"]"
);
try
{
// 验证签名需要用银联发给商户的公钥证书.
boolean
result
=
SecureUtil
.
validateSignBySoft256
(
x509Cert
.
getPublicKey
(),
SecureUtil
.
base64Decode
(
stringSign
.
getBytes
(
encoding
)),
SecureUtil
.
sha256X16
(
stringData
,
encoding
));
log
.
info
(
"验证签名"
+
(
result
?
"成功"
:
"失败"
));
return
result
;
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
}
}
else
if
(
SDKConstants
.
SIGNMETHOD_SHA256
.
equals
(
signMethod
))
{
// 1.进行SHA256验证
String
stringSign
=
resData
.
get
(
SDKConstants
.
param_signature
);
log
.
info
(
"签名原文:["
+
stringSign
+
"]"
);
// 将Map信息转换成key1=value1&key2=value2的形式
String
stringData
=
coverMap2String
(
resData
);
log
.
info
(
"待验签返回报文串:["
+
stringData
+
"]"
);
String
strBeforeSha256
=
stringData
+
SDKConstants
.
AMPERSAND
+
SecureUtil
.
sha256X16Str
(
SDKConfig
.
getConfig
()
.
getSecureKey
(),
encoding
);
String
strAfterSha256
=
SecureUtil
.
sha256X16Str
(
strBeforeSha256
,
encoding
);
boolean
result
=
stringSign
.
equals
(
strAfterSha256
);
log
.
info
(
"验证签名"
+
(
result
?
"成功"
:
"失败"
));
return
result
;
}
else
if
(
SDKConstants
.
SIGNMETHOD_SM3
.
equals
(
signMethod
))
{
// 1.进行SM3验证
String
stringSign
=
resData
.
get
(
SDKConstants
.
param_signature
);
log
.
info
(
"签名原文:["
+
stringSign
+
"]"
);
// 将Map信息转换成key1=value1&key2=value2的形式
String
stringData
=
coverMap2String
(
resData
);
log
.
info
(
"待验签返回报文串:["
+
stringData
+
"]"
);
String
strBeforeSM3
=
stringData
+
SDKConstants
.
AMPERSAND
+
SecureUtil
.
sm3X16Str
(
SDKConfig
.
getConfig
().
getSecureKey
(),
encoding
);
String
strAfterSM3
=
SecureUtil
.
sm3X16Str
(
strBeforeSM3
,
encoding
);
boolean
result
=
stringSign
.
equals
(
strAfterSM3
);
log
.
info
(
"验证签名"
+
(
result
?
"成功"
:
"失败"
));
return
result
;
}
return
false
;
}
/**
* 将Map中的数据转换成key1=value1&key2=value2的形式 不包含签名域signature
*
* @param data 待拼接的Map数据
* @return 拼接好后的字符串
*/
public
static
String
coverMap2String
(
Map
<
String
,
String
>
data
)
{
TreeMap
<
String
,
String
>
tree
=
new
TreeMap
<>();
Iterator
<
Entry
<
String
,
String
>>
it
=
data
.
entrySet
().
iterator
();
while
(
it
.
hasNext
())
{
Entry
<
String
,
String
>
en
=
it
.
next
();
if
(
SDKConstants
.
param_signature
.
equals
(
en
.
getKey
().
trim
()))
{
continue
;
}
tree
.
put
(
en
.
getKey
(),
en
.
getValue
());
}
it
=
tree
.
entrySet
().
iterator
();
StringBuffer
sf
=
new
StringBuffer
();
while
(
it
.
hasNext
())
{
Entry
<
String
,
String
>
en
=
it
.
next
();
sf
.
append
(
en
.
getKey
()
+
SDKConstants
.
EQUAL
+
en
.
getValue
()
+
SDKConstants
.
AMPERSAND
);
}
return
sf
.
substring
(
0
,
sf
.
length
()
-
1
);
}
/**
* 兼容老方法 将形如key=value&key=value的字符串转换为相应的Map对象
*
* @param result
* @return
*/
public
static
Map
<
String
,
String
>
coverResultString2Map
(
String
result
)
{
return
convertResultStringToMap
(
result
);
}
/**
* 将形如key=value&key=value的字符串转换为相应的Map对象
*
* @param result
* @return
*/
public
static
Map
<
String
,
String
>
convertResultStringToMap
(
String
result
)
{
Map
<
String
,
String
>
map
=
null
;
if
(
result
!=
null
&&
!
""
.
equals
(
result
.
trim
()))
{
if
(
result
.
startsWith
(
"{"
)
&&
result
.
endsWith
(
"}"
))
{
result
=
result
.
substring
(
1
,
result
.
length
()
-
1
);
}
map
=
parseQString
(
result
);
}
return
map
;
}
/**
* 解析应答字符串,生成应答要素
*
* @param str 需要解析的字符串
* @return 解析的结果map
* @throws UnsupportedEncodingException
*/
public
static
Map
<
String
,
String
>
parseQString
(
String
str
)
{
Map
<
String
,
String
>
map
=
new
HashMap
<
String
,
String
>();
int
len
=
str
.
length
();
StringBuilder
temp
=
new
StringBuilder
();
char
curChar
;
String
key
=
null
;
boolean
isKey
=
true
;
boolean
isOpen
=
false
;
//值里有嵌套
char
openName
=
0
;
if
(
len
>
0
)
{
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
// 遍历整个带解析的字符串
curChar
=
str
.
charAt
(
i
);
// 取当前字符
if
(
isKey
)
{
// 如果当前生成的是key
if
(
curChar
==
'='
)
{
// 如果读取到=分隔符
key
=
temp
.
toString
();
temp
.
setLength
(
0
);
isKey
=
false
;
}
else
{
temp
.
append
(
curChar
);
}
}
else
{
// 如果当前生成的是value
if
(
isOpen
)
{
if
(
curChar
==
openName
)
{
isOpen
=
false
;
}
}
else
{
//如果没开启嵌套
if
(
curChar
==
'{'
)
{
//如果碰到,就开启嵌套
isOpen
=
true
;
openName
=
'}'
;
}
if
(
curChar
==
'['
)
{
isOpen
=
true
;
openName
=
']'
;
}
}
if
(
curChar
==
'&'
&&
!
isOpen
)
{
// 如果读取到&分割符,同时这个分割符不是值域,这时将map里添加
putKeyValueToMap
(
temp
,
isKey
,
key
,
map
);
temp
.
setLength
(
0
);
isKey
=
true
;
}
else
{
temp
.
append
(
curChar
);
}
}
}
putKeyValueToMap
(
temp
,
isKey
,
key
,
map
);
}
return
map
;
}
private
static
void
putKeyValueToMap
(
StringBuilder
temp
,
boolean
isKey
,
String
key
,
Map
<
String
,
String
>
map
)
{
if
(
isKey
)
{
key
=
temp
.
toString
();
if
(
key
.
length
()
==
0
)
{
throw
new
RuntimeException
(
"QString format illegal"
);
}
map
.
put
(
key
,
""
);
}
else
{
if
(
key
.
length
()
==
0
)
{
throw
new
RuntimeException
(
"QString format illegal"
);
}
map
.
put
(
key
,
temp
.
toString
());
}
}
/**
* 获取应答报文中的加密公钥证书,并存储到本地,并备份原始证书<br>
* 更新成功则返回1,无更新返回0,失败异常返回-1。
*
* @param resData
* @param encoding
* @return
*/
public
static
int
getEncryptCert
(
Map
<
String
,
String
>
resData
,
String
encoding
)
{
String
strCert
=
resData
.
get
(
SDKConstants
.
param_encryptPubKeyCert
);
String
certType
=
resData
.
get
(
SDKConstants
.
param_certType
);
if
(
isEmpty
(
strCert
)
||
isEmpty
(
certType
))
{
return
-
1
;
}
X509Certificate
x509Cert
=
CertUtil
.
genCertificateByStr
(
strCert
);
if
(
SDKConstants
.
CERTTYPE_01
.
equals
(
certType
))
{
// 更新敏感信息加密公钥
if
(!
CertUtil
.
getEncryptCertId
().
equals
(
x509Cert
.
getSerialNumber
().
toString
()))
{
// ID不同时进行本地证书更新操作
String
localCertPath
=
SDKConfig
.
getConfig
().
getEncryptCertPath
();
String
newLocalCertPath
=
genBackupName
(
localCertPath
);
// 1.将本地证书进行备份存储
if
(!
copyFile
(
localCertPath
,
newLocalCertPath
))
{
return
-
1
;
}
// 2.备份成功,进行新证书的存储
if
(!
writeFile
(
localCertPath
,
strCert
,
encoding
))
{
return
-
1
;
}
log
.
info
(
"save new encryptPubKeyCert success"
);
CertUtil
.
resetEncryptCertPublicKey
();
return
1
;
}
else
{
return
0
;
}
}
else
if
(
SDKConstants
.
CERTTYPE_02
.
equals
(
certType
))
{
// // 更新磁道加密公钥
// if (!CertUtil.getEncryptTrackCertId().equals(
// x509Cert.getSerialNumber().toString())) {
// // ID不同时进行本地证书更新操作
// String localCertPath = SDKConfig.getConfig().getEncryptTrackCertPath();
// String newLocalCertPath = genBackupName(localCertPath);
// // 1.将本地证书进行备份存储
// if (!copyFile(localCertPath, newLocalCertPath))
// return -1;
// // 2.备份成功,进行新证书的存储
// if (!writeFile(localCertPath, strCert, encoding))
// return -1;
// log.info("save new encryptPubKeyCert success");
// CertUtil.resetEncryptTrackCertPublicKey();
// return 1;
// }else {
return
0
;
// }
}
else
{
log
.
info
(
"unknown cerType:"
+
certType
);
return
-
1
;
}
}
/**
* 文件拷贝方法
*
* @param srcFile 源文件
* @param destFile 目标文件
* @return
* @throws IOException
*/
public
static
boolean
copyFile
(
String
srcFile
,
String
destFile
)
{
boolean
flag
=
false
;
FileInputStream
fin
=
null
;
FileOutputStream
fout
=
null
;
FileChannel
fcin
=
null
;
FileChannel
fcout
=
null
;
try
{
// 获取源文件和目标文件的输入输出流
fin
=
new
FileInputStream
(
srcFile
);
fout
=
new
FileOutputStream
(
destFile
);
// 获取输入输出通道
fcin
=
fin
.
getChannel
();
fcout
=
fout
.
getChannel
();
// 创建缓冲区
ByteBuffer
buffer
=
ByteBuffer
.
allocate
(
1024
);
while
(
true
)
{
// clear方法重设缓冲区,使它可以接受读入的数据
buffer
.
clear
();
// 从输入通道中将数据读到缓冲区
int
r
=
fcin
.
read
(
buffer
);
// read方法返回读取的字节数,可能为零,如果该通道已到达流的末尾,则返回-1
if
(
r
==
-
1
)
{
flag
=
true
;
break
;
}
// flip方法让缓冲区可以将新读入的数据写入另一个通道
buffer
.
flip
();
// 从输出通道中将数据写入缓冲区
fcout
.
write
(
buffer
);
}
fout
.
flush
();
}
catch
(
IOException
e
)
{
log
.
error
(
"CopyFile fail"
,
e
);
}
finally
{
try
{
if
(
null
!=
fin
)
{
fin
.
close
();
}
if
(
null
!=
fout
)
{
fout
.
close
();
}
if
(
null
!=
fcin
)
{
fcin
.
close
();
}
if
(
null
!=
fcout
)
{
fcout
.
close
();
}
}
catch
(
IOException
ex
)
{
log
.
error
(
"Releases any system resources fail"
,
ex
);
}
}
return
flag
;
}
/**
* 写文件方法
*
* @param filePath 文件路径
* @param fileContent 文件内容
* @param encoding 编码
* @return
*/
public
static
boolean
writeFile
(
String
filePath
,
String
fileContent
,
String
encoding
)
{
FileOutputStream
fout
=
null
;
FileChannel
fcout
=
null
;
File
file
=
new
File
(
filePath
);
if
(
file
.
exists
())
{
file
.
delete
();
}
try
{
fout
=
new
FileOutputStream
(
filePath
);
// 获取输出通道
fcout
=
fout
.
getChannel
();
// 创建缓冲区
// ByteBuffer buffer = ByteBuffer.allocate(1024);
ByteBuffer
buffer
=
ByteBuffer
.
wrap
(
fileContent
.
getBytes
(
encoding
));
fcout
.
write
(
buffer
);
fout
.
flush
();
}
catch
(
FileNotFoundException
e
)
{
log
.
error
(
"WriteFile fail"
,
e
);
return
false
;
}
catch
(
IOException
ex
)
{
log
.
error
(
"WriteFile fail"
,
ex
);
return
false
;
}
finally
{
try
{
if
(
null
!=
fout
)
{
fout
.
close
();
}
if
(
null
!=
fcout
)
{
fcout
.
close
();
}
}
catch
(
IOException
ex
)
{
log
.
error
(
"Releases any system resources fail"
,
ex
);
return
false
;
}
}
return
true
;
}
/**
* 将传入的文件名(xxx)改名 <br>
* 结果为: xxx_backup.cer
*
* @param fileName
* @return
*/
public
static
String
genBackupName
(
String
fileName
)
{
if
(
isEmpty
(
fileName
))
{
return
""
;
}
int
i
=
fileName
.
lastIndexOf
(
SDKConstants
.
POINT
);
String
leftFileName
=
fileName
.
substring
(
0
,
i
);
String
rightFileName
=
fileName
.
substring
(
i
+
1
);
String
newFileName
=
leftFileName
+
"_backup"
+
SDKConstants
.
POINT
+
rightFileName
;
return
newFileName
;
}
public
static
byte
[]
readFileByNIO
(
String
filePath
)
{
FileInputStream
in
=
null
;
FileChannel
fc
=
null
;
ByteBuffer
bf
=
null
;
try
{
in
=
new
FileInputStream
(
filePath
);
fc
=
in
.
getChannel
();
bf
=
ByteBuffer
.
allocate
((
int
)
fc
.
size
());
fc
.
read
(
bf
);
return
bf
.
array
();
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
null
;
}
finally
{
try
{
if
(
null
!=
fc
)
{
fc
.
close
();
}
if
(
null
!=
in
)
{
in
.
close
();
}
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
null
;
}
}
}
/**
* 过滤请求报文中的空字符串或者空字符串
*
* @param contentData
* @return
*/
public
static
Map
<
String
,
String
>
filterBlank
(
Map
<
String
,
String
>
contentData
)
{
Map
<
String
,
String
>
submitFromData
=
new
HashMap
<>();
Set
<
String
>
keySet
=
contentData
.
keySet
();
for
(
String
key
:
keySet
)
{
String
value
=
contentData
.
get
(
key
);
if
(
value
!=
null
&&
!
""
.
equals
(
value
.
trim
()))
{
// 对value值进行去除前后空处理
submitFromData
.
put
(
key
,
value
.
trim
());
}
}
return
submitFromData
;
}
/**
* 解压缩.
*
* @param inputByte byte[]数组类型的数据
* @return 解压缩后的数据
* @throws IOException
*/
public
static
byte
[]
inflater
(
final
byte
[]
inputByte
)
throws
IOException
{
int
compressedDataLength
=
0
;
Inflater
compresser
=
new
Inflater
(
false
);
compresser
.
setInput
(
inputByte
,
0
,
inputByte
.
length
);
ByteArrayOutputStream
o
=
new
ByteArrayOutputStream
(
inputByte
.
length
);
byte
[]
result
=
new
byte
[
1024
];
try
{
while
(!
compresser
.
finished
())
{
compressedDataLength
=
compresser
.
inflate
(
result
);
if
(
compressedDataLength
==
0
)
{
break
;
}
o
.
write
(
result
,
0
,
compressedDataLength
);
}
}
catch
(
Exception
ex
)
{
log
.
error
(
"Data format error!"
,
ex
);
}
finally
{
o
.
close
();
}
compresser
.
end
();
return
o
.
toByteArray
();
}
/**
* 压缩.
*
* @param inputByte 需要解压缩的byte[]数组
* @return 压缩后的数据
* @throws IOException
*/
public
static
byte
[]
deflater
(
final
byte
[]
inputByte
)
throws
IOException
{
int
compressedDataLength
=
0
;
Deflater
compresser
=
new
Deflater
();
compresser
.
setInput
(
inputByte
);
compresser
.
finish
();
ByteArrayOutputStream
o
=
new
ByteArrayOutputStream
(
inputByte
.
length
);
byte
[]
result
=
new
byte
[
1024
];
try
{
while
(!
compresser
.
finished
())
{
compressedDataLength
=
compresser
.
deflate
(
result
);
o
.
write
(
result
,
0
,
compressedDataLength
);
}
}
finally
{
o
.
close
();
}
compresser
.
end
();
return
o
.
toByteArray
();
}
/**
* 判断字符串是否为NULL或空
*
* @param s 待判断的字符串数据
* @return 判断结果 true-是 false-否
*/
public
static
boolean
isEmpty
(
String
s
)
{
return
null
==
s
||
""
.
equals
(
s
.
trim
());
}
}
src/main/java/com/esv/freight/customer/common/unionpay/SecureUtil.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
common
.
unionpay
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.codec.binary.Base64
;
import
org.bouncycastle.crypto.digests.SM3Digest
;
import
javax.crypto.Cipher
;
import
java.io.IOException
;
import
java.io.UnsupportedEncodingException
;
import
java.security.MessageDigest
;
import
java.security.PrivateKey
;
import
java.security.PublicKey
;
import
java.security.Signature
;
/**
* @description: 银联支付:acpsdk安全算法工具类
* @project: freight-customer-service
* @name: com.esv.freight.customer.common.unionpay.SecureUtil
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/05/30 14:07
* @version:1.0
*/
@Slf4j
public
class
SecureUtil
{
/**
* 算法常量: SHA1
*/
private
static
final
String
ALGORITHM_SHA1
=
"SHA-1"
;
/**
* 算法常量: SHA256
*/
private
static
final
String
ALGORITHM_SHA256
=
"SHA-256"
;
/**
* 算法常量:SHA1withRSA
*/
private
static
final
String
BC_PROV_ALGORITHM_SHA1RSA
=
"SHA1withRSA"
;
/**
* 算法常量:SHA256withRSA
*/
private
static
final
String
BC_PROV_ALGORITHM_SHA256RSA
=
"SHA256withRSA"
;
/**
* sm3计算后进行16进制转换
*
* @param data 待计算的数据
* @param encoding 编码
* @return 计算结果
*/
public
static
String
sm3X16Str
(
String
data
,
String
encoding
)
{
byte
[]
bytes
=
sm3
(
data
,
encoding
);
StringBuilder
sm3StrBuff
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
bytes
.
length
;
i
++)
{
if
(
Integer
.
toHexString
(
0xFF
&
bytes
[
i
]).
length
()
==
1
)
{
sm3StrBuff
.
append
(
"0"
).
append
(
Integer
.
toHexString
(
0xFF
&
bytes
[
i
]));
}
else
{
sm3StrBuff
.
append
(
Integer
.
toHexString
(
0xFF
&
bytes
[
i
]));
}
}
return
sm3StrBuff
.
toString
();
}
/**
* sha1计算后进行16进制转换
*
* @param data 待计算的数据
* @param encoding 编码
* @return 计算结果
*/
public
static
byte
[]
sha1X16
(
String
data
,
String
encoding
)
{
byte
[]
bytes
=
sha1
(
data
,
encoding
);
StringBuilder
sha1StrBuff
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
bytes
.
length
;
i
++)
{
if
(
Integer
.
toHexString
(
0xFF
&
bytes
[
i
]).
length
()
==
1
)
{
sha1StrBuff
.
append
(
"0"
).
append
(
Integer
.
toHexString
(
0xFF
&
bytes
[
i
]));
}
else
{
sha1StrBuff
.
append
(
Integer
.
toHexString
(
0xFF
&
bytes
[
i
]));
}
}
try
{
return
sha1StrBuff
.
toString
().
getBytes
(
encoding
);
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
null
;
}
}
/**
* sha256计算后进行16进制转换
*
* @param data 待计算的数据
* @param encoding 编码
* @return 计算结果
*/
public
static
String
sha256X16Str
(
String
data
,
String
encoding
)
{
byte
[]
bytes
=
sha256
(
data
,
encoding
);
StringBuilder
sha256StrBuff
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
bytes
.
length
;
i
++)
{
if
(
Integer
.
toHexString
(
0xFF
&
bytes
[
i
]).
length
()
==
1
)
{
sha256StrBuff
.
append
(
"0"
).
append
(
Integer
.
toHexString
(
0xFF
&
bytes
[
i
]));
}
else
{
sha256StrBuff
.
append
(
Integer
.
toHexString
(
0xFF
&
bytes
[
i
]));
}
}
return
sha256StrBuff
.
toString
();
}
/**
* sha256计算后进行16进制转换
*
* @param data 待计算的数据
* @param encoding 编码
* @return 计算结果
*/
public
static
byte
[]
sha256X16
(
String
data
,
String
encoding
)
{
byte
[]
bytes
=
sha256
(
data
,
encoding
);
StringBuilder
sha256StrBuff
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
bytes
.
length
;
i
++)
{
if
(
Integer
.
toHexString
(
0xFF
&
bytes
[
i
]).
length
()
==
1
)
{
sha256StrBuff
.
append
(
"0"
).
append
(
Integer
.
toHexString
(
0xFF
&
bytes
[
i
]));
}
else
{
sha256StrBuff
.
append
(
Integer
.
toHexString
(
0xFF
&
bytes
[
i
]));
}
}
try
{
return
sha256StrBuff
.
toString
().
getBytes
(
encoding
);
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
null
;
}
}
/**
* sha1计算.
*
* @param data 待计算的数据
* @return 计算结果
*/
private
static
byte
[]
sha1
(
byte
[]
data
)
{
MessageDigest
md
;
try
{
md
=
MessageDigest
.
getInstance
(
ALGORITHM_SHA1
);
md
.
reset
();
md
.
update
(
data
);
return
md
.
digest
();
}
catch
(
Exception
e
)
{
log
.
error
(
"SHA1计算失败"
,
e
);
return
null
;
}
}
/**
* sha256计算.
*
* @param data 待计算的数据
* @return 计算结果
*/
private
static
byte
[]
sha256
(
byte
[]
data
)
{
MessageDigest
md
;
try
{
md
=
MessageDigest
.
getInstance
(
ALGORITHM_SHA256
);
md
.
reset
();
md
.
update
(
data
);
return
md
.
digest
();
}
catch
(
Exception
e
)
{
log
.
error
(
"SHA256计算失败"
,
e
);
return
null
;
}
}
/**
* SM3计算.
*
* @param data 待计算的数据
* @return 计算结果
*/
private
static
byte
[]
sm3
(
byte
[]
data
)
{
SM3Digest
sm3
=
new
SM3Digest
();
sm3
.
update
(
data
,
0
,
data
.
length
);
byte
[]
result
=
new
byte
[
sm3
.
getDigestSize
()];
sm3
.
doFinal
(
result
,
0
);
return
result
;
}
/**
* sha1计算
*
* @param datas 待计算的数据
* @param encoding 字符集编码
* @return
*/
private
static
byte
[]
sha1
(
String
datas
,
String
encoding
)
{
try
{
return
sha1
(
datas
.
getBytes
(
encoding
));
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
"SHA1计算失败"
,
e
);
return
null
;
}
}
/**
* sha256计算
*
* @param datas 待计算的数据
* @param encoding 字符集编码
* @return
*/
private
static
byte
[]
sha256
(
String
datas
,
String
encoding
)
{
try
{
return
sha256
(
datas
.
getBytes
(
encoding
));
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
"SHA256计算失败"
,
e
);
return
null
;
}
}
/**
* sm3计算
*
* @param datas 待计算的数据
* @param encoding 字符集编码
* @return
*/
private
static
byte
[]
sm3
(
String
datas
,
String
encoding
)
{
try
{
return
sm3
(
datas
.
getBytes
(
encoding
));
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
"SM3计算失败"
,
e
);
return
null
;
}
}
/**
* @param privateKey
* @param data
* @return
* @throws Exception
*/
public
static
byte
[]
signBySoft
(
PrivateKey
privateKey
,
byte
[]
data
)
throws
Exception
{
byte
[]
result
;
Signature
st
=
Signature
.
getInstance
(
BC_PROV_ALGORITHM_SHA1RSA
,
"BC"
);
st
.
initSign
(
privateKey
);
st
.
update
(
data
);
result
=
st
.
sign
();
return
result
;
}
/**
* @param privateKey
* @param data
* @return
* @throws Exception
*/
public
static
byte
[]
signBySoft256
(
PrivateKey
privateKey
,
byte
[]
data
)
throws
Exception
{
byte
[]
result
;
Signature
st
=
Signature
.
getInstance
(
BC_PROV_ALGORITHM_SHA256RSA
,
"BC"
);
st
.
initSign
(
privateKey
);
st
.
update
(
data
);
result
=
st
.
sign
();
return
result
;
}
public
static
boolean
validateSignBySoft
(
PublicKey
publicKey
,
byte
[]
signData
,
byte
[]
srcData
)
throws
Exception
{
Signature
st
=
Signature
.
getInstance
(
BC_PROV_ALGORITHM_SHA1RSA
,
"BC"
);
st
.
initVerify
(
publicKey
);
st
.
update
(
srcData
);
return
st
.
verify
(
signData
);
}
public
static
boolean
validateSignBySoft256
(
PublicKey
publicKey
,
byte
[]
signData
,
byte
[]
srcData
)
throws
Exception
{
Signature
st
=
Signature
.
getInstance
(
BC_PROV_ALGORITHM_SHA256RSA
,
"BC"
);
st
.
initVerify
(
publicKey
);
st
.
update
(
srcData
);
return
st
.
verify
(
signData
);
}
/**
* 对数据通过公钥进行加密,并进行base64计算
*
* @param dataString 待处理数据
* @param encoding 字符编码
* @param key 公钥
* @return
*/
public
static
String
encryptData
(
String
dataString
,
String
encoding
,
PublicKey
key
)
{
/** 使用公钥对密码加密 **/
byte
[]
data
;
try
{
data
=
encryptData
(
key
,
dataString
.
getBytes
(
encoding
));
return
new
String
(
SecureUtil
.
base64Encode
(
data
),
encoding
);
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
""
;
}
}
/**
* 对数据通过公钥进行加密,并进行base64计算
*
* @param accNo 待处理数据
* @param pin pin
* @param encoding 字符编码
* @param key 公钥
* @return
*/
public
static
String
encryptPin
(
String
accNo
,
String
pin
,
String
encoding
,
PublicKey
key
)
{
/** 使用公钥对密码加密 **/
byte
[]
data
;
try
{
data
=
pin2PinBlockWithCardNO
(
pin
,
accNo
);
data
=
encryptData
(
key
,
data
);
return
new
String
(
SecureUtil
.
base64Encode
(
data
),
encoding
);
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
""
;
}
}
/**
* 通过私钥解密
*
* @param dataString base64过的数据
* @param encoding 编码
* @param key 私钥
* @return 解密后的数据
*/
public
static
String
decryptData
(
String
dataString
,
String
encoding
,
PrivateKey
key
)
{
byte
[]
data
;
try
{
data
=
SecureUtil
.
base64Decode
(
dataString
.
getBytes
(
encoding
));
data
=
decryptData
(
key
,
data
);
return
new
String
(
data
,
encoding
);
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
""
;
}
}
/**
* BASE64解码
*
* @param inputByte 待解码数据
* @return 解码后的数据
* @throws IOException
*/
public
static
byte
[]
base64Decode
(
byte
[]
inputByte
)
throws
IOException
{
return
Base64
.
decodeBase64
(
inputByte
);
}
/**
* BASE64编码
*
* @param inputByte 待编码数据
* @return 解码后的数据
* @throws IOException
*/
public
static
byte
[]
base64Encode
(
byte
[]
inputByte
)
throws
IOException
{
return
Base64
.
encodeBase64
(
inputByte
);
}
/**
* 加密除pin之外的其他信息
*
* @param publicKey
* @param plainData
* @return
* @throws Exception
*/
private
static
byte
[]
encryptData
(
PublicKey
publicKey
,
byte
[]
plainData
)
throws
Exception
{
try
{
Cipher
cipher
=
Cipher
.
getInstance
(
"RSA/ECB/PKCS1Padding"
,
"BC"
);
cipher
.
init
(
Cipher
.
ENCRYPT_MODE
,
publicKey
);
return
cipher
.
doFinal
(
plainData
);
}
catch
(
Exception
e
)
{
throw
new
Exception
(
e
.
getMessage
());
}
}
/**
* @param privateKey
* @param data
* @return
* @throws Exception
*/
private
static
byte
[]
decryptData
(
PrivateKey
privateKey
,
byte
[]
data
)
throws
Exception
{
try
{
Cipher
cipher
=
Cipher
.
getInstance
(
"RSA/ECB/PKCS1Padding"
,
"BC"
);
cipher
.
init
(
Cipher
.
DECRYPT_MODE
,
privateKey
);
return
cipher
.
doFinal
(
data
);
}
catch
(
Exception
e
)
{
log
.
error
(
"解密失败"
,
e
);
}
return
null
;
}
/**
* @param aPin
* @return
*/
private
static
byte
[]
pin2PinBlock
(
String
aPin
)
{
int
tTemp
=
1
;
int
tPinLen
=
aPin
.
length
();
byte
[]
tByte
=
new
byte
[
8
];
try
{
/*******************************************************************
* if (tPinLen > 9) { tByte[0] = (byte) Integer.parseInt(new
* Integer(tPinLen) .toString(), 16); } else { tByte[0] = (byte)
* Integer.parseInt(new Integer(tPinLen) .toString(), 10); }
******************************************************************/
// tByte[0] = (byte) Integer.parseInt(new Integer(tPinLen).toString(),
// 10);
tByte
[
0
]
=
(
byte
)
Integer
.
parseInt
(
Integer
.
toString
(
tPinLen
),
10
);
if
(
tPinLen
%
2
==
0
)
{
for
(
int
i
=
0
;
i
<
tPinLen
;
)
{
String
a
=
aPin
.
substring
(
i
,
i
+
2
);
tByte
[
tTemp
]
=
(
byte
)
Integer
.
parseInt
(
a
,
16
);
if
(
i
==
(
tPinLen
-
2
))
{
if
(
tTemp
<
7
)
{
for
(
int
x
=
(
tTemp
+
1
);
x
<
8
;
x
++)
{
tByte
[
x
]
=
(
byte
)
0xff
;
}
}
}
tTemp
++;
i
=
i
+
2
;
}
}
else
{
for
(
int
i
=
0
;
i
<
tPinLen
-
1
;
)
{
String
a
;
a
=
aPin
.
substring
(
i
,
i
+
2
);
tByte
[
tTemp
]
=
(
byte
)
Integer
.
parseInt
(
a
,
16
);
if
(
i
==
(
tPinLen
-
3
))
{
String
b
=
aPin
.
substring
(
tPinLen
-
1
)
+
"F"
;
tByte
[
tTemp
+
1
]
=
(
byte
)
Integer
.
parseInt
(
b
,
16
);
if
((
tTemp
+
1
)
<
7
)
{
for
(
int
x
=
(
tTemp
+
2
);
x
<
8
;
x
++)
{
tByte
[
x
]
=
(
byte
)
0xff
;
}
}
}
tTemp
++;
i
=
i
+
2
;
}
}
}
catch
(
Exception
e
)
{
}
return
tByte
;
}
/**
* @param aPan
* @return
*/
private
static
byte
[]
formatPan
(
String
aPan
)
{
int
tPanLen
=
aPan
.
length
();
byte
[]
tByte
=
new
byte
[
8
];
;
int
temp
=
tPanLen
-
13
;
try
{
tByte
[
0
]
=
(
byte
)
0x00
;
tByte
[
1
]
=
(
byte
)
0x00
;
for
(
int
i
=
2
;
i
<
8
;
i
++)
{
String
a
=
aPan
.
substring
(
temp
,
temp
+
2
);
tByte
[
i
]
=
(
byte
)
Integer
.
parseInt
(
a
,
16
);
temp
=
temp
+
2
;
}
}
catch
(
Exception
e
)
{
}
return
tByte
;
}
/**
* @param aPin
* @param aCardNO
* @return
*/
private
static
byte
[]
pin2PinBlockWithCardNO
(
String
aPin
,
String
aCardNO
)
{
byte
[]
tPinByte
=
pin2PinBlock
(
aPin
);
if
(
aCardNO
.
length
()
==
11
)
{
aCardNO
=
"00"
+
aCardNO
;
}
else
if
(
aCardNO
.
length
()
==
12
)
{
aCardNO
=
"0"
+
aCardNO
;
}
byte
[]
tPanByte
=
formatPan
(
aCardNO
);
byte
[]
tByte
=
new
byte
[
8
];
for
(
int
i
=
0
;
i
<
8
;
i
++)
{
tByte
[
i
]
=
(
byte
)
(
tPinByte
[
i
]
^
tPanByte
[
i
]);
}
return
tByte
;
}
/**
* luhn算法
*
* @param number
* @return
*/
public
static
int
genLuhn
(
String
number
)
{
number
=
number
+
"0"
;
int
s1
=
0
,
s2
=
0
;
String
reverse
=
new
StringBuffer
(
number
).
reverse
().
toString
();
for
(
int
i
=
0
;
i
<
reverse
.
length
();
i
++)
{
int
digit
=
Character
.
digit
(
reverse
.
charAt
(
i
),
10
);
if
(
i
%
2
==
0
)
{
// this is for odd digits, they are 1-indexed in //
// the algorithm
s1
+=
digit
;
}
else
{
// add 2 * digit for 0-4, add 2 * digit - 9 for 5-9
s2
+=
2
*
digit
;
if
(
digit
>=
5
)
{
s2
-=
9
;
}
}
}
int
check
=
10
-
((
s1
+
s2
)
%
10
);
if
(
check
==
10
)
{
check
=
0
;
}
return
check
;
}
}
src/main/java/com/esv/freight/customer/common/unionpay/UnionPayComponent.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
common
.
unionpay
;
import
com.esv.freight.customer.common.exception.EException
;
import
com.esv.freight.customer.common.pojo.AppUnionPayOrderReq
;
import
com.esv.freight.customer.common.pojo.AppUnionPayOrderRes
;
import
com.esv.freight.customer.common.response.ECode
;
import
com.esv.freight.customer.common.util.DateUtils
;
import
com.esv.freight.customer.common.util.MapUtils
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Component
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* @description: 银联开放平台组件
* @project: freight-customer-service
* @name: com.esv.freight.customer.common.unionpay.UnionPayComponent
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/05/29 9:29
* @version:1.0
*/
@Slf4j
@Component
public
class
UnionPayComponent
{
/**
* description 创建手机APP支付订单
* param [appUnionPayOrder]
* return AppUnionPayOrderRes
* author HuangChaobin
* createTime 2020/05/30 13:51
**/
public
AppUnionPayOrderRes
createAppUnionPayOrder
(
AppUnionPayOrderReq
appUnionPayOrderReq
)
throws
EException
{
Map
<
String
,
String
>
contentData
=
new
HashMap
<>(
128
);
/***银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改***/
//版本号 全渠道默认值
contentData
.
put
(
"version"
,
DemoBase
.
version
);
//字符集编码 可以使用UTF-8,GBK两种方式
contentData
.
put
(
"encoding"
,
DemoBase
.
encoding
);
//签名方法
contentData
.
put
(
"signMethod"
,
SDKConfig
.
getConfig
().
getSignMethod
());
//交易类型 01:消费
contentData
.
put
(
"txnType"
,
"01"
);
//交易子类 01:消费
contentData
.
put
(
"txnSubType"
,
"01"
);
//填写000201
contentData
.
put
(
"bizType"
,
"000201"
);
//渠道类型 08手机
contentData
.
put
(
"channelType"
,
"08"
);
/***商户接入参数***/
//商户号码,请改成自己申请的商户号或者open上注册得来的777商户号测试
contentData
.
put
(
"merId"
,
appUnionPayOrderReq
.
getMerId
());
//接入类型,商户接入填0 ,不需修改(0:直连商户, 1: 收单机构 2:平台商户)
contentData
.
put
(
"accessType"
,
"0"
);
//商户订单号,8-40位数字字母,不能含“-”或“_”,可以自行定制规则
contentData
.
put
(
"orderId"
,
appUnionPayOrderReq
.
getBillId
());
//订单描述
contentData
.
put
(
"orderDesc"
,
appUnionPayOrderReq
.
getBillDesc
());
//订单发送时间,取系统时间,格式为yyyyMMddHHmmss,必须取当前时间,否则会报txnTime无效
contentData
.
put
(
"txnTime"
,
appUnionPayOrderReq
.
getTxnTime
());
//账号类型 01:银行卡02:存折03:IC卡帐号类型(卡介质)
contentData
.
put
(
"accType"
,
"01"
);
//交易金额 单位为分,不能带小数点
contentData
.
put
(
"txnAmt"
,
String
.
valueOf
(
appUnionPayOrderReq
.
getTxnAmt
()));
//境内商户固定 156 人民币
contentData
.
put
(
"currencyCode"
,
"156"
);
// 请求方保留域,
// 透传字段,查询、通知、对账文件中均会原样出现,如有需要请启用并修改自己希望透传的数据。
// 出现部分特殊字符时可能影响解析,请按下面建议的方式填写:
// 1. 如果能确定内容不会出现&={}[]"'等符号时,可以直接填写数据,建议的方法如下。
// contentData.put("reqReserved", "透传信息1|透传信息2|透传信息3");
// 2. 内容可能出现&={}[]"'符号时:
// 1) 如果需要对账文件里能显示,可将字符替换成全角&={}【】“‘字符(自己写代码,此处不演示);
// 2) 如果对账文件没有显示要求,可做一下base64(如下)。
// 注意控制数据长度,实际传输的数据长度不能超过1024位。
// 查询、通知等接口解析时使用new String(Base64.decodeBase64(reqReserved), DemoBase.encoding);解base64后再对数据做后续解析。
// contentData.put("reqReserved", Base64.encodeBase64String("任意格式的信息都可以".toString().getBytes(DemoBase.encoding)));
//后台通知地址(需设置为外网能访问 http https均可),支付成功后银联会自动将异步通知报文post到商户上送的该地址,【支付失败的交易银联不会发送后台通知】
//后台通知参数详见open.unionpay.com帮助中心 下载 产品接口规范 网关支付产品接口规范 消费交易 商户通知
//注意:1.需设置为外网能访问,否则收不到通知
// 2.http https均可
// 3.收单后台通知后需要10秒内返回http200或302状态码
// 4.如果银联通知服务器发送通知后10秒内未收到返回状态码或者应答码非http200或302,那么银联会间隔一段时间再次发送。总共发送5次,银联后续间隔1、2、4、5 分钟后会再次通知。
// 5.后台通知地址如果上送了带有?的参数,例如:http://abc/web?a=b&c=d 在后台通知处理程序验证签名之前需要编写逻辑将这些字段去掉再验签,否则将会验签失败
contentData
.
put
(
"backUrl"
,
DemoBase
.
backUrl
);
// 前台返回商户结果时使用,前台类交易需上送
contentData
.
put
(
"frontUrl"
,
DemoBase
.
frontUrl
);
/**对请求参数进行签名并发送http post请求,接收同步应答报文**/
//报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。
Map
<
String
,
String
>
reqData
=
AcpService
.
sign
(
contentData
,
DemoBase
.
encoding
);
String
reqDataJsonStr
=
MapUtils
.
map2Json
(
reqData
).
toJSONString
();
log
.
info
(
"[银联开放平台]请求银联参数:{}"
,
reqDataJsonStr
);
//交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.backTransUrl
String
requestAppUrl
=
SDKConfig
.
getConfig
().
getAppRequestUrl
();
//发送请求报文并接受同步应答(默认连接超时时间30秒,读取返回结果超时时间30秒);这里调用signData之后,调用submitUrl之前不能对submitFromData中的键值对做任何修改,如果修改会导致验签不通过
Map
<
String
,
String
>
rspData
=
AcpService
.
post
(
reqData
,
requestAppUrl
,
DemoBase
.
encoding
);
String
resDataJsonStr
=
MapUtils
.
map2Json
(
rspData
).
toJSONString
();
log
.
info
(
"[银联开放平台]银联响应参数:{}"
,
resDataJsonStr
);
/**对应答码的处理,请根据您的业务逻辑来编写程序,以下应答码处理逻辑仅供参考------------->**/
//应答码规范参考open.unionpay.com帮助中心 下载 产品接口规范 《平台接入接口规范-第5部分-附录》
String
tn
;
if
(!
rspData
.
isEmpty
())
{
if
(
AcpService
.
validate
(
rspData
,
DemoBase
.
encoding
))
{
log
.
info
(
"[银联开放平台]验证签名成功"
);
String
respCode
=
rspData
.
get
(
"respCode"
);
if
((
"00"
).
equals
(
respCode
))
{
//成功,获取tn号
tn
=
rspData
.
get
(
"tn"
);
}
else
{
//其他应答码为失败请排查原因或做失败处理
throw
new
EException
(
ECode
.
THIRD_PARTY_ERROR
.
code
(),
"未定义异常"
);
}
}
else
{
log
.
error
(
"验证签名失败"
);
throw
new
EException
(
ECode
.
THIRD_PARTY_ERROR
.
code
(),
"创建银联受理订单号失败"
);
}
}
else
{
//未返回正确的http状态
log
.
error
(
"[银联开放平台]未获取到返回报文或返回http状态码非200"
);
throw
new
EException
(
ECode
.
THIRD_PARTY_ERROR
.
code
(),
"[银联开放平台]创建银联受理订单号失败"
);
}
AppUnionPayOrderRes
appUnionPayOrderRes
=
new
AppUnionPayOrderRes
();
appUnionPayOrderRes
.
setReqMessage
(
reqDataJsonStr
);
appUnionPayOrderRes
.
setRspMessage
(
resDataJsonStr
);
appUnionPayOrderRes
.
setTn
(
tn
);
return
appUnionPayOrderRes
;
}
/**
* description 查询交易
* param [appUnionPayOrderReq]
* return java.util.Map<java.lang.String,java.lang.String>
* author HuangChaobin
* createTime 2020/06/03 10:44
**/
public
Map
<
String
,
String
>
queryUnionPayOrder
(
AppUnionPayOrderReq
appUnionPayOrderReq
)
throws
EException
{
Map
<
String
,
String
>
data
=
new
HashMap
<>(
32
);
/***银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改***/
//版本号 全渠道默认值
data
.
put
(
"version"
,
DemoBase
.
version
);
//字符集编码 可以使用UTF-8,GBK两种方式
data
.
put
(
"encoding"
,
DemoBase
.
encoding
);
//签名方法
data
.
put
(
"signMethod"
,
SDKConfig
.
getConfig
().
getSignMethod
());
//交易类型 00-默认
data
.
put
(
"txnType"
,
"00"
);
//交易子类型 默认00
data
.
put
(
"txnSubType"
,
"00"
);
//业务类型
data
.
put
(
"bizType"
,
"000201"
);
/***商户接入参数***/
//商户号码,请改成自己申请的商户号或者open上注册得来的777商户号测试
data
.
put
(
"merId"
,
appUnionPayOrderReq
.
getMerId
());
//接入类型,商户接入固定填0,不需修改
data
.
put
(
"accessType"
,
"0"
);
/***要调通交易以下字段必须修改***/
//****商户订单号,每次发交易测试需修改为被查询的交易的订单号
data
.
put
(
"orderId"
,
appUnionPayOrderReq
.
getBillId
());
//****订单发送时间,每次发交易测试需修改为被查询的交易的订单发送时间
data
.
put
(
"txnTime"
,
appUnionPayOrderReq
.
getTxnTime
());
/**请求参数设置完毕,以下对请求参数进行签名并发送http post请求,接收同步应答报文------------->**/
//报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。
Map
<
String
,
String
>
reqData
=
AcpService
.
sign
(
data
,
DemoBase
.
encoding
);
//交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.singleQueryUrl
String
url
=
SDKConfig
.
getConfig
().
getSingleQueryUrl
();
//发送请求报文并接受同步应答(默认连接超时时间30秒,读取返回结果超时时间30秒);这里调用signData之后,调用submitUrl之前不能对submitFromData中的键值对做任何修改,如果修改会导致验签不通过
Map
<
String
,
String
>
rspData
=
AcpService
.
post
(
reqData
,
url
,
DemoBase
.
encoding
);
/**对应答码的处理,请根据您的业务逻辑来编写程序,以下应答码处理逻辑仅供参考------------->**/
//应答码规范参考open.unionpay.com帮助中心 下载 产品接口规范 《平台接入接口规范-第5部分-附录》
if
(!
rspData
.
isEmpty
())
{
if
(
AcpService
.
validate
(
rspData
,
DemoBase
.
encoding
))
{
log
.
info
(
"[银联开放平台]验证签名成功"
);
}
else
{
log
.
error
(
"[银联开放平台]验证签名失败"
);
throw
new
EException
(
ECode
.
THIRD_PARTY_ERROR
.
code
(),
"[银联开放平台]验证签名失败"
);
}
}
else
{
//未返回正确的http状态
log
.
error
(
"[银联开放平台]未获取到返回报文或返回http状态码非200"
);
throw
new
EException
(
ECode
.
THIRD_PARTY_ERROR
.
code
(),
"[银联开放平台]银联响应异常"
);
}
return
rspData
;
}
}
src/main/java/com/esv/freight/customer/common/util/MapUtils.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
common
.
util
;
import
com.alibaba.fastjson.JSONObject
;
import
lombok.extern.slf4j.Slf4j
;
import
java.util.Iterator
;
import
java.util.Map
;
/**
* @description: Map工具类
* @project: freight-customer-service
* @name: com.esv.freight.customer.common.util.MapUtils
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/06/02 16:04
* @version:1.0
*/
@Slf4j
public
class
MapUtils
{
/**
* description Map转Json
* param [map]
* return com.alibaba.fastjson.JSONObject
* author HuangChaobin
* createTime 2020/06/02 16:04
**/
public
static
JSONObject
map2Json
(
Map
<
String
,
String
>
map
)
{
JSONObject
json
=
new
JSONObject
();
Iterator
<
Map
.
Entry
<
String
,
String
>>
it
=
map
.
entrySet
().
iterator
();
while
(
it
.
hasNext
())
{
Map
.
Entry
<
String
,
String
>
en
=
it
.
next
();
json
.
put
(
en
.
getKey
(),
en
.
getValue
());
}
return
json
;
}
}
src/main/java/com/esv/freight/customer/common/util/ReqUtils.java
View file @
4f9a20eb
...
...
@@ -11,6 +11,13 @@ import org.springframework.web.context.request.RequestContextHolder;
import
org.springframework.web.context.request.ServletRequestAttributes
;
import
javax.servlet.http.HttpServletRequest
;
import
java.io.BufferedReader
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStreamReader
;
import
java.nio.charset.Charset
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* @description:Http请求工具类
...
...
@@ -106,4 +113,63 @@ public class ReqUtils {
}
}
/**
* description 获取Post请求Body
* param [req]
* return java.lang.String
* author HuangChaobin
* createTime 2020/06/02 19:45
**/
public
static
String
getPostBody
(
HttpServletRequest
req
)
{
String
reqBody
=
null
;
String
method
=
req
.
getMethod
();
if
(!
CommonConstants
.
HTTP_REQUEST_METHOD_POST
.
equalsIgnoreCase
(
method
))
{
return
reqBody
;
}
StringBuilder
sb
=
new
StringBuilder
();
InputStream
inputStream
=
null
;
BufferedReader
reader
=
null
;
try
{
inputStream
=
req
.
getInputStream
();
reader
=
new
BufferedReader
(
new
InputStreamReader
(
inputStream
,
Charset
.
forName
(
CommonConstants
.
DEFAULT_CHARACTER_ENCODING
)));
String
line
=
""
;
while
((
line
=
reader
.
readLine
())
!=
null
)
{
sb
.
append
(
line
);
}
if
(
0
==
sb
.
length
())
{
Map
<
String
,
String
>
bodyMap
=
new
HashMap
<>();
Map
<
String
,
String
[]>
parameterMap
=
req
.
getParameterMap
();
for
(
Map
.
Entry
<
String
,
String
[]>
entry
:
parameterMap
.
entrySet
())
{
for
(
String
value
:
entry
.
getValue
())
{
bodyMap
.
put
(
entry
.
getKey
(),
value
);
}
}
reqBody
=
bodyMap
.
toString
();
}
else
{
reqBody
=
sb
.
toString
();
}
}
catch
(
IOException
e
)
{
log
.
error
(
"解析post参数时发生错误:{}"
,
e
.
getMessage
(),
e
);
}
finally
{
if
(
inputStream
!=
null
)
{
try
{
inputStream
.
close
();
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
}
if
(
reader
!=
null
)
{
try
{
reader
.
close
();
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
}
}
return
reqBody
;
}
}
src/main/java/com/esv/freight/customer/common/util/ResUtils.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
common
.
util
;
import
lombok.extern.slf4j.Slf4j
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.IOException
;
import
java.io.OutputStreamWriter
;
import
java.io.PrintWriter
;
/**
* @description: Http响应工具类
* @project: freight-customer-service
* @name: com.esv.freight.customer.common.util.ResUtils
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/06/02 19:26
* @version:1.0
*/
@Slf4j
public
class
ResUtils
{
/**
* description Http响应
* param [response, status, contentType, resContent]
* return void
* author HuangChaobin
* createTime 2020/06/02 19:27
**/
public
static
void
response
(
HttpServletResponse
response
,
int
status
,
String
contentType
,
String
resContent
)
{
response
.
setCharacterEncoding
(
"UTF-8"
);
response
.
setContentType
(
contentType
);
response
.
setStatus
(
status
);
OutputStreamWriter
osw
=
null
;
PrintWriter
writer
=
null
;
try
{
osw
=
new
OutputStreamWriter
(
response
.
getOutputStream
(),
"UTF-8"
);
writer
=
new
PrintWriter
(
osw
,
true
);
writer
.
write
(
resContent
);
writer
.
flush
();
osw
.
close
();
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
finally
{
if
(
null
!=
writer
)
{
writer
.
close
();
}
if
(
null
!=
osw
)
{
try
{
osw
.
close
();
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
}
}
}
}
src/main/java/com/esv/freight/customer/config/ServletConfig.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
config
;
import
com.esv.freight.customer.module.servlet.AppFrontRcvServlet
;
import
com.esv.freight.customer.module.servlet.UnionpayBackRcvServlet
;
import
org.springframework.boot.web.servlet.ServletRegistrationBean
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
/**
* @description: 注册Servlet
* @project: freight-customer-service
* @name: com.esv.freight.customer.config.ServletConfig
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/06/02 18:59
* @version:1.0
*/
@Configuration
public
class
ServletConfig
{
@Bean
public
AppFrontRcvServlet
getAppFrontRcvServlet
()
{
return
new
AppFrontRcvServlet
();
}
@Bean
public
ServletRegistrationBean
appFrontRcvServletRegistrationBean
()
{
ServletRegistrationBean
registrationBean
=
new
ServletRegistrationBean
(
getAppFrontRcvServlet
(),
"/pay/frontRcvResponse"
);
return
registrationBean
;
}
@Bean
public
UnionpayBackRcvServlet
getUnionpayBackRcvServlet
()
{
return
new
UnionpayBackRcvServlet
();
}
@Bean
public
ServletRegistrationBean
unionpayBackRcvServletRegistrationBean
()
{
ServletRegistrationBean
registrationBean
=
new
ServletRegistrationBean
(
getUnionpayBackRcvServlet
(),
"/pay/backRcvResponse"
);
return
registrationBean
;
}
}
src/main/java/com/esv/freight/customer/feign/FreightBillService.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
feign
;
import
com.alibaba.fastjson.JSONObject
;
import
org.springframework.cloud.openfeign.FeignClient
;
import
org.springframework.web.bind.annotation.PostMapping
;
/**
* @description:
* @project: freight-customer-service
* @name: com.esv.freight.customer.feign.FreightBillService
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/06/04 9:48
* @version:1.0
*/
@FeignClient
(
value
=
"freight-bill-service"
)
public
interface
FreightBillService
{
/**
* description 更改应收账单支付状态
* param [bodyJson]
* return com.alibaba.fastjson.JSONObject
* author HuangChaobin
* createTime 2020/06/04 9:49
**/
@PostMapping
(
value
=
"/bill/verify/recvbill/updatePayState"
)
JSONObject
updatePayState
(
JSONObject
bodyJson
);
}
src/main/java/com/esv/freight/customer/module/pay/PayConstants.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
module
.
pay
;
/**
* @description:
* @project: freight-customer-service
* @name: com.esv.freight.customer.module.pay.PayConstants
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/06/01 19:47
* @version:1.0
*/
public
class
PayConstants
{
/**
* 支付方式:10-银联
*/
public
static
final
Integer
PAY_TYPE_UNIONPAY
=
10
;
/**
* 交易状态查询次数,最多6次
*/
public
static
final
Integer
UNIONPAY_QUERY_MAX_COUNT
=
6
;
/**
* 交易状态查询时间间隔(30分钟),单位:毫秒
*/
public
static
final
Long
UNIONPAY_QUERY_MAX_TIME
=
1800000L
;
/**
* 订单状态:1-支付中、2-支付结果确认中、3-支付成功、4-支付失败
*/
public
static
final
Integer
ORDER_STATUS_PAYING
=
1
;
public
static
final
Integer
ORDER_STATUS_CONFIRM
=
2
;
public
static
final
Integer
ORDER_STATUS_SUCCESS
=
3
;
public
static
final
Integer
ORDER_STATUS_FAILURE
=
4
;
}
src/main/java/com/esv/freight/customer/module/pay/controller/PayController.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
module
.
pay
.
controller
;
import
com.alibaba.fastjson.JSONObject
;
import
com.esv.freight.customer.common.exception.EException
;
import
com.esv.freight.customer.common.response.ECode
;
import
com.esv.freight.customer.common.response.EResponse
;
import
com.esv.freight.customer.module.pay.form.CustomerPayOrderForm
;
import
com.esv.freight.customer.module.pay.form.UnionPayOrderQueryForm
;
import
com.esv.freight.customer.module.pay.service.UnionpayOrderService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
/**
* @description: 支付Controller
* @project: freight-customer-service
* @name: com.esv.freight.customer.module.pay.controller.PayController
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/06/01 16:44
* @version:1.0
*/
@Slf4j
@RestController
@RequestMapping
(
"/goodsowner/pay"
)
@Validated
public
class
PayController
{
private
UnionpayOrderService
unionpayOrderService
;
@Autowired
public
PayController
(
UnionpayOrderService
unionpayOrderService
)
{
this
.
unionpayOrderService
=
unionpayOrderService
;
}
/**
* description 创建支付订单
* param [form]
* return com.esv.freight.customer.common.response.EResponse
* author HuangChaobin
* createTime 2020/06/02 9:13
**/
@PostMapping
(
"/createPayOrder"
)
public
EResponse
createPayOrder
(
@RequestBody
@Validated
CustomerPayOrderForm
form
)
{
String
tn
=
unionpayOrderService
.
createCustomerPayOrder
(
form
);
JSONObject
data
=
new
JSONObject
();
data
.
put
(
"tn"
,
tn
);
return
EResponse
.
ok
(
data
);
}
/**
* description 通过流水号查询订单状态
* param [form]
* return com.esv.freight.customer.common.response.EResponse
* author HuangChaobin
* createTime 2020/06/03 13:34
**/
@PostMapping
(
"/getOrderStatusByTn"
)
public
EResponse
getOrderStatusByTn
(
@RequestBody
@Validated
UnionPayOrderQueryForm
form
)
{
if
(
StringUtils
.
isBlank
(
form
.
getTn
()))
{
throw
new
EException
(
ECode
.
PARAM_ERROR
.
code
(),
"参数tn不能为空"
);
}
Integer
orderStatus
=
unionpayOrderService
.
getOrderStatusByTn
(
form
.
getTn
());
JSONObject
data
=
new
JSONObject
();
data
.
put
(
"orderStatus"
,
orderStatus
);
return
EResponse
.
ok
(
data
);
}
/**
* description 通过账单号查询订单状态
* param [form]
* return com.esv.freight.customer.common.response.EResponse
* author HuangChaobin
* createTime 2020/06/03 13:34
**/
@PostMapping
(
"/getOrderStatusByBillId"
)
public
EResponse
getOrderStatusByBillId
(
@RequestBody
@Validated
UnionPayOrderQueryForm
form
)
{
if
(
StringUtils
.
isBlank
(
form
.
getBillId
()))
{
throw
new
EException
(
ECode
.
PARAM_ERROR
.
code
(),
"参数orderId不能为空"
);
}
Integer
orderStatus
=
unionpayOrderService
.
getOrderStatusByBillId
(
form
.
getBillId
());
JSONObject
data
=
new
JSONObject
();
data
.
put
(
"orderStatus"
,
orderStatus
);
return
EResponse
.
ok
(
data
);
}
}
src/main/java/com/esv/freight/customer/module/pay/dao/
GoodsOwnerP
ayOrderDao.java
→
src/main/java/com/esv/freight/customer/module/pay/dao/
CustomerUnionp
ayOrderDao.java
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
module
.
pay
.
dao
;
import
com.esv.freight.customer.module.pay.entity.GoodsOwnerPayOrderEntity
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
import
com.esv.freight.customer.module.pay.entity.CustomerUnionpayOrderEntity
;
import
org.apache.ibatis.annotations.Mapper
;
import
java.util.List
;
/**
*
货主
支付订单表
*
客户银联
支付订单表
*
* @author 黄朝斌
* @email huangchaobin@esvtek.com
* @date 2020-0
5-30 13:41:5
1
* @date 2020-0
6-03 14:45:3
1
*/
@Mapper
public
interface
GoodsOwnerPayOrderDao
extends
BaseMapper
<
GoodsOwnerPayOrderEntity
>
{
public
interface
CustomerUnionpayOrderDao
extends
BaseMapper
<
CustomerUnionpayOrderEntity
>
{
/**
* description 通过账单号查询支付订单记录
* param [billId]
* return List<CustomerPayOrderEntity>
* author HuangChaobin
* createTime 2020/06/03 9:27
**/
List
<
CustomerUnionpayOrderEntity
>
selectByBillId
(
String
billId
);
}
src/main/java/com/esv/freight/customer/module/pay/entity/
GoodsOwnerP
ayOrderEntity.java
→
src/main/java/com/esv/freight/customer/module/pay/entity/
CustomerUnionp
ayOrderEntity.java
View file @
4f9a20eb
...
...
@@ -4,21 +4,21 @@ import com.baomidou.mybatisplus.annotation.FieldFill;
import
com.baomidou.mybatisplus.annotation.TableField
;
import
com.baomidou.mybatisplus.annotation.TableId
;
import
com.baomidou.mybatisplus.annotation.TableName
;
import
lombok.Data
;
import
java.io.Serializable
;
import
java.util.Date
;
import
lombok.Data
;
/**
*
货主
支付订单表
*
客户银联
支付订单表
*
* @author 黄朝斌
* @email huangchaobin@esvtek.com
* @date 2020-05-30 13:41:51
*/
@Data
@TableName
(
"
goods_owner_
pay_order"
)
public
class
GoodsOwnerP
ayOrderEntity
implements
Serializable
{
@TableName
(
"
customer_union
pay_order"
)
public
class
CustomerUnionp
ayOrderEntity
implements
Serializable
{
private
static
final
long
serialVersionUID
=
1L
;
/**
...
...
@@ -37,17 +37,21 @@ public class GoodsOwnerPayOrderEntity implements Serializable {
@TableField
(
fill
=
FieldFill
.
INSERT
)
private
Long
departmentId
;
/**
*
支付方式:10-银联
*
客户ID
*/
private
Integer
payType
;
private
Long
customerId
;
/**
* 商户代码(网络货运平台在支付平台的商户号)
*/
private
String
merId
;
/**
*
业务订
单号
*
账
单号
*/
private
String
orderId
;
private
String
billId
;
/**
* 账单描述
*/
private
String
billDesc
;
/**
* 请求支付平台订单发送时间
*/
...
...
@@ -56,22 +60,22 @@ public class GoodsOwnerPayOrderEntity implements Serializable {
* 交易金额(单位为分)
*/
private
Long
txnAmt
;
/**
* 订单描述
*/
private
String
orderDesc
;
/**
* 支付平台受理订单号
*/
private
String
tn
;
/**
* 订单状态:1-支付中、2-支付成功、3-支付失败
* 订单状态:1-支付中、2-支付结果确认中、3-支付成功、4-支付失败
*/
private
Integer
orderStatus
;
/**
* 请求银联查询次数,最多6次
*/
private
Long
orderStatus
;
private
Integer
queryCount
;
/**
*
查询流水号(消费交易的流水号,供后续查询用)
*
银联交易状态
*/
private
String
queryId
;
private
String
origRespCode
;
/**
* 创建时间
*/
...
...
@@ -80,10 +84,7 @@ public class GoodsOwnerPayOrderEntity implements Serializable {
/**
* 修改时间
*/
@TableField
(
fill
=
FieldFill
.
UPDATE
)
private
Date
updateTime
;
/**
* 支付平台回调时间
*/
private
Date
callbackTime
;
}
src/main/java/com/esv/freight/customer/module/pay/form/CustomerPayOrderForm.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
module
.
pay
.
form
;
import
lombok.Data
;
import
org.apache.commons.lang3.builder.ToStringBuilder
;
import
org.apache.commons.lang3.builder.ToStringStyle
;
import
org.hibernate.validator.constraints.Length
;
import
javax.validation.constraints.NotBlank
;
import
javax.validation.constraints.NotNull
;
/**
* @description:
* @project: freight-customer-service
* @name: com.esv.freight.customer.module.pay.form.CustomerPayOrderForm
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/06/01 17:15
* @version:1.0
*/
@Data
public
class
CustomerPayOrderForm
{
/**
* 客户ID
*/
@NotNull
(
message
=
"参数customerId不能为空"
)
private
Long
customerId
;
/**
* 账单号
*/
@NotBlank
(
message
=
"参数billId不能为空"
)
@Length
(
min
=
8
,
max
=
40
,
message
=
"参数billId长度不合法"
)
private
String
billId
;
/**
* 账单描述
*/
@NotBlank
(
message
=
"参数billDesc不能为空"
)
@Length
(
max
=
32
,
message
=
"参数billDesc长度不合法"
)
private
String
billDesc
;
/**
* 交易金额(单位为分)
*/
@NotNull
(
message
=
"参数txnAmt不能为空"
)
private
Long
txnAmt
;
@Override
public
String
toString
()
{
return
ToStringBuilder
.
reflectionToString
(
this
,
ToStringStyle
.
JSON_STYLE
);
}
}
src/main/java/com/esv/freight/customer/module/pay/form/UnionPayOrderQueryForm.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
module
.
pay
.
form
;
import
lombok.Data
;
import
org.apache.commons.lang3.builder.ToStringBuilder
;
import
org.apache.commons.lang3.builder.ToStringStyle
;
import
org.hibernate.validator.constraints.Length
;
/**
* @description:
* @project: freight-customer-service
* @name: com.esv.freight.customer.module.pay.form.UnionPayOrderQueryForm
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/06/03 13:29
* @version:1.0
*/
@Data
public
class
UnionPayOrderQueryForm
{
/**
* 订单流水号
*/
@Length
(
max
=
50
,
message
=
"参数tn长度不合法"
)
private
String
tn
;
/**
* 订单号
*/
@Length
(
max
=
50
,
message
=
"参数billId长度不合法"
)
private
String
billId
;
@Override
public
String
toString
()
{
return
ToStringBuilder
.
reflectionToString
(
this
,
ToStringStyle
.
JSON_STYLE
);
}
}
src/main/java/com/esv/freight/customer/module/pay/service/GoodsOwnerPayOrderService.java
deleted
100644 → 0
View file @
802de6d9
package
com
.
esv
.
freight
.
customer
.
module
.
pay
.
service
;
import
com.baomidou.mybatisplus.extension.service.IService
;
import
com.esv.freight.customer.module.pay.entity.GoodsOwnerPayOrderEntity
;
/**
* 货主支付订单表
*
* @author 黄朝斌
* @email huangchaobin@esvtek.com
* @date 2020-05-30 13:41:51
*/
public
interface
GoodsOwnerPayOrderService
extends
IService
<
GoodsOwnerPayOrderEntity
>
{
}
src/main/java/com/esv/freight/customer/module/pay/service/UnionpayOrderService.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
module
.
pay
.
service
;
import
com.baomidou.mybatisplus.extension.service.IService
;
import
com.esv.freight.customer.module.pay.entity.CustomerUnionpayOrderEntity
;
import
com.esv.freight.customer.module.pay.form.CustomerPayOrderForm
;
import
java.util.List
;
/**
* 货主支付订单表
*
* @author 黄朝斌
* @email huangchaobin@esvtek.com
* @date 2020-05-30 13:41:51
*/
public
interface
UnionpayOrderService
extends
IService
<
CustomerUnionpayOrderEntity
>
{
/**
* description 通过账单号查询记录
* param [billId]
* return com.esv.freight.customer.module.pay.entity.GoodsOwnerPayOrderEntity
* author HuangChaobin
* createTime 2020/06/02 15:48
**/
CustomerUnionpayOrderEntity
getRecordByBillId
(
String
billId
);
/**
* description 通过订单流水号查询记录
* param [tn]
* return com.esv.freight.customer.module.pay.entity.CustomerUnionpayOrderEntity
* author HuangChaobin
* createTime 2020/06/03 19:38
**/
CustomerUnionpayOrderEntity
getRecordByTn
(
String
tn
);
/**
* description 创建客户支付订单
* param [form]
* return java.lang.String
* author HuangChaobin
* createTime 2020/06/03 9:38
**/
String
createCustomerPayOrder
(
CustomerPayOrderForm
form
);
/**
* description 通过订单流水号查询订单支付状态
* param [tn]
* return java.lang.Integer
* author HuangChaobin
* createTime 2020/06/03 10:58
**/
Integer
getOrderStatusByTn
(
String
tn
);
/**
* description 通过账单号查询订单支付状态
* param [billId]
* return java.lang.Integer
* author HuangChaobin
* createTime 2020/06/03 11:01
**/
Integer
getOrderStatusByBillId
(
String
billId
);
/**
* description 请求银联查询订单支付状态
* param [customerUnionPayOrderEntity]
* return java.lang.Integer
* author HuangChaobin
* createTime 2020/06/04 9:44
**/
Integer
queryOrderStatus2Unionpay
(
CustomerUnionpayOrderEntity
customerUnionPayOrderEntity
);
}
src/main/java/com/esv/freight/customer/module/pay/service/impl/GoodsOwnerPayOrderServiceImpl.java
deleted
100644 → 0
View file @
802de6d9
package
com
.
esv
.
freight
.
customer
.
module
.
pay
.
service
.
impl
;
import
com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
;
import
com.esv.freight.customer.module.pay.dao.GoodsOwnerPayOrderDao
;
import
com.esv.freight.customer.module.pay.entity.GoodsOwnerPayOrderEntity
;
import
com.esv.freight.customer.module.pay.service.GoodsOwnerPayOrderService
;
import
org.springframework.stereotype.Service
;
@Service
(
"goodsOwnerPayOrderService"
)
public
class
GoodsOwnerPayOrderServiceImpl
extends
ServiceImpl
<
GoodsOwnerPayOrderDao
,
GoodsOwnerPayOrderEntity
>
implements
GoodsOwnerPayOrderService
{
}
\ No newline at end of file
src/main/java/com/esv/freight/customer/module/pay/service/impl/UnionpayOrderServiceImpl.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
module
.
pay
.
service
.
impl
;
import
com.alibaba.fastjson.JSONObject
;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
;
import
com.esv.freight.customer.common.component.ErrorMessageComponent
;
import
com.esv.freight.customer.common.exception.EException
;
import
com.esv.freight.customer.common.pojo.AppUnionPayOrderReq
;
import
com.esv.freight.customer.common.pojo.AppUnionPayOrderRes
;
import
com.esv.freight.customer.common.unionpay.UnionPayComponent
;
import
com.esv.freight.customer.common.util.DateUtils
;
import
com.esv.freight.customer.feign.FreightBillService
;
import
com.esv.freight.customer.module.pay.PayConstants
;
import
com.esv.freight.customer.module.pay.dao.CustomerUnionpayOrderDao
;
import
com.esv.freight.customer.module.pay.entity.CustomerUnionpayOrderEntity
;
import
com.esv.freight.customer.module.pay.form.CustomerPayOrderForm
;
import
com.esv.freight.customer.module.pay.service.UnionpayOrderService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.stereotype.Service
;
import
java.util.Map
;
@Service
(
"unionpayOrderService"
)
@Slf4j
public
class
UnionpayOrderServiceImpl
extends
ServiceImpl
<
CustomerUnionpayOrderDao
,
CustomerUnionpayOrderEntity
>
implements
UnionpayOrderService
{
@Value
(
"${unionpay.mer-id}"
)
private
String
unionPayMerId
;
private
ErrorMessageComponent
errorMessageComponent
;
private
UnionPayComponent
unionPayComponent
;
private
FreightBillService
freightBillService
;
@Autowired
public
UnionpayOrderServiceImpl
(
ErrorMessageComponent
errorMessageComponent
,
UnionPayComponent
unionPayComponent
,
FreightBillService
freightBillService
)
{
this
.
errorMessageComponent
=
errorMessageComponent
;
this
.
unionPayComponent
=
unionPayComponent
;
this
.
freightBillService
=
freightBillService
;
}
@Override
public
CustomerUnionpayOrderEntity
getRecordByBillId
(
String
billId
)
{
return
this
.
baseMapper
.
selectOne
(
new
LambdaQueryWrapper
<
CustomerUnionpayOrderEntity
>().
eq
(
CustomerUnionpayOrderEntity:
:
getBillId
,
billId
));
}
@Override
public
CustomerUnionpayOrderEntity
getRecordByTn
(
String
tn
)
{
return
this
.
baseMapper
.
selectOne
(
new
LambdaQueryWrapper
<
CustomerUnionpayOrderEntity
>().
eq
(
CustomerUnionpayOrderEntity:
:
getTn
,
tn
));
}
@Override
public
String
createCustomerPayOrder
(
CustomerPayOrderForm
form
)
{
// 判断订单是否存在
CustomerUnionpayOrderEntity
unionpayOrderEntity
=
this
.
getRecordByBillId
(
form
.
getBillId
());
if
(
null
!=
unionpayOrderEntity
)
{
if
(
PayConstants
.
ORDER_STATUS_SUCCESS
.
equals
(
unionpayOrderEntity
.
getOrderStatus
()))
{
throw
new
EException
(
1001
,
errorMessageComponent
.
getPayCustomerOrderCreate1001
());
}
else
{
// TODO 请求银联查询订单支付状态
}
}
// 请求支付平台获取支付订单号
AppUnionPayOrderReq
appUnionPayOrderReq
=
new
AppUnionPayOrderReq
();
appUnionPayOrderReq
.
setMerId
(
unionPayMerId
);
appUnionPayOrderReq
.
setBillId
(
form
.
getBillId
());
appUnionPayOrderReq
.
setBillDesc
(
form
.
getBillDesc
());
appUnionPayOrderReq
.
setTxnAmt
(
form
.
getTxnAmt
());
appUnionPayOrderReq
.
setTxnTime
(
DateUtils
.
format
(
DateUtils
.
getSysdate
(),
DateUtils
.
DATE_FORMAT4
));
AppUnionPayOrderRes
appUnionPayOrderRes
=
unionPayComponent
.
createAppUnionPayOrder
(
appUnionPayOrderReq
);
String
tn
=
appUnionPayOrderRes
.
getTn
();
// 新增或更新订单
CustomerUnionpayOrderEntity
customerUnionPayOrderEntity
=
new
CustomerUnionpayOrderEntity
();
if
(
null
==
unionpayOrderEntity
)
{
// 新增订单信息
customerUnionPayOrderEntity
.
setCustomerId
(
form
.
getCustomerId
());
customerUnionPayOrderEntity
.
setMerId
(
unionPayMerId
);
customerUnionPayOrderEntity
.
setBillId
(
form
.
getBillId
());
customerUnionPayOrderEntity
.
setBillDesc
(
form
.
getBillDesc
());
customerUnionPayOrderEntity
.
setTxnTime
(
appUnionPayOrderReq
.
getTxnTime
());
customerUnionPayOrderEntity
.
setTxnAmt
(
form
.
getTxnAmt
());
customerUnionPayOrderEntity
.
setTn
(
tn
);
customerUnionPayOrderEntity
.
setOrderStatus
(
PayConstants
.
ORDER_STATUS_PAYING
);
this
.
getBaseMapper
().
insert
(
customerUnionPayOrderEntity
);
}
else
{
// 更新订单信息
customerUnionPayOrderEntity
.
setId
(
unionpayOrderEntity
.
getId
());
customerUnionPayOrderEntity
.
setTn
(
tn
);
customerUnionPayOrderEntity
.
setTxnTime
(
appUnionPayOrderReq
.
getTxnTime
());
customerUnionPayOrderEntity
.
setBillDesc
(
form
.
getBillDesc
());
customerUnionPayOrderEntity
.
setTxnAmt
(
form
.
getTxnAmt
());
this
.
baseMapper
.
updateById
(
customerUnionPayOrderEntity
);
}
return
tn
;
}
@Override
public
Integer
getOrderStatusByTn
(
String
tn
)
{
CustomerUnionpayOrderEntity
customerUnionPayOrderEntity
=
this
.
getRecordByTn
(
tn
);
if
(
null
==
customerUnionPayOrderEntity
)
{
throw
new
EException
(
1001
,
"该支付订单流水号["
+
tn
+
"]不存在"
);
}
return
this
.
queryOrderStatus2Unionpay
(
customerUnionPayOrderEntity
);
}
@Override
public
Integer
getOrderStatusByBillId
(
String
billId
)
{
CustomerUnionpayOrderEntity
customerUnionPayOrderEntity
=
this
.
getRecordByBillId
(
billId
);
if
(
null
==
customerUnionPayOrderEntity
)
{
throw
new
EException
(
1001
,
"该账单号["
+
billId
+
"]不存在"
);
}
return
this
.
queryOrderStatus2Unionpay
(
customerUnionPayOrderEntity
);
}
/**
* description 请求银联查询订单支付状态
* param [customerUnionPayOrderEntity]
* return java.lang.Integer
* author HuangChaobin
* createTime 2020/06/03 11:08
**/
@Override
public
Integer
queryOrderStatus2Unionpay
(
CustomerUnionpayOrderEntity
customerUnionPayOrderEntity
)
{
Integer
orderStatus
;
// 判断订单是否支付完成
orderStatus
=
customerUnionPayOrderEntity
.
getOrderStatus
();
if
(
PayConstants
.
ORDER_STATUS_SUCCESS
.
equals
(
orderStatus
))
{
return
orderStatus
;
}
else
{
// 判断订单是否超过30分钟,暂时取消这个判断逻辑
// Long current = System.currentTimeMillis();
// Long createTime = customerUnionPayOrderEntity.getCreateTime().getTime();
// if (PayConstants.UNIONPAY_QUERY_MAX_TIME < (current - createTime)) {
// return orderStatus;
// }
}
// 请求银联查询订单支付状态
AppUnionPayOrderReq
appUnionPayOrderReq
=
new
AppUnionPayOrderReq
();
appUnionPayOrderReq
.
setMerId
(
unionPayMerId
);
appUnionPayOrderReq
.
setBillId
(
customerUnionPayOrderEntity
.
getBillId
());
appUnionPayOrderReq
.
setTxnTime
(
customerUnionPayOrderEntity
.
getTxnTime
());
Map
<
String
,
String
>
queryResultMap
=
unionPayComponent
.
queryUnionPayOrder
(
appUnionPayOrderReq
);
if
(
"00"
.
equals
(
queryResultMap
.
get
(
"respCode"
)))
{
String
origRespCode
=
queryResultMap
.
get
(
"origRespCode"
);
if
((
"00"
).
equals
(
origRespCode
))
{
//交易成功,更新商户订单状态
orderStatus
=
PayConstants
.
ORDER_STATUS_SUCCESS
;
}
else
if
((
"03"
).
equals
(
origRespCode
)
||
(
"04"
).
equals
(
origRespCode
)
||
(
"05"
).
equals
(
origRespCode
))
{
//订单处理中或交易状态未明,需稍后发起交易状态查询交易 【如果最终尚未确定交易是否成功请以对账文件为准】
orderStatus
=
PayConstants
.
ORDER_STATUS_CONFIRM
;
}
else
{
//其他应答码为交易失败
orderStatus
=
PayConstants
.
ORDER_STATUS_FAILURE
;
}
// 更新订单支付状态
CustomerUnionpayOrderEntity
orderEntity
=
new
CustomerUnionpayOrderEntity
();
orderEntity
.
setId
(
customerUnionPayOrderEntity
.
getId
());
orderEntity
.
setQueryCount
(
customerUnionPayOrderEntity
.
getQueryCount
()
+
1
);
orderEntity
.
setOrigRespCode
(
origRespCode
);
orderEntity
.
setOrderStatus
(
orderStatus
);
this
.
baseMapper
.
updateById
(
orderEntity
);
// 通知账单服务:更改应收账单支付状态
JSONObject
feignReqJson
=
new
JSONObject
();
feignReqJson
.
put
(
"billNo"
,
customerUnionPayOrderEntity
.
getBillId
());
feignReqJson
.
put
(
"payState"
,
orderStatus
);
try
{
log
.
info
(
"Feign请求[账单服务]传参:{}"
,
feignReqJson
.
toJSONString
());
JSONObject
feignResJson
=
freightBillService
.
updatePayState
(
feignReqJson
);
log
.
info
(
"Feign请求[账单服务]返回:{}"
,
feignResJson
.
toJSONString
());
}
catch
(
Exception
e
)
{
log
.
error
(
"Feign请求[账单服务]失败:{}"
,
e
.
getMessage
(),
e
);
}
}
return
orderStatus
;
}
}
\ No newline at end of file
src/main/java/com/esv/freight/customer/module/servlet/AppFrontRcvServlet.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
module
.
servlet
;
import
com.esv.freight.customer.common.util.ResUtils
;
import
lombok.extern.slf4j.Slf4j
;
import
javax.servlet.http.HttpServlet
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.IOException
;
import
java.util.Enumeration
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* @description:
* @project: freight-customer-service
* @name: com.esv.freight.customer.module.servlet.AppFrontRcvServlet
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/06/02 18:57
* @version:1.0
*/
@Slf4j
public
class
AppFrontRcvServlet
extends
HttpServlet
{
/**
* description 前端APP支付成功通过银联支付控件调用(frontUrl)
* param [req, resp]
* return void
* author HuangChaobin
* createTime 2020/06/02 19:28
**/
@Override
protected
void
service
(
HttpServletRequest
req
,
HttpServletResponse
resp
)
throws
IOException
{
Map
<
String
,
String
>
reqParam
=
this
.
getAllRequestParam
(
req
);
log
.
info
(
reqParam
.
toString
());
//返回给银联服务器http 200 状态码
ResUtils
.
response
(
resp
,
HttpServletResponse
.
SC_OK
,
"text/plain;charset=utf-8"
,
"ok"
);
}
/**
* 获取请求参数中所有的信息
*
* @param request
* @return
*/
private
Map
<
String
,
String
>
getAllRequestParam
(
final
HttpServletRequest
request
)
{
Map
<
String
,
String
>
res
=
new
HashMap
<>(
32
);
Enumeration
<?>
temp
=
request
.
getParameterNames
();
if
(
null
!=
temp
)
{
while
(
temp
.
hasMoreElements
())
{
String
en
=
(
String
)
temp
.
nextElement
();
String
value
=
request
.
getParameter
(
en
);
res
.
put
(
en
,
value
);
// 在报文上送时,如果字段的值为空,则不上送<下面的处理为在获取所有参数数据时,判断若值为空,则删除这个字段>
if
(
null
==
res
.
get
(
en
)
||
""
.
equals
(
res
.
get
(
en
)))
{
res
.
remove
(
en
);
}
}
}
return
res
;
}
}
src/main/java/com/esv/freight/customer/module/servlet/UnionpayBackRcvServlet.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
module
.
servlet
;
import
com.esv.freight.customer.common.constants.SDKConstants
;
import
com.esv.freight.customer.common.unionpay.AcpService
;
import
com.esv.freight.customer.common.unionpay.DemoBase
;
import
com.esv.freight.customer.common.util.ResUtils
;
import
com.esv.freight.customer.module.pay.entity.CustomerUnionpayOrderEntity
;
import
com.esv.freight.customer.module.pay.service.UnionpayOrderService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.io.IOUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
javax.servlet.http.HttpServlet
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.IOException
;
import
java.net.URLDecoder
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* @description:
* @project: freight-customer-service
* @name: com.esv.freight.customer.module.servlet.UnionpayBackRcvServlet
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/06/02 19:35
* @version:1.0
*/
@Slf4j
public
class
UnionpayBackRcvServlet
extends
HttpServlet
{
@Autowired
private
UnionpayOrderService
unionpayOrderService
;
/**
* description 银联异步通知支付结果
* param [req, resp]
* return void
* author HuangChaobin
* createTime 2020/06/02 19:40
**/
@Override
protected
void
service
(
HttpServletRequest
req
,
HttpServletResponse
resp
)
throws
IOException
{
log
.
info
(
"[银联开放平台]接收后台通知开始"
);
// 获取银联通知服务器发送的后台通知参数
Map
<
String
,
String
>
reqParam
=
getAllRequestParamStream
(
req
);
//重要!验证签名前不要修改reqParam中的键值对的内容,否则会验签不过
boolean
validateResult
=
AcpService
.
validate
(
reqParam
,
reqParam
.
get
(
SDKConstants
.
param_encoding
));
if
(!
validateResult
)
{
log
.
error
(
"[银联开放平台]验证签名结果:失败"
);
}
else
{
log
.
info
(
"[银联开放平台]验证签名结果:成功"
);
//判断respCode=00、A6后,对涉及资金类的交易,请再发起查询接口查询,确定交易成功后更新数据库。
String
respCode
=
reqParam
.
get
(
"respCode"
);
if
(
"00"
.
equals
(
respCode
)
||
"A6"
.
equals
(
respCode
))
{
String
orderId
=
reqParam
.
get
(
"orderId"
);
CustomerUnionpayOrderEntity
customerUnionPayOrderEntity
=
unionpayOrderService
.
getRecordByBillId
(
orderId
);
if
(
null
==
customerUnionPayOrderEntity
)
{
log
.
error
(
"[银联开放平台]该账单号["
+
orderId
+
"]不存在"
);
}
else
{
unionpayOrderService
.
queryOrderStatus2Unionpay
(
customerUnionPayOrderEntity
);
}
}
}
log
.
info
(
"[银联开放平台]接收后台通知结束"
);
//返回给银联服务器http 200 状态码
ResUtils
.
response
(
resp
,
HttpServletResponse
.
SC_OK
,
"text/plain;charset=utf-8"
,
"ok"
);
}
/**
* 获取请求参数中所有的信息。
* 非struts可以改用此方法获取,好处是可以过滤掉request.getParameter方法过滤不掉的url中的参数。
* struts可能对某些content-type会提前读取参数导致从inputstream读不到信息,所以可能用不了这个方法。理论应该可以调整struts配置使不影响,但请自己去研究。
* 调用本方法之前不能调用req.getParameter("key");这种方法,否则会导致request取不到输入流。
* @param request
* @return
*/
private
Map
<
String
,
String
>
getAllRequestParamStream
(
final
HttpServletRequest
request
)
{
Map
<
String
,
String
>
res
=
new
HashMap
<>(
32
);
try
{
String
notifyStr
=
new
String
(
IOUtils
.
toByteArray
(
request
.
getInputStream
()),
DemoBase
.
encoding
);
log
.
info
(
"[银联开放平台]收到通知报文:"
+
notifyStr
);
String
[]
kvs
=
notifyStr
.
split
(
"&"
);
for
(
String
kv
:
kvs
)
{
String
[]
tmp
=
kv
.
split
(
"="
);
if
(
tmp
.
length
>=
2
)
{
String
key
=
tmp
[
0
];
String
value
=
URLDecoder
.
decode
(
tmp
[
1
],
DemoBase
.
encoding
);
res
.
put
(
key
,
value
);
}
}
}
catch
(
Exception
e
)
{
log
.
error
(
"[银联开放平台]报文解析出错: {}"
,
e
.
getMessage
(),
e
);
}
return
res
;
}
}
src/main/resources/acp_sdk.properties
0 → 100644
View file @
4f9a20eb
##############SDK配置文件(证书方式签名)################
# 说明:
# 1. 使用时请将此文件复制到src文件夹下替换原来的acp_sdk.properties。
# 2. 具体配置项请根据注释修改。
#
################################################
##########################入网测试环境交易发送地址(线上测试需要使用生产环境交易请求地址)#############################
##交易请求地址
acpsdk.frontTransUrl
=
https://gateway.test.95516.com/gateway/api/frontTransReq.do
acpsdk.backTransUrl
=
https://gateway.test.95516.com/gateway/api/backTransReq.do
acpsdk.singleQueryUrl
=
https://gateway.test.95516.com/gateway/api/queryTrans.do
acpsdk.batchTransUrl
=
https://gateway.test.95516.com/gateway/api/batchTrans.do
acpsdk.fileTransUrl
=
https://filedownload.test.95516.com/
acpsdk.appTransUrl
=
https://gateway.test.95516.com/gateway/api/appTransReq.do
acpsdk.cardTransUrl
=
https://gateway.test.95516.com/gateway/api/cardTransReq.do
#以下缴费产品使用,其余产品用不到
acpsdk.jfFrontTransUrl
=
https://gateway.test.95516.com/jiaofei/api/frontTransReq.do
acpsdk.jfBackTransUrl
=
https://gateway.test.95516.com/jiaofei/api/backTransReq.do
acpsdk.jfSingleQueryUrl
=
https://gateway.test.95516.com/jiaofei/api/queryTrans.do
acpsdk.jfCardTransUrl
=
https://gateway.test.95516.com/jiaofei/api/cardTransReq.do
acpsdk.jfAppTransUrl
=
https://gateway.test.95516.com/jiaofei/api/appTransReq.do
########################################################################
# 报文版本号,固定5.1.0,请勿改动
acpsdk.version
=
5.1.0
# 签名方式,证书方式固定01,请勿改动
acpsdk.signMethod
=
01
# 是否验证验签证书的CN,测试环境请设置false,生产环境请设置true。非false的值默认都当true处理。
acpsdk.ifValidateCNName
=
false
# 是否验证https证书,测试环境请设置false,生产环境建议优先尝试true,不行再false。非true的值默认都当false处理。
acpsdk.ifValidateRemoteCert
=
false
#后台通知地址,填写接收银联后台通知的地址,必须外网能访问
acpsdk.backUrl
=
http://esvsy.wicp.vip:8082/customer/pay/backRcvResponse
#前台通知地址,填写处理银联前台通知的地址,必须外网能访问
acpsdk.frontUrl
=
http://esvsy.wicp.vip:8082/customer/pay/frontRcvResponse
#########################入网测试环境签名证书配置 ################################
# 多证书的情况证书路径为代码指定,可不对此块做配置。
# 签名证书路径,必须使用绝对路径,如果不想使用绝对路径,可以自行实现相对路径获取证书的方法;测试证书所有商户共用开发包中的测试签名证书,生产环境请从cfca下载得到。
# windows样例:
acpsdk.signCert.path
=
/home/esv/app/tomcat/freight/customer-service/certs/acp_test_sign.pfx
# 签名证书密码,测试环境固定000000,生产环境请修改为从cfca下载的正式证书的密码,正式环境证书密码位数需小于等于6位,否则上传到商户服务网站会失败
acpsdk.signCert.pwd
=
000000
# 签名证书类型,固定不需要修改
acpsdk.signCert.type
=
PKCS12
##########################加密证书配置################################
# 敏感信息加密证书路径(商户号开通了商户对敏感信息加密的权限,需要对 卡号accNo,pin和phoneNo,cvn2,expired加密(如果这些上送的话),对敏感信息加密使用)
acpsdk.encryptCert.path
=
/home/esv/app/tomcat/freight/customer-service/certs/acp_test_enc.cer
##########################验签证书配置################################
# 验签中级证书路径(银联提供)
acpsdk.middleCert.path
=
/home/esv/app/tomcat/freight/customer-service/certs/acp_test_middle.cer
# 验签根证书路径(银联提供)
acpsdk.rootCert.path
=
/home/esv/app/tomcat/freight/customer-service/certs/acp_test_root.cer
src/main/resources/acp_sdk_dev.properties
0 → 100644
View file @
4f9a20eb
##############SDK配置文件(证书方式签名)################
# 说明:
# 1. 使用时请将此文件复制到src文件夹下替换原来的acp_sdk.properties。
# 2. 具体配置项请根据注释修改。
#
################################################
##########################入网测试环境交易发送地址(线上测试需要使用生产环境交易请求地址)#############################
##交易请求地址
acpsdk.frontTransUrl
=
https://gateway.test.95516.com/gateway/api/frontTransReq.do
acpsdk.backTransUrl
=
https://gateway.test.95516.com/gateway/api/backTransReq.do
acpsdk.singleQueryUrl
=
https://gateway.test.95516.com/gateway/api/queryTrans.do
acpsdk.batchTransUrl
=
https://gateway.test.95516.com/gateway/api/batchTrans.do
acpsdk.fileTransUrl
=
https://filedownload.test.95516.com/
acpsdk.appTransUrl
=
https://gateway.test.95516.com/gateway/api/appTransReq.do
acpsdk.cardTransUrl
=
https://gateway.test.95516.com/gateway/api/cardTransReq.do
#以下缴费产品使用,其余产品用不到
acpsdk.jfFrontTransUrl
=
https://gateway.test.95516.com/jiaofei/api/frontTransReq.do
acpsdk.jfBackTransUrl
=
https://gateway.test.95516.com/jiaofei/api/backTransReq.do
acpsdk.jfSingleQueryUrl
=
https://gateway.test.95516.com/jiaofei/api/queryTrans.do
acpsdk.jfCardTransUrl
=
https://gateway.test.95516.com/jiaofei/api/cardTransReq.do
acpsdk.jfAppTransUrl
=
https://gateway.test.95516.com/jiaofei/api/appTransReq.do
########################################################################
# 报文版本号,固定5.1.0,请勿改动
acpsdk.version
=
5.1.0
# 签名方式,证书方式固定01,请勿改动
acpsdk.signMethod
=
01
# 是否验证验签证书的CN,测试环境请设置false,生产环境请设置true。非false的值默认都当true处理。
acpsdk.ifValidateCNName
=
false
# 是否验证https证书,测试环境请设置false,生产环境建议优先尝试true,不行再false。非true的值默认都当false处理。
acpsdk.ifValidateRemoteCert
=
false
#后台通知地址,填写接收银联后台通知的地址,必须外网能访问
acpsdk.backUrl
=
http://esvsy.wicp.vip:8082/customer/pay/backRcvResponse
#前台通知地址,填写处理银联前台通知的地址,必须外网能访问
acpsdk.frontUrl
=
http://esvsy.wicp.vip:8082/customer/pay/frontRcvResponse
#########################入网测试环境签名证书配置 ################################
# 多证书的情况证书路径为代码指定,可不对此块做配置。
# 签名证书路径,必须使用绝对路径,如果不想使用绝对路径,可以自行实现相对路径获取证书的方法;测试证书所有商户共用开发包中的测试签名证书,生产环境请从cfca下载得到。
# windows样例:
acpsdk.signCert.path
=
D:/certs/acp_test_sign.pfx
# 签名证书密码,测试环境固定000000,生产环境请修改为从cfca下载的正式证书的密码,正式环境证书密码位数需小于等于6位,否则上传到商户服务网站会失败
acpsdk.signCert.pwd
=
000000
# 签名证书类型,固定不需要修改
acpsdk.signCert.type
=
PKCS12
##########################加密证书配置################################
# 敏感信息加密证书路径(商户号开通了商户对敏感信息加密的权限,需要对 卡号accNo,pin和phoneNo,cvn2,expired加密(如果这些上送的话),对敏感信息加密使用)
acpsdk.encryptCert.path
=
d:/certs/acp_test_enc.cer
##########################验签证书配置################################
# 验签中级证书路径(银联提供)
acpsdk.middleCert.path
=
D:/certs/acp_test_middle.cer
# 验签根证书路径(银联提供)
acpsdk.rootCert.path
=
D:/certs/acp_test_root.cer
src/main/resources/application-dev.yml
View file @
4f9a20eb
...
...
@@ -63,10 +63,16 @@ hystrix:
ribbon
:
eager-load
:
enabled
:
true
clients
:
freight-base-service,freight-file-service,freight-app-service
clients
:
freight-base-service,freight-file-service,freight-app-service
,freight-bill-service
font
:
windows
:
dir
:
/usr/share/fonts/windows
#商户代码(网络货运平台在支付平台的商户号)
unionpay
:
mer-id
:
777290058182031
acp-sdk
:
properties
:
path
:
/home/esv/app/tomcat/freight/customer-service/config/acp_sdk.properties
error-message
:
goodsowner
:
account
:
...
...
@@ -272,3 +278,8 @@ error-message:
1001
:
无效的合同编号
get-by-number
:
1001
:
无效的合同编号
pay
:
customer
:
order
:
create
:
1001
:
订单已支付成功
\ No newline at end of file
src/main/resources/application-test.yml
View file @
4f9a20eb
...
...
@@ -63,10 +63,16 @@ hystrix:
ribbon
:
eager-load
:
enabled
:
true
clients
:
freight-base-service,freight-file-service,freight-app-service
clients
:
freight-base-service,freight-file-service,freight-app-service
,freight-bill-service
font
:
windows
:
dir
:
/usr/share/fonts/windows
#商户代码(网络货运平台在支付平台的商户号)
unionpay
:
mer-id
:
777290058182031
acp-sdk
:
properties
:
path
:
/home/esv/app/tomcat/freight/customer-service/config/acp_sdk.properties
error-message
:
goodsowner
:
account
:
...
...
@@ -272,3 +278,8 @@ error-message:
1001
:
无效的合同编号
get-by-number
:
1001
:
无效的合同编号
pay
:
customer
:
order
:
create
:
1001
:
订单已支付成功
\ No newline at end of file
src/main/resources/mapper/pay/
GoodsOwnerP
ayOrderDao.xml
→
src/main/resources/mapper/pay/
CustomerUnionp
ayOrderDao.xml
View file @
4f9a20eb
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace=
"com.esv.freight.customer.module.pay.dao.
GoodsOwnerP
ayOrderDao"
>
<mapper
namespace=
"com.esv.freight.customer.module.pay.dao.
CustomerUnionp
ayOrderDao"
>
<!-- 可根据自己的需求,是否要使用 -->
<resultMap
type=
"com.esv.freight.customer.module.pay.entity.
GoodsOwnerPayOrderEntity"
id=
"goodsOwnerP
ayOrderMap"
>
<resultMap
type=
"com.esv.freight.customer.module.pay.entity.
CustomerUnionpayOrderEntity"
id=
"customerUnionp
ayOrderMap"
>
<result
property=
"id"
column=
"id"
/>
<result
property=
"tenantId"
column=
"tenant_id"
/>
<result
property=
"departmentId"
column=
"department_id"
/>
<result
property=
"
payType"
column=
"pay_type
"
/>
<result
property=
"
customerId"
column=
"customer_id
"
/>
<result
property=
"merId"
column=
"mer_id"
/>
<result
property=
"orderId"
column=
"order_id"
/>
<result
property=
"billId"
column=
"bill_id"
/>
<result
property=
"billDesc"
column=
"bill_desc"
/>
<result
property=
"txnTime"
column=
"txn_time"
/>
<result
property=
"txnAmt"
column=
"txn_amt"
/>
<result
property=
"orderDesc"
column=
"order_desc"
/>
<result
property=
"tn"
column=
"tn"
/>
<result
property=
"orderStatus"
column=
"order_status"
/>
<result
property=
"queryId"
column=
"query_id"
/>
<result
property=
"queryCount"
column=
"query_count"
/>
<result
property=
"origRespCode"
column=
"orig_resp_code"
/>
<result
property=
"createTime"
column=
"create_time"
/>
<result
property=
"updateTime"
column=
"update_time"
/>
<result
property=
"callbackTime"
column=
"callback_time"
/>
</resultMap>
<select
id=
"selectByBillId"
parameterType=
"java.lang.String"
resultType=
"com.esv.freight.customer.module.pay.entity.CustomerUnionpayOrderEntity"
>
select *
from customer_unionpay_order
where bill_id = #{billId}
order by txn_time desc
</select>
</mapper>
\ No newline at end of file
src/test/java/com/esv/freight/customer/common/unionpay/UnionPayComponentTest.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
common
.
unionpay
;
import
com.esv.freight.customer.BaseTestController
;
import
com.esv.freight.customer.common.pojo.AppUnionPayOrderReq
;
import
lombok.extern.slf4j.Slf4j
;
import
org.junit.FixMethodOrder
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.junit.runners.MethodSorters
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.test.annotation.Rollback
;
import
org.springframework.test.context.junit4.SpringRunner
;
import
org.springframework.transaction.annotation.Transactional
;
/**
* @description:
* @project: freight-customer-service
* @name: com.esv.freight.customer.common.unionpay.UnionPayComponentTest
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/05/30 15:00
* @version:1.0
*/
@RunWith
(
SpringRunner
.
class
)
@SpringBootTest
@Slf4j
@FixMethodOrder
(
MethodSorters
.
NAME_ASCENDING
)
@Transactional
@Rollback
(
false
)
public
class
UnionPayComponentTest
extends
BaseTestController
{
@Autowired
UnionPayComponent
unionPayComponent
;
@Test
public
void
a1_createAppUnionPayOrder_test
()
throws
Exception
{
AppUnionPayOrderReq
appUnionPayOrderReq
=
new
AppUnionPayOrderReq
();
appUnionPayOrderReq
.
setMerId
(
"777290058182031"
);
appUnionPayOrderReq
.
setBillId
(
"DD"
+
System
.
currentTimeMillis
());
appUnionPayOrderReq
.
setTxnAmt
(
100L
);
appUnionPayOrderReq
.
setBillDesc
(
"测试订单"
);
unionPayComponent
.
createAppUnionPayOrder
(
appUnionPayOrderReq
);
}
}
src/test/java/com/esv/freight/customer/module/pay/controller/PayControllerTest.java
0 → 100644
View file @
4f9a20eb
package
com
.
esv
.
freight
.
customer
.
module
.
pay
.
controller
;
import
com.alibaba.fastjson.JSONObject
;
import
com.esv.freight.customer.BaseTestController
;
import
com.esv.freight.customer.common.response.ECode
;
import
com.esv.freight.customer.module.pay.form.CustomerPayOrderForm
;
import
com.esv.freight.customer.module.pay.form.UnionPayOrderQueryForm
;
import
lombok.extern.slf4j.Slf4j
;
import
org.junit.Assert
;
import
org.junit.FixMethodOrder
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.junit.runners.MethodSorters
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.http.MediaType
;
import
org.springframework.test.annotation.Rollback
;
import
org.springframework.test.context.junit4.SpringRunner
;
import
org.springframework.test.web.servlet.MvcResult
;
import
org.springframework.test.web.servlet.request.MockMvcRequestBuilders
;
import
org.springframework.test.web.servlet.result.MockMvcResultHandlers
;
import
org.springframework.test.web.servlet.result.MockMvcResultMatchers
;
import
org.springframework.transaction.annotation.Transactional
;
/**
* @description:
* @project: freight-customer-service
* @name: com.esv.freight.customer.module.pay.controller.PayControllerTest
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/06/02 9:21
* @version:1.0
*/
@RunWith
(
SpringRunner
.
class
)
@SpringBootTest
@Slf4j
@FixMethodOrder
(
MethodSorters
.
NAME_ASCENDING
)
@Transactional
@Rollback
(
false
)
public
class
PayControllerTest
extends
BaseTestController
{
/**
* 创建支付订单
**/
@Test
public
void
a1_createPayOrder_success_test
()
throws
Exception
{
String
url
=
"/goodsowner/pay/createPayOrder"
;
// 构造数据
CustomerPayOrderForm
form
=
new
CustomerPayOrderForm
();
form
.
setCustomerId
(
1L
);
form
.
setBillId
(
"DD"
+
System
.
currentTimeMillis
());
form
.
setBillDesc
(
"测试支付订单"
);
form
.
setTxnAmt
(
1L
);
MvcResult
mvcResult
=
this
.
getMockMvc
().
perform
(
MockMvcRequestBuilders
.
post
(
url
)
.
contentType
(
MediaType
.
APPLICATION_JSON_UTF8_VALUE
)
.
headers
(
this
.
getDefaultHttpHeaders
())
.
content
(
form
.
toString
()))
.
andDo
(
MockMvcResultHandlers
.
print
())
.
andExpect
(
MockMvcResultMatchers
.
status
().
isOk
())
.
andReturn
();
String
responseStr
=
mvcResult
.
getResponse
().
getContentAsString
();
log
.
info
(
responseStr
);
JSONObject
result
=
JSONObject
.
parseObject
(
responseStr
);
Assert
.
assertEquals
(
ECode
.
SUCCESS
.
code
(),
result
.
getIntValue
(
"code"
));
Assert
.
assertTrue
(
result
.
getJSONObject
(
"data"
).
containsKey
(
"tn"
));
}
/**
* 通过流水号查询订单状态
**/
@Test
public
void
b1_getOrderStatusByTn_success_test
()
throws
Exception
{
String
url
=
"/goodsowner/pay/getOrderStatusByTn"
;
// 构造数据
UnionPayOrderQueryForm
form
=
new
UnionPayOrderQueryForm
();
form
.
setTn
(
"981455249750781438820"
);
MvcResult
mvcResult
=
this
.
getMockMvc
().
perform
(
MockMvcRequestBuilders
.
post
(
url
)
.
contentType
(
MediaType
.
APPLICATION_JSON_UTF8_VALUE
)
.
headers
(
this
.
getDefaultHttpHeaders
())
.
content
(
form
.
toString
()))
.
andDo
(
MockMvcResultHandlers
.
print
())
.
andExpect
(
MockMvcResultMatchers
.
status
().
isOk
())
.
andReturn
();
String
responseStr
=
mvcResult
.
getResponse
().
getContentAsString
();
log
.
info
(
responseStr
);
JSONObject
result
=
JSONObject
.
parseObject
(
responseStr
);
Assert
.
assertEquals
(
ECode
.
SUCCESS
.
code
(),
result
.
getIntValue
(
"code"
));
Assert
.
assertTrue
(
result
.
getJSONObject
(
"data"
).
containsKey
(
"orderStatus"
));
}
/**
* 通过流水号查询订单状态
**/
@Test
public
void
b1_getOrderStatusByOrderId_success_test
()
throws
Exception
{
String
url
=
"/goodsowner/pay/getOrderStatusByOrderId"
;
// 构造数据
UnionPayOrderQueryForm
form
=
new
UnionPayOrderQueryForm
();
form
.
setBillId
(
"DD1591163252774"
);
MvcResult
mvcResult
=
this
.
getMockMvc
().
perform
(
MockMvcRequestBuilders
.
post
(
url
)
.
contentType
(
MediaType
.
APPLICATION_JSON_UTF8_VALUE
)
.
headers
(
this
.
getDefaultHttpHeaders
())
.
content
(
form
.
toString
()))
.
andDo
(
MockMvcResultHandlers
.
print
())
.
andExpect
(
MockMvcResultMatchers
.
status
().
isOk
())
.
andReturn
();
String
responseStr
=
mvcResult
.
getResponse
().
getContentAsString
();
log
.
info
(
responseStr
);
JSONObject
result
=
JSONObject
.
parseObject
(
responseStr
);
Assert
.
assertEquals
(
ECode
.
SUCCESS
.
code
(),
result
.
getIntValue
(
"code"
));
Assert
.
assertTrue
(
result
.
getJSONObject
(
"data"
).
containsKey
(
"orderStatus"
));
}
}
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