初始项目
This commit is contained in:
2
mallplus-pay/.gitignore
vendored
Normal file
2
mallplus-pay/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# MyBatis generate files #
|
||||
src\main\resources\com\zscat\mall\mapper
|
||||
BIN
mallplus-pay/libs/bcprov-jdk15on-1.54.jar
Normal file
BIN
mallplus-pay/libs/bcprov-jdk15on-1.54.jar
Normal file
Binary file not shown.
140
mallplus-pay/pom.xml
Normal file
140
mallplus-pay/pom.xml
Normal file
@@ -0,0 +1,140 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.zscat.mallplus</groupId>
|
||||
<artifactId>mallplus-pay</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>mallplus-pay</name>
|
||||
<description>mallplus-pay project for mall</description>
|
||||
<properties>
|
||||
<alipay.version>4.8.10.ALL</alipay.version>
|
||||
<fastjson.version>1.2.62</fastjson.version>
|
||||
<jdk.version>1.8</jdk.version>
|
||||
<junit.version>4.12</junit.version>
|
||||
<hutool.version>5.0.4</hutool.version>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- 全局单元测试 -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- huTool 工具包 -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
<!-- huTool 工具包 End -->
|
||||
<dependency>
|
||||
<groupId>com.alipay.sdk</groupId>
|
||||
<artifactId>alipay-sdk-java</artifactId>
|
||||
<version>${alipay.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<groupId>com.alibaba</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>4.0.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>4.0.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 开源多维码生成工具 -->
|
||||
<dependency>
|
||||
<groupId>com.google.zxing</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>3.4.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.zxing</groupId>
|
||||
<artifactId>javase</artifactId>
|
||||
<version>3.4.0</version>
|
||||
</dependency>
|
||||
<!-- 开源多维码生成工具 -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.10</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.13</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 银联必须 -->
|
||||
<dependency>
|
||||
<groupId>com.unionpay</groupId>
|
||||
<artifactId>unionpay-sdk-java</artifactId>
|
||||
<version>1.54</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/libs/bcprov-jdk15on-1.54.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.13</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.17</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.28</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>1.7.28</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.9</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- 银联必须 -->
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
4
mallplus-pay/src/main/java/com/zscat/mallplus/T.java
Normal file
4
mallplus-pay/src/main/java/com/zscat/mallplus/T.java
Normal file
@@ -0,0 +1,4 @@
|
||||
package com.zscat.mallplus;
|
||||
|
||||
public class T {
|
||||
}
|
||||
@@ -0,0 +1,889 @@
|
||||
package com.zscat.mallplus.alipay;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.alipay.api.AlipayClient;
|
||||
import com.alipay.api.DefaultAlipayClient;
|
||||
import com.alipay.api.domain.*;
|
||||
import com.alipay.api.request.*;
|
||||
import com.alipay.api.response.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>支付宝支付相关接口</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
@Slf4j
|
||||
public class AliPayApi {
|
||||
|
||||
/**
|
||||
* 支付宝提供给商户的服务接入网关URL(新)
|
||||
*/
|
||||
private static final String GATEWAY_NEW = "https://mapi.alipay.com/gateway.do?";
|
||||
|
||||
|
||||
/**
|
||||
* APP支付
|
||||
*
|
||||
* @param model {@link AlipayTradeAppPayModel}
|
||||
* @param notifyUrl 异步通知 URL
|
||||
* @return {@link AlipayTradeAppPayResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradeAppPayResponse appPayToResponse(AlipayTradeAppPayModel model, String notifyUrl, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
|
||||
request.setBizModel(model);
|
||||
request.setNotifyUrl(notifyUrl);
|
||||
AlipayTradeAppPayResponse response = aliPayApiConfig.getAliPayClient().sdkExecute(request);
|
||||
System.out.println(response.getBody());
|
||||
return aliPayApiConfig.getAliPayClient().sdkExecute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* WAP支付
|
||||
*
|
||||
* @param response {@link HttpServletResponse}
|
||||
* @param model {@link AlipayTradeWapPayModel}
|
||||
* @param returnUrl 异步通知URL
|
||||
* @param notifyUrl 同步通知URL
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
* @throws IOException IO 异常
|
||||
*/
|
||||
public static void wapPay(HttpServletResponse response, AlipayTradeWapPayModel model, String returnUrl, String notifyUrl, AliPayApiConfig aliPayApiConfig) throws AlipayApiException, IOException {
|
||||
String form = wapPayStr(model, returnUrl, notifyUrl, aliPayApiConfig);
|
||||
response.setContentType("text/html;charset=" + aliPayApiConfig.getCharset());
|
||||
PrintWriter out = response.getWriter();
|
||||
log.info(returnUrl);
|
||||
log.info(form);
|
||||
out.write(form);
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>WAP支付</p>
|
||||
* <p>
|
||||
* <p>为了解决 Filter 中使用 OutputStream getOutputStream() 和 PrintWriter getWriter() 冲突异常问题</p>
|
||||
*
|
||||
* @param response {@link HttpServletResponse}
|
||||
* @param model {@link AlipayTradeWapPayModel}
|
||||
* @param returnUrl 异步通知URL
|
||||
* @param notifyUrl 同步通知URL
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
* @throws IOException IO 异常
|
||||
*/
|
||||
public static void wapPayByOutputStream(HttpServletResponse response, AlipayTradeWapPayModel model, String returnUrl, String notifyUrl, AliPayApiConfig aliPayApiConfig) throws AlipayApiException, IOException {
|
||||
String form = wapPayStr(model, returnUrl, notifyUrl, aliPayApiConfig);
|
||||
log.info(form);
|
||||
response.setContentType("text/html;charset=" + aliPayApiConfig.getCharset());
|
||||
OutputStream out = response.getOutputStream();
|
||||
out.write(form.getBytes(aliPayApiConfig.getCharset()));
|
||||
response.getOutputStream().flush();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* WAP支付
|
||||
*
|
||||
* @param model {@link AlipayTradeWapPayModel}
|
||||
* @param returnUrl 异步通知URL
|
||||
* @param notifyUrl 同步通知URL
|
||||
* @return {String}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static String wapPayStr(AlipayTradeWapPayModel model, String returnUrl, String notifyUrl, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradeWapPayRequest aliPayRequest = new AlipayTradeWapPayRequest();
|
||||
aliPayRequest.setReturnUrl(returnUrl);
|
||||
aliPayRequest.setNotifyUrl(notifyUrl);
|
||||
aliPayRequest.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().pageExecute(aliPayRequest).getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一收单交易支付接口接口 <br>
|
||||
* 适用于:条形码支付、声波支付等 <br>
|
||||
*
|
||||
* @param model {@link AlipayTradePayModel}
|
||||
* @param notifyUrl 异步通知URL
|
||||
* @return {@link AlipayTradePayResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradePayResponse tradePayToResponse(AlipayTradePayModel model, String notifyUrl, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradePayRequest request = new AlipayTradePayRequest();
|
||||
// 填充业务参数
|
||||
request.setBizModel(model);
|
||||
request.setNotifyUrl(notifyUrl);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一收单交易支付接口接口 <br>
|
||||
* 适用于:条形码支付、声波支付等 <br>
|
||||
*
|
||||
* @param model {AlipayTradePayModel}
|
||||
* @param notifyUrl 异步通知URL
|
||||
* @param appAuthToken 应用授权token
|
||||
* @return {AlipayTradePayResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradePayResponse tradePayToResponse(AlipayTradePayModel model, String notifyUrl, String appAuthToken, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradePayRequest request = new AlipayTradePayRequest();
|
||||
request.setBizModel(model);
|
||||
request.setNotifyUrl(notifyUrl);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request, null, appAuthToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一收单线下交易预创建 <br>
|
||||
* 适用于:扫码支付等 <br>
|
||||
*
|
||||
* @param model {@link AlipayTradePrecreateModel}
|
||||
* @param notifyUrl 异步通知URL
|
||||
* @return {@link AlipayTradePrecreateResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradePrecreateResponse tradePrecreatePayToResponse(AlipayTradePrecreateModel model, String notifyUrl, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
|
||||
request.setBizModel(model);
|
||||
request.setNotifyUrl(notifyUrl);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一收单线下交易预创建 <br>
|
||||
* 适用于:扫码支付等 <br>
|
||||
*
|
||||
* @param model {@link AlipayTradePrecreateModel}
|
||||
* @param notifyUrl 异步通知URL
|
||||
* @param appAuthToken 应用授权token
|
||||
* @return {@link AlipayTradePrecreateResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradePrecreateResponse tradePrecreatePayToResponse(AlipayTradePrecreateModel model,
|
||||
String notifyUrl, String appAuthToken, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
|
||||
request.setBizModel(model);
|
||||
request.setNotifyUrl(notifyUrl);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request, null, appAuthToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 单笔转账到支付宝账户
|
||||
*
|
||||
* @param model {@link AlipayFundTransToaccountTransferModel}
|
||||
* @return 转账是否成功
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static boolean transfer(AlipayFundTransToaccountTransferModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayFundTransToaccountTransferResponse response = transferToResponse(model, aliPayApiConfig);
|
||||
String result = response.getBody();
|
||||
if (response.isSuccess()) {
|
||||
return true;
|
||||
} else {
|
||||
// 调用查询接口查询数据
|
||||
JSONObject jsonObject = JSONObject.parseObject(result);
|
||||
String outBizNo = jsonObject.getJSONObject("alipay_fund_trans_toaccount_transfer_response").getString("out_biz_no");
|
||||
AlipayFundTransOrderQueryModel queryModel = new AlipayFundTransOrderQueryModel();
|
||||
model.setOutBizNo(outBizNo);
|
||||
return transferQuery(queryModel, aliPayApiConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 单笔转账到支付宝账户
|
||||
*
|
||||
* @param model {@link AlipayFundTransToaccountTransferModel}
|
||||
* @return {@link AlipayFundTransToaccountTransferResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayFundTransToaccountTransferResponse transferToResponse(AlipayFundTransToaccountTransferModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayFundTransToaccountTransferRequest request = new AlipayFundTransToaccountTransferRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转账查询接口
|
||||
*
|
||||
* @param model {@link AlipayFundTransOrderQueryModel}
|
||||
* @return 是否存在此
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static boolean transferQuery(AlipayFundTransOrderQueryModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayFundTransOrderQueryResponse response = transferQueryToResponse(model, aliPayApiConfig);
|
||||
return response.isSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转账查询接口
|
||||
*
|
||||
* @param model {@link AlipayFundTransOrderQueryModel}
|
||||
* @return {@link AlipayFundTransOrderQueryResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayFundTransOrderQueryResponse transferQueryToResponse(AlipayFundTransOrderQueryModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayFundTransOrderQueryRequest request = new AlipayFundTransOrderQueryRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一收单线下交易查询接口
|
||||
*
|
||||
* @param model {@link AlipayTradeQueryModel}
|
||||
* @return {@link AlipayTradeQueryResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradeQueryResponse tradeQueryToResponse(AlipayTradeQueryModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一收单线下交易查询接口
|
||||
*
|
||||
* @param model {@link AlipayTradeQueryModel}
|
||||
* @param appAuthToken 应用授权token
|
||||
* @return {@link AlipayTradeQueryResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradeQueryResponse tradeQueryToResponse(AlipayTradeQueryModel model, String appAuthToken, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request, null, appAuthToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一收单交易撤销接口
|
||||
*
|
||||
* @param model {@link AlipayTradeCancelModel}
|
||||
* @param appAuthToken 应用授权token
|
||||
* @return {@link AlipayTradeCancelResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradeCancelResponse tradeCancelToResponse(AlipayTradeCancelModel model, String appAuthToken, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradeCancelRequest request = new AlipayTradeCancelRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request, null, appAuthToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一收单交易撤销接口
|
||||
*
|
||||
* @param model {@link AlipayTradeCancelModel}
|
||||
* @return {@link AlipayTradeCancelResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradeCancelResponse tradeCancelToResponse(AlipayTradeCancelModel model, AliPayApiConfig aliPayApiConfig)
|
||||
throws AlipayApiException {
|
||||
AlipayTradeCancelRequest request = new AlipayTradeCancelRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一收单交易关闭接口
|
||||
*
|
||||
* @param model {@link AlipayTradeCloseModel}
|
||||
* @param appAuthToken 应用授权token
|
||||
* @return {@link AlipayTradeCloseResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradeCloseResponse tradeCloseToResponse(AlipayTradeCloseModel model, String appAuthToken, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request, null, appAuthToken);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一收单交易关闭接口
|
||||
*
|
||||
* @param model {@link AlipayTradeCloseModel}
|
||||
* @return {@link AlipayTradeCloseResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradeCloseResponse tradeCloseToResponse(AlipayTradeCloseModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一收单交易创建接口
|
||||
*
|
||||
* @param model {@link AlipayTradeCreateModel}
|
||||
* @param notifyUrl 异步通知URL
|
||||
* @return {@link AlipayTradeCreateResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradeCreateResponse tradeCreateToResponse(AlipayTradeCreateModel model, String notifyUrl, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
|
||||
request.setBizModel(model);
|
||||
request.setNotifyUrl(notifyUrl);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一收单交易创建接口
|
||||
*
|
||||
* @param model {@link AlipayTradeCreateModel}
|
||||
* @param notifyUrl 异步通知URL
|
||||
* @param appAuthToken 应用授权token
|
||||
* @return {@link AlipayTradeCreateResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradeCreateResponse tradeCreateToResponse(AlipayTradeCreateModel model, String notifyUrl, String appAuthToken, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
|
||||
request.setBizModel(model);
|
||||
request.setNotifyUrl(notifyUrl);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request, null, appAuthToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一收单交易退款接口
|
||||
*
|
||||
* @param model {@link AlipayTradeRefundModel}
|
||||
* @return {@link AlipayTradeRefundResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradeRefundResponse tradeRefundToResponse(AlipayTradeRefundModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一收单交易退款接口
|
||||
*
|
||||
* @param model {@link AlipayTradeRefundModel}
|
||||
* @param appAuthToken 应用授权token
|
||||
* @return {@link AlipayTradeRefundResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradeRefundResponse tradeRefundToResponse(AlipayTradeRefundModel model, String appAuthToken, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request, null, appAuthToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一收单交易退款查询
|
||||
*
|
||||
* @param model {@link AlipayTradeFastpayRefundQueryModel}
|
||||
* @return {@link AlipayTradeFastpayRefundQueryResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradeFastpayRefundQueryResponse tradeRefundQueryToResponse(AlipayTradeFastpayRefundQueryModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一收单交易退款查询
|
||||
*
|
||||
* @param model {@link AlipayTradeFastpayRefundQueryModel}
|
||||
* @param appAuthToken 应用授权token
|
||||
* @return {@link AlipayTradeFastpayRefundQueryResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradeFastpayRefundQueryResponse tradeRefundQueryToResponse(AlipayTradeFastpayRefundQueryModel model, String appAuthToken, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request, null, appAuthToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询对账单下载地址
|
||||
*
|
||||
* @param model {@link AlipayDataDataserviceBillDownloadurlQueryModel}
|
||||
* @return 对账单下载地址
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static String billDownloadurlQuery(AlipayDataDataserviceBillDownloadurlQueryModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayDataDataserviceBillDownloadurlQueryResponse response = billDownloadUrlQueryToResponse(model, aliPayApiConfig);
|
||||
return response.getBillDownloadUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询对账单下载地址
|
||||
*
|
||||
* @param model {@link AlipayDataDataserviceBillDownloadurlQueryModel}
|
||||
* @return {@link AlipayDataDataserviceBillDownloadurlQueryResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayDataDataserviceBillDownloadurlQueryResponse billDownloadUrlQueryToResponse(AlipayDataDataserviceBillDownloadurlQueryModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayDataDataserviceBillDownloadurlQueryRequest request = new AlipayDataDataserviceBillDownloadurlQueryRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一收单交易结算接口
|
||||
*
|
||||
* @param model {@link AlipayTradeOrderSettleModel}
|
||||
* @param appAuthToken 应用授权token
|
||||
* @return {@link AlipayTradeOrderSettleResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradeOrderSettleResponse tradeOrderSettleToResponse(AlipayTradeOrderSettleModel model, String appAuthToken, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradeOrderSettleRequest request = new AlipayTradeOrderSettleRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request, null, appAuthToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一收单交易结算接口
|
||||
*
|
||||
* @param model {@link AlipayTradeOrderSettleModel}
|
||||
* @return {@link AlipayTradeOrderSettleResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayTradeOrderSettleResponse tradeOrderSettleToResponse(AlipayTradeOrderSettleModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayTradeOrderSettleRequest request = new AlipayTradeOrderSettleRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 电脑网站支付(PC支付)
|
||||
*
|
||||
* @param response {@link HttpServletResponse}
|
||||
* @param model {@link AlipayTradePagePayModel}
|
||||
* @param notifyUrl 异步通知URL
|
||||
* @param returnUrl 同步通知URL
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
* @throws IOException IO 异常
|
||||
*/
|
||||
public static void tradePage(HttpServletResponse response, AlipayTradePagePayModel model, String notifyUrl, String returnUrl, AliPayApiConfig aliPayApiConfig) throws AlipayApiException, IOException {
|
||||
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
|
||||
request.setBizModel(model);
|
||||
request.setNotifyUrl(notifyUrl);
|
||||
request.setReturnUrl(returnUrl);
|
||||
String form = aliPayApiConfig.getAliPayClient().pageExecute(request).getBody();// 调用SDK生成表单
|
||||
log.info(returnUrl);
|
||||
log.info(form);
|
||||
response.setContentType("text/html;charset=" + aliPayApiConfig.getCharset());
|
||||
PrintWriter out = response.getWriter();
|
||||
out.write(form);
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 电脑网站支付(PC支付)
|
||||
*
|
||||
* @param response {@link HttpServletResponse}
|
||||
* @param model {@link AlipayTradePagePayModel}
|
||||
* @param notifyUrl 异步通知URL
|
||||
* @param returnUrl 同步通知URL
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
* @throws IOException IO 异常
|
||||
*/
|
||||
public static void tradePageByOutputStream(HttpServletResponse response, AlipayTradePagePayModel model, String notifyUrl, String returnUrl, AliPayApiConfig aliPayApiConfig) throws AlipayApiException, IOException {
|
||||
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
|
||||
request.setBizModel(model);
|
||||
request.setNotifyUrl(notifyUrl);
|
||||
request.setReturnUrl(returnUrl);
|
||||
String form = aliPayApiConfig.getAliPayClient().pageExecute(request).getBody();// 调用SDK生成表单
|
||||
response.setContentType("text/html;charset=" + aliPayApiConfig.getCharset());
|
||||
OutputStream out = response.getOutputStream();
|
||||
out.write(form.getBytes(aliPayApiConfig.getCharset()));
|
||||
response.getOutputStream().flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* 资金预授权冻结接口
|
||||
*
|
||||
* @param model {@link AlipayFundAuthOrderFreezeModel}
|
||||
* @return {@link AlipayFundAuthOrderFreezeResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayFundAuthOrderFreezeResponse authOrderFreezeToResponse(AlipayFundAuthOrderFreezeModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayFundAuthOrderFreezeRequest request = new AlipayFundAuthOrderFreezeRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 资金授权解冻接口
|
||||
*
|
||||
* @param model {@link AlipayFundAuthOrderUnfreezeModel}
|
||||
* @return {@link AlipayFundAuthOrderUnfreezeResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayFundAuthOrderUnfreezeResponse authOrderUnfreezeToResponse(AlipayFundAuthOrderUnfreezeModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayFundAuthOrderUnfreezeRequest request = new AlipayFundAuthOrderUnfreezeRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 资金预授权冻结接口
|
||||
*
|
||||
* @param model {@link AlipayFundAuthOrderVoucherCreateModel}
|
||||
* @return {@link AlipayFundAuthOrderVoucherCreateResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayFundAuthOrderVoucherCreateResponse authOrderVoucherCreateToResponse(AlipayFundAuthOrderVoucherCreateModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayFundAuthOrderVoucherCreateRequest request = new AlipayFundAuthOrderVoucherCreateRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 资金授权撤销接口
|
||||
*
|
||||
* @param model {@link AlipayFundAuthOperationCancelModel}
|
||||
* @return {@link AlipayFundAuthOperationCancelResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayFundAuthOperationCancelResponse authOperationCancelToResponse(AlipayFundAuthOperationCancelModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayFundAuthOperationCancelRequest request = new AlipayFundAuthOperationCancelRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 资金授权操作查询接口
|
||||
*
|
||||
* @param model {@link AlipayFundAuthOperationDetailQueryModel}
|
||||
* @return {@link AlipayFundAuthOperationDetailQueryResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayFundAuthOperationDetailQueryResponse authOperationDetailQueryToResponse(AlipayFundAuthOperationDetailQueryModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayFundAuthOperationDetailQueryRequest request = new AlipayFundAuthOperationDetailQueryRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 红包无线支付接口
|
||||
*
|
||||
* @param model {@link AlipayFundCouponOrderAppPayModel}
|
||||
* @return {@link AlipayFundCouponOrderAppPayResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayFundCouponOrderAppPayResponse fundCouponOrderAppPayToResponse(AlipayFundCouponOrderAppPayModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayFundCouponOrderAppPayRequest request = new AlipayFundCouponOrderAppPayRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 红包页面支付接口
|
||||
*
|
||||
* @param model {@link AlipayFundCouponOrderPagePayModel}
|
||||
* @return {@link AlipayFundCouponOrderPagePayResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayFundCouponOrderPagePayResponse fundCouponOrderPagePayToResponse(AlipayFundCouponOrderPagePayModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayFundCouponOrderPagePayRequest request = new AlipayFundCouponOrderPagePayRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 红包协议支付接口
|
||||
*
|
||||
* @param model {@link AlipayFundCouponOrderAgreementPayModel}
|
||||
* @return {@link AlipayFundCouponOrderAgreementPayResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayFundCouponOrderAgreementPayResponse fundCouponOrderAgreementPayToResponse(AlipayFundCouponOrderAgreementPayModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayFundCouponOrderAgreementPayRequest request = new AlipayFundCouponOrderAgreementPayRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 红包打款接口
|
||||
*
|
||||
* @param model {@link AlipayFundCouponOrderDisburseModel}
|
||||
* @return {@link AlipayFundCouponOrderDisburseResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayFundCouponOrderDisburseResponse fundCouponOrderDisburseToResponse(AlipayFundCouponOrderDisburseModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayFundCouponOrderDisburseRequest request = new AlipayFundCouponOrderDisburseRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 红包退回接口
|
||||
*
|
||||
* @param model {@link AlipayFundCouponOrderRefundModel}
|
||||
* @return {@link AlipayFundCouponOrderRefundResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayFundCouponOrderRefundResponse fundCouponOrderRefundToResponse(AlipayFundCouponOrderRefundModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayFundCouponOrderRefundRequest request = new AlipayFundCouponOrderRefundRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 红包退回接口
|
||||
*
|
||||
* @param model {@link AlipayFundCouponOperationQueryModel}
|
||||
* @return {@link AlipayFundCouponOperationQueryResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayFundCouponOperationQueryResponse fundCouponOperationQueryToResponse(AlipayFundCouponOperationQueryModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayFundCouponOperationQueryRequest request = new AlipayFundCouponOperationQueryRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用授权 URL 拼装
|
||||
*
|
||||
* @param appId 应用编号
|
||||
* @param redirectUri 回调 URI
|
||||
* @return 应用授权 URL
|
||||
* @throws UnsupportedEncodingException 编码异常
|
||||
*/
|
||||
public static String getOauth2Url(String appId, String redirectUri) throws UnsupportedEncodingException {
|
||||
return new StringBuffer().append("https://openauth.alipay.com/oauth2/appToAppAuth.htm?app_id=").append(appId).append("&redirect_uri=").append(URLEncoder.encode(redirectUri, "UTF-8")).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 app_auth_code 换取 app_auth_token
|
||||
*
|
||||
* @param model {@link AlipayOpenAuthTokenAppModel}
|
||||
* @return {@link AlipayOpenAuthTokenAppResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayOpenAuthTokenAppResponse openAuthTokenAppToResponse(AlipayOpenAuthTokenAppModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayOpenAuthTokenAppRequest request = new AlipayOpenAuthTokenAppRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询授权信息
|
||||
*
|
||||
* @param model {@link AlipayOpenAuthTokenAppQueryModel}
|
||||
* @return {@link AlipayOpenAuthTokenAppQueryResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayOpenAuthTokenAppQueryResponse openAuthTokenAppQueryToResponse(AlipayOpenAuthTokenAppQueryModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayOpenAuthTokenAppQueryRequest request = new AlipayOpenAuthTokenAppQueryRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 地铁购票发码
|
||||
*
|
||||
* @param model {@link AlipayCommerceCityfacilitatorVoucherGenerateModel}
|
||||
* @return {@link AlipayCommerceCityfacilitatorVoucherGenerateResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayCommerceCityfacilitatorVoucherGenerateResponse voucherGenerateToResponse(AlipayCommerceCityfacilitatorVoucherGenerateModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayCommerceCityfacilitatorVoucherGenerateRequest request = new AlipayCommerceCityfacilitatorVoucherGenerateRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 地铁购票发码退款
|
||||
*
|
||||
* @param model {@link AlipayCommerceCityfacilitatorVoucherRefundModel}
|
||||
* @return {@link AlipayCommerceCityfacilitatorVoucherRefundResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayCommerceCityfacilitatorVoucherRefundResponse metroRefundToResponse(AlipayCommerceCityfacilitatorVoucherRefundModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayCommerceCityfacilitatorVoucherRefundRequest request = new AlipayCommerceCityfacilitatorVoucherRefundRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 地铁车站数据查询
|
||||
*
|
||||
* @param model {@link AlipayCommerceCityfacilitatorStationQueryModel}
|
||||
* @return {@link AlipayCommerceCityfacilitatorStationQueryResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayCommerceCityfacilitatorStationQueryResponse stationQueryToResponse(AlipayCommerceCityfacilitatorStationQueryModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayCommerceCityfacilitatorStationQueryRequest request = new AlipayCommerceCityfacilitatorStationQueryRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 核销码批量查询
|
||||
*
|
||||
* @param model {@link AlipayCommerceCityfacilitatorVoucherBatchqueryModel}
|
||||
* @return {@link AlipayCommerceCityfacilitatorVoucherBatchqueryResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayCommerceCityfacilitatorVoucherBatchqueryResponse voucherBatchqueryToResponse(AlipayCommerceCityfacilitatorVoucherBatchqueryModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayCommerceCityfacilitatorVoucherBatchqueryRequest request = new AlipayCommerceCityfacilitatorVoucherBatchqueryRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
public static void batchTrans(Map<String, String> params, String privateKey, String signType, HttpServletResponse response) throws IOException {
|
||||
params.put("service", "batch_trans_notify");
|
||||
params.put("_input_charset", "UTF-8");
|
||||
params.put("pay_date", DateUtil.format(new Date(), "YYYYMMDD"));
|
||||
Map<String, String> param = AliPayCore.buildRequestPara(params, privateKey, signType);
|
||||
response.sendRedirect(GATEWAY_NEW.concat(AliPayCore.createLinkString(param)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将异步通知的参数转化为Map
|
||||
*
|
||||
* @param request {HttpServletRequest}
|
||||
* @return 转化后的Map
|
||||
*/
|
||||
public static Map<String, String> toMap(HttpServletRequest request) {
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
Map<String, String[]> requestParams = request.getParameterMap();
|
||||
for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
|
||||
String name = iter.next();
|
||||
String[] values = requestParams.get(name);
|
||||
String valueStr = "";
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
|
||||
}
|
||||
// 乱码解决,这段代码在出现乱码时使用
|
||||
// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
|
||||
params.put(name, valueStr);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生活缴费查询账单
|
||||
*
|
||||
* @param orderType 支付宝订单类型
|
||||
* @param merchantOrderNo 业务流水号
|
||||
* @return {@link AlipayEbppBillGetResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static AlipayEbppBillGetResponse ebppBillGet(String orderType, String merchantOrderNo, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
AlipayEbppBillGetRequest request = new AlipayEbppBillGetRequest();
|
||||
request.setOrderType(orderType);
|
||||
request.setMerchantOrderNo(merchantOrderNo);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* H5刷脸认证初始化
|
||||
*
|
||||
* @param model {@link ZolozIdentificationUserWebInitializeModel}
|
||||
* @return {@link ZolozIdentificationUserWebInitializeResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static ZolozIdentificationUserWebInitializeResponse identificationUserWebInitialize(ZolozIdentificationUserWebInitializeModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
ZolozIdentificationUserWebInitializeRequest request = new ZolozIdentificationUserWebInitializeRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* H5刷脸认证查询
|
||||
*
|
||||
* @param model {@link ZolozIdentificationUserWebQueryModel}
|
||||
* @return {@link ZolozIdentificationUserWebQueryResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static ZolozIdentificationUserWebQueryResponse identificationUserWebInitialize(ZolozIdentificationUserWebQueryModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
ZolozIdentificationUserWebQueryRequest request = new ZolozIdentificationUserWebQueryRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 热脸入库
|
||||
*
|
||||
* @param model {@link ZolozAuthenticationCustomerFacemanageCreateModel}
|
||||
* @return {@link ZolozAuthenticationCustomerFacemanageCreateResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static ZolozAuthenticationCustomerFacemanageCreateResponse authenticationCustomerFaceManageCreate(ZolozAuthenticationCustomerFacemanageCreateModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
ZolozAuthenticationCustomerFacemanageCreateRequest request = new ZolozAuthenticationCustomerFacemanageCreateRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 热脸出库
|
||||
*
|
||||
* @param model {@link ZolozAuthenticationCustomerFacemanageDeleteModel}
|
||||
* @return {@link ZolozAuthenticationCustomerFacemanageDeleteResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static ZolozAuthenticationCustomerFacemanageDeleteResponse authenticationCustomerFaceManageDelete(ZolozAuthenticationCustomerFacemanageDeleteModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
ZolozAuthenticationCustomerFacemanageDeleteRequest request = new ZolozAuthenticationCustomerFacemanageDeleteRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 人脸 ftoken 查询消费接口
|
||||
*
|
||||
* @param model {@link ZolozAuthenticationCustomerFtokenQueryModel}
|
||||
* @return {@link ZolozAuthenticationCustomerFtokenQueryResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static ZolozAuthenticationCustomerFtokenQueryResponse authenticationCustomerFTokenQuery(ZolozAuthenticationCustomerFtokenQueryModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
ZolozAuthenticationCustomerFtokenQueryRequest request = new ZolozAuthenticationCustomerFtokenQueryRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 人脸初始化刷脸付
|
||||
*
|
||||
* @param model {@link ZolozAuthenticationSmilepayInitializeModel}
|
||||
* @return {@link ZolozAuthenticationSmilepayInitializeResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static ZolozAuthenticationSmilepayInitializeResponse authenticationSmilePayInitialize(ZolozAuthenticationSmilepayInitializeModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
ZolozAuthenticationSmilepayInitializeRequest request = new ZolozAuthenticationSmilepayInitializeRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 人脸初始化唤起zim
|
||||
*
|
||||
* @param model {@link ZolozAuthenticationCustomerSmilepayInitializeModel}
|
||||
* @return {@link ZolozAuthenticationCustomerSmilepayInitializeResponse}
|
||||
* @throws AlipayApiException 支付宝 Api 异常
|
||||
*/
|
||||
public static ZolozAuthenticationCustomerSmilepayInitializeResponse authenticationCustomerSmilePayInitialize(ZolozAuthenticationCustomerSmilepayInitializeModel model, AliPayApiConfig aliPayApiConfig) throws AlipayApiException {
|
||||
ZolozAuthenticationCustomerSmilepayInitializeRequest request = new ZolozAuthenticationCustomerSmilepayInitializeRequest();
|
||||
request.setBizModel(model);
|
||||
return aliPayApiConfig.getAliPayClient().execute(request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
package com.zscat.mallplus.alipay;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.alipay.api.AlipayClient;
|
||||
import com.alipay.api.CertAlipayRequest;
|
||||
import com.alipay.api.DefaultAlipayClient;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>支付宝支付配置</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public class AliPayApiConfig implements Serializable {
|
||||
private static final long serialVersionUID = -4736760736935998953L;
|
||||
|
||||
private String privateKey;
|
||||
private String aliPayPublicKey;
|
||||
private String appId;
|
||||
private String serviceUrl;
|
||||
private String charset;
|
||||
private String signType;
|
||||
private String format;
|
||||
private String appCertPath;
|
||||
private String aliPayCertPath;
|
||||
private String aliPayRootCertPath;
|
||||
private AlipayClient alipayClient;
|
||||
|
||||
private AliPayApiConfig() {
|
||||
}
|
||||
|
||||
public static AliPayApiConfig builder() {
|
||||
return new AliPayApiConfig();
|
||||
}
|
||||
|
||||
public AliPayApiConfig build() {
|
||||
this.alipayClient = new DefaultAlipayClient(getServiceUrl(), getAppId(), getPrivateKey(), getFormat(),
|
||||
getCharset(), getAliPayPublicKey(), getSignType());
|
||||
return this;
|
||||
}
|
||||
|
||||
public AliPayApiConfig buildByCert() throws AlipayApiException {
|
||||
return build(getAppCertPath(), getAliPayCertPath(), getAliPayRootCertPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param appCertPath 应用公钥证书路径
|
||||
* @param aliPayCertPath 支付宝公钥证书文件路径
|
||||
* @param aliPayRootCertPath 支付宝CA根证书文件路径
|
||||
* @return {@link AliPayApiConfig} 支付宝支付配置
|
||||
* @throws AlipayApiException
|
||||
*/
|
||||
public AliPayApiConfig build(String appCertPath, String aliPayCertPath, String aliPayRootCertPath) throws AlipayApiException {
|
||||
CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
|
||||
certAlipayRequest.setServerUrl(getServiceUrl());
|
||||
certAlipayRequest.setAppId(getAppId());
|
||||
certAlipayRequest.setPrivateKey(getPrivateKey());
|
||||
certAlipayRequest.setFormat(getFormat());
|
||||
certAlipayRequest.setCharset(getCharset());
|
||||
certAlipayRequest.setSignType(getSignType());
|
||||
certAlipayRequest.setCertPath(appCertPath);
|
||||
certAlipayRequest.setAlipayPublicCertPath(aliPayCertPath);
|
||||
certAlipayRequest.setRootCertPath(aliPayRootCertPath);
|
||||
this.alipayClient = new DefaultAlipayClient(certAlipayRequest);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPrivateKey() {
|
||||
if (StrUtil.isBlank(privateKey)) {
|
||||
throw new IllegalStateException("privateKey 未被赋值");
|
||||
}
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
public AliPayApiConfig setPrivateKey(String privateKey) {
|
||||
if (StrUtil.isEmpty(privateKey)) {
|
||||
throw new IllegalArgumentException("privateKey 值不能为 null");
|
||||
}
|
||||
this.privateKey = privateKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getAliPayPublicKey() {
|
||||
if (StrUtil.isEmpty(aliPayPublicKey)) {
|
||||
throw new IllegalStateException("aliPayPublicKey 未被赋值");
|
||||
}
|
||||
return aliPayPublicKey;
|
||||
}
|
||||
|
||||
public AliPayApiConfig setAliPayPublicKey(String aliPayPublicKey) {
|
||||
if (StrUtil.isEmpty(aliPayPublicKey)) {
|
||||
throw new IllegalArgumentException("aliPayPublicKey 值不能为 null");
|
||||
}
|
||||
this.aliPayPublicKey = aliPayPublicKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getAppId() {
|
||||
if (StrUtil.isEmpty(appId)) {
|
||||
throw new IllegalStateException("appId 未被赋值");
|
||||
}
|
||||
return appId;
|
||||
}
|
||||
|
||||
public AliPayApiConfig setAppId(String appId) {
|
||||
if (StrUtil.isEmpty(appId)) {
|
||||
throw new IllegalArgumentException("appId 值不能为 null");
|
||||
}
|
||||
this.appId = appId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getServiceUrl() {
|
||||
if (StrUtil.isEmpty(serviceUrl)) {
|
||||
throw new IllegalStateException("serviceUrl 未被赋值");
|
||||
}
|
||||
return serviceUrl;
|
||||
}
|
||||
|
||||
public AliPayApiConfig setServiceUrl(String serviceUrl) {
|
||||
if (StrUtil.isEmpty(serviceUrl)) {
|
||||
serviceUrl = "https://openapi.alipay.com/gateway.do";
|
||||
}
|
||||
this.serviceUrl = serviceUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getCharset() {
|
||||
if (StrUtil.isEmpty(charset)) {
|
||||
charset = "UTF-8";
|
||||
}
|
||||
return charset;
|
||||
}
|
||||
|
||||
public AliPayApiConfig setCharset(String charset) {
|
||||
if (StrUtil.isEmpty(charset)) {
|
||||
charset = "UTF-8";
|
||||
}
|
||||
this.charset = charset;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getSignType() {
|
||||
if (StrUtil.isEmpty(signType)) {
|
||||
signType = "RSA2";
|
||||
}
|
||||
return signType;
|
||||
}
|
||||
|
||||
public AliPayApiConfig setSignType(String signType) {
|
||||
if (StrUtil.isEmpty(signType)) {
|
||||
signType = "RSA2";
|
||||
}
|
||||
this.signType = signType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getFormat() {
|
||||
if (StrUtil.isEmpty(format)) {
|
||||
format = "json";
|
||||
}
|
||||
return format;
|
||||
}
|
||||
|
||||
public String getAppCertPath() {
|
||||
return appCertPath;
|
||||
}
|
||||
|
||||
public AliPayApiConfig setAppCertPath(String appCertPath) {
|
||||
this.appCertPath = appCertPath;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getAliPayCertPath() {
|
||||
return aliPayCertPath;
|
||||
}
|
||||
|
||||
public AliPayApiConfig setAliPayCertPath(String aliPayCertPath) {
|
||||
this.aliPayCertPath = aliPayCertPath;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getAliPayRootCertPath() {
|
||||
return aliPayRootCertPath;
|
||||
}
|
||||
|
||||
public AliPayApiConfig setAliPayRootCertPath(String aliPayRootCertPath) {
|
||||
this.aliPayRootCertPath = aliPayRootCertPath;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AlipayClient getAliPayClient() {
|
||||
if (alipayClient == null) {
|
||||
throw new IllegalStateException("aliPayClient 未被初始化");
|
||||
}
|
||||
return alipayClient;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package com.zscat.mallplus.alipay;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public class AliPayApiConfigKit {
|
||||
private static final ThreadLocal<String> TL = new ThreadLocal<String>();
|
||||
|
||||
private static final Map<String, AliPayApiConfig> CFG_MAP = new ConcurrentHashMap<String, AliPayApiConfig>();
|
||||
private static final String DEFAULT_CFG_KEY = "_default_key_";
|
||||
|
||||
/**
|
||||
* <p>向缓存中设置 AliPayApiConfig </p>
|
||||
* <p>每个 appId 只需添加一次,相同 appId 将被覆盖</p>
|
||||
*
|
||||
* @param aliPayApiConfig 支付宝支付配置
|
||||
* @return {@link AliPayApiConfig}
|
||||
*/
|
||||
public static AliPayApiConfig putApiConfig(AliPayApiConfig aliPayApiConfig) {
|
||||
if (CFG_MAP.size() == 0) {
|
||||
CFG_MAP.put(DEFAULT_CFG_KEY, aliPayApiConfig);
|
||||
}
|
||||
return CFG_MAP.put(aliPayApiConfig.getAppId(), aliPayApiConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 向当前线程中设置 {@link AliPayApiConfig}
|
||||
*
|
||||
* @param aliPayApiConfig {@link AliPayApiConfig} 支付宝配置对象
|
||||
* @return {@link AliPayApiConfig}
|
||||
*/
|
||||
public static AliPayApiConfig setThreadLocalAliPayApiConfig(AliPayApiConfig aliPayApiConfig) {
|
||||
if (StrUtil.isNotEmpty(aliPayApiConfig.getAppId())) {
|
||||
setThreadLocalAppId(aliPayApiConfig.getAppId());
|
||||
}
|
||||
return putApiConfig(aliPayApiConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过 AliPayApiConfig 移除支付配置
|
||||
*
|
||||
* @param aliPayApiConfig {@link AliPayApiConfig} 支付宝配置对象
|
||||
* @return {@link AliPayApiConfig}
|
||||
*/
|
||||
public static AliPayApiConfig removeApiConfig(AliPayApiConfig aliPayApiConfig) {
|
||||
return removeApiConfig(aliPayApiConfig.getAppId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过 appId 移除支付配置
|
||||
*
|
||||
* @param appId 支付宝应用编号
|
||||
* @return {@link AliPayApiConfig}
|
||||
*/
|
||||
public static AliPayApiConfig removeApiConfig(String appId) {
|
||||
return CFG_MAP.remove(appId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 向当前线程中设置 appId
|
||||
*
|
||||
* @param appId 支付宝应用编号
|
||||
*/
|
||||
public static void setThreadLocalAppId(String appId) {
|
||||
if (StrUtil.isEmpty(appId)) {
|
||||
appId = CFG_MAP.get(DEFAULT_CFG_KEY).getAppId();
|
||||
}
|
||||
TL.set(appId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除当前线程中的 appId
|
||||
*/
|
||||
public static void removeThreadLocalAppId() {
|
||||
TL.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前线程中的 appId
|
||||
*
|
||||
* @return 支付宝应用编号 appId
|
||||
*/
|
||||
public static String getAppId() {
|
||||
String appId = TL.get();
|
||||
if (StrUtil.isEmpty(appId)) {
|
||||
appId = CFG_MAP.get(DEFAULT_CFG_KEY).getAppId();
|
||||
}
|
||||
return appId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前线程中的 AliPayApiConfig
|
||||
*
|
||||
* @return {@link AliPayApiConfig}
|
||||
*/
|
||||
public static AliPayApiConfig getAliPayApiConfig() {
|
||||
// AliPayApiConfig aliPayApiConfig = null;
|
||||
AliPayBean aliPayBean = new AliPayBean();
|
||||
aliPayBean.setAppId("2018082761134635");
|
||||
aliPayBean.setDomain("http://192.168.43.195:8083/api");
|
||||
aliPayBean.setServerUrl("https://openapi.alipay.com/gateway.do");
|
||||
aliPayBean.setPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlOOOOWg4e2deSDMRG2y5EzG7/udMfTzYkn4u/3PWIOlpcUd2ujCztqKY2HdFhIaWE4q8PCLtT5XtBWCq2IVvpCPE8HRzgSZckh6J36SnO0JG1pZe8HajUgIw+T1NM7/b2Nb4OaI5HKNsQ5ei9NlN9RvlIUSpum/nIyk/9CBvNAg8xUlHUFPaPL0WCMJ9zIwRO+aEn2kwA7JQ8AvjuPy390oil0W4fxfHonJYxuzOo6Lx369Vti5N9UmXczXUcOiVwyCveoH05chNr3r8xu5QqpD1o32cO01Zt4EA9j6aM2H09g08VzoLam2OoU3umKOV0vvX+bMmb1GwrkussSvDpQIDAQAB");
|
||||
aliPayBean.setPrivateKey("MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCjI8p9Vh3QrBsa2BdTLAa9YrPGdHAo4DeYx79rlrITI4kIwy6/q/JDaXNBQgl80mUYh4Zinc0mDZ68n14zIL0f4At+EzzfxT5RIVYKZb/EEj6ijElldvijblcCAkrcoTl+oWDEKEOyyJW2UFbRIUYUZcszfi+pue1BIdvwlfxHTI77o1H6d2ApkyIHgs6zYeeauDkYYTdAjSCV7PHhTO6H6yS5uyc0rOLxUTdABA+b+ewSnTw2uvuVTTnrC7xIqjfj1fRocsNh/1KfqF4I5iMQmrRaIlujRSTQrO7kLVbYW45D+Qr4mB3TlhTGAFcTL+ovugA+66NASZmUyNsZHcBZAgMBAAECggEAao+eXHA72WoR6l7sHW/Mlzg5pY+5E3oh1rHi3yv39XhoskiL6Lcv78iZeC7ic54aWwNrTE83CXwsC5kttsfTwVZfK2L1iFUWd3gG85OyxygDsblg1932Wwpf2vgUXjkRjR1sT7TdQ5Kx9/xSORg65mf3axMpnvvLdZfgSi4uM4NJ94NzCLwH7zSWuK6CsPfl24RQlQfczRUy4GzG+wtXjDj5XLNNO6GQacQY4BUkcjCfrkUrQ9Lf2joYiXRyVNWUN1HivmfMouG37WQhUzz0CL8tF1EfooCfPhetAF5Aursve3O8l0Lno6K1auziN8g/Jfuo+efKfImzwvyo3m1n4QKBgQDjtfOWqcVP611OSTm1L1RFHCJMZN5wgOLEquO/2VC4VItV7vy0odNrLydd9Eg77VbC0IVcqunQIHjON3fFEVlj0bEVOaEN+X26oP84UNBK12QcLWvxxXQvOyaXg0hqgae5dpG5LvZHIP6b27jF3IuTG3lILZDjZsO9NcZbBr+NGwKBgQC3aD5VAUjCn+xnHIzGd0/avFYIGzqGUw2hZfFfuI3r58gRo/bjlOny7jLTxOFa+2SGggdDVm/izWut2FacNr3/GVTkcZc6ZEIXWq793vFky69PwGj24bCbplLYaCWM79HczM9sIWBl5WKmI7k1O/AIJrPteTa/Du/T+IfcATQDmwKBgQCCNjXI3eP6w3hjn/Pj6+CgdGoYjUW1x73lAGOj/Tzva0kSJstS74baL+ivDVWRDzMhy+O3DfUOEsOCCK3wfu9C6VH99Spnt1dyNUY8idnSMkEI6+BiLKs3pvd2hJgQb3vdzjOeVYB3RCLUNVz/qBIYWQmNgKDtqIId3HZE7yLyKQKBgQCq4Blq00Z55cu4CZZy9ghVL7Er3kp5iXmijLsExoqbZpg1L0E/qacJ6bk7KiwXuy5eT1j6+NZHRcHz9yJCapI70NsR927BPVWCMr/k0Uiv80FDmW1xzrXfXmfDLc0GcQ1inQMHqFUKultdlNziZxRsU7rBHnTOLtls8RmK9SgDzwKBgBnWfQNVF/BSIP/pOkudu966DwqySamzy/HrdOIq92r+OtAWqtLMq8bbIkMW1asC8+MLE81JD9fn7YmKeZTbMwxE2z5Tv1z+UUqy//79Vkj8FmlSfY0kraj9ZXjMp+Hg0kCpavOU4QFXONn2LVvrrh0tACcgJoJGRJJYuJMQeu7c");
|
||||
AliPayApiConfig aliPayApiConfig = AliPayApiConfig.builder()
|
||||
.setAppId(aliPayBean.getAppId())
|
||||
.setAliPayPublicKey(aliPayBean.getPublicKey())
|
||||
.setCharset("UTF-8")
|
||||
.setPrivateKey(aliPayBean.getPrivateKey())
|
||||
.setServiceUrl(aliPayBean.getServerUrl())
|
||||
.setSignType("RSA2")
|
||||
.build();
|
||||
return aliPayApiConfig;
|
||||
/* String appId = getAppId();
|
||||
return getApiConfig(appId);*/
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过 appId 获取 AliPayApiConfig
|
||||
*
|
||||
* @param appId 支付宝应用编号
|
||||
* @return {@link AliPayApiConfig}
|
||||
*/
|
||||
public static AliPayApiConfig getApiConfig(String appId) {
|
||||
AliPayApiConfig cfg = CFG_MAP.get(appId);
|
||||
if (cfg == null) {
|
||||
throw new IllegalStateException("需事先调用 AliPayApiConfigKit.putApiConfig(aliPayApiConfig) 将 appId对应的 aliPayApiConfig 对象存入,才可以使用 AliPayApiConfigKit.getAliPayApiConfig() 的系列方法");
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.zscat.mallplus.alipay;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>支付宝配置 Bean</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public class AliPayBean {
|
||||
private String appId;
|
||||
private String privateKey;
|
||||
private String publicKey;
|
||||
private String serverUrl;
|
||||
private String domain;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.zscat.mallplus.alipay;
|
||||
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import com.zscat.mallplus.core.enums.SignType;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public class AliPayCore {
|
||||
|
||||
/**
|
||||
* 生成签名结果
|
||||
*
|
||||
* @param params 要签名的数组
|
||||
* @param key 签名密钥
|
||||
* @param signType 签名类型
|
||||
* @return 签名结果字符串
|
||||
*/
|
||||
public static String buildRequestMySign(Map<String, String> params, String key, String signType) {
|
||||
// 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
|
||||
String preStr = createLinkString(params);
|
||||
if (SignType.MD5.getType().equals(signType)) {
|
||||
return SecureUtil.md5(preStr.concat(key));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成要请求给支付宝的参数数组
|
||||
*
|
||||
* @param params 请求前的参数数组
|
||||
* @param key 商户的私钥
|
||||
* @param signType 签名类型
|
||||
* @return 要请求的参数数组
|
||||
*/
|
||||
public static Map<String, String> buildRequestPara(Map<String, String> params, String key, String signType) {
|
||||
// 除去数组中的空值和签名参数
|
||||
Map<String, String> tempMap = paraFilter(params);
|
||||
// 生成签名结果
|
||||
String mySign = buildRequestMySign(params, key, signType);
|
||||
|
||||
// 签名结果与签名方式加入请求提交参数组中
|
||||
tempMap.put("sign", mySign);
|
||||
tempMap.put("sign_type", signType);
|
||||
|
||||
return tempMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 除去数组中的空值和签名参数
|
||||
*
|
||||
* @param sArray 签名参数组
|
||||
* @return 去掉空值与签名参数后的新签名参数组
|
||||
*/
|
||||
public static Map<String, String> paraFilter(Map<String, String> sArray) {
|
||||
Map<String, String> result = new HashMap<String, String>(sArray.size());
|
||||
if (sArray == null || sArray.size() <= 0) {
|
||||
return result;
|
||||
}
|
||||
for (String key : sArray.keySet()) {
|
||||
String value = sArray.get(key);
|
||||
if (value == null || "".equals(value) || "sign".equalsIgnoreCase(key)
|
||||
|| "sign_type".equalsIgnoreCase(key)) {
|
||||
continue;
|
||||
}
|
||||
result.put(key, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 把数组所有元素排序
|
||||
*
|
||||
* @param params 需要排序并参与字符拼接的参数组
|
||||
* @return 拼接后字符串
|
||||
*/
|
||||
public static String createLinkString(Map<String, String> params) {
|
||||
List<String> keys = new ArrayList<String>(params.keySet());
|
||||
Collections.sort(keys);
|
||||
StringBuffer content = new StringBuffer();
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
String key = keys.get(i);
|
||||
String value = params.get(key);
|
||||
// 拼接时,不包括最后一个&字符
|
||||
if (i == keys.size() - 1) {
|
||||
content.append(key + "=" + value);
|
||||
} else {
|
||||
content.append(key + "=" + value + "&");
|
||||
}
|
||||
}
|
||||
return content.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
package com.zscat.mallplus.core;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* xpath解析xml
|
||||
* <p>
|
||||
* <pre>
|
||||
* 文档地址:
|
||||
* http://www.w3school.com.cn/xpath/index.asp
|
||||
* </pre>
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
public class XmlHelper {
|
||||
private final XPath path;
|
||||
private final Document doc;
|
||||
|
||||
private XmlHelper(InputSource inputSource) throws ParserConfigurationException, SAXException, IOException {
|
||||
DocumentBuilderFactory dbf = getDocumentBuilderFactory();
|
||||
// This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all
|
||||
// XML entity attacks are prevented
|
||||
// Xerces 2 only -
|
||||
// http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
|
||||
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
|
||||
// If you can't completely disable DTDs, then at least do the following:
|
||||
// Xerces 1 -
|
||||
// http://xerces.apache.org/xerces-j/features.html#external-general-entities
|
||||
// Xerces 2 -
|
||||
// http://xerces.apache.org/xerces2-j/features.html#external-general-entities
|
||||
// JDK7+ - http://xml.org/sax/features/external-general-entities
|
||||
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
||||
|
||||
// Xerces 1 -
|
||||
// http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
|
||||
// Xerces 2 -
|
||||
// http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
|
||||
// JDK7+ - http://xml.org/sax/features/external-parameter-entities
|
||||
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
||||
|
||||
// Disable external DTDs as well
|
||||
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
|
||||
|
||||
// and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and
|
||||
// Entity Attacks"
|
||||
dbf.setXIncludeAware(false);
|
||||
dbf.setExpandEntityReferences(false);
|
||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
doc = db.parse(inputSource);
|
||||
path = getXpathFactory().newXPath();
|
||||
}
|
||||
|
||||
private static XmlHelper create(InputSource inputSource) {
|
||||
try {
|
||||
return new XmlHelper(inputSource);
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (SAXException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static XmlHelper of(InputStream is) {
|
||||
InputSource inputSource = new InputSource(is);
|
||||
return create(inputSource);
|
||||
}
|
||||
|
||||
public static XmlHelper of(File file) {
|
||||
InputSource inputSource = new InputSource(file.toURI().toASCIIString());
|
||||
return create(inputSource);
|
||||
}
|
||||
|
||||
public static XmlHelper of(String xmlStr) {
|
||||
StringReader sr = new StringReader(xmlStr.trim());
|
||||
InputSource inputSource = new InputSource(sr);
|
||||
XmlHelper xmlHelper = create(inputSource);
|
||||
sr.close();
|
||||
return xmlHelper;
|
||||
}
|
||||
|
||||
private static DocumentBuilderFactory getDocumentBuilderFactory() {
|
||||
return XmlHelper.XmlHelperHolder.documentBuilderFactory;
|
||||
}
|
||||
|
||||
private static XPathFactory getXpathFactory() {
|
||||
return XmlHelper.XmlHelperHolder.xPathFactory;
|
||||
}
|
||||
|
||||
private Object evalXpath(String expression, Object item, QName returnType) {
|
||||
item = null == item ? doc : item;
|
||||
try {
|
||||
return path.evaluate(expression, item, returnType);
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取String
|
||||
*
|
||||
* @param expression 路径
|
||||
* @return String
|
||||
*/
|
||||
public String getString(String expression) {
|
||||
return (String) evalXpath(expression, null, XPathConstants.STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Boolean
|
||||
*
|
||||
* @param expression 路径
|
||||
* @return String
|
||||
*/
|
||||
public Boolean getBoolean(String expression) {
|
||||
return (Boolean) evalXpath(expression, null, XPathConstants.BOOLEAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Number
|
||||
*
|
||||
* @param expression 路径
|
||||
* @return {Number}
|
||||
*/
|
||||
public Number getNumber(String expression) {
|
||||
return (Number) evalXpath(expression, null, XPathConstants.NUMBER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个节点
|
||||
*
|
||||
* @param expression 路径
|
||||
* @return {Node}
|
||||
*/
|
||||
public Node getNode(String expression) {
|
||||
return (Node) evalXpath(expression, null, XPathConstants.NODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取子节点
|
||||
*
|
||||
* @param expression 路径
|
||||
* @return NodeList
|
||||
*/
|
||||
public NodeList getNodeList(String expression) {
|
||||
return (NodeList) evalXpath(expression, null, XPathConstants.NODESET);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取String
|
||||
*
|
||||
* @param node 节点
|
||||
* @param expression 相对于node的路径
|
||||
* @return String
|
||||
*/
|
||||
public String getString(Object node, String expression) {
|
||||
return (String) evalXpath(expression, node, XPathConstants.STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取
|
||||
*
|
||||
* @param node 节点
|
||||
* @param expression 相对于node的路径
|
||||
* @return String
|
||||
*/
|
||||
public Boolean getBoolean(Object node, String expression) {
|
||||
return (Boolean) evalXpath(expression, node, XPathConstants.BOOLEAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取
|
||||
*
|
||||
* @param node 节点
|
||||
* @param expression 相对于node的路径
|
||||
* @return {Number}
|
||||
*/
|
||||
public Number getNumber(Object node, String expression) {
|
||||
return (Number) evalXpath(expression, node, XPathConstants.NUMBER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个节点
|
||||
*
|
||||
* @param node 节点
|
||||
* @param expression 路径
|
||||
* @return {Node}
|
||||
*/
|
||||
public Node getNode(Object node, String expression) {
|
||||
return (Node) evalXpath(expression, node, XPathConstants.NODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取子节点
|
||||
*
|
||||
* @param node 节点
|
||||
* @param expression 相对于node的路径
|
||||
* @return NodeList
|
||||
*/
|
||||
public NodeList getNodeList(Object node, String expression) {
|
||||
return (NodeList) evalXpath(expression, node, XPathConstants.NODESET);
|
||||
}
|
||||
|
||||
/**
|
||||
* 针对没有嵌套节点的简单处理
|
||||
*
|
||||
* @return map集合
|
||||
*/
|
||||
public Map<String, String> toMap() {
|
||||
Element root = doc.getDocumentElement();
|
||||
|
||||
// 将节点封装成map形式
|
||||
NodeList list = root.getChildNodes();
|
||||
Map<String, String> params = new HashMap<String, String>(list.getLength());
|
||||
for (int i = 0; i < list.getLength(); i++) {
|
||||
Node node = list.item(i);
|
||||
params.put(node.getNodeName(), node.getTextContent());
|
||||
}
|
||||
// 含有空白符会生成一个#text参数
|
||||
params.remove("#text");
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部类单例
|
||||
*/
|
||||
private static class XmlHelperHolder {
|
||||
private static DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
private static XPathFactory xPathFactory = XPathFactory.newInstance();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.zscat.mallplus.core.enums;
|
||||
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>商户平台模式</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public enum PayModel {
|
||||
/**
|
||||
* 商户模式
|
||||
*/
|
||||
BUSINESS_MODEL("BUSINESS_MODEL"),
|
||||
/**
|
||||
* 服务商模式
|
||||
*/
|
||||
SERVICE_MODE("SERVICE_MODE");
|
||||
|
||||
/**
|
||||
* 商户模式
|
||||
*/
|
||||
private final String payModel;
|
||||
|
||||
PayModel(String payModel) {
|
||||
this.payModel = payModel;
|
||||
}
|
||||
|
||||
public String getPayModel() {
|
||||
return payModel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.zscat.mallplus.core.enums;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>签名方式</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public enum SignType {
|
||||
/**
|
||||
* HMAC-SHA256 加密
|
||||
*/
|
||||
HMACSHA256("HMAC-SHA256"),
|
||||
/**
|
||||
* MD5 加密
|
||||
*/
|
||||
MD5("MD5");
|
||||
|
||||
private final String type;
|
||||
|
||||
SignType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.zscat.mallplus.core.enums;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>支付方式</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public enum TradeType {
|
||||
/**
|
||||
* 微信公众号支付或者小程序支付
|
||||
*/
|
||||
JSAPI("JSAPI"),
|
||||
/**
|
||||
* 微信扫码支付
|
||||
*/
|
||||
NATIVE("NATIVE"),
|
||||
/**
|
||||
* 微信APP支付
|
||||
*/
|
||||
APP("APP"),
|
||||
/**
|
||||
* 付款码支付
|
||||
*/
|
||||
MICROPAY("MICROPAY"),
|
||||
/**
|
||||
* H5支付
|
||||
*/
|
||||
MWEB("MWEB");
|
||||
|
||||
/**
|
||||
* 交易类型
|
||||
*/
|
||||
private final String tradeType;
|
||||
|
||||
TradeType(String tradeType) {
|
||||
this.tradeType = tradeType;
|
||||
}
|
||||
|
||||
public String getTradeType() {
|
||||
return tradeType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package com.zscat.mallplus.core.http;
|
||||
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.http.ssl.SSLSocketFactoryBuilder;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyStore;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>Http 代理类</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public abstract class AbstractHttpDelegate {
|
||||
/**
|
||||
* get 请求
|
||||
*
|
||||
* @param url 请求url
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public String get(String url) {
|
||||
return HttpUtil.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* get 请求
|
||||
*
|
||||
* @param url 请求url
|
||||
* @param paramMap 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public String get(String url, Map<String, Object> paramMap) {
|
||||
return HttpUtil.get(url, paramMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* post 请求
|
||||
*
|
||||
* @param url 请求url
|
||||
* @param data 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public String post(String url, String data) {
|
||||
return HttpUtil.post(url, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* post 请求
|
||||
*
|
||||
* @param url 请求url
|
||||
* @param paramMap 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public String post(String url, Map<String, Object> paramMap) {
|
||||
return HttpUtil.post(url, paramMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* post 请求
|
||||
*
|
||||
* @param url 请求url
|
||||
* @param data 请求参数
|
||||
* @param certPath 证书路径
|
||||
* @param certPass 证书密码
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public String post(String url, String data, String certPath, String certPass) {
|
||||
try {
|
||||
return HttpRequest.post(url)
|
||||
.setSSLSocketFactory(SSLSocketFactoryBuilder
|
||||
.create()
|
||||
.setProtocol(SSLSocketFactoryBuilder.TLSv1)
|
||||
.setKeyManagers(getKeyManager(certPass, certPath, null))
|
||||
.setSecureRandom(new SecureRandom())
|
||||
.build()
|
||||
)
|
||||
.body(data)
|
||||
.execute()
|
||||
.body();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* post 请求
|
||||
*
|
||||
* @param url 请求url
|
||||
* @param data 请求参数
|
||||
* @param certFile 证书文件输入流
|
||||
* @param certPass 证书密码
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public String post(String url, String data, InputStream certFile, String certPass) {
|
||||
try {
|
||||
return HttpRequest.post(url)
|
||||
.setSSLSocketFactory(SSLSocketFactoryBuilder
|
||||
.create()
|
||||
.setProtocol(SSLSocketFactoryBuilder.TLSv1)
|
||||
.setKeyManagers(getKeyManager(certPass, null, certFile))
|
||||
.setSecureRandom(new SecureRandom())
|
||||
.build()
|
||||
)
|
||||
.body(data)
|
||||
.execute()
|
||||
.body();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private KeyManager[] getKeyManager(String certPass, String certPath, InputStream certFile) throws Exception {
|
||||
KeyStore clientStore = KeyStore.getInstance("PKCS12");
|
||||
if (certFile != null) {
|
||||
clientStore.load(certFile, certPass.toCharArray());
|
||||
} else {
|
||||
clientStore.load(new FileInputStream(certPath), certPass.toCharArray());
|
||||
}
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
kmf.init(clientStore, certPass.toCharArray());
|
||||
return kmf.getKeyManagers();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.zscat.mallplus.core.kit;
|
||||
|
||||
|
||||
import com.zscat.mallplus.core.http.AbstractHttpDelegate;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>Http 工具类</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public class HttpKit {
|
||||
|
||||
private static AbstractHttpDelegate delegate = new DefaultHttpKit();
|
||||
|
||||
public static AbstractHttpDelegate getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
public static void setDelegate(AbstractHttpDelegate delegate) {
|
||||
HttpKit.delegate = delegate;
|
||||
}
|
||||
|
||||
public static String readData(HttpServletRequest request) {
|
||||
BufferedReader br = null;
|
||||
try {
|
||||
StringBuilder result = new StringBuilder();
|
||||
br = request.getReader();
|
||||
for (String line; (line = br.readLine()) != null; ) {
|
||||
if (result.length() > 0) {
|
||||
result.append("\n");
|
||||
}
|
||||
result.append(line);
|
||||
}
|
||||
return result.toString();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if (br != null) {
|
||||
try {
|
||||
br.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 huTool 实现的 Http 工具类
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
class DefaultHttpKit extends AbstractHttpDelegate {
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.zscat.mallplus.core.kit;
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by Fernflower decompiler)
|
||||
//
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @author Javen
|
||||
*/
|
||||
public class IpKit {
|
||||
public IpKit() {
|
||||
}
|
||||
|
||||
public static String getRealIp(HttpServletRequest request) {
|
||||
String ip = request.getHeader("x-forwarded-for");
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("Proxy-Client-IP");
|
||||
}
|
||||
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("WL-Proxy-Client-IP");
|
||||
}
|
||||
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getRemoteAddr();
|
||||
}
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
public static String getRealIpV2(HttpServletRequest request) {
|
||||
String accessIp = request.getHeader("x-forwarded-for");
|
||||
return null == accessIp ? request.getRemoteAddr() : accessIp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package com.zscat.mallplus.core.kit;
|
||||
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.crypto.digest.HmacAlgorithm;
|
||||
import com.zscat.mallplus.core.XmlHelper;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 工具类</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public class PayKit {
|
||||
|
||||
public static String hmacSha256(String data, String key) {
|
||||
return SecureUtil.hmac(HmacAlgorithm.HmacSHA256, key).digestHex(data, CharsetUtil.UTF_8);
|
||||
}
|
||||
|
||||
public static String md5(String data) {
|
||||
return SecureUtil.md5(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* AES 解密
|
||||
*
|
||||
* @param base64Data 需要解密的数据
|
||||
* @param key 密钥
|
||||
* @return 解密后的数据
|
||||
*/
|
||||
public static String decryptData(String base64Data, String key) {
|
||||
return SecureUtil.aes(md5(key).toLowerCase().getBytes()).decryptStr(base64Data);
|
||||
}
|
||||
|
||||
/**
|
||||
* AES 加密
|
||||
*
|
||||
* @param data 需要加密的数据
|
||||
* @param key 密钥
|
||||
* @return 加密后的数据
|
||||
*/
|
||||
public static String encryptData(String data, String key) {
|
||||
return SecureUtil.aes(md5(key).toLowerCase().getBytes()).encryptBase64(data.getBytes());
|
||||
}
|
||||
|
||||
public static String generateStr() {
|
||||
return IdUtil.fastSimpleUUID();
|
||||
}
|
||||
|
||||
/**
|
||||
* 把所有元素排序
|
||||
*
|
||||
* @param params 需要排序并参与字符拼接的参数组
|
||||
* @return 拼接后字符串
|
||||
*/
|
||||
public static String createLinkString(Map<String, String> params) {
|
||||
return createLinkString(params, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param params 需要排序并参与字符拼接的参数组
|
||||
* @param encode 是否进行URLEncoder
|
||||
* @return 拼接后字符串
|
||||
*/
|
||||
public static String createLinkString(Map<String, String> params, boolean encode) {
|
||||
List<String> keys = new ArrayList<String>(params.keySet());
|
||||
Collections.sort(keys);
|
||||
StringBuffer content = new StringBuffer();
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
String key = keys.get(i);
|
||||
String value = params.get(key);
|
||||
// 拼接时,不包括最后一个&字符
|
||||
if (i == keys.size() - 1) {
|
||||
content.append(key + "=" + (encode ? urlEncode(value) : value));
|
||||
} else {
|
||||
content.append(key + "=" + (encode ? urlEncode(value) : value) + "&");
|
||||
}
|
||||
}
|
||||
return content.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* URL 编码
|
||||
*
|
||||
* @param src 需要编码的字符串
|
||||
* @return 编码后的字符串
|
||||
*/
|
||||
public static String urlEncode(String src) {
|
||||
try {
|
||||
return URLEncoder.encode(src, CharsetUtil.UTF_8).replace("+", "%20");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历 Map 并构建 xml 数据
|
||||
*
|
||||
* @param params 需要遍历的 Map
|
||||
* @param prefix xml 前缀
|
||||
* @param suffix xml 后缀
|
||||
* @return
|
||||
*/
|
||||
public static StringBuilder forEachMap(Map<String, String> params, String prefix, String suffix) {
|
||||
StringBuilder xml = new StringBuilder();
|
||||
if (StrUtil.isNotEmpty(prefix)) {
|
||||
xml.append(prefix);
|
||||
}
|
||||
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
// 略过空值
|
||||
if (StrUtil.isEmpty(value)) {
|
||||
continue;
|
||||
}
|
||||
xml.append("<").append(key).append(">");
|
||||
xml.append(entry.getValue());
|
||||
xml.append("</").append(key).append(">");
|
||||
}
|
||||
if (StrUtil.isNotEmpty(suffix)) {
|
||||
xml.append(suffix);
|
||||
}
|
||||
return xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信下单 map to xml
|
||||
*
|
||||
* @param params Map 参数
|
||||
* @return xml 字符串
|
||||
*/
|
||||
public static String toXml(Map<String, String> params) {
|
||||
StringBuilder xml = forEachMap(params, "<xml>", "</xml>");
|
||||
return xml.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 针对支付的 xml,没有嵌套节点的简单处理
|
||||
*
|
||||
* @param xmlStr xml 字符串
|
||||
* @return 转化后的 Map
|
||||
*/
|
||||
public static Map<String, String> xmlToMap(String xmlStr) {
|
||||
XmlHelper xmlHelper = XmlHelper.of(xmlStr);
|
||||
return xmlHelper.toMap();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package com.zscat.mallplus.core.kit;
|
||||
|
||||
import com.google.zxing.*;
|
||||
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
|
||||
import com.google.zxing.client.j2se.MatrixToImageConfig;
|
||||
import com.google.zxing.client.j2se.MatrixToImageWriter;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.HybridBinarizer;
|
||||
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p> google 开源图形码工具类</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public class QrCodeKit {
|
||||
/**
|
||||
* 图形码生成工具
|
||||
*
|
||||
* @param contents 内容
|
||||
* @param barcodeFormat BarcodeFormat对象
|
||||
* @param format 图片格式,可选[png,jpg,bmp]
|
||||
* @param width 宽
|
||||
* @param height 高
|
||||
* @param margin 边框间距px
|
||||
* @param saveImgFilePath 存储图片的完整位置,包含文件名
|
||||
* @return {boolean}
|
||||
*/
|
||||
public static boolean encode(String contents, BarcodeFormat barcodeFormat, Integer margin,
|
||||
ErrorCorrectionLevel errorLevel, String format, int width, int height, String saveImgFilePath) {
|
||||
Boolean bool = false;
|
||||
BufferedImage bufImg;
|
||||
Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>(3);
|
||||
// 指定纠错等级
|
||||
hints.put(EncodeHintType.ERROR_CORRECTION, errorLevel);
|
||||
hints.put(EncodeHintType.MARGIN, margin);
|
||||
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
|
||||
try {
|
||||
BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, barcodeFormat, width, height, hints);
|
||||
MatrixToImageConfig config = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF);
|
||||
bufImg = MatrixToImageWriter.toBufferedImage(bitMatrix, config);
|
||||
bool = writeToFile(bufImg, format, saveImgFilePath);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return bool;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param outputStream 可以来自response,也可以来自文件
|
||||
* @param contents 内容
|
||||
* @param barcodeFormat BarcodeFormat对象
|
||||
* @param margin 图片格式,可选[png,jpg,bmp]
|
||||
* @param errorLevel 纠错级别 一般为:ErrorCorrectionLevel.H
|
||||
* @param format 图片格式,可选[png,jpg,bmp]
|
||||
* @param width 宽
|
||||
* @param height 高
|
||||
*/
|
||||
public static void encodeOutPutSteam(OutputStream outputStream, String contents, BarcodeFormat barcodeFormat, Integer margin, ErrorCorrectionLevel errorLevel, String format, int width, int height) throws IOException {
|
||||
Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>(3);
|
||||
hints.put(EncodeHintType.ERROR_CORRECTION, errorLevel);
|
||||
hints.put(EncodeHintType.MARGIN, margin);
|
||||
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
|
||||
|
||||
try {
|
||||
BitMatrix bitMatrix = (new MultiFormatWriter()).encode(contents, barcodeFormat, width, height, hints);
|
||||
MatrixToImageWriter.writeToStream(bitMatrix, format, outputStream);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (outputStream != null) {
|
||||
outputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param srcImgFilePath 要解码的图片地址
|
||||
* @return {Result}
|
||||
*/
|
||||
public static Result decode(String srcImgFilePath) {
|
||||
Result result = null;
|
||||
BufferedImage image;
|
||||
try {
|
||||
File srcFile = new File(srcImgFilePath);
|
||||
image = ImageIO.read(srcFile);
|
||||
if (null != image) {
|
||||
LuminanceSource source = new BufferedImageLuminanceSource(image);
|
||||
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
|
||||
|
||||
Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>();
|
||||
hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
|
||||
result = new MultiFormatReader().decode(bitmap, hints);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Could not decode image.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将BufferedImage对象写入文件
|
||||
*
|
||||
* @param bufImg BufferedImage对象
|
||||
* @param format 图片格式,可选[png,jpg,bmp]
|
||||
* @param saveImgFilePath 存储图片的完整位置,包含文件名
|
||||
* @return {boolean}
|
||||
*/
|
||||
public static boolean writeToFile(BufferedImage bufImg, String format, String saveImgFilePath) {
|
||||
Boolean bool = false;
|
||||
try {
|
||||
bool = ImageIO.write(bufImg, format, new File(saveImgFilePath));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return bool;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String saveImgFilePath = "/Users/Javen/Documents/dev/mallplus Pay/qrCode.png";
|
||||
Boolean encode = encode("https://gitee.com/javen205/mallplus Pay", BarcodeFormat.QR_CODE, 3,
|
||||
ErrorCorrectionLevel.H, "png", 200, 200, saveImgFilePath);
|
||||
if (encode) {
|
||||
Result result = decode(saveImgFilePath);
|
||||
String text = result.getText();
|
||||
System.out.println(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
package com.zscat.mallplus.core.kit;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.*;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>RSA 非对称加密工具类</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public class RsaKit {
|
||||
|
||||
/**
|
||||
* RSA最大加密明文大小
|
||||
*/
|
||||
private static final int MAX_ENCRYPT_BLOCK = 117;
|
||||
|
||||
/**
|
||||
* RSA最大解密密文大小
|
||||
*/
|
||||
private static final int MAX_DECRYPT_BLOCK = 128;
|
||||
|
||||
/**
|
||||
* 加密算法RSA
|
||||
*/
|
||||
private static final String KEY_ALGORITHM = "RSA";
|
||||
|
||||
/**
|
||||
* 生成公钥和私钥
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public static Map<String, String> getKeys() throws Exception {
|
||||
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
|
||||
keyPairGen.initialize(1024);
|
||||
KeyPair keyPair = keyPairGen.generateKeyPair();
|
||||
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
|
||||
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
|
||||
|
||||
String publicKeyStr = getPublicKeyStr(publicKey);
|
||||
String privateKeyStr = getPrivateKeyStr(privateKey);
|
||||
|
||||
Map<String, String> map = new HashMap<String, String>(2);
|
||||
map.put("publicKey", publicKeyStr);
|
||||
map.put("privateKey", privateKeyStr);
|
||||
|
||||
System.out.println("公钥\r\n" + publicKeyStr);
|
||||
System.out.println("私钥\r\n" + privateKeyStr);
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用模和指数生成RSA公钥
|
||||
* 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA
|
||||
* /None/NoPadding】
|
||||
*
|
||||
* @param modulus 模
|
||||
* @param exponent 公钥指数
|
||||
* @return
|
||||
*/
|
||||
public static RSAPublicKey getPublicKey(String modulus, String exponent) {
|
||||
try {
|
||||
BigInteger b1 = new BigInteger(modulus);
|
||||
BigInteger b2 = new BigInteger(exponent);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
||||
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
|
||||
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用模和指数生成RSA私钥
|
||||
* 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA
|
||||
* /None/NoPadding】
|
||||
*
|
||||
* @param modulus 模
|
||||
* @param exponent 指数
|
||||
* @return
|
||||
*/
|
||||
public static RSAPrivateKey getPrivateKey(String modulus, String exponent) {
|
||||
try {
|
||||
BigInteger b1 = new BigInteger(modulus);
|
||||
BigInteger b2 = new BigInteger(exponent);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
||||
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);
|
||||
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 公钥加密
|
||||
*
|
||||
* @param data 需要加密的数据
|
||||
* @param publicKey 公钥
|
||||
* @return 加密后的数据
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String encryptByPublicKey(String data, String publicKey) throws Exception {
|
||||
return encryptByPublicKey(data, publicKey, "RSA/ECB/PKCS1Padding");
|
||||
}
|
||||
|
||||
public static String encryptByPublicKeyByWx(String data, String publicKey) throws Exception {
|
||||
return encryptByPublicKey(data, publicKey, "RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING");
|
||||
}
|
||||
|
||||
/**
|
||||
* 公钥加密
|
||||
*
|
||||
* @param data 需要加密的数据
|
||||
* @param publicKey 公钥
|
||||
* @param fillMode 填充模式
|
||||
* @return 加密后的数据
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String encryptByPublicKey(String data, String publicKey, String fillMode) throws Exception {
|
||||
byte[] dataByte = data.getBytes("UTF-8");
|
||||
byte[] keyBytes = Base64.decode(publicKey);
|
||||
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
||||
Key key = keyFactory.generatePublic(x509KeySpec);
|
||||
// 对数据加密
|
||||
Cipher cipher = Cipher.getInstance(fillMode);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
||||
int inputLen = dataByte.length;
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
int offSet = 0;
|
||||
byte[] cache;
|
||||
int i = 0;
|
||||
// 对数据分段加密
|
||||
while (inputLen - offSet > 0) {
|
||||
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
|
||||
cache = cipher.doFinal(dataByte, offSet, MAX_ENCRYPT_BLOCK);
|
||||
} else {
|
||||
cache = cipher.doFinal(dataByte, offSet, inputLen - offSet);
|
||||
}
|
||||
out.write(cache, 0, cache.length);
|
||||
i++;
|
||||
offSet = i * MAX_ENCRYPT_BLOCK;
|
||||
}
|
||||
byte[] encryptedData = out.toByteArray();
|
||||
out.close();
|
||||
return StrUtil.str(Base64.encode(encryptedData));
|
||||
}
|
||||
|
||||
/**
|
||||
* 私钥签名
|
||||
*
|
||||
* @param data 需要加密的数据
|
||||
* @param privateKey 私钥
|
||||
* @return 加密后的数据
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String encryptByPrivateKey(String data, String privateKey) throws Exception {
|
||||
PKCS8EncodedKeySpec priPkcs8 = new PKCS8EncodedKeySpec(Base64.decode(privateKey));
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
||||
PrivateKey priKey = keyFactory.generatePrivate(priPkcs8);
|
||||
Signature signature = Signature.getInstance("SHA256WithRSA");
|
||||
|
||||
signature.initSign(priKey);
|
||||
signature.update(data.getBytes("UTF-8"));
|
||||
byte[] signed = signature.sign();
|
||||
return StrUtil.str(Base64.encode(signed));
|
||||
}
|
||||
|
||||
/**
|
||||
* 公钥验证签名
|
||||
*
|
||||
* @param data 需要加密的数据
|
||||
* @param sign 签名
|
||||
* @param publicKey 公钥
|
||||
* @return 验证结果
|
||||
* @throws Exception
|
||||
*/
|
||||
public static boolean checkByPublicKey(String data, String sign, String publicKey) throws Exception {
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
||||
byte[] encodedKey = Base64.decode(publicKey);
|
||||
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
|
||||
Signature signature = Signature.getInstance("SHA256WithRSA");
|
||||
signature.initVerify(pubKey);
|
||||
signature.update(data.getBytes("UTF-8"));
|
||||
return signature.verify(Base64.decode(sign.getBytes("UTF-8")));
|
||||
}
|
||||
|
||||
/**
|
||||
* 私钥解密
|
||||
*
|
||||
* @param data
|
||||
* @param privateKey
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String decryptByPrivateKey(String data, String privateKey) throws Exception {
|
||||
return decryptByPrivateKey(data, privateKey, "RSA/ECB/PKCS1Padding");
|
||||
}
|
||||
|
||||
public static String decryptByPrivateKeyByWx(String data, String privateKey) throws Exception {
|
||||
return decryptByPrivateKey(data, privateKey, "RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING");
|
||||
}
|
||||
|
||||
/**
|
||||
* 私钥解密
|
||||
*
|
||||
* @param data
|
||||
* @param privateKey
|
||||
* @param fillMode 填充模式
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String decryptByPrivateKey(String data, String privateKey, String fillMode) throws Exception {
|
||||
byte[] encryptedData = Base64.decode(data);
|
||||
byte[] keyBytes = Base64.decode(privateKey);
|
||||
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
||||
Key key = keyFactory.generatePrivate(pkcs8KeySpec);
|
||||
Cipher cipher = Cipher.getInstance(fillMode);
|
||||
|
||||
cipher.init(Cipher.DECRYPT_MODE, key);
|
||||
int inputLen = encryptedData.length;
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
int offSet = 0;
|
||||
byte[] cache;
|
||||
int i = 0;
|
||||
// 对数据分段解密
|
||||
while (inputLen - offSet > 0) {
|
||||
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
|
||||
cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
|
||||
} else {
|
||||
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
|
||||
}
|
||||
out.write(cache, 0, cache.length);
|
||||
i++;
|
||||
offSet = i * MAX_DECRYPT_BLOCK;
|
||||
}
|
||||
byte[] decryptedData = out.toByteArray();
|
||||
out.close();
|
||||
return new String(decryptedData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模数和密钥
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Map<String, String> getModulusAndKeys() {
|
||||
|
||||
Map<String, String> map = new HashMap<String, String>(3);
|
||||
|
||||
try {
|
||||
InputStream in = RsaKit.class.getResourceAsStream("/rsa.properties");
|
||||
Properties prop = new Properties();
|
||||
prop.load(in);
|
||||
|
||||
String modulus = prop.getProperty("modulus");
|
||||
String publicKey = prop.getProperty("publicKey");
|
||||
String privateKey = prop.getProperty("privateKey");
|
||||
|
||||
in.close();
|
||||
|
||||
map.put("modulus", modulus);
|
||||
map.put("publicKey", publicKey);
|
||||
map.put("privateKey", privateKey);
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从字符串中加载公钥
|
||||
*
|
||||
* @param publicKeyStr 公钥数据字符串
|
||||
* @throws Exception 加载公钥时产生的异常
|
||||
*/
|
||||
public static PublicKey loadPublicKey(String publicKeyStr) throws Exception {
|
||||
try {
|
||||
byte[] buffer = Base64.decode(publicKeyStr);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
||||
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
|
||||
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new Exception("无此算法");
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw new Exception("公钥非法");
|
||||
} catch (NullPointerException e) {
|
||||
throw new Exception("公钥数据为空");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从字符串中加载私钥<br>
|
||||
* 加载时使用的是PKCS8EncodedKeySpec(PKCS#8编码的Key指令)。
|
||||
*
|
||||
* @param privateKeyStr
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static PrivateKey loadPrivateKey(String privateKeyStr) throws Exception {
|
||||
try {
|
||||
byte[] buffer = Base64.decode(privateKeyStr);
|
||||
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
||||
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new Exception("无此算法");
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw new Exception("私钥非法");
|
||||
} catch (NullPointerException e) {
|
||||
throw new Exception("私钥数据为空");
|
||||
}
|
||||
}
|
||||
|
||||
public static String getPrivateKeyStr(PrivateKey privateKey) throws Exception {
|
||||
return new String(Base64.encode(privateKey.getEncoded()));
|
||||
}
|
||||
|
||||
public static String getPublicKeyStr(PublicKey publicKey) throws Exception {
|
||||
return new String(Base64.encode(publicKey.getEncoded()));
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Map<String, String> keys = getKeys();
|
||||
String publicKey = keys.get("publicKey");
|
||||
String privateKey = keys.get("privateKey");
|
||||
String content = "我是Javen,I am Javen";
|
||||
String encrypt = encryptByPublicKey(content, publicKey);
|
||||
String decrypt = decryptByPrivateKey(encrypt, privateKey);
|
||||
System.out.println("加密之后:" + encrypt);
|
||||
System.out.println("解密之后:" + decrypt);
|
||||
|
||||
System.out.println("======华丽的分割线=========");
|
||||
|
||||
content = "我是Javen,I am Javen";
|
||||
encrypt = encryptByPublicKeyByWx(content, publicKey);
|
||||
decrypt = decryptByPrivateKeyByWx(encrypt, privateKey);
|
||||
System.out.println("加密之后:" + encrypt);
|
||||
System.out.println("解密之后:" + decrypt);
|
||||
|
||||
//OPPO
|
||||
String sign = encryptByPrivateKey(content, privateKey);
|
||||
System.out.println("加密之后:" + sign);
|
||||
System.out.println(checkByPublicKey(content, sign, publicKey));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
package com.zscat.mallplus.core.kit;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.zscat.mallplus.core.enums.SignType;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>微信支付工具类</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public class WxPayKit {
|
||||
private static final String FIELD_SIGN = "sign";
|
||||
private static final String FIELD_SIGN_TYPE = "sign_type";
|
||||
|
||||
public static String hmacSha256(String data, String key) {
|
||||
return PayKit.hmacSha256(data, key);
|
||||
}
|
||||
|
||||
public static String md5(String data) {
|
||||
return PayKit.md5(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* AES 解密
|
||||
*
|
||||
* @param base64Data 需要解密的数据
|
||||
* @param key 密钥
|
||||
* @return 解密后的数据
|
||||
*/
|
||||
public static String decryptData(String base64Data, String key) {
|
||||
return PayKit.decryptData(base64Data, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* AES 加密
|
||||
*
|
||||
* @param data 需要加密的数据
|
||||
* @param key 密钥
|
||||
* @return 加密后的数据
|
||||
*/
|
||||
public static String encryptData(String data, String key) {
|
||||
return PayKit.encryptData(data, key);
|
||||
}
|
||||
|
||||
public static String generateStr() {
|
||||
return PayKit.generateStr();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 支付异步通知时校验 sign
|
||||
*
|
||||
* @param params 参数
|
||||
* @param partnerKey 支付密钥
|
||||
* @return {boolean}
|
||||
*/
|
||||
public static boolean verifyNotify(Map<String, String> params, String partnerKey) {
|
||||
String sign = params.get("sign");
|
||||
String localSign = createSign(params, partnerKey, SignType.MD5);
|
||||
return sign.equals(localSign);
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付异步通知时校验 sign
|
||||
*
|
||||
* @param params 参数
|
||||
* @param partnerKey 支付密钥
|
||||
* @param signType {@link SignType}
|
||||
* @return
|
||||
*/
|
||||
public static boolean verifyNotify(Map<String, String> params, String partnerKey, SignType signType) {
|
||||
String sign = params.get("sign");
|
||||
String localSign = createSign(params, partnerKey, signType);
|
||||
return sign.equals(localSign);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成签名
|
||||
*
|
||||
* @param params 需要签名的参数
|
||||
* @param partnerKey 密钥
|
||||
* @param signType 签名类型
|
||||
* @return 签名后的数据
|
||||
*/
|
||||
public static String createSign(Map<String, String> params, String partnerKey, SignType signType) {
|
||||
if (signType == null) {
|
||||
signType = SignType.MD5;
|
||||
}
|
||||
// 生成签名前先去除sign
|
||||
params.remove(FIELD_SIGN);
|
||||
String tempStr = PayKit.createLinkString(params);
|
||||
String stringSignTemp = tempStr + "&key=" + partnerKey;
|
||||
if (signType == SignType.MD5) {
|
||||
return md5(stringSignTemp).toUpperCase();
|
||||
} else {
|
||||
return hmacSha256(stringSignTemp, partnerKey).toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建签名
|
||||
*
|
||||
* @param params 需要签名的参数
|
||||
* @param partnerKey 密钥
|
||||
* @param signType 签名类型
|
||||
* @return 签名后的 Map
|
||||
*/
|
||||
public static Map<String, String> buildSign(Map<String, String> params, String partnerKey, SignType signType) {
|
||||
return buildSign(params, partnerKey, signType, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建签名
|
||||
*
|
||||
* @param params 需要签名的参数
|
||||
* @param partnerKey 密钥
|
||||
* @param signType 签名类型
|
||||
* @param haveSignType 签名是否包含 sign_type 字段
|
||||
* @return 签名后的 Map
|
||||
*/
|
||||
public static Map<String, String> buildSign(Map<String, String> params, String partnerKey, SignType signType, boolean haveSignType) {
|
||||
if (haveSignType) {
|
||||
params.put(FIELD_SIGN_TYPE, signType.getType());
|
||||
}
|
||||
String sign = createSign(params, partnerKey, signType);
|
||||
params.put(FIELD_SIGN, sign);
|
||||
return params;
|
||||
}
|
||||
|
||||
public static StringBuilder forEachMap(Map<String, String> params, String prefix, String suffix) {
|
||||
return PayKit.forEachMap(params, prefix, suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信下单 map to xml
|
||||
*
|
||||
* @param params Map 参数
|
||||
* @return xml 字符串
|
||||
*/
|
||||
public static String toXml(Map<String, String> params) {
|
||||
return PayKit.toXml(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 针对支付的 xml,没有嵌套节点的简单处理
|
||||
*
|
||||
* @param xmlStr xml 字符串
|
||||
* @return 转化后的 Map
|
||||
*/
|
||||
public static Map<String, String> xmlToMap(String xmlStr) {
|
||||
return PayKit.xmlToMap(xmlStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>生成二维码链接</p>
|
||||
* <p>原生支付接口模式一(扫码模式一)</p>
|
||||
*
|
||||
* @param sign 签名
|
||||
* @param appId 公众账号ID
|
||||
* @param mchId 商户号
|
||||
* @param productId 商品ID
|
||||
* @param timeStamp 时间戳
|
||||
* @param nonceStr 随机字符串
|
||||
* @return
|
||||
*/
|
||||
public static String bizPayUrl(String sign, String appId, String mchId, String productId, String timeStamp, String nonceStr) {
|
||||
String rules = "weixin://wxpay/bizpayurl?sign=Temp&appid=Temp&mch_id=Temp&product_id=Temp&time_stamp=Temp&nonce_str=Temp";
|
||||
return replace(rules, "Temp", sign, appId, mchId, productId, timeStamp, nonceStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>生成二维码链接</p>
|
||||
* <p>原生支付接口模式一(扫码模式一)</p>
|
||||
*
|
||||
* @param partnerKey 密钥
|
||||
* @param appId 公众账号ID
|
||||
* @param mchId 商户号
|
||||
* @param productId 商品ID
|
||||
* @param timeStamp 时间戳
|
||||
* @param nonceStr 随机字符串
|
||||
* @param signType 签名类型
|
||||
* @return
|
||||
*/
|
||||
public static String bizPayUrl(String partnerKey, String appId, String mchId, String productId, String timeStamp, String nonceStr, SignType signType) {
|
||||
HashMap<String, String> map = new HashMap<String, String>(5);
|
||||
map.put("appid", appId);
|
||||
map.put("mch_id", mchId);
|
||||
map.put("time_stamp", StrUtil.isEmpty(timeStamp) ? Long.toString(System.currentTimeMillis() / 1000) : timeStamp);
|
||||
map.put("nonce_str", StrUtil.isEmpty(nonceStr) ? WxPayKit.generateStr() : nonceStr);
|
||||
map.put("product_id", productId);
|
||||
return bizPayUrl(createSign(map, partnerKey, signType), appId, mchId, productId, timeStamp, nonceStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>生成二维码链接</p>
|
||||
* <p>原生支付接口模式一(扫码模式一)</p>
|
||||
*
|
||||
* @param partnerKey 密钥
|
||||
* @param appId 公众账号ID
|
||||
* @param mchId 商户号
|
||||
* @param productId 商品ID
|
||||
* @return
|
||||
*/
|
||||
public static String bizPayUrl(String partnerKey, String appId, String mchId, String productId) {
|
||||
String timeStamp = Long.toString(System.currentTimeMillis() / 1000);
|
||||
String nonceStr = WxPayKit.generateStr();
|
||||
HashMap<String, String> map = new HashMap<String, String>(5);
|
||||
map.put("appid", appId);
|
||||
map.put("mch_id", mchId);
|
||||
map.put("time_stamp", timeStamp);
|
||||
map.put("nonce_str", nonceStr);
|
||||
map.put("product_id", productId);
|
||||
return bizPayUrl(createSign(map, partnerKey, null), appId, mchId, productId, timeStamp, nonceStr);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 替换url中的参数
|
||||
*
|
||||
* @param str 原始字符串
|
||||
* @param regex 表达式
|
||||
* @param args 替换字符串
|
||||
* @return {String}
|
||||
*/
|
||||
public static String replace(String str, String regex, String... args) {
|
||||
for (String arg : args) {
|
||||
str = str.replaceFirst(regex, arg);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断接口返回的 code
|
||||
*
|
||||
* @param codeValue code 值
|
||||
* @return 是否是 SUCCESS
|
||||
*/
|
||||
public static boolean codeIsOk(String codeValue) {
|
||||
return StrUtil.isNotEmpty(codeValue) && "SUCCESS".equals(codeValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>公众号支付-预付订单再次签名</p>
|
||||
* <p>注意此处签名方式需与统一下单的签名类型一致</p>
|
||||
*
|
||||
* @param prepayId 预付订单号
|
||||
* @param appId 应用编号
|
||||
* @param partnerKey API Key
|
||||
* @param signType 签名方式
|
||||
* @return 再次签名后的 Map
|
||||
*/
|
||||
public static Map<String, String> prepayIdCreateSign(String prepayId, String appId, String partnerKey, SignType signType) {
|
||||
Map<String, String> packageParams = new HashMap<String, String>(6);
|
||||
packageParams.put("appId", appId);
|
||||
packageParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
|
||||
packageParams.put("nonceStr", String.valueOf(System.currentTimeMillis()));
|
||||
packageParams.put("package", "prepay_id=" + prepayId);
|
||||
if (signType == null) {
|
||||
signType = SignType.MD5;
|
||||
}
|
||||
packageParams.put("signType", signType.getType());
|
||||
String packageSign = WxPayKit.createSign(packageParams, partnerKey, signType);
|
||||
packageParams.put("paySign", packageSign);
|
||||
return packageParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>APP 支付-预付订单再次签名</p>
|
||||
* <p>注意此处签名方式需与统一下单的签名类型一致</p>
|
||||
*
|
||||
* @param appId 应用编号
|
||||
* @param partnerId 商户号
|
||||
* @param prepayId 预付订单号
|
||||
* @param partnerKey API Key
|
||||
* @param signType 签名方式
|
||||
* @return 再次签名后的 Map
|
||||
*/
|
||||
public static Map<String, String> appPrepayIdCreateSign(String appId, String partnerId, String prepayId, String partnerKey, SignType signType) {
|
||||
Map<String, String> packageParams = new HashMap<String, String>(8);
|
||||
packageParams.put("appid", appId);
|
||||
packageParams.put("partnerid", partnerId);
|
||||
packageParams.put("prepayid", prepayId);
|
||||
packageParams.put("package", "Sign=WXPay");
|
||||
packageParams.put("noncestr", String.valueOf(System.currentTimeMillis()));
|
||||
packageParams.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
|
||||
if (signType == null) {
|
||||
signType = SignType.MD5;
|
||||
}
|
||||
String packageSign = createSign(packageParams, partnerKey, signType);
|
||||
packageParams.put("sign", packageSign);
|
||||
return packageParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>小程序-预付订单再次签名</p>
|
||||
* <p>注意此处签名方式需与统一下单的签名类型一致</p>
|
||||
*
|
||||
* @param appId 应用编号
|
||||
* @param prepayId 预付订单号
|
||||
* @param partnerKey API Key
|
||||
* @param signType 签名方式
|
||||
* @return 再次签名后的 Map
|
||||
*/
|
||||
public static Map<String, String> miniAppPrepayIdCreateSign(String appId, String prepayId, String partnerKey, SignType signType) {
|
||||
Map<String, String> packageParams = new HashMap<String, String>(6);
|
||||
packageParams.put("appId", appId);
|
||||
packageParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
|
||||
packageParams.put("nonceStr", String.valueOf(System.currentTimeMillis()));
|
||||
packageParams.put("package", "prepay_id=" + prepayId);
|
||||
if (signType == null) {
|
||||
signType = SignType.MD5;
|
||||
}
|
||||
packageParams.put("signType", signType.getType());
|
||||
String packageSign = createSign(packageParams, partnerKey, signType);
|
||||
packageParams.put("paySign", packageSign);
|
||||
return packageParams;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>Model 公用方法</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.core.model;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.zscat.mallplus.core.enums.SignType;
|
||||
import com.zscat.mallplus.core.kit.WxPayKit;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class BaseModel {
|
||||
|
||||
/**
|
||||
* 将建构的 builder 转为 Map
|
||||
*
|
||||
* @return 转化后的 Map
|
||||
*/
|
||||
public Map<String, String> toMap() {
|
||||
String[] fieldNames = getFiledNames(this);
|
||||
HashMap<String, String> map = new HashMap<String, String>(fieldNames.length);
|
||||
for (int i = 0; i < fieldNames.length; i++) {
|
||||
String name = fieldNames[i];
|
||||
String value = (String) getFieldValueByName(name, this);
|
||||
if (StrUtil.isNotEmpty(value)) {
|
||||
map.put(name, value);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建签名 Map
|
||||
*
|
||||
* @param partnerKey API KEY
|
||||
* @param signType {@link SignType} 签名类型
|
||||
* @return 构建签名后的 Map
|
||||
*/
|
||||
public Map<String, String> createSign(String partnerKey, SignType signType) {
|
||||
return createSign(partnerKey, signType, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建签名 Map
|
||||
*
|
||||
* @param partnerKey API KEY
|
||||
* @param signType {@link SignType} 签名类型
|
||||
* @param haveSignType 签名是否包含 sign_type 字段
|
||||
* @return 构建签名后的 Map
|
||||
*/
|
||||
public Map<String, String> createSign(String partnerKey, SignType signType, boolean haveSignType) {
|
||||
return WxPayKit.buildSign(toMap(), partnerKey, signType, haveSignType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取属性名数组
|
||||
*
|
||||
* @param obj 对象
|
||||
* @return 返回对象属性名数组
|
||||
*/
|
||||
public String[] getFiledNames(Object obj) {
|
||||
Field[] fields = obj.getClass().getDeclaredFields();
|
||||
String[] fieldNames = new String[fields.length];
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
fieldNames[i] = fields[i].getName();
|
||||
}
|
||||
return fieldNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据属性名获取属性值
|
||||
*
|
||||
* @param fieldName 属性名称
|
||||
* @param obj 对象
|
||||
* @return 返回对应属性的值
|
||||
*/
|
||||
public Object getFieldValueByName(String fieldName, Object obj) {
|
||||
try {
|
||||
String firstLetter = fieldName.substring(0, 1).toUpperCase();
|
||||
String getter = new StringBuffer().append("get")
|
||||
.append(firstLetter)
|
||||
.append(fieldName.substring(1))
|
||||
.toString();
|
||||
Method method = obj.getClass().getMethod(getter, new Class[]{});
|
||||
return method.invoke(obj, new Object[]{});
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p> 京东支付 Api</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.jdpay;
|
||||
|
||||
|
||||
import com.zscat.mallplus.core.kit.HttpKit;
|
||||
|
||||
public class JdPayApi {
|
||||
/**
|
||||
* PC 在线支付接口
|
||||
*/
|
||||
public static String PC_SAVE_ORDER_URL = "https://wepay.jd.com/jdpay/saveOrder";
|
||||
/**
|
||||
* H5 在线支付接口
|
||||
*/
|
||||
public static String H5_SAVE_ORDER_URL = "https://h5pay.jd.com/jdpay/saveOrder";
|
||||
/**
|
||||
* 统一下单接口
|
||||
*/
|
||||
public static String UNI_ORDER_URL = "https://paygate.jd.com/service/uniorder";
|
||||
/**
|
||||
* 商户二维码支付接口
|
||||
*/
|
||||
public static String CUSTOMER_PAY_URL = "https://h5pay.jd.com/jdpay/customerPay";
|
||||
/**
|
||||
* 付款码支付接口
|
||||
*/
|
||||
public static String FKM_PAY_URL = "https://paygate.jd.com/service/fkmPay";
|
||||
|
||||
/**
|
||||
* 白条分期策略查询接口
|
||||
*/
|
||||
public static String QUERY_BAI_TIAO_FQ_URL = "https://paygate.jd.com/service/queryBaiTiaoFQ";
|
||||
|
||||
/**
|
||||
* 交易查询接口
|
||||
*/
|
||||
public static String QUERY_ORDER_URL = "https://paygate.jd.com/service/query";
|
||||
/**
|
||||
* 退款申请接口
|
||||
*/
|
||||
public static String REFUND_URL = "https://paygate.jd.com/service/refund";
|
||||
/**
|
||||
* 撤销申请接口
|
||||
*/
|
||||
public static String REVOKE_URL = "https://paygate.jd.com/service/revoke";
|
||||
/**
|
||||
* 用户关系查询接口
|
||||
*/
|
||||
public static String GET_USER_RELATION_URL = "https://paygate.jd.com/service/getUserRelation";
|
||||
/**
|
||||
* 用户关系解绑接口
|
||||
*/
|
||||
public static String CANCEL_USER_RELATION_URL = "https://paygate.jd.com/service/cancelUserRelation";
|
||||
|
||||
/**
|
||||
* 统一下单
|
||||
*
|
||||
* @param xml 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String uniOrder(String xml) {
|
||||
return doPost(UNI_ORDER_URL, xml);
|
||||
}
|
||||
|
||||
/**
|
||||
* 付款码支付
|
||||
*
|
||||
* @param xml 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String fkmPay(String xml) {
|
||||
return doPost(FKM_PAY_URL, xml);
|
||||
}
|
||||
|
||||
/**
|
||||
* 白条分期策略查询
|
||||
*
|
||||
* @param xml 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String queryBaiTiaoFq(String xml) {
|
||||
return doPost(QUERY_BAI_TIAO_FQ_URL, xml);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询订单
|
||||
*
|
||||
* @param xml 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String queryOrder(String xml) {
|
||||
return doPost(QUERY_ORDER_URL, xml);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款申请
|
||||
*
|
||||
* @param xml 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String refund(String xml) {
|
||||
return doPost(REFUND_URL, xml);
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤销申请
|
||||
*
|
||||
* @param xml 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String revoke(String xml) {
|
||||
return doPost(REVOKE_URL, xml);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户关系
|
||||
*
|
||||
* @param xml 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String getUserRelation(String xml) {
|
||||
return doPost(GET_USER_RELATION_URL, xml);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解除用户关系
|
||||
*
|
||||
* @param xml 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String cancelUserRelation(String xml) {
|
||||
return doPost(GET_USER_RELATION_URL, xml);
|
||||
}
|
||||
|
||||
public static String doPost(String url, String reqXml) {
|
||||
return HttpKit.getDelegate().post(url, reqXml);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.zscat.mallplus.jdpay;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、京东支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>京东支付常用配置</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class JdPayApiConfig implements Serializable {
|
||||
private static final long serialVersionUID = -9044503427692786302L;
|
||||
|
||||
private String appId;
|
||||
private String mchId;
|
||||
private String rsaPrivateKey;
|
||||
private String rsaPublicKey;
|
||||
private String desKey;
|
||||
private String domain;
|
||||
private String certPath;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.zscat.mallplus.jdpay;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、京东支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>京东支付常用配置 Kit</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public class JdPayApiConfigKit {
|
||||
|
||||
private static final ThreadLocal<String> TL = new ThreadLocal<String>();
|
||||
|
||||
private static final Map<String, JdPayApiConfig> CFG_MAP = new ConcurrentHashMap<String, JdPayApiConfig>();
|
||||
private static final String DEFAULT_CFG_KEY = "_default_key_";
|
||||
|
||||
/**
|
||||
* 添加微信支付配置,每个appId只需添加一次,相同appId将被覆盖
|
||||
*
|
||||
* @param jdPayApiConfig 微信支付配置
|
||||
* @return {WxPayApiConfig} 微信支付配置
|
||||
*/
|
||||
public static JdPayApiConfig putApiConfig(JdPayApiConfig jdPayApiConfig) {
|
||||
if (CFG_MAP.size() == 0) {
|
||||
CFG_MAP.put(DEFAULT_CFG_KEY, jdPayApiConfig);
|
||||
}
|
||||
return CFG_MAP.put(jdPayApiConfig.getAppId(), jdPayApiConfig);
|
||||
}
|
||||
|
||||
public static JdPayApiConfig setThreadLocalJdPayApiConfig(JdPayApiConfig jdPayApiConfig) {
|
||||
if (StrUtil.isNotEmpty(jdPayApiConfig.getAppId())) {
|
||||
setThreadLocalAppId(jdPayApiConfig.getAppId());
|
||||
}
|
||||
return putApiConfig(jdPayApiConfig);
|
||||
}
|
||||
|
||||
public static JdPayApiConfig removeApiConfig(JdPayApiConfig jdPayApiConfig) {
|
||||
return removeApiConfig(jdPayApiConfig.getAppId());
|
||||
}
|
||||
|
||||
public static JdPayApiConfig removeApiConfig(String appId) {
|
||||
return CFG_MAP.remove(appId);
|
||||
}
|
||||
|
||||
public static void setThreadLocalAppId(String appId) {
|
||||
if (StrUtil.isEmpty(appId)) {
|
||||
appId = CFG_MAP.get(DEFAULT_CFG_KEY).getAppId();
|
||||
}
|
||||
TL.set(appId);
|
||||
}
|
||||
|
||||
public static void removeThreadLocalAppId() {
|
||||
TL.remove();
|
||||
}
|
||||
|
||||
public static String getAppId() {
|
||||
String appId = TL.get();
|
||||
if (StrUtil.isEmpty(appId)) {
|
||||
appId = CFG_MAP.get(DEFAULT_CFG_KEY).getAppId();
|
||||
}
|
||||
return appId;
|
||||
}
|
||||
|
||||
public static JdPayApiConfig getJdPayApiConfig() {
|
||||
String appId = getAppId();
|
||||
return getApiConfig(appId);
|
||||
}
|
||||
|
||||
public static JdPayApiConfig getApiConfig(String appId) {
|
||||
JdPayApiConfig cfg = CFG_MAP.get(appId);
|
||||
if (cfg == null) {
|
||||
throw new IllegalStateException("需事先调用 JdPayApiConfigKit.putApiConfig(jdPayApiConfig) 将 appId 对应的 jdPayApiConfig 对象存入,才可以使用 JdPayApiConfigKit.getJdPayApiConfig() 的系列方法");
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>京东支付 Kit</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.jdpay.kit;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.XmlUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import com.zscat.mallplus.core.kit.WxPayKit;
|
||||
import com.zscat.mallplus.jdpay.util.SignUtil;
|
||||
import com.zscat.mallplus.jdpay.util.ThreeDesUtil;
|
||||
import com.zscat.mallplus.jdpay.util.XmlEncryptUtil;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class JdPayKit {
|
||||
/**
|
||||
* MD5 加密
|
||||
*
|
||||
* @param data 需要加密的数据
|
||||
* @return 加密后的数据
|
||||
*/
|
||||
public static String md5LowerCase(String data) {
|
||||
return SecureUtil.md5(data).toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求参数 Map 转化为京东支付 xml
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @return
|
||||
*/
|
||||
public static String toJdXml(Map<String, String> params) {
|
||||
return WxPayKit.forEachMap(params, "<jdpay>", "</jdpay>").toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求参数签名
|
||||
*
|
||||
* @param rsaPrivateKey RSA 私钥
|
||||
* @param strDesKey DES 密钥
|
||||
* @param genSignStr xml 数据
|
||||
* @return 签名后的数据
|
||||
*/
|
||||
public static String encrypt(String rsaPrivateKey, String strDesKey, String genSignStr) {
|
||||
return XmlEncryptUtil.encrypt(rsaPrivateKey, strDesKey, genSignStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密接口返回的 xml 数据
|
||||
*
|
||||
* @param rsaPubKey RSA 公钥
|
||||
* @param strDesKey DES 密钥
|
||||
* @param encrypt 加密的 xml 数据
|
||||
* @return 解密后的数据
|
||||
*/
|
||||
public static String decrypt(String rsaPubKey, String strDesKey, String encrypt) {
|
||||
return XmlEncryptUtil.decrypt(rsaPubKey, strDesKey, encrypt);
|
||||
}
|
||||
|
||||
/**
|
||||
* 明文验证签名
|
||||
*
|
||||
* @param rsaPubKey RSA 公钥
|
||||
* @param reqBody xml 数据
|
||||
* @return 明文数据
|
||||
*/
|
||||
public static String decrypt(String rsaPubKey, String reqBody) {
|
||||
return XmlEncryptUtil.decrypt(rsaPubKey, reqBody);
|
||||
}
|
||||
|
||||
public static String signRemoveSelectedKeys(Map<String, String> map, String rsaPriKey, List<String> unSignKeyList) {
|
||||
return SignUtil.signRemoveSelectedKeys(map, rsaPriKey, unSignKeyList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 3DES加密
|
||||
*
|
||||
* @param desKey DES 密钥
|
||||
* @param sourceData 需要加密的字符串
|
||||
* @return 加密后的字符串
|
||||
*/
|
||||
public static String threeDesEncrypt(String desKey, String sourceData) {
|
||||
byte[] key = Base64.decode(desKey);
|
||||
return ThreeDesUtil.encrypt2HexStr(key, sourceData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 3DES解密
|
||||
*
|
||||
* @param desKey DES 密钥
|
||||
* @param sourceData 需要解密的字符串
|
||||
* @return 解密后的字符串
|
||||
*/
|
||||
public static String threeDecDecrypt(String desKey, String sourceData) {
|
||||
byte[] key = Base64.decode(desKey);
|
||||
return ThreeDesUtil.decrypt4HexStr(key, sourceData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>在线支付接口</p>
|
||||
* <p>除了merchant(商户号)、version(版本号)、sign(签名)以外,其余字段全部采用3DES进行加密。</p>
|
||||
*
|
||||
* @return 转化后的 Map
|
||||
*/
|
||||
public static Map<String, String> threeDesToMap(Map<String, String> map, String desKey) {
|
||||
|
||||
HashMap<String, String> tempMap = new HashMap<String, String>(map.size());
|
||||
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
if (StrUtil.isNotEmpty(value)) {
|
||||
if ("merchant".equals(name) || "version".equals(name) || "sign".equals(name)) {
|
||||
tempMap.put(name, value);
|
||||
} else {
|
||||
tempMap.put(name, threeDesEncrypt(desKey, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
return tempMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将支付接口返回的 xml 数据转化为 Map
|
||||
*
|
||||
* @param xml 接口返回的 xml 数据
|
||||
* @return 解析后的数据
|
||||
*/
|
||||
public static Map<String, String> parseResp(String xml) {
|
||||
if (StrUtil.isEmpty(xml)) {
|
||||
return null;
|
||||
}
|
||||
Map<String, String> map = new HashMap<String, String>(3);
|
||||
Document docResult = XmlUtil.parseXml(xml);
|
||||
String code = (String) XmlUtil.getByXPath("//jdpay/result/code", docResult, XPathConstants.STRING);
|
||||
String desc = (String) XmlUtil.getByXPath("//jdpay/result/desc", docResult, XPathConstants.STRING);
|
||||
map.put("code", code);
|
||||
map.put("desc", desc);
|
||||
if ("000000".equals(code)) {
|
||||
String encrypt = (String) XmlUtil.getByXPath("//jdpay/encrypt", docResult, XPathConstants.STRING);
|
||||
map.put("encrypt", encrypt);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>商户二维码支付接口 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.jdpay.model;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class CustomerPayModel extends JdBaseModel {
|
||||
private String version;
|
||||
private String sign;
|
||||
private String merchant;
|
||||
private String payMerchant;
|
||||
private String device;
|
||||
private String tradeNum;
|
||||
private String tradeName;
|
||||
private String tradeDesc;
|
||||
private String tradeTime;
|
||||
private String amount;
|
||||
private String orderType;
|
||||
private String industryCategoryCode;
|
||||
private String currency;
|
||||
private String note;
|
||||
private String callbackUrl;
|
||||
private String notifyUrl;
|
||||
private String ip;
|
||||
private String expireTime;
|
||||
private String riskInfo;
|
||||
private String goodsInfo;
|
||||
private String bizTp;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>付款码支付接口 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.jdpay.model;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class FkmModel extends JdBaseModel {
|
||||
private String token;
|
||||
private String version;
|
||||
private String merchant;
|
||||
private String device;
|
||||
private String tradeNum;
|
||||
private String tradeName;
|
||||
private String tradeDesc;
|
||||
private String tradeTime;
|
||||
private String amount;
|
||||
private String industryCategoryCode;
|
||||
private String currency;
|
||||
private String note;
|
||||
private String notifyUrl;
|
||||
private String orderGoodsNum;
|
||||
private String vendorId;
|
||||
private String goodsInfoList;
|
||||
private String receiverInfo;
|
||||
private String termInfo;
|
||||
private String payMerchant;
|
||||
private String sign;
|
||||
private String riskInfo;
|
||||
private String bizTp;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>Model 公用方法</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.jdpay.model;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import com.zscat.mallplus.jdpay.kit.JdPayKit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
public class JdBaseModel extends BaseModel {
|
||||
/**
|
||||
* 自动生成请求接口的 xml
|
||||
*
|
||||
* @param rsaPrivateKey RSA 私钥
|
||||
* @param strDesKey DES 密钥
|
||||
* @param version 版本号
|
||||
* @param merchant 商户号
|
||||
* @return 生成的 xml 数据
|
||||
*/
|
||||
public String genReqXml(String rsaPrivateKey, String strDesKey, String version, String merchant) {
|
||||
|
||||
if (StrUtil.isEmpty(version) || StrUtil.isEmpty(merchant)) {
|
||||
throw new RuntimeException("version or merchant is empty");
|
||||
}
|
||||
String encrypt = JdPayKit.encrypt(rsaPrivateKey, strDesKey, JdPayKit.toJdXml(toMap()));
|
||||
Map<String, String> requestMap = JdRequestModel.builder()
|
||||
.version(version)
|
||||
.merchant(merchant)
|
||||
.encrypt(encrypt)
|
||||
.build()
|
||||
.toMap();
|
||||
return JdPayKit.toJdXml(requestMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* PC H5 支付创建签名
|
||||
*
|
||||
* @param rsaPrivateKey RSA 私钥
|
||||
* @param strDesKey DES 密钥
|
||||
* @return 生成签名后的 Map
|
||||
*/
|
||||
public Map<String, String> createSign(String rsaPrivateKey, String strDesKey) {
|
||||
Map<String, String> map = toMap();
|
||||
// 生成签名
|
||||
String sign = JdPayKit.signRemoveSelectedKeys(map, rsaPrivateKey, new ArrayList<String>());
|
||||
map.put("sign", sign);
|
||||
// 3DES进行加密
|
||||
return JdPayKit.threeDesToMap(map, strDesKey);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>请求参数 Model </p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.jdpay.model;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class JdRequestModel extends JdBaseModel {
|
||||
private String version;
|
||||
private String merchant;
|
||||
private String encrypt;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>白条分期策略查询接口 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.jdpay.model;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class QueryBaiTiaoFqModel extends JdBaseModel {
|
||||
private String version;
|
||||
private String merchant;
|
||||
private String tradeNum;
|
||||
private String amount;
|
||||
private String sign;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>交易查询接口 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.jdpay.model;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class QueryOrderModel extends JdBaseModel {
|
||||
private String version;
|
||||
private String merchant;
|
||||
private String tradeNum;
|
||||
private String oTradeNum;
|
||||
private String tradeType;
|
||||
private String sign;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>退款申请接口 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.jdpay.model;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class RefundModel extends JdBaseModel {
|
||||
private String version;
|
||||
private String merchant;
|
||||
private String tradeNum;
|
||||
private String oTradeNum;
|
||||
private String amount;
|
||||
private String currency;
|
||||
private String tradeTime;
|
||||
private String notifyUrl;
|
||||
private String note;
|
||||
private String sign;
|
||||
private String device;
|
||||
private String termInfoId;
|
||||
private String cert;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>撤销申请接口 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.jdpay.model;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class RevokeModel extends JdBaseModel {
|
||||
private String version;
|
||||
private String merchant;
|
||||
private String tradeNum;
|
||||
private String oTradeNum;
|
||||
private String amount;
|
||||
private String currency;
|
||||
private String tradeTime;
|
||||
private String note;
|
||||
private String sign;
|
||||
private String cert;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p> 在线支付接口 </p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.jdpay.model;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class SaveOrderModel extends JdBaseModel {
|
||||
private String version;
|
||||
private String sign;
|
||||
private String merchant;
|
||||
private String payMerchant;
|
||||
private String device;
|
||||
private String tradeNum;
|
||||
private String tradeName;
|
||||
private String tradeDesc;
|
||||
private String tradeTime;
|
||||
private String amount;
|
||||
private String orderType;
|
||||
private String industryCategoryCode;
|
||||
private String currency;
|
||||
private String note;
|
||||
private String callbackUrl;
|
||||
private String notifyUrl;
|
||||
private String ip;
|
||||
private String specCardNo;
|
||||
private String specId;
|
||||
private String specName;
|
||||
private String userId;
|
||||
private String expireTime;
|
||||
private String orderGoodsNum;
|
||||
private String vendorId;
|
||||
private String goodsInfo;
|
||||
private String receiverInfo;
|
||||
private String termInfo;
|
||||
private String riskInfo;
|
||||
private String settleCurrency;
|
||||
private String kjInfo;
|
||||
private String installmentNum;
|
||||
private String preProduct;
|
||||
private String bizTp;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p> 统一下单接口 </p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.jdpay.model;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class UniOrderModel extends JdBaseModel {
|
||||
private String version;
|
||||
private String sign;
|
||||
private String merchant;
|
||||
private String payMerchant;
|
||||
private String device;
|
||||
private String tradeNum;
|
||||
private String tradeName;
|
||||
private String tradeDesc;
|
||||
private String tradeTime;
|
||||
private String amount;
|
||||
private String orderType;
|
||||
private String industryCategoryCode;
|
||||
private String currency;
|
||||
private String note;
|
||||
private String callbackUrl;
|
||||
private String notifyUrl;
|
||||
private String ip;
|
||||
private String specCardNo;
|
||||
private String specId;
|
||||
private String specName;
|
||||
private String tradeType;
|
||||
private String expireTime;
|
||||
private String orderGoodsNum;
|
||||
private String vendorId;
|
||||
private String goodsInfo;
|
||||
private String receiverInfo;
|
||||
private String termInfo;
|
||||
private String riskInfo;
|
||||
private String installmentNum;
|
||||
private String preProduct;
|
||||
private String bizTp;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>用户关系 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.jdpay.model;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class UserRelationModel extends JdBaseModel {
|
||||
private String version;
|
||||
private String merchant;
|
||||
private String userId;
|
||||
private String sign;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.zscat.mallplus.jdpay.util;
|
||||
|
||||
import java.util.Scanner;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class JdPayXmlUtil {
|
||||
private static String XML_HEAD = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
|
||||
private static String XML_JDPAY_START = "<jdpay>";
|
||||
private static String XML_JDPAY_END = "</jdpay>";
|
||||
private static Pattern PATTERN = Pattern.compile("\t|\r|\n");
|
||||
|
||||
public static String fomatXmlStr(String xml) {
|
||||
StringBuilder formatStr = new StringBuilder();
|
||||
Scanner scanner = new Scanner(xml);
|
||||
scanner.useDelimiter(PATTERN);
|
||||
while (scanner.hasNext()) {
|
||||
formatStr.append(scanner.next().trim());
|
||||
}
|
||||
return formatStr.toString();
|
||||
}
|
||||
|
||||
|
||||
public static String addXmlHead(String xml) {
|
||||
if (xml != null && !"".equals(xml) &&
|
||||
!xml.trim().startsWith("<?xml")) {
|
||||
xml = XML_HEAD + xml;
|
||||
}
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
|
||||
public static String addXmlHeadAndElJdPay(String xml) {
|
||||
if (xml != null && !"".equals(xml)) {
|
||||
if (!xml.contains(XML_JDPAY_START)) {
|
||||
xml = XML_JDPAY_START + xml;
|
||||
}
|
||||
if (!xml.contains(XML_JDPAY_END)) {
|
||||
xml = xml + XML_JDPAY_END;
|
||||
}
|
||||
if (!xml.trim().startsWith("<?xml")) {
|
||||
xml = XML_HEAD + xml;
|
||||
}
|
||||
}
|
||||
return xml;
|
||||
}
|
||||
|
||||
|
||||
public static String getXmlElm(String xml, String elName) {
|
||||
String result = "";
|
||||
String elStart = "<" + elName + ">";
|
||||
String elEnd = "</" + elName + ">";
|
||||
if (xml.contains(elStart) && xml.contains(elEnd)) {
|
||||
int from = xml.indexOf(elStart) + elStart.length();
|
||||
int to = xml.lastIndexOf(elEnd);
|
||||
result = xml.substring(from, to);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static String delXmlElm(String xml, String elmName) {
|
||||
String elStart = "<" + elmName + ">";
|
||||
String elEnd = "</" + elmName + ">";
|
||||
if (xml.contains(elStart) && xml.contains(elEnd)) {
|
||||
int i1 = xml.indexOf(elStart);
|
||||
int i2 = xml.lastIndexOf(elEnd);
|
||||
String start = xml.substring(0, i1);
|
||||
int length = elEnd.length();
|
||||
String end = xml.substring(i2 + length, xml.length());
|
||||
xml = start + end;
|
||||
}
|
||||
return xml;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
package com.zscat.mallplus.jdpay.util;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.security.*;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class RSACoder extends RsaUtil {
|
||||
public static final String KEY_ALGORITHM = "RSA";
|
||||
public static final String KEY_ALGORITHM_DETAIL = "RSA/ECB/PKCS1Padding";
|
||||
public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
|
||||
public static final String PUBLIC_KEY = "RSAPublicKey";
|
||||
public static final String PRIVATE_KEY = "RSAPrivateKey";
|
||||
|
||||
public static String sign(byte[] data, String privateKey) throws Exception {
|
||||
byte[] keyBytes = decryptBASE64(privateKey);
|
||||
|
||||
|
||||
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
|
||||
|
||||
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
|
||||
|
||||
PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
|
||||
|
||||
|
||||
Signature signature = Signature.getInstance("MD5withRSA");
|
||||
signature.initSign(priKey);
|
||||
signature.update(data);
|
||||
|
||||
return encryptBASE64(signature.sign());
|
||||
}
|
||||
|
||||
|
||||
public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
|
||||
byte[] keyBytes = decryptBASE64(publicKey);
|
||||
|
||||
|
||||
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
|
||||
|
||||
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
|
||||
|
||||
PublicKey pubKey = keyFactory.generatePublic(keySpec);
|
||||
|
||||
Signature signature = Signature.getInstance("MD5withRSA");
|
||||
signature.initVerify(pubKey);
|
||||
signature.update(data);
|
||||
|
||||
|
||||
return signature.verify(decryptBASE64(sign));
|
||||
}
|
||||
|
||||
|
||||
public static byte[] decryptByPrivateKey(byte[] data, String key) throws Exception {
|
||||
byte[] keyBytes = decryptBASE64(key);
|
||||
|
||||
|
||||
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
|
||||
|
||||
|
||||
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||
cipher.init(2, privateKey);
|
||||
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
|
||||
public static byte[] decryptByPublicKey(byte[] data, String key) throws Exception {
|
||||
byte[] keyBytes = decryptBASE64(key);
|
||||
|
||||
|
||||
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
Key publicKey = keyFactory.generatePublic(x509KeySpec);
|
||||
|
||||
|
||||
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||
cipher.init(2, publicKey);
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
|
||||
public static byte[] encryptByPublicKey(byte[] data, String key) throws Exception {
|
||||
byte[] keyBytes = decryptBASE64(key);
|
||||
|
||||
|
||||
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
Key publicKey = keyFactory.generatePublic(x509KeySpec);
|
||||
|
||||
|
||||
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||
cipher.init(1, publicKey);
|
||||
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
|
||||
public static byte[] encryptByPrivateKey(byte[] data, String key) throws Exception {
|
||||
byte[] keyBytes = decryptBASE64(key);
|
||||
|
||||
|
||||
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
|
||||
|
||||
|
||||
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||
cipher.init(1, privateKey);
|
||||
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
|
||||
public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {
|
||||
Key key = (Key) keyMap.get("RSAPrivateKey");
|
||||
|
||||
return encryptBASE64(key.getEncoded());
|
||||
}
|
||||
|
||||
|
||||
public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
|
||||
Key key = (Key) keyMap.get("RSAPublicKey");
|
||||
|
||||
return encryptBASE64(key.getEncoded());
|
||||
}
|
||||
|
||||
|
||||
public static Map<String, Object> initKey() throws Exception {
|
||||
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen.initialize(1024);
|
||||
KeyPair keyPair = keyPairGen.generateKeyPair();
|
||||
|
||||
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
|
||||
|
||||
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
|
||||
Map<String, Object> keyMap = new HashMap<String, Object>(2);
|
||||
keyMap.put("RSAPublicKey", publicKey);
|
||||
keyMap.put("RSAPrivateKey", privateKey);
|
||||
return keyMap;
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
FileOutputStream fop = null;
|
||||
|
||||
StringBuilder content = new StringBuilder("");
|
||||
|
||||
|
||||
try {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
|
||||
Map<String, Object> map = initKey();
|
||||
|
||||
|
||||
String pk = getPublicKey(map).replace("\r\n", "");
|
||||
String sk = getPrivateKey(map).replace("\r\n", "");
|
||||
content.append("publicKey:");
|
||||
content.append(pk);
|
||||
content.append("\n\n");
|
||||
content.append("privateKey:");
|
||||
content.append(sk);
|
||||
content.append("\n\n\n");
|
||||
}
|
||||
|
||||
|
||||
File file = new File("E:/<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>/<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>/key.txt");
|
||||
fop = new FileOutputStream(file);
|
||||
|
||||
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
|
||||
|
||||
byte[] contentInBytes = content.toString().getBytes();
|
||||
|
||||
fop.write(contentInBytes);
|
||||
fop.flush();
|
||||
fop.close();
|
||||
|
||||
System.out.println("Done");
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.zscat.mallplus.jdpay.util;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
|
||||
public class RsaUtil {
|
||||
public static final String KEY_MAC = "HmacMD5";
|
||||
private static final String KEY_SHA = "SHA";
|
||||
private static final String KEY_MD5 = "MD5";
|
||||
private static String hexString = "0123456789ABCDEF";
|
||||
|
||||
public static byte[] decryptBASE64(String key) throws Exception {
|
||||
return Base64.decodeBase64(key);
|
||||
}
|
||||
|
||||
|
||||
public static String encryptBASE64(byte[] key) throws Exception {
|
||||
return Base64.encodeBase64String(key);
|
||||
}
|
||||
|
||||
|
||||
public static byte[] encryptMD5(byte[] data) throws Exception {
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
md5.update(data);
|
||||
return md5.digest();
|
||||
}
|
||||
|
||||
|
||||
public static byte[] encryptSHA(byte[] data) throws Exception {
|
||||
MessageDigest sha = MessageDigest.getInstance("SHA");
|
||||
sha.update(data);
|
||||
return sha.digest();
|
||||
}
|
||||
|
||||
|
||||
public static String initMacKey() throws Exception {
|
||||
KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5");
|
||||
SecretKey secretKey = keyGenerator.generateKey();
|
||||
return encryptBASE64(secretKey.getEncoded());
|
||||
}
|
||||
|
||||
|
||||
public static byte[] encryptHMAC(byte[] data, String key) throws Exception {
|
||||
SecretKey secretKey = new SecretKeySpec(decryptBASE64(key), "HmacMD5");
|
||||
Mac mac = Mac.getInstance(secretKey.getAlgorithm());
|
||||
mac.init(secretKey);
|
||||
return mac.doFinal(data);
|
||||
}
|
||||
|
||||
|
||||
public static String bytesToString(byte[] src) throws Exception {
|
||||
StringBuilder stringBuilder = new StringBuilder("");
|
||||
if (src == null || src.length <= 0) {
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < src.length; i++) {
|
||||
int v = src[i] & 0xFF;
|
||||
String hv = Integer.toHexString(v);
|
||||
if (hv.length() < 2) {
|
||||
stringBuilder.append(0);
|
||||
}
|
||||
stringBuilder.append(hv);
|
||||
}
|
||||
String bytes = stringBuilder.toString();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(bytes.length() / 2);
|
||||
|
||||
for (int i = 0; i < bytes.length(); i += 2)
|
||||
baos.write(hexString.indexOf(bytes.charAt(i)) << 4 | hexString.indexOf(bytes.charAt(i + 1)));
|
||||
return new String(baos.toByteArray());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.zscat.mallplus.jdpay.util;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public class SHAUtil {
|
||||
public static String Encrypt(String strSrc, String encName) {
|
||||
MessageDigest md = null;
|
||||
String strDes = null;
|
||||
byte[] bt = new byte[0];
|
||||
try {
|
||||
bt = strSrc.getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
if (encName == null || encName.equals("")) {
|
||||
encName = "SHA-256";
|
||||
}
|
||||
md = MessageDigest.getInstance(encName);
|
||||
md.update(bt);
|
||||
strDes = bytes2Hex(md.digest());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return null;
|
||||
}
|
||||
return strDes;
|
||||
}
|
||||
|
||||
public static String bytes2Hex(byte[] bts) {
|
||||
String des = "";
|
||||
String tmp = null;
|
||||
for (int i = 0; i < bts.length; i++) {
|
||||
tmp = Integer.toHexString(bts[i] & 0xFF);
|
||||
if (tmp.length() == 1) {
|
||||
des = des + "0";
|
||||
}
|
||||
des = des + tmp;
|
||||
}
|
||||
return des;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package com.zscat.mallplus.jdpay.util;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
|
||||
public class SignUtil {
|
||||
private static List<String> unSignKeyList = Arrays.asList(new String[]{"merchantSign", "token", "version"});
|
||||
|
||||
public static String sign4SelectedKeys(Object object, String rsaPriKey, List<String> signKeyList) {
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
String sourceSignString = signString4SelectedKeys(object, signKeyList);
|
||||
String sha256SourceSignString = SHAUtil.Encrypt(sourceSignString, null);
|
||||
|
||||
byte[] newsks = RSACoder.encryptByPrivateKey(sha256SourceSignString.getBytes("UTF-8"), rsaPriKey);
|
||||
result = Base64.encodeBase64String(newsks);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("sign4SelectedKeys>error", e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static String signRemoveSelectedKeys(Object object, String rsaPriKey, List<String> signKeyList) {
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
String sourceSignString = signString(object, signKeyList);
|
||||
|
||||
String sha256SourceSignString = SHAUtil.Encrypt(sourceSignString, null);
|
||||
|
||||
byte[] newK = RSACoder.encryptByPrivateKey(sha256SourceSignString.getBytes("UTF-8"), rsaPriKey);
|
||||
result = Base64.encodeBase64String(newK);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static String signString(Object object, List<String> unSignKeyList) throws IllegalArgumentException, IllegalAccessException {
|
||||
TreeMap<String, Object> map = objectToMap(object);
|
||||
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (String str : unSignKeyList) {
|
||||
map.remove(str);
|
||||
}
|
||||
|
||||
Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, Object> entry = (Map.Entry) iterator.next();
|
||||
if (entry.getValue() == null) {
|
||||
continue;
|
||||
}
|
||||
String value = (String) entry.getValue();
|
||||
if (value.trim().length() > 0) {
|
||||
sb.append((String) entry.getKey()).append("=").append(entry.getValue()).append("&");
|
||||
}
|
||||
}
|
||||
|
||||
String result = sb.toString();
|
||||
if (result.endsWith("&")) {
|
||||
result = result.substring(0, result.length() - 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static String signString4SelectedKeys(Object object, List<String> signedKeyList) throws IllegalArgumentException, IllegalAccessException {
|
||||
TreeMap<String, Object> map = objectToMap(object);
|
||||
if (map == null || map.isEmpty() || signedKeyList == null || signedKeyList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TreeMap<String, Object> signMap = new TreeMap<String, Object>();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (String str : signedKeyList) {
|
||||
Object o = map.get(str);
|
||||
if (o != null) {
|
||||
signMap.put(str, o);
|
||||
continue;
|
||||
}
|
||||
signMap.put(str, "");
|
||||
}
|
||||
|
||||
|
||||
Iterator iterator = signMap.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) iterator.next();
|
||||
sb.append(entry.getKey() + "=" + (
|
||||
(entry.getValue() == null) ? "" : entry.getValue()) + "&");
|
||||
}
|
||||
|
||||
String result = sb.toString();
|
||||
if (result.endsWith("&")) {
|
||||
result = result.substring(0, result.length() - 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static TreeMap<String, Object> objectToMap(Object object) throws IllegalArgumentException, IllegalAccessException {
|
||||
TreeMap<String, Object> map = new TreeMap<String, Object>();
|
||||
if (object instanceof Map) {
|
||||
Map<String, Object> objectMap = (Map) object;
|
||||
for (String str : objectMap.keySet()) {
|
||||
map.put(str, objectMap.get(str));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
for (Class<?> cls = object.getClass(); cls != Object.class; cls = cls.getSuperclass()) {
|
||||
|
||||
Field[] fields = cls.getDeclaredFields();
|
||||
for (Field f : fields) {
|
||||
f.setAccessible(true);
|
||||
map.put(f.getName(), f.get(object));
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
public static String sign4PCString(Object object, List<String> unSignKeyList) throws IllegalArgumentException, IllegalAccessException {
|
||||
TreeMap<String, Object> map = objectToMap(object);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (String str : unSignKeyList) {
|
||||
map.remove(str);
|
||||
}
|
||||
|
||||
|
||||
Iterator iterator = map.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) iterator.next();
|
||||
sb.append(entry.getKey() + "=" + ((entry.getValue() == null) ? "" : entry.getValue()) + "&");
|
||||
}
|
||||
|
||||
String result = sb.toString();
|
||||
if (result.endsWith("&")) {
|
||||
result = result.substring(0, result.length() - 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.zscat.mallplus.jdpay.util;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
|
||||
public class SignatureUtil {
|
||||
public static void checkArguments(Map<String, String> merchantSignMap, List<String> signKeyList, String signData, String key) {
|
||||
if (merchantSignMap == null || merchantSignMap.isEmpty()) {
|
||||
throw new IllegalArgumentException("Argument 'merchantSignMap' is null or empty");
|
||||
}
|
||||
if (signKeyList == null || signKeyList.isEmpty()) {
|
||||
throw new IllegalArgumentException("Argument 'signKeyList' is null or empty");
|
||||
}
|
||||
if (signData == null || signData.isEmpty()) {
|
||||
throw new IllegalArgumentException("Argument 'signData' is null or empty");
|
||||
}
|
||||
if (key == null || key.isEmpty()) {
|
||||
throw new IllegalArgumentException("Argument 'key' is null or empty");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String generateSrcData(Map<String, String> merchantSignMap, List<String> signKeyList) {
|
||||
TreeMap<String, Object> signMap = new TreeMap<String, Object>();
|
||||
|
||||
for (String str : signKeyList) {
|
||||
Object o = merchantSignMap.get(str);
|
||||
if (o != null) {
|
||||
signMap.put(str, o);
|
||||
continue;
|
||||
}
|
||||
signMap.put(str, "");
|
||||
}
|
||||
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Iterator iterator = signMap.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) iterator.next();
|
||||
sb.append(entry.getKey() + "=" + ((entry.getValue() == null) ? "" : entry.getValue()) + "&");
|
||||
}
|
||||
|
||||
String result = sb.toString();
|
||||
if (result.endsWith("&")) {
|
||||
result = result.substring(0, result.length() - 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
package com.zscat.mallplus.jdpay.util;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
|
||||
public class ThreeDesUtil {
|
||||
public static final byte[] DEFAULT_KEY = {
|
||||
49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52};
|
||||
|
||||
|
||||
public static byte[] encrypt(byte[] keybyte, byte[] src) {
|
||||
try {
|
||||
SecretKey deskey = new SecretKeySpec(keybyte, "DESede");
|
||||
|
||||
Cipher c1 = Cipher.getInstance("DESede/ECB/NoPadding");
|
||||
c1.init(1, deskey);
|
||||
return c1.doFinal(src);
|
||||
} catch (NoSuchAlgorithmException e1) {
|
||||
e1.printStackTrace();
|
||||
} catch (NoSuchPaddingException e2) {
|
||||
e2.printStackTrace();
|
||||
} catch (Exception e3) {
|
||||
e3.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private static byte[] decrypt(byte[] keybyte, byte[] src) {
|
||||
try {
|
||||
SecretKey deskey = new SecretKeySpec(keybyte, "DESede");
|
||||
|
||||
Cipher c1 = Cipher.getInstance("DESede/ECB/NoPadding");
|
||||
c1.init(2, deskey);
|
||||
return c1.doFinal(src);
|
||||
} catch (NoSuchAlgorithmException e1) {
|
||||
e1.printStackTrace();
|
||||
} catch (NoSuchPaddingException e2) {
|
||||
e2.printStackTrace();
|
||||
} catch (Exception e3) {
|
||||
e3.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private static String byte2Hex(byte[] b) {
|
||||
String hs = "";
|
||||
String stmp = "";
|
||||
for (int n = 0; n < b.length; n++) {
|
||||
stmp = Integer.toHexString(b[n] & 0xFF);
|
||||
if (stmp.length() == 1) {
|
||||
hs = hs + "0" + stmp;
|
||||
} else {
|
||||
hs = hs + stmp;
|
||||
}
|
||||
if (n < b.length - 1) hs = hs + ":";
|
||||
}
|
||||
return hs.toUpperCase();
|
||||
}
|
||||
|
||||
|
||||
public static String encrypt2HexStr(byte[] keys, String sourceData) {
|
||||
try {
|
||||
byte[] source = sourceData.getBytes("UTF-8");
|
||||
int merchantData = source.length;
|
||||
int x = (merchantData + 4) % 8;
|
||||
int y = (x == 0) ? 0 : (8 - x);
|
||||
byte[] sizeByte = intToByteArray(merchantData);
|
||||
byte[] resultByte = new byte[merchantData + 4 + y];
|
||||
resultByte[0] = sizeByte[0];
|
||||
resultByte[1] = sizeByte[1];
|
||||
resultByte[2] = sizeByte[2];
|
||||
resultByte[3] = sizeByte[3];
|
||||
for (int i = 0; i < merchantData; i++) {
|
||||
resultByte[4 + i] = source[i];
|
||||
}
|
||||
for (int i = 0; i < y; i++) {
|
||||
resultByte[merchantData + 4 + i] = 0;
|
||||
}
|
||||
byte[] desdata = encrypt(keys, resultByte);
|
||||
return bytes2Hex(desdata);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String decrypt4HexStr(byte[] keys, String data) {
|
||||
byte[] hexSourceData = new byte[0];
|
||||
try {
|
||||
hexSourceData = hex2byte(data.getBytes("UTF-8"));
|
||||
byte[] unDesResult = decrypt(keys, hexSourceData);
|
||||
byte[] dataSizeByte = new byte[4];
|
||||
dataSizeByte[0] = unDesResult[0];
|
||||
dataSizeByte[1] = unDesResult[1];
|
||||
dataSizeByte[2] = unDesResult[2];
|
||||
dataSizeByte[3] = unDesResult[3];
|
||||
int dsb = byteArrayToInt(dataSizeByte, 0);
|
||||
if (dsb > 16384) {
|
||||
throw new RuntimeException("msg over MAX_MSG_LENGTH or msg error");
|
||||
}
|
||||
byte[] tempData = new byte[dsb];
|
||||
for (int i = 0; i < dsb; i++) {
|
||||
tempData[i] = unDesResult[4 + i];
|
||||
}
|
||||
return hex2bin(toHexString(tempData));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String hex2bin(String hex) throws UnsupportedEncodingException {
|
||||
String digital = "0123456789abcdef";
|
||||
char[] hex2char = hex.toCharArray();
|
||||
byte[] bytes = new byte[hex.length() / 2];
|
||||
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
int temp = digital.indexOf(hex2char[2 * i]) * 16;
|
||||
temp += digital.indexOf(hex2char[2 * i + 1]);
|
||||
bytes[i] = (byte) (temp & 0xFF);
|
||||
}
|
||||
|
||||
return new String(bytes, "UTF-8");
|
||||
}
|
||||
|
||||
|
||||
private static String toHexString(byte[] ba) {
|
||||
StringBuilder str = new StringBuilder();
|
||||
for (int i = 0; i < ba.length; i++) {
|
||||
str.append(String.format("%x", new Object[]{Byte.valueOf(ba[i])}));
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
|
||||
private static String bytes2Hex(byte[] bts) {
|
||||
String des = "";
|
||||
String tmp = null;
|
||||
for (int i = 0; i < bts.length; i++) {
|
||||
tmp = Integer.toHexString(bts[i] & 0xFF);
|
||||
if (tmp.length() == 1) {
|
||||
des = des + "0";
|
||||
}
|
||||
des = des + tmp;
|
||||
}
|
||||
return des;
|
||||
}
|
||||
|
||||
public static byte[] hex2byte(byte[] b) {
|
||||
if (b.length % 2 != 0) {
|
||||
throw new IllegalArgumentException("长度不是偶数");
|
||||
}
|
||||
byte[] b2 = new byte[b.length / 2];
|
||||
for (int n = 0; n < b.length; n += 2) {
|
||||
String item = new String(b, n, 2);
|
||||
|
||||
b2[n / 2] = (byte) Integer.parseInt(item, 16);
|
||||
}
|
||||
b = null;
|
||||
return b2;
|
||||
}
|
||||
|
||||
|
||||
private static byte[] intToByteArray(int i) {
|
||||
byte[] result = new byte[4];
|
||||
result[0] = (byte) (i >> 24 & 0xFF);
|
||||
result[1] = (byte) (i >> 16 & 0xFF);
|
||||
result[2] = (byte) (i >> 8 & 0xFF);
|
||||
result[3] = (byte) (i & 0xFF);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static int byteArrayToInt(byte[] b, int offset) {
|
||||
int value = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int shift = (3 - i) * 8;
|
||||
value += ((b[i + offset] & 0xFF) << shift);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
String szSrc = "This is a 3DES test. 测试abcdf";
|
||||
System.out.println("加密前的字符串:" + szSrc);
|
||||
byte[] encoded = new byte[0];
|
||||
try {
|
||||
System.out.println("加密前长度:" + szSrc.getBytes("UTF-8").length);
|
||||
System.out.println("加密前HEX:" + bytes2Hex(szSrc.getBytes("UTF-8")));
|
||||
encoded = encrypt(DEFAULT_KEY, szSrc.getBytes("UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
System.out.println("加密后长度:" + encoded.length);
|
||||
System.out.println("加密后的字符串:" + new String(encoded, "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
byte[] srcBytes = decrypt(DEFAULT_KEY, encoded);
|
||||
|
||||
System.out.println("解密后HEX:" + bytes2Hex(srcBytes));
|
||||
System.out.println("解密后的字符串:" + new String(srcBytes));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.zscat.mallplus.jdpay.util;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
|
||||
public class VerifySignatureUtl {
|
||||
|
||||
public static String encryptMerchant(String sourceSignString, String rsaPriKey) {
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
String sha256SourceSignString = SHAUtil.Encrypt(sourceSignString, null);
|
||||
|
||||
byte[] newsks = RSACoder.encryptByPrivateKey(sha256SourceSignString.getBytes("UTF-8"), rsaPriKey);
|
||||
result = Base64.encodeBase64String(newsks);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("verify signature failed.", e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static boolean decryptMerchant(String strSourceData, String signData, String rsaPubKey) {
|
||||
if (signData == null || signData.isEmpty()) {
|
||||
throw new IllegalArgumentException("Argument 'signData' is null or empty");
|
||||
}
|
||||
if (rsaPubKey == null || rsaPubKey.isEmpty()) {
|
||||
throw new IllegalArgumentException("Argument 'key' is null or empty");
|
||||
}
|
||||
|
||||
try {
|
||||
String sha256SourceSignString = SHAUtil.Encrypt(strSourceData, null);
|
||||
|
||||
byte[] signByte = Base64.decodeBase64(signData);
|
||||
|
||||
byte[] decryptArr = RSACoder.decryptByPublicKey(signByte, rsaPubKey);
|
||||
|
||||
String decryptStr = RSACoder.bytesToString(decryptArr);
|
||||
if (sha256SourceSignString.equals(decryptStr)) {
|
||||
return true;
|
||||
} else {
|
||||
throw new RuntimeException("Signature verification failed.");
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("verify signature failed.", e);
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("verify signature failed.", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String rsaPubKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+tBTL7NrtsYpAmwDVqIUECPpZTpxa6GzIfk85J/7BlchTVQQZsk/Ho/umuqNvG9lRpTD/qDhkUo6ybqsu6cDCajL1j8UppjI06m4vxWJiTSX2JnBB63/CcJ+TxSTdmwkHbIlyX4jKrryU4kgw1fZuNzQl3HKf8B169FENOTgGJQIDAQAB";
|
||||
String rsaPriKey = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAL60FMvs2u2xikCbANWohQQI+llOnFrobMh+Tzkn/sGVyFNVBBmyT8ej+6a6o28b2VGlMP+oOGRSjrJuqy7pwMJqMvWPxSmmMjTqbi/FYmJNJfYmcEHrf8Jwn5PFJN2bCQdsiXJfiMquvJTiSDDV9m43NCXccp/wHXr0UQ05OAYlAgMBAAECgYEAhBrNeUKXmibtxblah6eYlWX+vtT0/QibKvxMtyRclw/CWO/Aymg6WerfzezmgHaDQcq0ObX3co+6KCL/1Jy7GP/Hk32BgfFpbp90PtQXGjVp03wUobJUBlGFfIxQjnIPUMT145z7aYN0u+ycz17IhA6K3M0QSn39VaOxpp37XcECQQDp6Xfj5dZ1TPcnPMRnSbARwo6fluMmCSRKffO032UOThZkE8un5nD5VhI3KCEllhB6LiIeG35CR5yf++lBUcbRAkEA0LYZnUu8WeNaHwAlKshvquiPzk3xugjum3Gld3wrY6neMSP1F84pbGumpIMnUuglWtKaWPD5anC8sAlF6qMHFQJAFAif8Q/lT0SZQm4M8D+6abr9FiQJLl/IEO06qzoa4J/FgSrE3Yt6D5DUnI6+UAbLQHulBmkaZjjV7EnaD3MekQJAJHOJabVugex5MuzdkOlMx3aylv959lnVAoUItyOSmGd0jPSQu8Wf6nWqtxTI62vsCj66Akqj5Pknmz8jXOV4OQJBANtNmkZH79AQl3heWHnFsr6pPyiZwVopHphzifjddHu3Mvu8/nwQvgXGRu+2vXeUGGhVRlw9W8YYRfNEFiQ+L3o=";
|
||||
String sourceData = "amount=16500&callbackUrl=http://fplocal.jd.com¤cy=CNY&device=111&expireTime=20190624205928&industryCategoryCode=20JD9601&ip=192.168.178.16&merchant=22318136¬e={\"merchantId\":\"22318136\",\"orderIdList\":[\"100560406493366\"]}¬ifyUrl=http://jdpaydemo.jd.com/asynNotify.htm&orderType=1&tradeDesc=<3D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>&tradeName=<3D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>&tradeNum=1005604093366&tradeTime=20190625144314&version=V2.0";
|
||||
|
||||
|
||||
String sha256SourceSignString = SHAUtil.Encrypt(sourceData, null);
|
||||
byte[] newsks = RSACoder.encryptByPrivateKey(sha256SourceSignString.getBytes("UTF-8"), rsaPriKey);
|
||||
String sign = Base64.encodeBase64String(newsks);
|
||||
System.out.println(sign);
|
||||
|
||||
|
||||
boolean result = decryptMerchant(sourceData, sign, rsaPubKey);
|
||||
System.out.println(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.zscat.mallplus.jdpay.util;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
|
||||
public class XmlEncryptUtil {
|
||||
private static String XML_JDPAY_END = "</jdpay>";
|
||||
private static String XML_SIGN_START = "<sign>";
|
||||
private static String XML_SIGN_END = "</sign>";
|
||||
private static String SIGN = "sign";
|
||||
private static String RESULT = "result";
|
||||
|
||||
|
||||
public static String encrypt(String rsaPrivateKey, String strDesKey, String genSignStr) {
|
||||
System.out.println("genSignStr>" + genSignStr);
|
||||
String encrypt = null;
|
||||
if (StrUtil.isNotEmpty(rsaPrivateKey) && StrUtil.isNotEmpty(strDesKey) && StrUtil.isNotEmpty(genSignStr)) {
|
||||
|
||||
try {
|
||||
genSignStr = JdPayXmlUtil.addXmlHeadAndElJdPay(genSignStr);
|
||||
|
||||
genSignStr = JdPayXmlUtil.fomatXmlStr(genSignStr);
|
||||
|
||||
genSignStr = JdPayXmlUtil.delXmlElm(genSignStr, SIGN);
|
||||
|
||||
String sign = VerifySignatureUtl.encryptMerchant(genSignStr, rsaPrivateKey);
|
||||
System.out.println("sign>" + sign);
|
||||
String data = genSignStr.substring(0, genSignStr.length() - XML_JDPAY_END.length()) + XML_SIGN_START + sign + XML_SIGN_END + XML_JDPAY_END;
|
||||
|
||||
encrypt = Base64.encodeBase64String(ThreeDesUtil.encrypt2HexStr(RsaUtil.decryptBASE64(strDesKey), data).getBytes("UTF-8"));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("signature failed");
|
||||
}
|
||||
}
|
||||
return encrypt;
|
||||
}
|
||||
|
||||
public static String decrypt(String rsaPubKey, String strDesKey, String encrypt) {
|
||||
String reqBody = "";
|
||||
|
||||
try {
|
||||
reqBody = ThreeDesUtil.decrypt4HexStr(RsaUtil.decryptBASE64(strDesKey), new String(Base64.decodeBase64(encrypt), "UTF-8"));
|
||||
|
||||
String inputSign = JdPayXmlUtil.getXmlElm(reqBody, SIGN);
|
||||
|
||||
reqBody = JdPayXmlUtil.addXmlHead(reqBody);
|
||||
|
||||
reqBody = JdPayXmlUtil.fomatXmlStr(reqBody);
|
||||
|
||||
String genSignStr = JdPayXmlUtil.delXmlElm(reqBody, SIGN);
|
||||
|
||||
boolean verifyResult = VerifySignatureUtl.decryptMerchant(genSignStr, inputSign, rsaPubKey);
|
||||
if (!verifyResult) {
|
||||
throw new RuntimeException("verify signature failed");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("data decrypt failed");
|
||||
}
|
||||
return reqBody;
|
||||
}
|
||||
|
||||
|
||||
public static String decrypt(String rsaPubKey, String reqBody) {
|
||||
String req = "";
|
||||
|
||||
try {
|
||||
String inputSign = JdPayXmlUtil.getXmlElm(reqBody, SIGN);
|
||||
|
||||
req = JdPayXmlUtil.addXmlHead(reqBody);
|
||||
|
||||
req = JdPayXmlUtil.fomatXmlStr(req);
|
||||
|
||||
String genSignStr = JdPayXmlUtil.delXmlElm(req, SIGN);
|
||||
|
||||
boolean verifyResult = VerifySignatureUtl.decryptMerchant(genSignStr, inputSign, rsaPubKey);
|
||||
if (!verifyResult) {
|
||||
throw new RuntimeException("verify signature failed");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("data decrypt failed");
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
String rsaPubKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3Q7knFjJBC0ZzQep5Wq3G+LcGtvPrCfUv6Wfo8Tz1rIfGvHFYjDz2z2iDCP6b5tRSePWfVjdz4O8OEdF+fQWFhJhAPNDIbT8wOALuKQ2MvpDRtZL9hOOr1K4eZNiRw2ppCXKPmi/obSf6maCP7URfhAa6rUixfcPJ5QCEaCWlteuRNYbWFRhORFGIrCOw4pULY42E2yXbgD+N7ORdNxzRZFCrdcwMyIDQ8dmFeWc17mHo/ZTxbVZxMgUQ1m3eBDc+5OGd7jiqSisohli7DvMt+VIwm1f0S5c7QtEFS0FBeul3sgLOM55mz5VlOZOdB61lDw+dh3RHf2ex6BABOb6ywIDAQAB";
|
||||
String rsaPrivateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDdDuScWMkELRnNB6nlarcb4twa28+sJ9S/pZ+jxPPWsh8a8cViMPPbPaIMI/pvm1FJ49Z9WN3Pg7w4R0X59BYWEmEA80MhtPzA4Au4pDYy+kNG1kv2E46vUrh5k2JHDamkJco+aL+htJ/qZoI/tRF+EBrqtSLF9w8nlAIRoJaW165E1htYVGE5EUYisI7DilQtjjYTbJduAP43s5F03HNFkUKt1zAzIgNDx2YV5ZzXuYej9lPFtVnEyBRDWbd4ENz7k4Z3uOKpKKyiGWLsO8y35UjCbV/RLlztC0QVLQUF66XeyAs4znmbPlWU5k50HrWUPD52HdEd/Z7HoEAE5vrLAgMBAAECggEAbZfTmPufdPWTJAXXogh9DVM0QhCV7ci1fenzsjKTnO4j46zXaa3RR/FPZGt13l0HOPW+wdgL57Rs3Q3g0GHFjV3BP8JaltxuroSk6v5mbHGMZxMZB798bsk48fUytP0+DEY79SLjVp0A5ym5CzKOoIwFfDUfLzwkBEApommWHuOUeW12yXWa4xEttB+JAoARBgg2mhGRN0s1N6x5XWLrc0epYNs0syx58YhetQ3X77aXvgyig0haHDOG671UAB+gPCatByR3u7DgzqGDfJp9s6MXZgSp2KmfYl4JLec065XNbThMURgqKpiZgpE3Mx6EChzO9dUXExbMnbsUvf3XCQKBgQD+OU8xtdrs9Het1oaKEMwnP9xJPVIr3j7E+WIi3zhqW2IQ+4gkhvAmnsHsy/f2bM0rYckeZZWz1iWOkqzAAFnPONJiVx4jIwQ86/1s+mbX1MlreyT+9AphXadjTc1QLyAgjqWwiabiAmuFc83Ql+LEK+jLGTc9PnhVhx1Jv4dX9QKBgQDemkPuQJ7ooRGSZMjSFydRanVysTY/Ng9C74eLnLzS4t0gyKxGUFa6MHCOixOIauM5k9cuFIBEPBrl8nLOH1aMMtHV5aw5l/3XMQdTDRX6/hCc26dWolnR+Wp7+11yTTha0B3d5lQHPOZaM47+xouTa60BBCpy7+L0jCU+g5EPvwKBgQDFO3cqjPlNjxjuwJnescuBw/TGyZFfwWwXa5dskJv3P/CkVlE4bYwRmme/rDszbxP6TUI4l/196W134GmwCFWlBGOMsiQKhJc8IKacDuUNG+Qsw/xe5LzM71j3HRxl0jntqF35ycG0ZMZAYijSZZQkOCDCuUx28mlviYT6e2KopQKBgQCIFMZyYA7FJ7IWTIZ36K+glfQ2qR8AhYvO3599OdQ1F3sXD5ZBZdue9v3YJi1KuA0wpbBl+yJulE/dQtnsKDxAeNDOchlXHBOR+ecAXn+RcL+3JJCn5ZgDRPZT1NbLiWlqGtAnVycHRbOMcPh5x+aLuMeKV4Gbwgp8dTBPhx6nAQKBgAHNFHusDx5zFIkS13mlN+7rG9oDJKwr+gLp0zqGOfzLznslXGS9dze56cmWRhHQdSQBYji51Bcb5TP6Pgwv18d6M0g8NiXanIktc3OtdCw9K1lB2nZpJP0hKxkBni15wURzN5Kj0MRtPoe5vXhKF/uDu9IUwY9/x2jzJgh2o8o9";
|
||||
|
||||
String strDesKey = "GX/CH6HIAT2Ubtn3ZKjfYdbxa6HgSVca";
|
||||
|
||||
|
||||
String param = "<jdpay><version>2.0</version><merchant>110025845001</merchant><tradeNum>201604080000055</tradeNum><tradeType>0</tradeType></jdpay>";
|
||||
String encrypt = encrypt(rsaPrivateKey, strDesKey, param);
|
||||
System.out.println("encrypt:" + encrypt);
|
||||
|
||||
|
||||
String decrypt = decrypt(rsaPubKey, strDesKey, encrypt);
|
||||
System.out.println("decrypt:" + decrypt);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>QQ 钱包支付 API</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.qqpay;
|
||||
|
||||
|
||||
import com.zscat.mallplus.core.kit.HttpKit;
|
||||
import com.zscat.mallplus.core.kit.WxPayKit;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
public class QqPayApi {
|
||||
/**
|
||||
* 提交付款码支付
|
||||
*/
|
||||
private static final String MICRO_PAY_URL = "https://qpay.qq.com/cgi-bin/pay/qpay_micro_pay.cgi";
|
||||
/**
|
||||
* 统一下单
|
||||
*/
|
||||
private static final String UNIFIED_ORDER_URL = "https://qpay.qq.com/cgi-bin/pay/qpay_unified_order.cgi";
|
||||
|
||||
/**
|
||||
* 订单查询
|
||||
*/
|
||||
private static final String ORDER_QUERY_URL = "https://qpay.qq.com/cgi-bin/pay/qpay_order_query.cgi";
|
||||
|
||||
/**
|
||||
* 关闭订单
|
||||
*/
|
||||
private static final String CLOSE_ORDER_URL = "https://qpay.qq.com/cgi-bin/pay/qpay_close_order.cgi";
|
||||
|
||||
/**
|
||||
* 撤销订单
|
||||
*/
|
||||
private static final String ORDER_REVERSE_URL = "https://api.qpay.qq.com/cgi-bin/pay/qpay_reverse.cgi";
|
||||
|
||||
/**
|
||||
* 申请退款
|
||||
*/
|
||||
private static final String ORDER_REFUND_URL = "https://api.qpay.qq.com/cgi-bin/pay/qpay_refund.cgi";
|
||||
|
||||
/**
|
||||
* 退款查询
|
||||
*/
|
||||
private static final String REFUND_QUERY_URL = "https://qpay.qq.com/cgi-bin/pay/qpay_refund_query.cgi";
|
||||
|
||||
/**
|
||||
* 对账单下载
|
||||
*/
|
||||
private static final String DOWNLOAD_BILL_URL = "https://qpay.qq.com/cgi-bin/sp_download/qpay_mch_statement_down.cgi";
|
||||
|
||||
/**
|
||||
* 创建现金红包
|
||||
*/
|
||||
private static final String CREATE_READ_PACK_URL = "https://api.qpay.qq.com/cgi-bin/hongbao/qpay_hb_mch_send.cgi";
|
||||
/**
|
||||
* 查询红包详情
|
||||
*/
|
||||
private static final String GET_HB_INFO_URL = "https://qpay.qq.com/cgi-bin/mch_query/qpay_hb_mch_list_query.cgi";
|
||||
/**
|
||||
* 红包对账单下载
|
||||
*/
|
||||
private static final String DOWNLOAD_HB_BILL_URL = "https://api.qpay.qq.com/cgi-bin/hongbao/qpay_hb_mch_down_list_file.cgi";
|
||||
|
||||
/**
|
||||
* 企业付款到余额
|
||||
*/
|
||||
private static final String TRANSFER_URL = "https://api.qpay.qq.com/cgi-bin/epay/qpay_epay_b2c.cgi";
|
||||
/**
|
||||
* 查询企业付款
|
||||
*/
|
||||
private static final String GET_TRANSFER_INFO_URL = "https://qpay.qq.com/cgi-bin/pay/qpay_epay_query.cgi";
|
||||
/**
|
||||
* 企业付款对账单下载
|
||||
*/
|
||||
private static final String DOWNLOAD_TRANSFER_BILL_URL = "https://qpay.qq.com/cgi-bin/pay/qpay_epay_statement_down.cgi";
|
||||
|
||||
|
||||
/**
|
||||
* 提交付款码支付
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String microPay(Map<String, String> params) {
|
||||
return doPost(MICRO_PAY_URL, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一下单
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String unifiedOrder(Map<String, String> params) {
|
||||
return doPost(UNIFIED_ORDER_URL, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单查询
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String orderQuery(Map<String, String> params) {
|
||||
return doPost(ORDER_QUERY_URL, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭订单
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String closeOrder(Map<String, String> params) {
|
||||
return doPost(CLOSE_ORDER_URL, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤销订单
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @param cerPath 证书文件目录
|
||||
* @param certPass 证书密码
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String orderReverse(Map<String, String> params, String cerPath, String certPass) {
|
||||
return doPost(ORDER_REVERSE_URL, params, cerPath, certPass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤销订单
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @param certFile 证书文件的 InputStream
|
||||
* @param certPass 证书密码
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String orderReverse(Map<String, String> params, InputStream certFile, String certPass) {
|
||||
return doPost(ORDER_REVERSE_URL, params, certFile, certPass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 申请退款
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @param cerPath 证书文件目录
|
||||
* @param certPass 证书密码
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String orderRefund(Map<String, String> params, String cerPath, String certPass) {
|
||||
return doPost(ORDER_REFUND_URL, params, cerPath, certPass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 申请退款
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @param certFile 证书文件的 InputStream
|
||||
* @param certPass 证书密码
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String orderRefund(Map<String, String> params, InputStream certFile, String certPass) {
|
||||
return doPost(ORDER_REFUND_URL, params, certFile, certPass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款查询
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String refundQuery(Map<String, String> params) {
|
||||
return doPost(REFUND_QUERY_URL, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对账单下载
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String downloadBill(Map<String, String> params) {
|
||||
return doPost(DOWNLOAD_BILL_URL, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建现金红包
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @param cerPath 证书文件目录
|
||||
* @param certPass 证书密码
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String createReadPack(Map<String, String> params, String cerPath, String certPass) {
|
||||
return doPost(CREATE_READ_PACK_URL, params, cerPath, certPass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建现金红包
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @param certFile 证书文件的 InputStream
|
||||
* @param certPass 证书密码
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String createReadPack(Map<String, String> params, InputStream certFile, String certPass) {
|
||||
return doPost(CREATE_READ_PACK_URL, params, certFile, certPass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询红包详情
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String getHbInfo(Map<String, String> params) {
|
||||
return doPost(GET_HB_INFO_URL, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载红包对账单
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String downloadHbBill(Map<String, String> params) {
|
||||
return doPost(DOWNLOAD_HB_BILL_URL, params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 企业付款到余额
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @param cerPath 证书文件目录
|
||||
* @param certPass 证书密码
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String transfer(Map<String, String> params, String cerPath, String certPass) {
|
||||
return doPost(TRANSFER_URL, params, cerPath, certPass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 企业付款到余额
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @param certFile 证书文件的 InputStream
|
||||
* @param certPass 证书密码
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String transfer(Map<String, String> params, InputStream certFile, String certPass) {
|
||||
return doPost(TRANSFER_URL, params, certFile, certPass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询企业付款
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String getTransferInfo(Map<String, String> params) {
|
||||
return doPost(GET_TRANSFER_INFO_URL, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载企业付款对账单
|
||||
*
|
||||
* @param params 请求参数
|
||||
* @return {@link String} 请求返回的结果
|
||||
*/
|
||||
public static String downloadTransferBill(Map<String, String> params) {
|
||||
return doPost(DOWNLOAD_TRANSFER_BILL_URL, params);
|
||||
}
|
||||
|
||||
|
||||
public static String doPost(String url, Map<String, String> params) {
|
||||
return HttpKit.getDelegate().post(url, WxPayKit.toXml(params));
|
||||
}
|
||||
|
||||
public static String doPost(String url, Map<String, String> params, String certPath, String certPass) {
|
||||
return HttpKit.getDelegate().post(url, WxPayKit.toXml(params), certPath, certPass);
|
||||
}
|
||||
|
||||
public static String doPost(String url, Map<String, String> params, InputStream certFile, String certPass) {
|
||||
return HttpKit.getDelegate().post(url, WxPayKit.toXml(params), certFile, certPass);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.zscat.mallplus.qqpay;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>QQ 钱包支付常用配置</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class QqPayApiConfig implements Serializable {
|
||||
private static final long serialVersionUID = 8365822256469245771L;
|
||||
|
||||
private String appId;
|
||||
private String mchId;
|
||||
private String slAppId;
|
||||
private String slMchId;
|
||||
private String partnerKey;
|
||||
private String domain;
|
||||
private String certPath;
|
||||
private Object exParams;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.zscat.mallplus.qqpay;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>QQ 钱包支付常用配置 Kit</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public class QqPayApiConfigKit {
|
||||
|
||||
private static final ThreadLocal<String> TL = new ThreadLocal<String>();
|
||||
|
||||
private static final Map<String, QqPayApiConfig> CFG_MAP = new ConcurrentHashMap<String, QqPayApiConfig>();
|
||||
private static final String DEFAULT_CFG_KEY = "_default_key_";
|
||||
|
||||
/**
|
||||
* 添加微信支付配置,每个appId只需添加一次,相同appId将被覆盖
|
||||
*
|
||||
* @param qqPayApiConfig 微信支付配置
|
||||
* @return {WxPayApiConfig} 微信支付配置
|
||||
*/
|
||||
public static QqPayApiConfig putApiConfig(QqPayApiConfig qqPayApiConfig) {
|
||||
if (CFG_MAP.size() == 0) {
|
||||
CFG_MAP.put(DEFAULT_CFG_KEY, qqPayApiConfig);
|
||||
}
|
||||
return CFG_MAP.put(qqPayApiConfig.getAppId(), qqPayApiConfig);
|
||||
}
|
||||
|
||||
public static QqPayApiConfig setThreadLocalQqPayApiConfig(QqPayApiConfig qqPayApiConfig) {
|
||||
if (StrUtil.isNotEmpty(qqPayApiConfig.getAppId())) {
|
||||
setThreadLocalAppId(qqPayApiConfig.getAppId());
|
||||
}
|
||||
return putApiConfig(qqPayApiConfig);
|
||||
}
|
||||
|
||||
public static QqPayApiConfig removeApiConfig(QqPayApiConfig qqPayApiConfig) {
|
||||
return removeApiConfig(qqPayApiConfig.getAppId());
|
||||
}
|
||||
|
||||
public static QqPayApiConfig removeApiConfig(String appId) {
|
||||
return CFG_MAP.remove(appId);
|
||||
}
|
||||
|
||||
public static void setThreadLocalAppId(String appId) {
|
||||
if (StrUtil.isEmpty(appId)) {
|
||||
appId = CFG_MAP.get(DEFAULT_CFG_KEY).getAppId();
|
||||
}
|
||||
TL.set(appId);
|
||||
}
|
||||
|
||||
public static void removeThreadLocalAppId() {
|
||||
TL.remove();
|
||||
}
|
||||
|
||||
public static String getAppId() {
|
||||
String appId = TL.get();
|
||||
if (StrUtil.isEmpty(appId)) {
|
||||
appId = CFG_MAP.get(DEFAULT_CFG_KEY).getAppId();
|
||||
}
|
||||
return appId;
|
||||
}
|
||||
|
||||
public static QqPayApiConfig getQqPayApiConfig() {
|
||||
String appId = getAppId();
|
||||
return getApiConfig(appId);
|
||||
}
|
||||
|
||||
public static QqPayApiConfig getApiConfig(String appId) {
|
||||
QqPayApiConfig cfg = CFG_MAP.get(appId);
|
||||
if (cfg == null) {
|
||||
throw new IllegalStateException("需事先调用 QqPayApiConfigKit.putApiConfig(qqPayApiConfig) 将 appId 对应的 QqPayApiConfig 对象存入,才可以使用 QqPayApiConfigKit.getQqPayApiConfig() 的系列方法");
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>关闭订单 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.qqpay.model;
|
||||
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class CloseOrderModel extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String out_trade_no;
|
||||
private String total_fee;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>创建现金红包 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.qqpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class CreateHbModel extends BaseModel {
|
||||
private String charset;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String mch_billno;
|
||||
private String mch_id;
|
||||
private String mch_name;
|
||||
private String qqappid;
|
||||
private String re_openid;
|
||||
private String total_amount;
|
||||
private String total_num;
|
||||
private String wishing;
|
||||
private String act_name;
|
||||
private String icon_id;
|
||||
private String banner_id;
|
||||
private String notify_url;
|
||||
private String not_send_msg;
|
||||
private String min_value;
|
||||
private String max_value;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>对账单下载 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.qqpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class DownloadBillModel extends BaseModel {
|
||||
private String appid;
|
||||
private String mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String bill_date;
|
||||
private String bill_type;
|
||||
private String tar_type;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>现金红包对账单下载 Model </p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.qqpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class DownloadHbBillModel extends BaseModel {
|
||||
private String sign;
|
||||
private String mch_id;
|
||||
private String date;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>企业付款对账单下载 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.qqpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class DownloadTransferBillModel extends BaseModel {
|
||||
private String mch_id;
|
||||
private String nonce_str;
|
||||
private String bill_date;
|
||||
private String sign;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>查询红包详情 Model </p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.qqpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class GetHbInfoModel extends BaseModel {
|
||||
private String send_type;
|
||||
private String nonce_str;
|
||||
private String mch_id;
|
||||
private String mch_billno;
|
||||
private String listid;
|
||||
private String sub_mch_id;
|
||||
private String sign;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>查询企业付款 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.qqpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class GetTransferInfoModel extends BaseModel {
|
||||
private String mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String out_trade_no;
|
||||
private String transaction_id;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>提交付款码支付 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.qqpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class MicroPayModel extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String body;
|
||||
private String attach;
|
||||
private String out_trade_no;
|
||||
private String fee_type;
|
||||
private String total_fee;
|
||||
private String spbill_create_ip;
|
||||
private String limit_pay;
|
||||
private String promotion_tag;
|
||||
private String notify_url;
|
||||
private String device_info;
|
||||
private String auth_code;
|
||||
private String trade_type;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>查询订单 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.qqpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class OrderQueryModel extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String transaction_id;
|
||||
private String out_trade_no;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>申请退款 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.qqpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class OrderRefundModel extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String transaction_id;
|
||||
private String out_trade_no;
|
||||
private String out_refund_no;
|
||||
private String refund_fee;
|
||||
private String op_user_id;
|
||||
private String op_user_passwd;
|
||||
private String refund_account;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>撤销订单 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.qqpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class OrderReverseModel extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String out_trade_no;
|
||||
private String op_user_id;
|
||||
private String op_user_passwd;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>退款查询 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.qqpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class RefundQueryModel extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String refund_id;
|
||||
private String out_refund_no;
|
||||
private String transaction_id;
|
||||
private String out_trade_no;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>企业付款到余额 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.qqpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class TransferModel extends BaseModel {
|
||||
private String input_charset;
|
||||
private String appid;
|
||||
private String openid;
|
||||
private String uin;
|
||||
private String mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String out_trade_no;
|
||||
private String fee_type;
|
||||
private String total_fee;
|
||||
private String memo;
|
||||
private String check_name;
|
||||
private String re_user_name;
|
||||
private String check_real_name;
|
||||
private String op_user_id;
|
||||
private String op_user_passwd;
|
||||
private String spbill_create_ip;
|
||||
private String notify_url;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>统一下单 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.qqpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class UnifiedOrderModel extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String body;
|
||||
private String attach;
|
||||
private String out_trade_no;
|
||||
private String fee_type;
|
||||
private String total_fee;
|
||||
private String spbill_create_ip;
|
||||
private String time_start;
|
||||
private String time_expire;
|
||||
private String limit_pay;
|
||||
private String contract_code;
|
||||
private String promotion_tag;
|
||||
private String trade_type;
|
||||
private String notify_url;
|
||||
private String device_info;
|
||||
private String mini_app_param;
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
package com.zscat.mallplus.unionpay;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author UnionPay
|
||||
*/
|
||||
public class AcpService {
|
||||
|
||||
public static Map<String, String> sign(Map<String, String> reqData, String encoding) {
|
||||
reqData = SDKUtil.filterBlank(reqData);
|
||||
SDKUtil.sign(reqData, encoding);
|
||||
return reqData;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public static boolean validate(Map<String, String> rspData, String encoding) {
|
||||
return SDKUtil.validate(rspData, encoding);
|
||||
}
|
||||
|
||||
public static boolean validateBySecureKey(Map<String, String> rspData, String secureKey, String encoding) {
|
||||
return SDKUtil.validateBySecureKey(rspData, secureKey, encoding);
|
||||
}
|
||||
|
||||
public static String createAutoFormHtml(String reqUrl, Map<String, String> hiddenMap, 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 != hiddenMap && 0 != hiddenMap.size()) {
|
||||
Set<Entry<String, String>> set = hiddenMap.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();
|
||||
}
|
||||
|
||||
|
||||
public static String enCodeFileContent(String filePath, String encoding) {
|
||||
String baseFileContent = "";
|
||||
|
||||
File file = new File(filePath);
|
||||
if (!file.exists()) {
|
||||
try {
|
||||
file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
LogUtil.writeErrorLog(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) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
} finally {
|
||||
if (null != in) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return baseFileContent;
|
||||
}
|
||||
|
||||
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) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
} catch (IOException e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
} finally {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public static String getFileContent(String fileContent, String encoding) {
|
||||
String fc = "";
|
||||
try {
|
||||
fc = new String(SDKUtil.inflater(SecureUtil.base64Decode(fileContent.getBytes())), encoding);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
} catch (IOException e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
}
|
||||
return fc;
|
||||
}
|
||||
|
||||
|
||||
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 ("pin".equals(key)) {
|
||||
if (null == accNo || "".equals(accNo.trim())) {
|
||||
LogUtil.writeLog("送了密码(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();
|
||||
LogUtil.writeLog("组装的customerInfo明文:" + customerInfo);
|
||||
try {
|
||||
return new String(SecureUtil.base64Encode(sf.toString().getBytes(
|
||||
encoding)), encoding);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
} catch (IOException e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
}
|
||||
return customerInfo;
|
||||
}
|
||||
|
||||
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 ("phoneNo".equals(key) || "cvn2".equals(key) || "expired".equals(key)) {
|
||||
encryptedInfoSb.append(key).append(SDKConstants.EQUAL).append(value).append(SDKConstants.AMPERSAND);
|
||||
} else {
|
||||
if ("pin".equals(key)) {
|
||||
if (null == accNo || "".equals(accNo.trim())) {
|
||||
LogUtil.writeLog("送了密码(PIN),必须在getCustomerInfoWithEncrypt参数中上传卡号");
|
||||
throw new RuntimeException("加密PIN没送卡号无法后续处理");
|
||||
} else {
|
||||
value = encryptPin(accNo, value, encoding);
|
||||
}
|
||||
}
|
||||
sf.append(key).append(SDKConstants.EQUAL).append(value).append(SDKConstants.AMPERSAND);
|
||||
}
|
||||
}
|
||||
|
||||
if (!"".equals(encryptedInfoSb.toString())) {
|
||||
//去掉最后一个&符号
|
||||
encryptedInfoSb.setLength(encryptedInfoSb.length() - 1);
|
||||
LogUtil.writeLog("组装的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();
|
||||
LogUtil.writeLog("组装的customerInfo明文:" + customerInfo);
|
||||
try {
|
||||
return new String(SecureUtil.base64Encode(sf.toString().getBytes(encoding)), encoding);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
} catch (IOException e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
}
|
||||
return customerInfo;
|
||||
}
|
||||
|
||||
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);
|
||||
LogUtil.writeLog("解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) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
} catch (IOException e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
}
|
||||
return customerInfoMap;
|
||||
}
|
||||
|
||||
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);
|
||||
LogUtil.writeLog("解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) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
} catch (IOException e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
}
|
||||
return customerInfoMap;
|
||||
}
|
||||
|
||||
public static String encryptPin(String accNo, String pin, String encoding) {
|
||||
return SecureUtil.encryptPin(accNo, pin, encoding, CertUtil
|
||||
.getEncryptCertPublicKey());
|
||||
}
|
||||
|
||||
public static String encryptData(String data, String encoding) {
|
||||
return SecureUtil.encryptData(data, encoding, CertUtil
|
||||
.getEncryptCertPublicKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* 敏感信息解密,使用配置文件acp_sdk.properties解密
|
||||
*
|
||||
* @param base64EncryptedInfo 加密信息
|
||||
* @param encoding 编码格式
|
||||
* @return 解密后的明文
|
||||
*/
|
||||
public static String decryptData(String base64EncryptedInfo, String encoding) {
|
||||
return SecureUtil.decryptData(base64EncryptedInfo, encoding, CertUtil.getSignCertPrivateKey());
|
||||
}
|
||||
|
||||
public static String decryptData(String base64EncryptedInfo, String certPath, String certPwd, String encoding) {
|
||||
return SecureUtil.decryptData(base64EncryptedInfo, encoding, CertUtil.getSignCertPrivateKeyByStoreMap(certPath, certPwd));
|
||||
}
|
||||
|
||||
public static String getEncryptCertId() {
|
||||
return CertUtil.getEncryptCertId();
|
||||
}
|
||||
|
||||
public static String base64Encode(String rawStr, String encoding) throws IOException {
|
||||
byte[] rawByte = rawStr.getBytes(encoding);
|
||||
return new String(SecureUtil.base64Encode(rawByte), encoding);
|
||||
}
|
||||
|
||||
public static String base64Decode(String base64Str, String encoding) throws IOException {
|
||||
byte[] rawByte = base64Str.getBytes(encoding);
|
||||
return new String(SecureUtil.base64Decode(rawByte), encoding);
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
|
||||
}
|
||||
|
||||
public static int updateEncryptCert(Map<String, String> resData, String encoding) {
|
||||
return SDKUtil.getEncryptCert(resData, encoding);
|
||||
}
|
||||
|
||||
public static int genLuHn(String number) {
|
||||
return SecureUtil.genLuHn(number);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,612 @@
|
||||
package com.zscat.mallplus.unionpay;
|
||||
|
||||
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;
|
||||
|
||||
import static com.zscat.mallplus.unionpay.SDKConstants.UNIONPAY_CNNAME;
|
||||
import static com.zscat.mallplus.unionpay.SDKUtil.isEmpty;
|
||||
|
||||
/**
|
||||
* @author UnionPay
|
||||
*/
|
||||
public class CertUtil {
|
||||
/**
|
||||
* 商户私钥存储Map
|
||||
*/
|
||||
private final static Map<String, KeyStore> keyStoreMap = new ConcurrentHashMap<String, KeyStore>();
|
||||
/**
|
||||
* 证书容器,存储对商户请求报文签名私钥证书.
|
||||
*/
|
||||
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>();
|
||||
|
||||
static {
|
||||
init();
|
||||
}
|
||||
|
||||
private static void init() {
|
||||
try {
|
||||
addProvider();//向系统添加BC provider
|
||||
initSignCert();//初始化签名私钥证书
|
||||
initMiddleCert();//初始化验签证书的中级证书
|
||||
initRootCert();//初始化验签证书的根证书
|
||||
initEncryptCert();//初始化加密公钥
|
||||
initTrackKey();//构建磁道加密公钥
|
||||
initValidateCertFromDir();//初始化所有的验签证书
|
||||
} catch (Exception e) {
|
||||
LogUtil.writeErrorLog("init失败。(如果是用对称密钥签名的可无视此异常。)", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addProvider() {
|
||||
if (Security.getProvider("BC") == null) {
|
||||
LogUtil.writeLog("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());
|
||||
LogUtil.writeLog("re-add BC provider");
|
||||
}
|
||||
printSysInfo();
|
||||
}
|
||||
|
||||
private static void initSignCert() {
|
||||
if (!"01".equals(SDKConfig.getConfig().getSignMethod())) {
|
||||
LogUtil.writeLog("非rsa签名方式,不加载签名证书。");
|
||||
return;
|
||||
}
|
||||
if (SDKConfig.getConfig().getSignCertPath() == null
|
||||
|| SDKConfig.getConfig().getSignCertPwd() == null
|
||||
|| SDKConfig.getConfig().getSignCertType() == null) {
|
||||
LogUtil.writeErrorLog("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());
|
||||
LogUtil.writeLog("InitSignCert Successful. CertId=["
|
||||
+ getSignCertId() + "]");
|
||||
} catch (IOException e) {
|
||||
LogUtil.writeErrorLog("InitSignCert Error", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void initMiddleCert() {
|
||||
LogUtil.writeLog("加载中级证书==>" + SDKConfig.getConfig().getMiddleCertPath());
|
||||
if (!isEmpty(SDKConfig.getConfig().getMiddleCertPath())) {
|
||||
middleCert = initCert(SDKConfig.getConfig().getMiddleCertPath());
|
||||
LogUtil.writeLog("Load MiddleCert Successful");
|
||||
} else {
|
||||
LogUtil.writeLog("WARN: acpsdk.middle.path is empty");
|
||||
}
|
||||
}
|
||||
|
||||
private static void initRootCert() {
|
||||
LogUtil.writeLog("加载根证书==>" + SDKConfig.getConfig().getRootCertPath());
|
||||
if (!isEmpty(SDKConfig.getConfig().getRootCertPath())) {
|
||||
rootCert = initCert(SDKConfig.getConfig().getRootCertPath());
|
||||
LogUtil.writeLog("Load RootCert Successful");
|
||||
} else {
|
||||
LogUtil.writeLog("WARN: acpsdk.rootCert.path is empty");
|
||||
}
|
||||
}
|
||||
|
||||
private static void initEncryptCert() {
|
||||
LogUtil.writeLog("加载敏感信息加密证书==>" + SDKConfig.getConfig().getEncryptCertPath());
|
||||
if (!isEmpty(SDKConfig.getConfig().getEncryptCertPath())) {
|
||||
encryptCert = initCert(SDKConfig.getConfig().getEncryptCertPath());
|
||||
LogUtil.writeLog("Load EncryptCert Successful");
|
||||
} else {
|
||||
LogUtil.writeLog("WARN: acpsdk.encryptCert.path is empty");
|
||||
}
|
||||
}
|
||||
|
||||
private static void initTrackKey() {
|
||||
if (!isEmpty(SDKConfig.getConfig().getEncryptTrackKeyModulus())
|
||||
&& !isEmpty(SDKConfig.getConfig().getEncryptTrackKeyExponent())) {
|
||||
encryptTrackKey = getPublicKey(SDKConfig.getConfig().getEncryptTrackKeyModulus(),
|
||||
SDKConfig.getConfig().getEncryptTrackKeyExponent());
|
||||
LogUtil.writeLog("LoadEncryptTrackKey Successful");
|
||||
} else {
|
||||
LogUtil.writeLog("WARN: acpsdk.encryptTrackKey.modulus or acpsdk.encryptTrackKey.exponent is empty");
|
||||
}
|
||||
}
|
||||
|
||||
private static void initValidateCertFromDir() {
|
||||
if (!"01".equals(SDKConfig.getConfig().getSignMethod())) {
|
||||
LogUtil.writeLog("非rsa签名方式,不加载验签证书。");
|
||||
return;
|
||||
}
|
||||
certMap.clear();
|
||||
String dir = SDKConfig.getConfig().getValidateCertDir();
|
||||
LogUtil.writeLog("加载验证签名证书目录==>" + dir + " 注:如果请求报文中version=5.1.0那么此验签证书目录使用不到,可以不需要设置(version=5.0.0必须设置)。");
|
||||
if (isEmpty(dir)) {
|
||||
LogUtil.writeErrorLog("WARN: acpsdk.validateCert.dir is empty");
|
||||
return;
|
||||
}
|
||||
CertificateFactory cf = null;
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
cf = CertificateFactory.getInstance("X.509", "BC");
|
||||
} catch (NoSuchProviderException e) {
|
||||
LogUtil.writeErrorLog("LoadVerifyCert Error: No BC Provider", e);
|
||||
return;
|
||||
} catch (CertificateException e) {
|
||||
LogUtil.writeErrorLog("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) {
|
||||
LogUtil.writeErrorLog("Load verify cert error, " + file.getAbsolutePath() + " has error cert content.");
|
||||
continue;
|
||||
}
|
||||
certMap.put(validateCert.getSerialNumber().toString(),
|
||||
validateCert);
|
||||
// 打印证书加载信息,供测试阶段调试
|
||||
LogUtil.writeLog("[" + file.getAbsolutePath() + "][CertId="
|
||||
+ validateCert.getSerialNumber().toString() + "]");
|
||||
} catch (CertificateException e) {
|
||||
LogUtil.writeErrorLog("LoadVerifyCert Error", e);
|
||||
} catch (FileNotFoundException e) {
|
||||
LogUtil.writeErrorLog("LoadVerifyCert Error File Not Found", e);
|
||||
} finally {
|
||||
if (null != in) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
LogUtil.writeErrorLog(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LogUtil.writeLog("LoadVerifyCert Finish");
|
||||
}
|
||||
|
||||
private static void loadSignCert(String certFilePath, String certPwd) {
|
||||
KeyStore keyStore = null;
|
||||
try {
|
||||
keyStore = getKeyInfo(certFilePath, certPwd, "PKCS12");
|
||||
keyStoreMap.put(certFilePath, keyStore);
|
||||
LogUtil.writeLog("LoadRsaCert Successful");
|
||||
} catch (IOException e) {
|
||||
LogUtil.writeErrorLog("LoadRsaCert Error", e);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
// 打印证书加载信息,供测试阶段调试
|
||||
LogUtil.writeLog("[" + path + "][CertId="
|
||||
+ encryptCertTemp.getSerialNumber().toString() + "]");
|
||||
} catch (CertificateException e) {
|
||||
LogUtil.writeErrorLog("InitCert Error", e);
|
||||
} catch (FileNotFoundException e) {
|
||||
LogUtil.writeErrorLog("InitCert Error File Not Found", e);
|
||||
} catch (NoSuchProviderException e) {
|
||||
LogUtil.writeErrorLog("LoadVerifyCert Error No BC Provider", e);
|
||||
} finally {
|
||||
if (null != in) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
LogUtil.writeErrorLog(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
return encryptCertTemp;
|
||||
}
|
||||
|
||||
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) {
|
||||
LogUtil.writeErrorLog("getSignCertPrivateKey Error", e);
|
||||
return null;
|
||||
} catch (UnrecoverableKeyException e) {
|
||||
LogUtil.writeErrorLog("getSignCertPrivateKey Error", e);
|
||||
return null;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
LogUtil.writeErrorLog("getSignCertPrivateKey Error", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
LogUtil.writeErrorLog("getSignCertPrivateKeyByStoreMap Error", e);
|
||||
return null;
|
||||
} catch (UnrecoverableKeyException e) {
|
||||
LogUtil.writeErrorLog("getSignCertPrivateKeyByStoreMap Error", e);
|
||||
return null;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
LogUtil.writeErrorLog("getSignCertPrivateKeyByStoreMap Error", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static PublicKey getEncryptCertPublicKey() {
|
||||
if (null == encryptCert) {
|
||||
String path = SDKConfig.getConfig().getEncryptCertPath();
|
||||
if (!isEmpty(path)) {
|
||||
encryptCert = initCert(path);
|
||||
return encryptCert.getPublicKey();
|
||||
} else {
|
||||
LogUtil.writeErrorLog("acpsdk.encryptCert.path is empty");
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return encryptCert.getPublicKey();
|
||||
}
|
||||
}
|
||||
|
||||
public static void resetEncryptCertPublicKey() {
|
||||
encryptCert = null;
|
||||
}
|
||||
|
||||
public static PublicKey getEncryptTrackPublicKey() {
|
||||
if (null == encryptTrackKey) {
|
||||
initTrackKey();
|
||||
}
|
||||
return encryptTrackKey;
|
||||
}
|
||||
|
||||
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 {
|
||||
LogUtil.writeErrorLog("缺少certId=[" + certId + "]对应的验签证书.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
LogUtil.writeErrorLog("getSignCertId Error", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getEncryptCertId() {
|
||||
if (null == encryptCert) {
|
||||
String path = SDKConfig.getConfig().getEncryptCertPath();
|
||||
if (!isEmpty(path)) {
|
||||
encryptCert = initCert(path);
|
||||
return encryptCert.getSerialNumber().toString();
|
||||
} else {
|
||||
LogUtil.writeErrorLog("acpsdk.encryptCert.path is empty");
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return encryptCert.getSerialNumber().toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static KeyStore getKeyInfo(String pfxkeyfile, String keypwd, String type) throws IOException {
|
||||
LogUtil.writeLog("加载签名证书==>" + pfxkeyfile);
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
KeyStore ks = KeyStore.getInstance(type, "BC");
|
||||
LogUtil.writeLog("Load RSA CertPath=[" + pfxkeyfile + "],Pwd=[" + keypwd + "],type=[" + type + "]");
|
||||
fis = new FileInputStream(pfxkeyfile);
|
||||
char[] nPassword = null;
|
||||
nPassword = null == keypwd || "".equals(keypwd.trim()) ? null : keypwd.toCharArray();
|
||||
if (null != ks) {
|
||||
ks.load(fis, nPassword);
|
||||
}
|
||||
return ks;
|
||||
} catch (Exception e) {
|
||||
LogUtil.writeErrorLog("getKeyInfo Error", e);
|
||||
return null;
|
||||
} finally {
|
||||
if (null != fis)
|
||||
fis.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getCertIdByKeyStoreMap(String certPath, String certPwd) {
|
||||
if (!keyStoreMap.containsKey(certPath)) {
|
||||
// 缓存中未查询到,则加载RSA证书
|
||||
loadSignCert(certPath, certPwd);
|
||||
}
|
||||
return getCertIdIdByStore(keyStoreMap.get(certPath));
|
||||
}
|
||||
|
||||
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) {
|
||||
LogUtil.writeErrorLog("getCertIdIdByStore Error", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
LogUtil.writeErrorLog("构造RSA公钥失败:" + e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
LogUtil.writeErrorLog("gen certificate error", e);
|
||||
}
|
||||
return x509Cert;
|
||||
}
|
||||
|
||||
public static X509Certificate getMiddleCert() {
|
||||
if (null == middleCert) {
|
||||
String path = SDKConfig.getConfig().getMiddleCertPath();
|
||||
if (!isEmpty(path)) {
|
||||
initMiddleCert();
|
||||
} else {
|
||||
LogUtil.writeErrorLog(SDKConfig.SDK_MIDDLECERT_PATH + " not set in " + SDKConfig.FILE_NAME);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return middleCert;
|
||||
}
|
||||
|
||||
public static X509Certificate getRootCert() {
|
||||
if (null == rootCert) {
|
||||
String path = SDKConfig.getConfig().getRootCertPath();
|
||||
if (!isEmpty(path)) {
|
||||
initRootCert();
|
||||
} else {
|
||||
LogUtil.writeErrorLog(SDKConfig.SDK_ROOTCERT_PATH + " not set in " + SDKConfig.FILE_NAME);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return rootCert;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private static boolean verifyCertificateChain(X509Certificate cert) {
|
||||
|
||||
if (null == cert) {
|
||||
LogUtil.writeErrorLog("cert must Not null");
|
||||
return false;
|
||||
}
|
||||
|
||||
X509Certificate middleCert = CertUtil.getMiddleCert();
|
||||
if (null == middleCert) {
|
||||
LogUtil.writeErrorLog("middleCert must Not null");
|
||||
return false;
|
||||
}
|
||||
|
||||
X509Certificate rootCert = CertUtil.getRootCert();
|
||||
if (null == rootCert) {
|
||||
LogUtil.writeErrorLog("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);
|
||||
LogUtil.writeLog("verify certificate chain succeed.");
|
||||
return true;
|
||||
} catch (java.security.cert.CertPathBuilderException e) {
|
||||
LogUtil.writeErrorLog("verify certificate chain fail.", e);
|
||||
} catch (Exception e) {
|
||||
LogUtil.writeErrorLog("verify certificate chain exception: ", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean verifyCertificate(X509Certificate cert) {
|
||||
|
||||
if (null == cert) {
|
||||
LogUtil.writeErrorLog("cert must Not null");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
cert.checkValidity();//验证有效期
|
||||
// cert.verify(middleCert.getPublicKey());
|
||||
if (!verifyCertificateChain(cert)) {
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.writeErrorLog("verifyCertificate fail", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SDKConfig.getConfig().isIfValidateCNName()) {
|
||||
// 验证公钥是否属于银联
|
||||
if (!UNIONPAY_CNNAME.equals(CertUtil.getIdentitiesFromCertficate(cert))) {
|
||||
LogUtil.writeErrorLog("cer owner is not CUP:" + CertUtil.getIdentitiesFromCertficate(cert));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// 验证公钥是否属于银联
|
||||
if (!UNIONPAY_CNNAME.equals(CertUtil.getIdentitiesFromCertficate(cert))
|
||||
&& !"00040000:SIGN".equals(CertUtil.getIdentitiesFromCertficate(cert))) {
|
||||
LogUtil.writeErrorLog("cer owner is not CUP:" + CertUtil.getIdentitiesFromCertficate(cert));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void printSysInfo() {
|
||||
LogUtil.writeLog("================= SYS INFO begin====================");
|
||||
LogUtil.writeLog("os_name:" + System.getProperty("os.name"));
|
||||
LogUtil.writeLog("os_arch:" + System.getProperty("os.arch"));
|
||||
LogUtil.writeLog("os_version:" + System.getProperty("os.version"));
|
||||
LogUtil.writeLog("java_vm_specification_version:"
|
||||
+ System.getProperty("java.vm.specification.version"));
|
||||
LogUtil.writeLog("java_vm_specification_vendor:"
|
||||
+ System.getProperty("java.vm.specification.vendor"));
|
||||
LogUtil.writeLog("java_vm_specification_name:"
|
||||
+ System.getProperty("java.vm.specification.name"));
|
||||
LogUtil.writeLog("java_vm_version:"
|
||||
+ System.getProperty("java.vm.version"));
|
||||
LogUtil.writeLog("java_vm_name:" + System.getProperty("java.vm.name"));
|
||||
LogUtil.writeLog("java.version:" + System.getProperty("java.version"));
|
||||
LogUtil.writeLog("java.vm.vendor=[" + System.getProperty("java.vm.vendor") + "]");
|
||||
LogUtil.writeLog("java.version=[" + System.getProperty("java.version") + "]");
|
||||
printProviders();
|
||||
LogUtil.writeLog("================= SYS INFO end=====================");
|
||||
}
|
||||
|
||||
private static void printProviders() {
|
||||
LogUtil.writeLog("Providers List:");
|
||||
Provider[] providers = Security.getProviders();
|
||||
for (int i = 0; i < providers.length; i++) {
|
||||
LogUtil.writeLog(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;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean accept(File dir, String name) {
|
||||
return isCer(name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.zscat.mallplus.unionpay;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* @author UnionPay
|
||||
*/
|
||||
public class LogUtil {
|
||||
|
||||
final static String LOG_STRING_REQ_MSG_BEGIN = "============================== SDK REQ MSG BEGIN ==============================";
|
||||
final static String LOG_STRING_REQ_MSG_END = "============================== SDK REQ MSG END ==============================";
|
||||
final static String LOG_STRING_RSP_MSG_BEGIN = "============================== SDK RSP MSG BEGIN ==============================";
|
||||
final static String LOG_STRING_RSP_MSG_END = "============================== SDK RSP MSG END ==============================";
|
||||
private final static Logger GATE_LOG = LoggerFactory.getLogger("ACP_SDK_LOG");
|
||||
private final static Logger GATE_LOG_ERROR = LoggerFactory.getLogger("SDK_ERR_LOG");
|
||||
private final static Logger GATE_LOG_MESSAGE = LoggerFactory.getLogger("SDK_MSG_LOG");
|
||||
|
||||
public static void writeLog(String cont) {
|
||||
GATE_LOG.info(cont);
|
||||
}
|
||||
|
||||
public static void writeErrorLog(String cont) {
|
||||
GATE_LOG_ERROR.error(cont);
|
||||
}
|
||||
|
||||
public static void writeErrorLog(String cont, Throwable ex) {
|
||||
GATE_LOG_ERROR.error(cont, ex);
|
||||
}
|
||||
|
||||
public static void writeMessage(String msg) {
|
||||
GATE_LOG_MESSAGE.info(msg);
|
||||
}
|
||||
|
||||
public static void printRequestLog(Map<String, String> reqParam) {
|
||||
writeMessage(LOG_STRING_REQ_MSG_BEGIN);
|
||||
Iterator<Entry<String, String>> it = reqParam.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Entry<String, String> en = it.next();
|
||||
writeMessage("[" + en.getKey() + "] = [" + en.getValue() + "]");
|
||||
}
|
||||
writeMessage(LOG_STRING_REQ_MSG_END);
|
||||
}
|
||||
|
||||
public static void printResponseLog(String res) {
|
||||
writeMessage(LOG_STRING_RSP_MSG_BEGIN);
|
||||
writeMessage(res);
|
||||
writeMessage(LOG_STRING_RSP_MSG_END);
|
||||
}
|
||||
|
||||
public static void debug(String cont) {
|
||||
if (GATE_LOG.isDebugEnabled()) {
|
||||
GATE_LOG.debug(cont);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,911 @@
|
||||
package com.zscat.mallplus.unionpay;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* @author UnionPay
|
||||
*/
|
||||
public class SDKConfig {
|
||||
public static final String FILE_NAME = "acp_sdk.properties";
|
||||
/**
|
||||
* 配置文件中的前台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();
|
||||
/**
|
||||
* 前台请求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;
|
||||
/**
|
||||
* 属性文件对象.
|
||||
*/
|
||||
private Properties properties;
|
||||
|
||||
private SDKConfig() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static SDKConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public void loadPropertiesFromPath(String rootPath) {
|
||||
if (rootPath != null && !"".equals(rootPath.trim())) {
|
||||
LogUtil.writeLog("从路径读取配置文件: " + rootPath + File.separator + FILE_NAME);
|
||||
File file = new File(rootPath + File.separator + FILE_NAME);
|
||||
InputStream in = null;
|
||||
if (file.exists()) {
|
||||
try {
|
||||
in = new FileInputStream(file);
|
||||
properties = new Properties();
|
||||
properties.load(in);
|
||||
loadProperties(properties);
|
||||
} catch (FileNotFoundException e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
} catch (IOException e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
} finally {
|
||||
if (null != in) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 由于此时可能还没有完成LOG的加载,因此采用标准输出来打印日志信息
|
||||
LogUtil.writeErrorLog(rootPath + FILE_NAME + "不存在,加载参数失败");
|
||||
}
|
||||
} else {
|
||||
loadPropertiesFromSrc();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void loadPropertiesFromSrc() {
|
||||
InputStream in = null;
|
||||
try {
|
||||
LogUtil.writeLog("从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 {
|
||||
LogUtil.writeErrorLog(FILE_NAME + "属性文件未能在classpath指定的目录下 " + SDKConfig.class.getClassLoader().getResource("").getPath() + " 找到!");
|
||||
return;
|
||||
}
|
||||
loadProperties(properties);
|
||||
} catch (IOException e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
} finally {
|
||||
if (null != in) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void loadProperties(Properties pro) {
|
||||
LogUtil.writeLog("开始从属性文件中加载配置项");
|
||||
String value = null;
|
||||
|
||||
value = pro.getProperty(SDK_SIGNCERT_PATH);
|
||||
if (!SDKUtil.isEmpty(value)) {
|
||||
this.signCertPath = value.trim();
|
||||
LogUtil.writeLog("配置项:私钥签名证书路径==>" + SDK_SIGNCERT_PATH + "==>" + value + " 已加载");
|
||||
}
|
||||
value = pro.getProperty(SDK_SIGNCERT_PWD);
|
||||
if (!SDKUtil.isEmpty(value)) {
|
||||
this.signCertPwd = value.trim();
|
||||
LogUtil.writeLog("配置项:私钥签名证书密码==>" + SDK_SIGNCERT_PWD + " 已加载");
|
||||
}
|
||||
value = pro.getProperty(SDK_SIGNCERT_TYPE);
|
||||
if (!SDKUtil.isEmpty(value)) {
|
||||
this.signCertType = value.trim();
|
||||
LogUtil.writeLog("配置项:私钥签名证书类型==>" + SDK_SIGNCERT_TYPE + "==>" + value + " 已加载");
|
||||
}
|
||||
value = pro.getProperty(SDK_ENCRYPTCERT_PATH);
|
||||
if (!SDKUtil.isEmpty(value)) {
|
||||
this.encryptCertPath = value.trim();
|
||||
LogUtil.writeLog("配置项:敏感信息加密证书==>" + SDK_ENCRYPTCERT_PATH + "==>" + value + " 已加载");
|
||||
}
|
||||
value = pro.getProperty(SDK_VALIDATECERT_DIR);
|
||||
if (!SDKUtil.isEmpty(value)) {
|
||||
this.validateCertDir = value.trim();
|
||||
LogUtil.writeLog("配置项:验证签名证书路径(这里配置的是目录,不要指定到公钥文件)==>" + 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,663 @@
|
||||
package com.zscat.mallplus.unionpay;
|
||||
|
||||
/**
|
||||
* @author UnionPay
|
||||
*/
|
||||
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";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,655 @@
|
||||
package com.zscat.mallplus.unionpay;
|
||||
|
||||
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;
|
||||
|
||||
import static com.zscat.mallplus.unionpay.SDKConstants.*;
|
||||
|
||||
/**
|
||||
* @author UnionPay
|
||||
*/
|
||||
public class SDKUtil {
|
||||
|
||||
public static boolean sign(Map<String, String> data, String encoding) {
|
||||
|
||||
if (isEmpty(encoding)) {
|
||||
encoding = "UTF-8";
|
||||
}
|
||||
String signMethod = data.get(param_signMethod);
|
||||
String version = data.get(SDKConstants.param_version);
|
||||
if (!VERSION_1_0_0.equals(version) && !VERSION_5_0_1.equals(version) && isEmpty(signMethod)) {
|
||||
LogUtil.writeErrorLog("signMethod must Not null");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isEmpty(version)) {
|
||||
LogUtil.writeErrorLog("version must Not null");
|
||||
return false;
|
||||
}
|
||||
if (SIGNMETHOD_RSA.equals(signMethod) || VERSION_1_0_0.equals(version) || VERSION_5_0_1.equals(version)) {
|
||||
if (VERSION_5_0_0.equals(version) || VERSION_1_0_0.equals(version) || VERSION_5_0_1.equals(version)) {
|
||||
// 设置签名证书序列号
|
||||
data.put(SDKConstants.param_certId, CertUtil.getSignCertId());
|
||||
// 将Map信息转换成key1=value1&key2=value2的形式
|
||||
String stringData = coverMap2String(data);
|
||||
LogUtil.writeLog("打印排序后待签名请求报文串(交易返回11验证签名失败时可以用来同正确的进行比对):[" + stringData + "]");
|
||||
byte[] byteSign = null;
|
||||
String stringSign = null;
|
||||
try {
|
||||
// 通过SHA1进行摘要并转16进制
|
||||
byte[] signDigest = SecureUtil.sha1X16(stringData, encoding);
|
||||
LogUtil.writeLog("打印摘要(交易返回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) {
|
||||
LogUtil.writeErrorLog("Sign Error", e);
|
||||
return false;
|
||||
}
|
||||
} else if (VERSION_5_1_0.equals(version)) {
|
||||
// 设置签名证书序列号
|
||||
data.put(SDKConstants.param_certId, CertUtil.getSignCertId());
|
||||
// 将Map信息转换成key1=value1&key2=value2的形式
|
||||
String stringData = coverMap2String(data);
|
||||
LogUtil.writeLog("打印待签名请求报文串(交易返回11验证签名失败时可以用来同正确的进行比对):[" + stringData + "]");
|
||||
byte[] byteSign = null;
|
||||
String stringSign = null;
|
||||
try {
|
||||
// 通过SHA256进行摘要并转16进制
|
||||
byte[] signDigest = SecureUtil.sha256X16(stringData, encoding);
|
||||
LogUtil.writeLog("打印摘要(交易返回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) {
|
||||
LogUtil.writeErrorLog("Sign Error", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (SIGNMETHOD_SHA256.equals(signMethod)) {
|
||||
return signBySecureKey(data, SDKConfig.getConfig().getSecureKey(), encoding);
|
||||
} else if (SIGNMETHOD_SM3.equals(signMethod)) {
|
||||
return signBySecureKey(data, SDKConfig.getConfig().getSecureKey(), encoding);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean signBySecureKey(Map<String, String> data, String secureKey, String encoding) {
|
||||
|
||||
if (isEmpty(encoding)) {
|
||||
encoding = "UTF-8";
|
||||
}
|
||||
if (isEmpty(secureKey)) {
|
||||
LogUtil.writeErrorLog("secureKey is empty");
|
||||
return false;
|
||||
}
|
||||
String signMethod = data.get(param_signMethod);
|
||||
if (isEmpty(signMethod)) {
|
||||
LogUtil.writeErrorLog("signMethod must Not null");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SIGNMETHOD_SHA256.equals(signMethod)) {
|
||||
// 将Map信息转换成key1=value1&key2=value2的形式
|
||||
String stringData = coverMap2String(data);
|
||||
LogUtil.writeLog("待签名请求报文串:[" + 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 (SIGNMETHOD_SM3.equals(signMethod)) {
|
||||
String stringData = coverMap2String(data);
|
||||
LogUtil.writeLog("待签名请求报文串:[" + 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;
|
||||
}
|
||||
|
||||
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)) {
|
||||
LogUtil.writeErrorLog("CertPath or CertPwd is empty");
|
||||
return false;
|
||||
}
|
||||
String signMethod = data.get(param_signMethod);
|
||||
String version = data.get(SDKConstants.param_version);
|
||||
if (!VERSION_1_0_0.equals(version) && !VERSION_5_0_1.equals(version) && isEmpty(signMethod)) {
|
||||
LogUtil.writeErrorLog("signMethod must Not null");
|
||||
return false;
|
||||
}
|
||||
if (isEmpty(version)) {
|
||||
LogUtil.writeErrorLog("version must Not null");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SIGNMETHOD_RSA.equals(signMethod) || VERSION_1_0_0.equals(version) || VERSION_5_0_1.equals(version)) {
|
||||
if (VERSION_5_0_0.equals(version) || VERSION_1_0_0.equals(version) || VERSION_5_0_1.equals(version)) {
|
||||
// 设置签名证书序列号
|
||||
data.put(SDKConstants.param_certId, CertUtil.getCertIdByKeyStoreMap(certPath, certPwd));
|
||||
// 将Map信息转换成key1=value1&key2=value2的形式
|
||||
String stringData = coverMap2String(data);
|
||||
LogUtil.writeLog("待签名请求报文串:[" + 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) {
|
||||
LogUtil.writeErrorLog("Sign Error", e);
|
||||
return false;
|
||||
}
|
||||
} else if (VERSION_5_1_0.equals(version)) {
|
||||
// 设置签名证书序列号
|
||||
data.put(SDKConstants.param_certId, CertUtil.getCertIdByKeyStoreMap(certPath, certPwd));
|
||||
// 将Map信息转换成key1=value1&key2=value2的形式
|
||||
String stringData = coverMap2String(data);
|
||||
LogUtil.writeLog("待签名请求报文串:[" + stringData + "]");
|
||||
byte[] byteSign = null;
|
||||
String stringSign = null;
|
||||
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) {
|
||||
LogUtil.writeErrorLog("Sign Error", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean validateBySecureKey(Map<String, String> resData, String secureKey, String encoding) {
|
||||
LogUtil.writeLog("验签处理开始");
|
||||
if (isEmpty(encoding)) {
|
||||
encoding = "UTF-8";
|
||||
}
|
||||
String signMethod = resData.get(param_signMethod);
|
||||
if (SIGNMETHOD_SHA256.equals(signMethod)) {
|
||||
// 1.进行SHA256验证
|
||||
String stringSign = resData.get(SDKConstants.param_signature);
|
||||
LogUtil.writeLog("签名原文:[" + stringSign + "]");
|
||||
// 将Map信息转换成key1=value1&key2=value2的形式
|
||||
String stringData = coverMap2String(resData);
|
||||
LogUtil.writeLog("待验签返回报文串:[" + stringData + "]");
|
||||
String strBeforeSha256 = stringData + SDKConstants.AMPERSAND + SecureUtil.sha256X16Str(secureKey, encoding);
|
||||
String strAfterSha256 = SecureUtil.sha256X16Str(strBeforeSha256, encoding);
|
||||
return stringSign.equals(strAfterSha256);
|
||||
} else if (SIGNMETHOD_SM3.equals(signMethod)) {
|
||||
// 1.进行SM3验证
|
||||
String stringSign = resData.get(SDKConstants.param_signature);
|
||||
LogUtil.writeLog("签名原文:[" + stringSign + "]");
|
||||
// 将Map信息转换成key1=value1&key2=value2的形式
|
||||
String stringData = coverMap2String(resData);
|
||||
LogUtil.writeLog("待验签返回报文串:[" + stringData + "]");
|
||||
String strBeforeSM3 = stringData + SDKConstants.AMPERSAND + SecureUtil.sm3X16Str(secureKey, encoding);
|
||||
String strAfterSM3 = SecureUtil.sm3X16Str(strBeforeSM3, encoding);
|
||||
return stringSign.equals(strAfterSM3);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean validate(Map<String, String> resData, String encoding) {
|
||||
LogUtil.writeLog("验签处理开始");
|
||||
if (isEmpty(encoding)) {
|
||||
encoding = "UTF-8";
|
||||
}
|
||||
String signMethod = resData.get(param_signMethod);
|
||||
String version = resData.get(SDKConstants.param_version);
|
||||
if (SIGNMETHOD_RSA.equals(signMethod) || VERSION_1_0_0.equals(version) || VERSION_5_0_1.equals(version)) {
|
||||
// 获取返回报文的版本号
|
||||
if (VERSION_5_0_0.equals(version) || VERSION_1_0_0.equals(version) || VERSION_5_0_1.equals(version)) {
|
||||
String stringSign = resData.get(SDKConstants.param_signature);
|
||||
LogUtil.writeLog("签名原文:[" + stringSign + "]");
|
||||
// 从返回报文中获取certId ,然后去证书静态Map中查询对应验签证书对象
|
||||
String certId = resData.get(SDKConstants.param_certId);
|
||||
LogUtil.writeLog("对返回报文串验签使用的验签公钥序列号:[" + certId + "]");
|
||||
// 将Map信息转换成key1=value1&key2=value2的形式
|
||||
String stringData = coverMap2String(resData);
|
||||
LogUtil.writeLog("待验签返回报文串:[" + stringData + "]");
|
||||
try {
|
||||
// 验证签名需要用银联发给商户的公钥证书.
|
||||
return SecureUtil.validateSignBySoft(CertUtil
|
||||
.getValidatePublicKey(certId), SecureUtil
|
||||
.base64Decode(stringSign.getBytes(encoding)),
|
||||
SecureUtil.sha1X16(stringData, encoding));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
}
|
||||
} else if (VERSION_5_1_0.equals(version)) {
|
||||
// 1.从返回报文中获取公钥信息转换成公钥对象
|
||||
String strCert = resData.get(SDKConstants.param_signPubKeyCert);
|
||||
// LogUtil.writeLog("验签公钥证书:["+strCert+"]");
|
||||
X509Certificate x509Cert = CertUtil.genCertificateByStr(strCert);
|
||||
if (x509Cert == null) {
|
||||
LogUtil.writeErrorLog("convert signPubKeyCert failed");
|
||||
return false;
|
||||
}
|
||||
// 2.验证证书链
|
||||
if (!CertUtil.verifyCertificate(x509Cert)) {
|
||||
LogUtil.writeErrorLog("验证公钥证书失败,证书信息:[" + strCert + "]");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3.验签
|
||||
String stringSign = resData.get(SDKConstants.param_signature);
|
||||
LogUtil.writeLog("签名原文:[" + stringSign + "]");
|
||||
// 将Map信息转换成key1=value1&key2=value2的形式
|
||||
String stringData = coverMap2String(resData);
|
||||
LogUtil.writeLog("待验签返回报文串:[" + stringData + "]");
|
||||
try {
|
||||
// 验证签名需要用银联发给商户的公钥证书.
|
||||
boolean result = SecureUtil.validateSignBySoft256(x509Cert
|
||||
.getPublicKey(), SecureUtil.base64Decode(stringSign
|
||||
.getBytes(encoding)), SecureUtil.sha256X16(
|
||||
stringData, encoding));
|
||||
LogUtil.writeLog("验证签名" + (result ? "成功" : "失败"));
|
||||
return result;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (SIGNMETHOD_SHA256.equals(signMethod)) {
|
||||
// 1.进行SHA256验证
|
||||
String stringSign = resData.get(SDKConstants.param_signature);
|
||||
LogUtil.writeLog("签名原文:[" + stringSign + "]");
|
||||
// 将Map信息转换成key1=value1&key2=value2的形式
|
||||
String stringData = coverMap2String(resData);
|
||||
LogUtil.writeLog("待验签返回报文串:[" + stringData + "]");
|
||||
String strBeforeSha256 = stringData
|
||||
+ SDKConstants.AMPERSAND
|
||||
+ SecureUtil.sha256X16Str(SDKConfig.getConfig()
|
||||
.getSecureKey(), encoding);
|
||||
String strAfterSha256 = SecureUtil.sha256X16Str(strBeforeSha256,
|
||||
encoding);
|
||||
boolean result = stringSign.equals(strAfterSha256);
|
||||
LogUtil.writeLog("验证签名" + (result ? "成功" : "失败"));
|
||||
return result;
|
||||
} else if (SIGNMETHOD_SM3.equals(signMethod)) {
|
||||
// 1.进行SM3验证
|
||||
String stringSign = resData.get(SDKConstants.param_signature);
|
||||
LogUtil.writeLog("签名原文:[" + stringSign + "]");
|
||||
// 将Map信息转换成key1=value1&key2=value2的形式
|
||||
String stringData = coverMap2String(resData);
|
||||
LogUtil.writeLog("待验签返回报文串:[" + stringData + "]");
|
||||
String strBeforeSM3 = stringData
|
||||
+ SDKConstants.AMPERSAND
|
||||
+ SecureUtil.sm3X16Str(SDKConfig.getConfig()
|
||||
.getSecureKey(), encoding);
|
||||
String strAfterSM3 = SecureUtil
|
||||
.sm3X16Str(strBeforeSM3, encoding);
|
||||
boolean result = stringSign.equals(strAfterSM3);
|
||||
LogUtil.writeLog("验证签名" + (result ? "成功" : "失败"));
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String coverMap2String(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();
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
public static Map<String, String> coverResultString2Map(String result) {
|
||||
return convertResultStringToMap(result);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
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 (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;
|
||||
LogUtil.writeLog("save new encryptPubKeyCert success");
|
||||
CertUtil.resetEncryptCertPublicKey();
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else if (CERTTYPE_02.equals(certType)) {
|
||||
return 0;
|
||||
} else {
|
||||
LogUtil.writeLog("unknown cerType:" + certType);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
LogUtil.writeErrorLog("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) {
|
||||
LogUtil.writeErrorLog("Releases any system resources fail", ex);
|
||||
}
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
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) {
|
||||
LogUtil.writeErrorLog("WriteFile fail", e);
|
||||
return false;
|
||||
} catch (IOException ex) {
|
||||
LogUtil.writeErrorLog("WriteFile fail", ex);
|
||||
return false;
|
||||
} finally {
|
||||
try {
|
||||
if (null != fout)
|
||||
fout.close();
|
||||
if (null != fcout)
|
||||
fcout.close();
|
||||
} catch (IOException ex) {
|
||||
LogUtil.writeErrorLog("Releases any system resources fail", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String genBackupName(String fileName) {
|
||||
if (isEmpty(fileName))
|
||||
return "";
|
||||
int i = fileName.lastIndexOf(POINT);
|
||||
String leftFileName = fileName.substring(0, i);
|
||||
String rightFileName = fileName.substring(i + 1);
|
||||
String newFileName = leftFileName + "_backup" + 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) {
|
||||
LogUtil.writeErrorLog(e.getMessage());
|
||||
return null;
|
||||
} finally {
|
||||
try {
|
||||
if (null != fc) {
|
||||
fc.close();
|
||||
}
|
||||
if (null != in) {
|
||||
in.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.writeErrorLog(e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<String, String> filterBlank(Map<String, String> contentData) {
|
||||
LogUtil.writeLog("打印请求报文域 :");
|
||||
Map<String, String> submitFromData = new HashMap<String, String>();
|
||||
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());
|
||||
LogUtil.writeLog(key + "-->" + String.valueOf(value));
|
||||
}
|
||||
}
|
||||
return submitFromData;
|
||||
}
|
||||
|
||||
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) {
|
||||
System.err.println("Data format error!\n");
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
o.close();
|
||||
}
|
||||
compresser.end();
|
||||
return o.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
public static boolean isEmpty(String s) {
|
||||
return null == s || "".equals(s.trim());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
package com.zscat.mallplus.unionpay;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author UnionPay
|
||||
*/
|
||||
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";
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] sha1(byte[] data) {
|
||||
MessageDigest md = null;
|
||||
try {
|
||||
md = MessageDigest.getInstance(ALGORITHM_SHA1);
|
||||
md.reset();
|
||||
md.update(data);
|
||||
return md.digest();
|
||||
} catch (Exception e) {
|
||||
LogUtil.writeErrorLog("SHA1计算失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] sha256(byte[] data) {
|
||||
MessageDigest md = null;
|
||||
try {
|
||||
md = MessageDigest.getInstance(ALGORITHM_SHA256);
|
||||
md.reset();
|
||||
md.update(data);
|
||||
return md.digest();
|
||||
} catch (Exception e) {
|
||||
LogUtil.writeErrorLog("SHA256计算失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private static byte[] sha1(String datas, String encoding) {
|
||||
try {
|
||||
return sha1(datas.getBytes(encoding));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LogUtil.writeErrorLog("SHA1计算失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] sha256(String datas, String encoding) {
|
||||
try {
|
||||
return sha256(datas.getBytes(encoding));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LogUtil.writeErrorLog("SHA256计算失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] sm3(String data, String encoding) {
|
||||
try {
|
||||
return sm3(data.getBytes(encoding));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LogUtil.writeErrorLog("SM3计算失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] signBySoft(PrivateKey privateKey, byte[] data)
|
||||
throws Exception {
|
||||
byte[] result = null;
|
||||
Signature st = Signature.getInstance(BC_PROV_ALGORITHM_SHA1RSA, "BC");
|
||||
st.initSign(privateKey);
|
||||
st.update(data);
|
||||
result = st.sign();
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] signBySoft256(PrivateKey privateKey, byte[] data)
|
||||
throws Exception {
|
||||
byte[] result = null;
|
||||
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);
|
||||
}
|
||||
|
||||
public static String encryptData(String dataString, String encoding,
|
||||
PublicKey key) {
|
||||
/** 使用公钥对密码加密 **/
|
||||
byte[] data = null;
|
||||
try {
|
||||
data = encryptData(key, dataString.getBytes(encoding));
|
||||
return new String(SecureUtil.base64Encode(data), encoding);
|
||||
} catch (Exception e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static String encryptPin(String accNo, String pin, String encoding,
|
||||
PublicKey key) {
|
||||
/** 使用公钥对密码加密 **/
|
||||
byte[] data = null;
|
||||
try {
|
||||
data = pin2PinBlockWithCardNo(pin, accNo);
|
||||
data = encryptData(key, data);
|
||||
return new String(SecureUtil.base64Encode(data), encoding);
|
||||
} catch (Exception e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static String decryptData(String dataString, String encoding,
|
||||
PrivateKey key) {
|
||||
byte[] data = null;
|
||||
try {
|
||||
data = SecureUtil.base64Decode(dataString.getBytes(encoding));
|
||||
data = decryptData(key, data);
|
||||
return new String(data, encoding);
|
||||
} catch (Exception e) {
|
||||
LogUtil.writeErrorLog(e.getMessage(), e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] base64Decode(byte[] inputByte) throws IOException {
|
||||
return Base64.decodeBase64(inputByte);
|
||||
}
|
||||
|
||||
public static byte[] base64Encode(byte[] inputByte) throws IOException {
|
||||
return Base64.encodeBase64(inputByte);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
LogUtil.writeErrorLog("解密失败", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static byte[] pin2PinBlock(String aPin) {
|
||||
int tTemp = 1;
|
||||
int tPinLen = aPin.length();
|
||||
|
||||
byte[] tByte = new byte[8];
|
||||
try {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
// this is for odd digits, they are 1-indexed in //
|
||||
if (i % 2 == 0) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
package com.zscat.mallplus.unionpay;
|
||||
|
||||
|
||||
import com.zscat.mallplus.core.kit.HttpKit;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>银联支付相关接口</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public class UnionPayApi {
|
||||
/**
|
||||
* PC网关支付、WAP支付
|
||||
*
|
||||
* @param resp HttpServletResponse
|
||||
* @param reqData 请求参数
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
@Deprecated
|
||||
public static void frontConsume(HttpServletResponse resp, Map<String, String> reqData) throws IOException {
|
||||
String html = AcpService.createAutoFormHtml(SDKConfig.getConfig().getFrontRequestUrl(), reqData, "UTF-8");
|
||||
resp.getWriter().write(html);
|
||||
}
|
||||
|
||||
/**
|
||||
* 前端请求
|
||||
*
|
||||
* @param resp HttpServletResponse
|
||||
* @param reqData 请求参数
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public static void frontRequest(HttpServletResponse resp, Map<String, String> reqData) throws IOException {
|
||||
String html = AcpService.createAutoFormHtml(SDKConfig.getConfig().getFrontRequestUrl(), reqData, "UTF-8");
|
||||
resp.getWriter().write(html);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退货交易、撤销交易
|
||||
*
|
||||
* @param reqData 请求参数
|
||||
* @return {String}
|
||||
*/
|
||||
@Deprecated
|
||||
public static String refund(Map<String, String> reqData) {
|
||||
return doPost(SDKConfig.getConfig().getBackRequestUrl(), reqData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退货交、撤销交易
|
||||
*
|
||||
* @param reqData 请求参数
|
||||
* @return 转化后的 Map
|
||||
*/
|
||||
@Deprecated
|
||||
public static Map<String, String> refundByMap(Map<String, String> reqData) {
|
||||
return SDKUtil.convertResultStringToMap(refund(reqData));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 后台请求返回String
|
||||
*
|
||||
* @param reqData 请求参数
|
||||
* @return {String}
|
||||
*/
|
||||
public static String backRequest(Map<String, String> reqData) {
|
||||
return doPost(SDKConfig.getConfig().getBackRequestUrl(), reqData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 后台请求返回Map
|
||||
*
|
||||
* @param reqData 请求参数
|
||||
* @return 转化后的 Map
|
||||
*/
|
||||
public static Map<String, String> backRequestByMap(Map<String, String> reqData) {
|
||||
return SDKUtil.convertResultStringToMap(backRequest(reqData));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 单订单查询返回String
|
||||
*
|
||||
* @param reqData 请求参数
|
||||
* @return {String}
|
||||
*/
|
||||
public static String singleQuery(Map<String, String> reqData) {
|
||||
return doPost(SDKConfig.getConfig().getSingleQueryUrl(), reqData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 单订单查询返回Map
|
||||
*
|
||||
* @param reqData 请求参数
|
||||
* @return 转化后的 Map
|
||||
*/
|
||||
public static Map<String, String> singleQueryByMap(Map<String, String> reqData) {
|
||||
return SDKUtil.convertResultStringToMap(singleQuery(reqData));
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件传输类接口
|
||||
*
|
||||
* @param reqData 请求参数
|
||||
* @return {String}
|
||||
*/
|
||||
public static String fileTransfer(Map<String, String> reqData) {
|
||||
return doPost(SDKConfig.getConfig().getFileTransUrl(), reqData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件传输类接口
|
||||
*
|
||||
* @param reqData 请求参数
|
||||
* @return 转化后的 Map
|
||||
*/
|
||||
public static Map<String, String> fileTransferByMap(Map<String, String> reqData) {
|
||||
return SDKUtil.convertResultStringToMap(fileTransfer(reqData));
|
||||
}
|
||||
|
||||
/**
|
||||
* APP控件支付
|
||||
*
|
||||
* @param reqData 请求参数
|
||||
* @return {String}
|
||||
*/
|
||||
public static String AppConsume(Map<String, String> reqData) {
|
||||
return doPost(SDKConfig.getConfig().getAppRequestUrl(), reqData);
|
||||
}
|
||||
|
||||
/**
|
||||
* APP控件支付
|
||||
*
|
||||
* @param reqData 请求参数
|
||||
* @return 转化后的 Map
|
||||
*/
|
||||
public static Map<String, String> AppConsumeByMap(Map<String, String> reqData) {
|
||||
return SDKUtil.convertResultStringToMap(AppConsume(reqData));
|
||||
}
|
||||
|
||||
/**
|
||||
* 网关缴费
|
||||
*
|
||||
* @param resp HttpServletResponse
|
||||
* @param reqData 请求参数
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public static void jfFrontConsume(HttpServletResponse resp, Map<String, String> reqData) throws IOException {
|
||||
String html = AcpService.createAutoFormHtml(SDKConfig.getConfig().getJfFrontRequestUrl(), reqData, "UTF-8");
|
||||
resp.getWriter().write(html);
|
||||
}
|
||||
|
||||
/**
|
||||
* APP缴费
|
||||
*
|
||||
* @param reqData 请求参数
|
||||
* @return {String}
|
||||
*/
|
||||
public static String jfAppTrans(Map<String, String> reqData) {
|
||||
return doPost(SDKConfig.getConfig().getAppRequestUrl(), reqData);
|
||||
}
|
||||
|
||||
/**
|
||||
* APP缴费
|
||||
*
|
||||
* @param reqData 请求参数
|
||||
* @return 转化后的 Map
|
||||
*/
|
||||
public static Map<String, String> jfAppTransByMap(Map<String, String> reqData) {
|
||||
return SDKUtil.convertResultStringToMap(jfAppTrans(reqData));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取地区列表
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
public static String getAllAreas() {
|
||||
return doGet("https://gateway.95516.com/jiaofei/config/s/areas");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取业务目录
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
public static String getAllCategories() {
|
||||
return doGet("https://gateway.95516.com/jiaofei/config/s/categories/00");
|
||||
}
|
||||
|
||||
public static String doGet(String url) {
|
||||
return HttpKit.getDelegate().get(url);
|
||||
}
|
||||
|
||||
public static String doPost(String url, Map<String, String> params) {
|
||||
Map<String, Object> temp = new HashMap<String, Object>(params.size());
|
||||
temp.putAll(params);
|
||||
return HttpKit.getDelegate().post(url, temp);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
package com.zscat.mallplus.unionpay;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Javen
|
||||
*/
|
||||
public class UnionPayApiConfig {
|
||||
private UnionPayApiConfig() {
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private String version;
|
||||
private String encoding;
|
||||
private String signMethod;
|
||||
private String txnType;
|
||||
private String txnSubType;
|
||||
private String bizType;
|
||||
private String channelType;
|
||||
private String accessType;
|
||||
private String merId;
|
||||
private String frontUrl;
|
||||
private String backUrl;
|
||||
private String orderId;
|
||||
private String currencyCode;
|
||||
private String txnAmt;
|
||||
private String txnTime;
|
||||
private String payTimeout;
|
||||
private String accNo;
|
||||
private String reqReserved;
|
||||
private String orderDesc;
|
||||
private String acqInsCode;
|
||||
private String merCatCode;
|
||||
private String merName;
|
||||
private String merAbbr;
|
||||
private String origQryId;
|
||||
private String settleDate;
|
||||
private String fileType;
|
||||
private String bussCode;
|
||||
private String billQueryInfo;
|
||||
private String qrNo;
|
||||
private String termId;
|
||||
private String accType;
|
||||
private String encryptCertId;
|
||||
private String customerInfo;
|
||||
|
||||
public Map<String, String> createMap() {
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
if (SDKUtil.isEmpty(version)) {
|
||||
version = "5.1.0";
|
||||
}
|
||||
if (SDKUtil.isEmpty(encoding)) {
|
||||
encoding = "UTF-8";
|
||||
}
|
||||
if (SDKUtil.isEmpty(signMethod)) {
|
||||
signMethod = "01";
|
||||
}
|
||||
if (SDKUtil.isEmpty(txnType)) {
|
||||
txnType = "01";
|
||||
}
|
||||
if (SDKUtil.isEmpty(txnSubType)) {
|
||||
txnSubType = "01";
|
||||
}
|
||||
if (SDKUtil.isEmpty(bizType)) {
|
||||
bizType = "000201";
|
||||
}
|
||||
if (SDKUtil.isEmpty(channelType)) {
|
||||
channelType = "07";
|
||||
}
|
||||
if (SDKUtil.isEmpty(accessType)) {
|
||||
accessType = "0";
|
||||
}
|
||||
if (SDKUtil.isEmpty(merId)) {
|
||||
throw new IllegalArgumentException("merId 值不能为 null");
|
||||
}
|
||||
if (SDKUtil.isEmpty(backUrl)) {
|
||||
backUrl = SDKConfig.getConfig().getBackUrl();
|
||||
}
|
||||
if (SDKUtil.isEmpty(frontUrl)) {
|
||||
frontUrl = SDKConfig.getConfig().getFrontUrl();
|
||||
}
|
||||
|
||||
if (SDKUtil.isEmpty(orderId)) {
|
||||
orderId = String.valueOf(System.currentTimeMillis());
|
||||
}
|
||||
if (orderId.contains("_") || orderId.contains("-")) {
|
||||
throw new IllegalArgumentException("orderId 值不应含“-”或“_”");
|
||||
}
|
||||
if (SDKUtil.isEmpty(currencyCode)) {
|
||||
currencyCode = "156";
|
||||
}
|
||||
if (SDKUtil.isEmpty(txnAmt)) {
|
||||
txnAmt = "1";
|
||||
}
|
||||
if (SDKUtil.isEmpty(txnTime)) {
|
||||
txnTime = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||
}
|
||||
if (SDKUtil.isEmpty(payTimeout)) {
|
||||
payTimeout = DateUtil.format(new Date(new Date().getTime() + 15 * 60 * 1000), "YYYYMMddHHmmss");
|
||||
}
|
||||
|
||||
|
||||
map.put("version", version);
|
||||
map.put("encoding", encoding);
|
||||
map.put("signMethod", signMethod);
|
||||
map.put("txnType", txnType);
|
||||
map.put("txnSubType", txnSubType);
|
||||
map.put("bizType", bizType);
|
||||
map.put("channelType", channelType);
|
||||
map.put("accessType", accessType);
|
||||
map.put("merId", merId);
|
||||
map.put("frontUrl", frontUrl);
|
||||
map.put("backUrl", backUrl);
|
||||
map.put("orderId", orderId);
|
||||
map.put("currencyCode", currencyCode);
|
||||
map.put("txnAmt", txnAmt);
|
||||
map.put("txnTime", txnTime);
|
||||
map.put("payTimeout", payTimeout);
|
||||
map.put("accNo", accNo);
|
||||
map.put("reqReserved", reqReserved);
|
||||
map.put("orderDesc", orderDesc);
|
||||
map.put("acqInsCode", acqInsCode);
|
||||
map.put("merCatCode", merCatCode);
|
||||
map.put("merName", merName);
|
||||
map.put("merAbbr", merAbbr);
|
||||
map.put("origQryId", origQryId);
|
||||
map.put("settleDate", settleDate);
|
||||
map.put("fileType", fileType);
|
||||
map.put("bussCode", bussCode);
|
||||
map.put("billQueryInfo", billQueryInfo);
|
||||
map.put("qrNo", qrNo);
|
||||
map.put("termId", termId);
|
||||
map.put("accType", accType);
|
||||
map.put("encryptCertId", encryptCertId);
|
||||
map.put("customerInfo", customerInfo);
|
||||
|
||||
return setSignMap(map);
|
||||
}
|
||||
|
||||
public Map<String, String> setSignMap(Map<String, String> map) {
|
||||
// 报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。
|
||||
return AcpService.sign(map, encoding);
|
||||
}
|
||||
|
||||
|
||||
public Builder setVersion(String version) {
|
||||
this.version = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setEncoding(String encoding) {
|
||||
this.encoding = encoding;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setSignMethod(String signMethod) {
|
||||
this.signMethod = signMethod;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setTxnType(String txnType) {
|
||||
this.txnType = txnType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setTxnSubType(String txnSubType) {
|
||||
this.txnSubType = txnSubType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setBizType(String bizType) {
|
||||
this.bizType = bizType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setChannelType(String channelType) {
|
||||
this.channelType = channelType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAccessType(String accessType) {
|
||||
this.accessType = accessType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMerId(String merId) {
|
||||
this.merId = merId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setFrontUrl(String frontUrl) {
|
||||
this.frontUrl = frontUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setBackUrl(String backUrl) {
|
||||
this.backUrl = backUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setOrderId(String orderId) {
|
||||
this.orderId = orderId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setCurrencyCode(String currencyCode) {
|
||||
this.currencyCode = currencyCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setTxnAmt(String txnAmt) {
|
||||
this.txnAmt = txnAmt;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setTxnTime(String txnTime) {
|
||||
this.txnTime = txnTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPayTimeout(String payTimeout) {
|
||||
this.payTimeout = payTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAccNo(String accNo) {
|
||||
this.accNo = accNo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setReqReserved(String reqReserved) {
|
||||
this.reqReserved = reqReserved;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setOrderDesc(String orderDesc) {
|
||||
this.orderDesc = orderDesc;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAcqInsCode(String acqInsCode) {
|
||||
this.acqInsCode = acqInsCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMerCatCode(String merCatCode) {
|
||||
this.merCatCode = merCatCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMerName(String merName) {
|
||||
this.merName = merName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMerAbbr(String merAbbr) {
|
||||
this.merAbbr = merAbbr;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setOrigQryId(String origQryId) {
|
||||
this.origQryId = origQryId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setSettleDate(String settleDate) {
|
||||
this.settleDate = settleDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setFileType(String fileType) {
|
||||
this.fileType = fileType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setBussCode(String bussCode) {
|
||||
this.bussCode = bussCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setBillQueryInfo(String billQueryInfo) {
|
||||
this.billQueryInfo = billQueryInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setQrNo(String qrNo) {
|
||||
this.qrNo = qrNo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setTermId(String termId) {
|
||||
this.termId = termId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAccType(String accType) {
|
||||
this.accType = accType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setEncryptCertId(String encryptCertId) {
|
||||
this.encryptCertId = encryptCertId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setCustomerInfo(String customerInfo) {
|
||||
this.customerInfo = customerInfo;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
1079
mallplus-pay/src/main/java/com/zscat/mallplus/wxpay/WxPayApi.java
Normal file
1079
mallplus-pay/src/main/java/com/zscat/mallplus/wxpay/WxPayApi.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,36 @@
|
||||
package com.zscat.mallplus.wxpay;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>微信支付常用配置</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class WxPayApiConfig implements Serializable {
|
||||
private static final long serialVersionUID = -9044503427692786302L;
|
||||
|
||||
private String appId;
|
||||
private String mchId;
|
||||
private String slAppId;
|
||||
private String slMchId;
|
||||
private String partnerKey;
|
||||
private String domain;
|
||||
private String certPath;
|
||||
private Object exParams;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.zscat.mallplus.wxpay;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>微信支付常用配置 Kit</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public class WxPayApiConfigKit {
|
||||
|
||||
private static final ThreadLocal<String> TL = new ThreadLocal<String>();
|
||||
|
||||
private static final Map<String, WxPayApiConfig> CFG_MAP = new ConcurrentHashMap<String, WxPayApiConfig>();
|
||||
private static final String DEFAULT_CFG_KEY = "_default_key_";
|
||||
|
||||
/**
|
||||
* 添加微信支付配置,每个appId只需添加一次,相同appId将被覆盖
|
||||
*
|
||||
* @param wxPayApiConfig 微信支付配置
|
||||
* @return {WxPayApiConfig} 微信支付配置
|
||||
*/
|
||||
public static WxPayApiConfig putApiConfig(WxPayApiConfig wxPayApiConfig) {
|
||||
if (CFG_MAP.size() == 0) {
|
||||
CFG_MAP.put(DEFAULT_CFG_KEY, wxPayApiConfig);
|
||||
}
|
||||
return CFG_MAP.put(wxPayApiConfig.getAppId(), wxPayApiConfig);
|
||||
}
|
||||
|
||||
public static WxPayApiConfig setThreadLocalWxPayApiConfig(WxPayApiConfig wxPayApiConfig) {
|
||||
if (StrUtil.isNotEmpty(wxPayApiConfig.getAppId())) {
|
||||
setThreadLocalAppId(wxPayApiConfig.getAppId());
|
||||
}
|
||||
return putApiConfig(wxPayApiConfig);
|
||||
}
|
||||
|
||||
public static WxPayApiConfig removeApiConfig(WxPayApiConfig wxPayApiConfig) {
|
||||
return removeApiConfig(wxPayApiConfig.getAppId());
|
||||
}
|
||||
|
||||
public static WxPayApiConfig removeApiConfig(String appId) {
|
||||
return CFG_MAP.remove(appId);
|
||||
}
|
||||
|
||||
public static void setThreadLocalAppId(String appId) {
|
||||
if (StrUtil.isEmpty(appId)) {
|
||||
appId = CFG_MAP.get(DEFAULT_CFG_KEY).getAppId();
|
||||
}
|
||||
TL.set(appId);
|
||||
}
|
||||
|
||||
public static void removeThreadLocalAppId() {
|
||||
TL.remove();
|
||||
}
|
||||
|
||||
public static String getAppId() {
|
||||
String appId = TL.get();
|
||||
if (StrUtil.isEmpty(appId)) {
|
||||
appId = CFG_MAP.get(DEFAULT_CFG_KEY).getAppId();
|
||||
}
|
||||
return appId;
|
||||
}
|
||||
|
||||
public static WxPayApiConfig getWxPayApiConfig() {
|
||||
String appId = getAppId();
|
||||
return getApiConfig(appId);
|
||||
}
|
||||
|
||||
public static WxPayApiConfig getApiConfig(String appId) {
|
||||
WxPayApiConfig cfg = CFG_MAP.get(appId);
|
||||
if (cfg == null) {
|
||||
throw new IllegalStateException("需事先调用 WxPayApiConfigKit.putApiConfig(wxPayApiConfig) 将 appId 对应的 WxPayApiConfig 对象存入,才可以使用 WxPayApiConfigKit.getWxPayApiConfig() 的系列方法");
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.zscat.mallplus.wxpay.enums;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>分账接收方类型</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
|
||||
public enum ReceiverType {
|
||||
/**
|
||||
* 商户ID
|
||||
*/
|
||||
MERCHANT("MERCHANT_ID"),
|
||||
/**
|
||||
* 个人微信号
|
||||
*/
|
||||
WECHATID("PERSONAL_WECHATID"),
|
||||
/**
|
||||
* 个人 openId(由父商户 appId 转换得到)
|
||||
*/
|
||||
OPENID("PERSONAL_OPENID"),
|
||||
/**
|
||||
* 个人 sub_openid(由子商户 appId 转换得到)
|
||||
*/
|
||||
SUB_OPENID("PERSONAL_SUB_OPENID");
|
||||
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final String type;
|
||||
|
||||
ReceiverType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
package com.zscat.mallplus.wxpay.enums;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>微信支付接口枚举</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public enum WxApiType {
|
||||
/**
|
||||
* 沙箱环境
|
||||
*/
|
||||
SAND_BOX_NEW("/sandboxnew"),
|
||||
/**
|
||||
* 获取沙箱环境验签秘钥
|
||||
*/
|
||||
GET_SIGN_KEY("/sandboxnew/pay/getsignkey"),
|
||||
/**
|
||||
* 统一下单
|
||||
*/
|
||||
UNIFIED_ORDER("/pay/unifiedorder"),
|
||||
/**
|
||||
* 提交付款码支付
|
||||
*/
|
||||
MICRO_PAY("/pay/micropay"),
|
||||
/**
|
||||
* 查询订单
|
||||
*/
|
||||
ORDER_QUERY("/pay/orderquery"),
|
||||
/**
|
||||
* 关闭订单
|
||||
*/
|
||||
CLOSE_ORDER("/pay/closeorder"),
|
||||
/**
|
||||
* 撤销订单
|
||||
*/
|
||||
REVERSE("/secapi/pay/reverse"),
|
||||
/**
|
||||
* 申请退款
|
||||
*/
|
||||
REFUND("/secapi/pay/refund"),
|
||||
/**
|
||||
* 查询退款
|
||||
*/
|
||||
REFUND_QUERY("/pay/refundquery"),
|
||||
/**
|
||||
* 下载对账单
|
||||
*/
|
||||
DOWNLOAD_BILL("/pay/downloadbill"),
|
||||
/**
|
||||
* 下载资金对账单
|
||||
*/
|
||||
DOWNLOAD_FUND_FLOW("/pay/downloadfundflow"),
|
||||
/**
|
||||
* 交易保障
|
||||
*/
|
||||
REPORT("/payitil/report"),
|
||||
/**
|
||||
* 转换短链接
|
||||
*/
|
||||
SHORT_URL("/tools/shorturl"),
|
||||
/**
|
||||
* 授权码查询 openId
|
||||
*/
|
||||
AUTH_CODE_TO_OPENID("/tools/authcodetoopenid"),
|
||||
/**
|
||||
* 拉取订单评价数据
|
||||
*/
|
||||
BATCH_QUERY_COMMENT("/billcommentsp/batchquerycomment"),
|
||||
/**
|
||||
* 企业付款
|
||||
*/
|
||||
TRANSFER("/mmpaymkttransfers/promotion/transfers"),
|
||||
/**
|
||||
* 查询企业付款
|
||||
*/
|
||||
GET_TRANSFER_INFO("/mmpaymkttransfers/gettransferinfo"),
|
||||
/**
|
||||
* 企业付款到银行卡
|
||||
*/
|
||||
TRANSFER_BANK("/mmpaysptrans/pay_bank"),
|
||||
/**
|
||||
* 查询企业付款到银行卡
|
||||
*/
|
||||
GET_TRANSFER_BANK_INFO("/mmpaysptrans/query_bank"),
|
||||
/**
|
||||
* 获取 RSA 加密公钥
|
||||
*/
|
||||
GET_PUBLIC_KEY("/risk/getpublickey"),
|
||||
/**
|
||||
* 发放红包
|
||||
*/
|
||||
SEND_RED_PACK("/mmpaymkttransfers/sendredpack"),
|
||||
/**
|
||||
* 发放裂变红包
|
||||
*/
|
||||
SEND_GROUP_RED_PACK("/mmpaymkttransfers/sendgroupredpack"),
|
||||
/**
|
||||
* 查询红包记录
|
||||
*/
|
||||
GET_HB_INFO("/mmpaymkttransfers/gethbinfo"),
|
||||
/**
|
||||
* 小程序发红包
|
||||
*/
|
||||
SEND_MINI_PROGRAM_HB("/mmpaymkttransfers/sendminiprogramhb"),
|
||||
/**
|
||||
* 发放代金券
|
||||
*/
|
||||
SEND_COUPON("/mmpaymkttransfers/send_coupon"),
|
||||
/**
|
||||
* 查询代金券批次
|
||||
*/
|
||||
QUERY_COUPON_STOCK("/mmpaymkttransfers/query_coupon_stock"),
|
||||
/**
|
||||
* 查询代金券信息
|
||||
*/
|
||||
QUERY_COUPONS_INFO("/mmpaymkttransfers/querycouponsinfo"),
|
||||
/**
|
||||
* 请求单次分账
|
||||
*/
|
||||
PROFIT_SHARING("/secapi/pay/profitsharing"),
|
||||
/**
|
||||
* 请求多次分账
|
||||
*/
|
||||
MULTI_PROFIT_SHARING("/secapi/pay/multiprofitsharing"),
|
||||
/**
|
||||
* 查询分账结果
|
||||
*/
|
||||
PROFIT_SHARING_QUERY("/pay/profitsharingquery"),
|
||||
/**
|
||||
* 添加分账接收方
|
||||
*/
|
||||
PROFITS_HARING_ADD_RECEIVER("/pay/profitsharingaddreceiver"),
|
||||
/**
|
||||
* 删除分账接收方
|
||||
*/
|
||||
PROFIT_SHARING_REMOVE_RECEIVER("/pay/profitsharingremovereceiver"),
|
||||
/**
|
||||
* 完结分账
|
||||
*/
|
||||
PROFIT_SHARING_FINISH("/secapi/pay/profitsharingfinish"),
|
||||
/**
|
||||
* 分账回退
|
||||
*/
|
||||
PROFIT_SHARING_RETURN("/secapi/pay/profitsharingreturn"),
|
||||
/**
|
||||
* 分账回退结果查询
|
||||
*/
|
||||
PROFIT_SHARING_RETURN_QUERY("/pay/profitsharingreturnquery"),
|
||||
/**
|
||||
* 支付押金(人脸支付)
|
||||
*/
|
||||
DEPOSIT_FACE_PAY("/deposit/facepay"),
|
||||
/**
|
||||
* 支付押金(付款码支付)
|
||||
*/
|
||||
DEPOSIT_MICRO_PAY("/deposit/micropay"),
|
||||
/**
|
||||
* 查询订单(押金)
|
||||
*/
|
||||
DEPOSIT_ORDER_QUERY("/deposit/orderquery"),
|
||||
/**
|
||||
* 撤销订单(押金)
|
||||
*/
|
||||
DEPOSIT_REVERSE("/deposit/reverse"),
|
||||
/**
|
||||
* 消费押金
|
||||
*/
|
||||
DEPOSIT_CONSUME("/deposit/consume"),
|
||||
/**
|
||||
* 申请退款(押金)
|
||||
*/
|
||||
DEPOSIT_REFUND("/deposit/refund"),
|
||||
/**
|
||||
* 查询退款(押金)
|
||||
*/
|
||||
DEPOSIT_REFUND_QUERY("deposit/refundquery"),
|
||||
/**
|
||||
* 公众号纯签约
|
||||
*/
|
||||
ENTRUST_WEB("/papay/entrustweb"),
|
||||
/**
|
||||
* 公众号纯签约(服务商模式)
|
||||
*/
|
||||
PARTNER_ENTRUST_WEB("/papay/partner/entrustweb"),
|
||||
/**
|
||||
* APP纯签约
|
||||
*/
|
||||
PRE_ENTRUST_WEB("/papay/preentrustweb"),
|
||||
/**
|
||||
* APP纯签约(服务商模式)
|
||||
*/
|
||||
PARTNER_PRE_ENTRUST_WEB("/papay/partner/preentrustweb"),
|
||||
/**
|
||||
* H5纯签约
|
||||
*/
|
||||
H5_ENTRUST_WEB("/papay/h5entrustweb"),
|
||||
/**
|
||||
* H5纯签约(服务商模式)
|
||||
*/
|
||||
PARTNER_H5_ENTRUST_WEB("/papay/partner/h5entrustweb"),
|
||||
/**
|
||||
* 支付中签约
|
||||
*/
|
||||
PAY_CONTRACT_ORDER("/pay/contractorder"),
|
||||
/**
|
||||
* 查询签约关系
|
||||
*/
|
||||
QUERY_ENTRUST_CONTRACT("/papay/querycontract"),
|
||||
/**
|
||||
* 查询签约关系(服务商模式)
|
||||
*/
|
||||
PARTNER_QUERY_ENTRUST_CONTRACT("/papay/partner/querycontract"),
|
||||
/**
|
||||
* 代扣申请扣款
|
||||
*/
|
||||
PAP_PAY_APPLY("/pay/pappayapply"),
|
||||
/**
|
||||
* 代扣申请扣款(服务商模式)
|
||||
*/
|
||||
PARTNER_PAP_PAY_APPLY("/pay/partner/pappayapply"),
|
||||
/**
|
||||
* 查询代扣订单
|
||||
*/
|
||||
PAP_ORDER_QUERY("/pay/paporderquery"),
|
||||
/**
|
||||
* 查询代扣订单
|
||||
*/
|
||||
PARTNER_PAP_ORDER_QUERY("/pay/partner/paporderquery"),
|
||||
/**
|
||||
* 代扣申请解约
|
||||
*/
|
||||
DELETE_ENTRUST_CONTRACT("/papay/deletecontract"),
|
||||
/**
|
||||
* 代扣申请解约(服务商模式)
|
||||
*/
|
||||
PARTNER_DELETE_ENTRUST_CONTRACT("/papay/partner/deletecontract"),
|
||||
/**
|
||||
* 刷脸支付
|
||||
*/
|
||||
FACE_PAY("/pay/facepay"),
|
||||
/**
|
||||
* 查询刷脸支付订单
|
||||
*/
|
||||
FACE_PAY_QUERY("/pay/facepayqueryy"),
|
||||
/**
|
||||
* 撤销刷脸支付订单
|
||||
*/
|
||||
FACE_PAY_REVERSE("/secapi/pay/facepayreverse"),
|
||||
/**
|
||||
* 小微商户申请入驻
|
||||
*/
|
||||
MICRO_SUBMIT("/applyment/micro/submit"),
|
||||
/**
|
||||
* 查询申请状态
|
||||
*/
|
||||
GET_MICRO_SUBMIT_STATE("/applyment/micro/getstate"),
|
||||
/**
|
||||
* 提交升级申请
|
||||
*/
|
||||
MICRO_SUBMIT_UPGRADE("/applyment/micro/submitupgrade"),
|
||||
/**
|
||||
* 查询升级申请单状态
|
||||
*/
|
||||
GET_MICRO_UPGRADE_STATE("/applyment/micro/getupgradestate"),
|
||||
/**
|
||||
* 查询提现状态
|
||||
*/
|
||||
QUERY_AUTO_WITH_DRAW_BY_DATE("/fund/queryautowithdrawbydate"),
|
||||
/**
|
||||
* 修改结算银行卡
|
||||
*/
|
||||
MICRO_MODIFY_ARCHIVES("/applyment/micro/modifyarchives"),
|
||||
/**
|
||||
* 重新发起提现
|
||||
*/
|
||||
RE_AUTO_WITH_DRAW_BY_DATE("/fund/reautowithdrawbydate"),
|
||||
/**
|
||||
* 修改联系信息
|
||||
*/
|
||||
MICRO_MODIFY_CONTACT_INFO("/applyment/micro/modifycontactinfo"),
|
||||
/**
|
||||
* 小微商户关注功能配置
|
||||
*/
|
||||
ADD_RECOMMEND_CONF("/secapi/mkt/addrecommendconf"),
|
||||
/**
|
||||
* 小微商户开发配置新增支付目录
|
||||
*/
|
||||
ADD_SUB_DEV_CONFIG("/secapi/mch/addsubdevconfig"),
|
||||
/**
|
||||
* 小微商户开发配置查询
|
||||
*/
|
||||
QUERY_SUB_DEV_CONFIG("/secapi/mch/querysubdevconfig");
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final String type;
|
||||
|
||||
WxApiType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.zscat.mallplus.wxpay.enums;
|
||||
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>微信支付可用域名枚举</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
public enum WxDomain {
|
||||
/**
|
||||
* 中国国内
|
||||
*/
|
||||
CHINA("https://api.mch.weixin.qq.com"),
|
||||
/**
|
||||
* 中国国内(备用域名)
|
||||
*/
|
||||
CHINA2("https://api2.mch.weixin.qq.com"),
|
||||
/**
|
||||
* 东南亚
|
||||
*/
|
||||
HK("https://apihk.mch.weixin.qq.com"),
|
||||
/**
|
||||
* 其它
|
||||
*/
|
||||
US("https://apius.mch.weixin.qq.com");
|
||||
|
||||
|
||||
/**
|
||||
* 域名
|
||||
*/
|
||||
private final String domain;
|
||||
|
||||
WxDomain(String domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return domain;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>授权码查询 openId Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class AuthCodeToOpenIdModel extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String auth_code;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_type;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>拉取订单评价数据 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class BatchQueryCommentModel extends BaseModel {
|
||||
private String appid;
|
||||
private String mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_type;
|
||||
private String begin_time;
|
||||
private String end_time;
|
||||
private String offset;
|
||||
private String limit;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>关闭订单 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class CloseOrderModel extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String out_trade_no;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_type;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>消费押金 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class DepositConsume extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String transaction_id;
|
||||
private String out_trade_no;
|
||||
private String total_fee;
|
||||
private String consume_fee;
|
||||
private String fee_type;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_type;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>下载对账单 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class DownloadBillModel extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_type;
|
||||
private String bill_date;
|
||||
private String bill_type;
|
||||
private String tar_type;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>下载资金账单 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class DownloadFundFlowModel extends BaseModel {
|
||||
private String appid;
|
||||
private String mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_type;
|
||||
private String bill_date;
|
||||
private String account_type;
|
||||
private String tar_type;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>查询红包记录</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class GetHbInfoModel extends BaseModel {
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String mch_billno;
|
||||
private String mch_id;
|
||||
private String appid;
|
||||
private String bill_type;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>企业付款到零钱 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class GetTransferInfoModel extends BaseModel {
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String partner_trade_no;
|
||||
private String mch_id;
|
||||
private String appid;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>付款码支付 Model</p>
|
||||
* <p>支持: 付款支付、支付押金(人脸支付)、支付押金(付款码支付)</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class MicroPayModel extends BaseModel {
|
||||
/**
|
||||
* 是否押金支付
|
||||
*/
|
||||
private String deposit;
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String device_info;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_type;
|
||||
private String body;
|
||||
private String detail;
|
||||
private String attach;
|
||||
private String out_trade_no;
|
||||
private String total_fee;
|
||||
private String fee_type;
|
||||
private String spbill_create_ip;
|
||||
private String goods_tag;
|
||||
private String limit_pay;
|
||||
private String time_start;
|
||||
private String time_expire;
|
||||
private String auth_code;
|
||||
private String receipt;
|
||||
private String scene_info;
|
||||
private String openid;
|
||||
/**
|
||||
* 人脸凭证,用于人脸支付
|
||||
*/
|
||||
private String face_code;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>查询订单 Model</p>
|
||||
* <p>支持: 普通订单查询、刷脸支付订单、查询分账结果、回退结果查询</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class OrderQueryModel extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String transaction_id;
|
||||
private String out_trade_no;
|
||||
private String order_id;
|
||||
private String out_order_no;
|
||||
private String out_return_no;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_type;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>分账 Model</p>
|
||||
* <p>
|
||||
* <p>支持: 请求单次分账、请求多次分账、添加分账接收方、删除分账接收方、完结分账</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class ProfitSharingModel extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_type;
|
||||
private String transaction_id;
|
||||
private String out_order_no;
|
||||
private String receivers;
|
||||
private String description;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>分账回退 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class ProfitSharingReturn extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_type;
|
||||
private String order_id;
|
||||
private String out_order_no;
|
||||
private String out_return_no;
|
||||
private String return_account_type;
|
||||
private String return_account;
|
||||
private String return_amount;
|
||||
private String description;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>申请退款 Model</p>
|
||||
* <p>支持: 普通接口申请退款、刷脸支付退款、支付押金退款</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class RefundModel extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_type;
|
||||
private String transaction_id;
|
||||
private String out_trade_no;
|
||||
private String out_refund_no;
|
||||
private String total_fee;
|
||||
private String refund_fee;
|
||||
private String refund_fee_type;
|
||||
private String refund_desc;
|
||||
private String refund_account;
|
||||
private String notify_url;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>查询退款 Model</p>
|
||||
* <p>支持: 普通接口退款查询、刷脸支付退款查询、支付押金退款查询</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class RefundQueryModel extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_type;
|
||||
private String transaction_id;
|
||||
private String out_trade_no;
|
||||
private String out_refund_no;
|
||||
private String refund_id;
|
||||
private String offset;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>交易保障 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class ReportModel extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String device_info;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_type;
|
||||
private String interface_url;
|
||||
private String execute_time;
|
||||
private String return_code;
|
||||
private String return_msg;
|
||||
private String result_code;
|
||||
private String err_code;
|
||||
private String err_code_des;
|
||||
private String out_trade_no;
|
||||
private String user_ip;
|
||||
private String time;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>撤销订单 Model</p>
|
||||
* <p>支持: 普通支付撤销订单、刷脸支付撤销订单</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class ReverseModel extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String transaction_id;
|
||||
private String out_trade_no;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_type;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p> 微信发送红包 Mode </p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class SendReadPackModel extends BaseModel {
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String mch_billno;
|
||||
private String mch_id;
|
||||
private String wxappid;
|
||||
private String send_name;
|
||||
private String re_openid;
|
||||
private String total_amount;
|
||||
private String total_num;
|
||||
private String amt_type;
|
||||
private String wishing;
|
||||
private String client_ip;
|
||||
private String act_name;
|
||||
private String remark;
|
||||
private String scene_id;
|
||||
private String risk_info;
|
||||
private String notify_way;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>转换短链接 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class ShortUrlModel extends BaseModel {
|
||||
private String appid;
|
||||
private String sub_appid;
|
||||
private String mch_id;
|
||||
private String sub_mch_id;
|
||||
private String long_url;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_type;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>企业付款到零钱 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class TransferModel extends BaseModel {
|
||||
private String mch_appid;
|
||||
private String mchid;
|
||||
private String device_info;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String partner_trade_no;
|
||||
private String openid;
|
||||
private String check_name;
|
||||
private String re_user_name;
|
||||
private String amount;
|
||||
private String desc;
|
||||
private String spbill_create_ip;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* <p>mallplus Pay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
|
||||
* <p>
|
||||
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
|
||||
* <p>
|
||||
* <p>mallplus Pay 交流群: 320860169</p>
|
||||
* <p>
|
||||
* <p>Node.js 版: https://gitee.com/javen205/TNW</p>
|
||||
* <p>
|
||||
* <p>统一下单 Model</p>
|
||||
*
|
||||
* @author Javen
|
||||
*/
|
||||
package com.zscat.mallplus.wxpay.model;
|
||||
|
||||
import com.zscat.mallplus.core.model.BaseModel;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class UnifiedOrderModel extends BaseModel {
|
||||
private String appid;
|
||||
private String mch_id;
|
||||
private String sub_appid;
|
||||
private String sub_mch_id;
|
||||
private String device_info;
|
||||
private String nonce_str;
|
||||
private String sign;
|
||||
private String sign_type;
|
||||
private String body;
|
||||
private String detail;
|
||||
private String attach;
|
||||
private String out_trade_no;
|
||||
private String fee_type;
|
||||
private String total_fee;
|
||||
private String spbill_create_ip;
|
||||
private String time_start;
|
||||
private String time_expire;
|
||||
private String goods_tag;
|
||||
private String notify_url;
|
||||
private String trade_type;
|
||||
private String product_id;
|
||||
private String limit_pay;
|
||||
private String openid;
|
||||
private String sub_openid;
|
||||
private String receipt;
|
||||
private String scene_info;
|
||||
private String profit_sharing;
|
||||
}
|
||||
Reference in New Issue
Block a user