mirror of
https://gitee.com/egzosn/pay-java-parent.git
synced 2026-06-01 13:29:55 +08:00
1. 撤销功能实现
2.代码相关优化,整理
This commit is contained in:
@@ -167,6 +167,12 @@
|
||||
Map result = service.close("支付宝单号", "我方系统单号");
|
||||
|
||||
```
|
||||
#### 交易撤销接口
|
||||
```java
|
||||
|
||||
Map result = service.cancel("支付宝单号", "我方系统单号");
|
||||
|
||||
```
|
||||
|
||||
|
||||
#### 申请退款接口
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.egzosn.pay.ali.bean.AliTransactionType;
|
||||
import com.egzosn.pay.common.api.BasePayService;
|
||||
import com.egzosn.pay.common.api.Callback;
|
||||
import com.egzosn.pay.common.bean.*;
|
||||
import com.egzosn.pay.common.bean.result.PayException;
|
||||
import com.egzosn.pay.common.exception.PayErrorException;
|
||||
@@ -20,30 +19,37 @@ import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 支付宝支付服务
|
||||
* @author egan
|
||||
* 支付宝支付服务
|
||||
*
|
||||
* email egzosn@gmail.com
|
||||
* date 2017-2-22 20:09
|
||||
* @author egan
|
||||
* <p>
|
||||
* email egzosn@gmail.com
|
||||
* date 2017-2-22 20:09
|
||||
*/
|
||||
public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
|
||||
|
||||
/**
|
||||
* 正式测试环境
|
||||
*/
|
||||
private final static String httpsReqUrl = "https://openapi.alipay.com/gateway.do";
|
||||
private static final String HTTPS_REQ_URL = "https://openapi.alipay.com/gateway.do";
|
||||
/**
|
||||
* 沙箱测试环境账号
|
||||
*/
|
||||
private final static String devReqUrl = "https://openapi.alipaydev.com/gateway.do";
|
||||
|
||||
private static final String DEV_REQ_URL = "https://openapi.alipaydev.com/gateway.do";
|
||||
|
||||
public static final String SIGN = "sign";
|
||||
|
||||
public static final String SUCCESS_CODE = "10000";
|
||||
|
||||
public static final String CODE = "code";
|
||||
|
||||
/**
|
||||
* 获取对应的请求地址
|
||||
*
|
||||
* @return 请求地址
|
||||
*/
|
||||
public String getReqUrl(){
|
||||
return payConfigStorage.isTest() ? devReqUrl : httpsReqUrl;
|
||||
public String getReqUrl() {
|
||||
return payConfigStorage.isTest() ? DEV_REQ_URL : HTTPS_REQ_URL;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,47 +75,43 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
@Override
|
||||
public boolean verify(Map<String, Object> params) {
|
||||
|
||||
|
||||
if (params.get("sign") == null) {
|
||||
if (params.get(SIGN) == null) {
|
||||
LOG.debug("支付宝支付异常:params:" + params);
|
||||
return false;
|
||||
}
|
||||
|
||||
return signVerify(params, (String) params.get("sign")) && verifySource( (String)params.get("notify_id"));
|
||||
return signVerify(params, (String) params.get(SIGN)) && verifySource((String) params.get("notify_id"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据反馈回来的信息,生成签名结果
|
||||
*
|
||||
* @param params 通知返回来的参数数组
|
||||
* @param sign 比对的签名结果
|
||||
* @param sign 比对的签名结果
|
||||
* @return 生成的签名结果
|
||||
*/
|
||||
@Override
|
||||
public boolean signVerify(Map<String, Object> params, String sign) {
|
||||
|
||||
if (params instanceof JSONObject){
|
||||
for (String key : params.keySet()){
|
||||
if ("sign".equals(key)){
|
||||
if (params instanceof JSONObject) {
|
||||
for (Map.Entry<String, Object> entry : params.entrySet()) {
|
||||
if (SIGN.equals(entry.getKey())) {
|
||||
continue;
|
||||
}
|
||||
TreeMap response = new TreeMap((Map) params.get(key));
|
||||
TreeMap<String, Object> response = new TreeMap((Map<String, Object> )entry.getValue());
|
||||
LinkedHashMap<Object, Object> linkedHashMap = new LinkedHashMap<>();
|
||||
linkedHashMap.put("code", response.remove("code") );
|
||||
linkedHashMap.put("msg", response.remove("msg") );
|
||||
linkedHashMap.put(CODE, response.remove(CODE));
|
||||
linkedHashMap.put("msg", response.remove("msg"));
|
||||
linkedHashMap.putAll(response);
|
||||
return SignUtils.valueOf(payConfigStorage.getSignType()).verify(JSON.toJSONString(linkedHashMap), sign, payConfigStorage.getKeyPublic(), payConfigStorage.getInputCharset());
|
||||
return SignUtils.valueOf(payConfigStorage.getSignType()).verify(JSON.toJSONString(linkedHashMap), sign, payConfigStorage.getKeyPublic(), payConfigStorage.getInputCharset());
|
||||
}
|
||||
}
|
||||
|
||||
return SignUtils.valueOf(payConfigStorage.getSignType()).verify(params, sign, payConfigStorage.getKeyPublic(), payConfigStorage.getInputCharset());
|
||||
return SignUtils.valueOf(payConfigStorage.getSignType()).verify(params, sign, payConfigStorage.getKeyPublic(), payConfigStorage.getInputCharset());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 校验数据来源
|
||||
*
|
||||
@@ -118,21 +120,21 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
*/
|
||||
@Override
|
||||
public boolean verifySource(String id) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成并设置签名
|
||||
* 生成并设置签名
|
||||
*
|
||||
* @param parameters 请求参数
|
||||
* @return 请求参数
|
||||
*/
|
||||
private Map<String, Object> setSign(Map<String, Object> parameters){
|
||||
private Map<String, Object> setSign(Map<String, Object> parameters) {
|
||||
parameters.put("sign_type", payConfigStorage.getSignType());
|
||||
String sign = createSign( SignUtils.parameterText(parameters, "&", "sign"), payConfigStorage.getInputCharset());
|
||||
String sign = createSign(SignUtils.parameterText(parameters, "&", SIGN), payConfigStorage.getInputCharset());
|
||||
|
||||
parameters.put("sign", sign);
|
||||
parameters.put(SIGN, sign);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@@ -151,7 +153,7 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* 支付宝创建订单信息
|
||||
* create the order info
|
||||
*
|
||||
@@ -159,7 +161,7 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
* @return 返回支付宝预下单信息
|
||||
* @see PayOrder 支付订单信息
|
||||
*/
|
||||
private Map<String, Object> getOrder(PayOrder order) {
|
||||
private Map<String, Object> getOrder(PayOrder order) {
|
||||
|
||||
|
||||
Map<String, Object> orderInfo = getPublicParameters(order.getTransactionType());
|
||||
@@ -174,7 +176,8 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
bizContent.put("subject", order.getSubject());
|
||||
bizContent.put("out_trade_no", order.getOutTradeNo());
|
||||
bizContent.put("total_amount", order.getPrice().setScale(2, BigDecimal.ROUND_HALF_UP).toString());
|
||||
switch ((AliTransactionType)order.getTransactionType()){
|
||||
switch ((AliTransactionType) order.getTransactionType()) {
|
||||
case PAGE:
|
||||
case DIRECT:
|
||||
bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
|
||||
orderInfo.put("return_url", payConfigStorage.getReturnUrl());
|
||||
@@ -194,8 +197,8 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
bizContent.put("product_code", "QUICK_MSECURITY_PAY");
|
||||
}
|
||||
}
|
||||
if (null != order.getExpirationTime()){
|
||||
bizContent.put("timeout_express", ((order.getExpirationTime().getTime() - System.currentTimeMillis())/1000/60 + "m"));
|
||||
if (null != order.getExpirationTime()) {
|
||||
bizContent.put("timeout_express", ((order.getExpirationTime().getTime() - System.currentTimeMillis()) / 1000 / 60 + "m"));
|
||||
}
|
||||
orderInfo.put("biz_content", JSON.toJSONString(bizContent));
|
||||
return orderInfo;
|
||||
@@ -203,10 +206,11 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
|
||||
/**
|
||||
* 获取公共请求参数
|
||||
*
|
||||
* @param transactionType 交易类型
|
||||
* @return 放回公共请求参数
|
||||
*/
|
||||
private Map<String, Object> getPublicParameters(TransactionType transactionType ){
|
||||
private Map<String, Object> getPublicParameters(TransactionType transactionType) {
|
||||
Map<String, Object> orderInfo = new TreeMap<>();
|
||||
orderInfo.put("app_id", payConfigStorage.getAppid());
|
||||
orderInfo.put("method", transactionType.getMethod());
|
||||
@@ -215,14 +219,14 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
df.setTimeZone(TimeZone.getTimeZone("GMT+8"));
|
||||
orderInfo.put("timestamp", df.format(new Date()));
|
||||
orderInfo.put("version", "1.0");
|
||||
return orderInfo;
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取输出消息,用户返回给支付端
|
||||
* @param code 状态
|
||||
*
|
||||
* @param code 状态
|
||||
* @param message 消息
|
||||
* @return 返回输出消息
|
||||
*/
|
||||
@@ -234,6 +238,7 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
/**
|
||||
* 获取成功输出消息,用户返回给支付端
|
||||
* 主要用于拦截器中返回
|
||||
*
|
||||
* @param payMessage 支付回调消息
|
||||
* @return 返回输出消息
|
||||
*/
|
||||
@@ -243,19 +248,18 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param orderInfo 发起支付的订单信息
|
||||
* @param method 请求方式 "post" "get",
|
||||
* @return 获取输出消息,用户返回给支付端, 针对于web端
|
||||
* @return 获取输出消息,用户返回给支付端, 针对于web端
|
||||
*/
|
||||
@Override
|
||||
public String buildRequest(Map<String, Object> orderInfo, MethodType method) {
|
||||
StringBuffer formHtml = new StringBuffer();
|
||||
formHtml.append("<form id=\"_alipaysubmit_\" name=\"alipaysubmit\" action=\"");
|
||||
String biz_content = (String)orderInfo.remove("biz_content");
|
||||
String bizContent = (String) orderInfo.remove("biz_content");
|
||||
formHtml.append(getReqUrl()).append("?").append(UriVariables.getMapToParameters(orderInfo))
|
||||
.append("\" method=\"").append(method.name().toLowerCase()).append("\">");
|
||||
formHtml.append("<input type=\"hidden\" name=\"biz_content\" value=\'" + biz_content + "\'/>");
|
||||
.append("\" method=\"").append(method.name().toLowerCase()).append("\">");
|
||||
formHtml.append("<input type=\"hidden\" name=\"biz_content\" value=\'" + bizContent + "\'/>");
|
||||
formHtml.append("</form>");
|
||||
formHtml.append("<script>document.forms['_alipaysubmit_'].submit();</script>");
|
||||
|
||||
@@ -264,6 +268,7 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
|
||||
/**
|
||||
* 生成二维码支付
|
||||
*
|
||||
* @param order 发起支付的订单信息
|
||||
* @return 返回图片信息,支付时需要的
|
||||
*/
|
||||
@@ -276,15 +281,16 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
//预订单
|
||||
JSONObject result = getHttpRequestTemplate().postForObject(getReqUrl() + "?" + UriVariables.getMapToParameters(orderInfo), null, JSONObject.class);
|
||||
JSONObject response = result.getJSONObject("alipay_trade_precreate_response");
|
||||
if ("10000".equals(response.getString("code"))){
|
||||
return MatrixToImageWriter.writeInfoToJpgBuff( response.getString("qr_code"));
|
||||
if (SUCCESS_CODE.equals(response.getString(CODE))) {
|
||||
return MatrixToImageWriter.writeInfoToJpgBuff(response.getString("qr_code"));
|
||||
}
|
||||
throw new PayErrorException(new PayException(response.getString("code"), response.getString("msg"), result.toJSONString()));
|
||||
throw new PayErrorException(new PayException(response.getString(CODE), response.getString("msg"), result.toJSONString()));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* pos主动扫码付款(条码付)
|
||||
*
|
||||
* @param order 发起支付的订单信息
|
||||
* @return 支付结果
|
||||
*/
|
||||
@@ -294,15 +300,16 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
//预订单
|
||||
JSONObject result = getHttpRequestTemplate().postForObject(getReqUrl() + "?" + UriVariables.getMapToParameters(orderInfo), null, JSONObject.class);
|
||||
JSONObject response = result.getJSONObject("alipay_trade_pay_response");
|
||||
if (!"10000".equals(response.getString("code"))){
|
||||
LOG.info("收款失败");
|
||||
if (!SUCCESS_CODE.equals(response.getString(CODE))) {
|
||||
LOG.info("收款失败");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 交易查询接口
|
||||
* @param tradeNo 支付平台订单号
|
||||
* 交易查询接口
|
||||
*
|
||||
* @param tradeNo 支付平台订单号
|
||||
* @param outTradeNo 商户单号
|
||||
* @return 返回查询回来的结果集,支付方原值返回
|
||||
*/
|
||||
@@ -313,7 +320,6 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 交易关闭接口
|
||||
*
|
||||
@@ -323,18 +329,34 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> close(String tradeNo, String outTradeNo) {
|
||||
return secondaryInterface(tradeNo, outTradeNo, AliTransactionType.CLOSE);
|
||||
return secondaryInterface(tradeNo, outTradeNo, AliTransactionType.CLOSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付交易返回失败或支付系统超时,调用该接口撤销交易。
|
||||
* 如果此订单用户支付失败,支付宝系统会将此订单关闭;如果用户支付成功,支付宝系统会将此订单资金退还给用户。
|
||||
* 注意:只有发生支付系统超时或者支付结果未知时可调用撤销,其他正常支付的单如需实现相同功能请调用申请退款API。
|
||||
* 提交支付交易后调用【查询订单API】,没有明确的支付结果再调用【撤销订单API】。
|
||||
*
|
||||
* @param tradeNo 支付平台订单号
|
||||
* @param outTradeNo 商户单号
|
||||
* @return 返回支付方交易撤销后的结果
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> cancel(String tradeNo, String outTradeNo) {
|
||||
return secondaryInterface(tradeNo, outTradeNo, AliTransactionType.CANCEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 申请退款接口
|
||||
* 废弃
|
||||
* @param tradeNo 支付平台订单号
|
||||
* @param outTradeNo 商户单号
|
||||
*
|
||||
* @param tradeNo 支付平台订单号
|
||||
* @param outTradeNo 商户单号
|
||||
* @param refundAmount 退款金额
|
||||
* @param totalAmount 总金额
|
||||
* @param totalAmount 总金额
|
||||
* @return 返回支付方申请退款后的结果
|
||||
* @see #refund(RefundOrder, Callback)
|
||||
* @see #refund(RefundOrder, com.egzosn.pay.common.api.Callback)
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
@@ -346,7 +368,7 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
/**
|
||||
* 申请退款接口
|
||||
*
|
||||
* @param refundOrder 退款订单信息
|
||||
* @param refundOrder 退款订单信息
|
||||
* @return 返回支付方申请退款后的结果
|
||||
*/
|
||||
@Override
|
||||
@@ -355,7 +377,7 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
Map<String, Object> parameters = getPublicParameters(AliTransactionType.REFUND);
|
||||
|
||||
Map<String, Object> bizContent = getBizContent(refundOrder.getTradeNo(), refundOrder.getOutTradeNo(), null);
|
||||
if (!StringUtils.isEmpty(refundOrder.getRefundNo())){
|
||||
if (!StringUtils.isEmpty(refundOrder.getRefundNo())) {
|
||||
bizContent.put("out_request_no", refundOrder.getRefundNo());
|
||||
}
|
||||
bizContent.put("refund_amount", refundOrder.getRefundAmount().setScale(2, BigDecimal.ROUND_HALF_UP));
|
||||
@@ -363,7 +385,7 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
parameters.put("biz_content", JSON.toJSONString(bizContent));
|
||||
//设置签名
|
||||
setSign(parameters);
|
||||
return requestTemplate.getForObject(getReqUrl() + "?" + UriVariables.getMapToParameters(parameters), JSONObject.class);
|
||||
return requestTemplate.getForObject(getReqUrl() + "?" + UriVariables.getMapToParameters(parameters), JSONObject.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -381,30 +403,31 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
/**
|
||||
* 查询退款
|
||||
*
|
||||
* @param refundOrder 退款订单单号信息
|
||||
* @param refundOrder 退款订单单号信息
|
||||
* @return 返回支付方查询退款后的结果
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> refundquery(RefundOrder refundOrder){
|
||||
public Map<String, Object> refundquery(RefundOrder refundOrder) {
|
||||
|
||||
//获取公共参数
|
||||
Map<String, Object> parameters = getPublicParameters(AliTransactionType.REFUNDQUERY);
|
||||
|
||||
Map<String, Object> bizContent = getBizContent(refundOrder.getTradeNo(), refundOrder.getOutTradeNo(), null);
|
||||
if (!StringUtils.isEmpty(refundOrder.getRefundNo())){
|
||||
if (!StringUtils.isEmpty(refundOrder.getRefundNo())) {
|
||||
bizContent.put("out_request_no", refundOrder.getRefundNo());
|
||||
}
|
||||
//设置请求参数的集合
|
||||
parameters.put("biz_content", JSON.toJSONString(bizContent));
|
||||
parameters.put("biz_content", JSON.toJSONString(bizContent));
|
||||
|
||||
//设置签名
|
||||
setSign(parameters);
|
||||
return requestTemplate.getForObject(getReqUrl() + "?" + UriVariables.getMapToParameters(parameters), JSONObject.class);
|
||||
return requestTemplate.getForObject(getReqUrl() + "?" + UriVariables.getMapToParameters(parameters), JSONObject.class);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 目前只支持日账单
|
||||
*
|
||||
* @param billDate 账单类型,商户通过接口或商户经开放平台授权后其所属服务商通过接口可以获取以下账单类型:trade、signcustomer;trade指商户基于支付宝交易收单的业务账单;signcustomer是指基于商户支付宝余额收入及支出等资金变动的帐务账单;
|
||||
* @param billType 账单时间:日账单格式为yyyy-MM-dd,月账单格式为yyyy-MM。
|
||||
* @return 返回支付方下载对账单的结果
|
||||
@@ -428,24 +451,22 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param tradeNoOrBillDate 支付平台订单号或者账单类型, 具体请
|
||||
* 类型为{@link String }或者 {@link Date },类型须强制限制,类型不对应则抛出异常{@link PayErrorException}
|
||||
* @param outTradeNoBillType 商户单号或者 账单类型
|
||||
* @param transactionType 交易类型
|
||||
* @param tradeNoOrBillDate 支付平台订单号或者账单类型, 具体请
|
||||
* 类型为{@link String }或者 {@link Date },类型须强制限制,类型不对应则抛出异常{@link PayErrorException}
|
||||
* @param outTradeNoBillType 商户单号或者 账单类型
|
||||
* @param transactionType 交易类型
|
||||
* @return 返回支付方对应接口的结果
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> secondaryInterface(Object tradeNoOrBillDate, String outTradeNoBillType, TransactionType transactionType){
|
||||
public Map<String, Object> secondaryInterface(Object tradeNoOrBillDate, String outTradeNoBillType, TransactionType transactionType) {
|
||||
|
||||
if (transactionType == AliTransactionType.REFUND){
|
||||
if (transactionType == AliTransactionType.REFUND) {
|
||||
throw new PayErrorException(new PayException("failure", "通用接口不支持:" + transactionType));
|
||||
}
|
||||
|
||||
if (transactionType == AliTransactionType.DOWNLOADBILL){
|
||||
if (tradeNoOrBillDate instanceof Date){
|
||||
if (transactionType == AliTransactionType.DOWNLOADBILL) {
|
||||
if (tradeNoOrBillDate instanceof Date) {
|
||||
return downloadbill((Date) tradeNoOrBillDate, outTradeNoBillType);
|
||||
}
|
||||
throw new PayErrorException(new PayException("failure", "非法类型异常:" + tradeNoOrBillDate.getClass()));
|
||||
@@ -457,14 +478,13 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
parameters.put("biz_content", getContentToJson(tradeNoOrBillDate.toString(), outTradeNoBillType));
|
||||
//设置签名
|
||||
setSign(parameters);
|
||||
return requestTemplate.getForObject(getReqUrl() + "?" + UriVariables.getMapToParameters(parameters), JSONObject.class);
|
||||
return requestTemplate.getForObject(getReqUrl() + "?" + UriVariables.getMapToParameters(parameters), JSONObject.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转账
|
||||
*
|
||||
* @param order 转账订单
|
||||
*
|
||||
* @return 对应的转账结果
|
||||
*/
|
||||
@Override
|
||||
@@ -476,7 +496,7 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
bizContent.put("out_biz_no", order.getOutNo());
|
||||
//默认 支付宝登录号,支持邮箱和手机号格式。
|
||||
bizContent.put("payee_type", "ALIPAY_LOGONID");
|
||||
if (null != order.getTransferType()){
|
||||
if (null != order.getTransferType()) {
|
||||
bizContent.put("payee_type", order.getTransferType().getType());
|
||||
}
|
||||
bizContent.put("payee_account", order.getPayeeAccount());
|
||||
@@ -496,7 +516,6 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
*
|
||||
* @param outNo 商户转账订单号
|
||||
* @param tradeNo 支付平台转账订单号
|
||||
*
|
||||
* @return 对应的转账订单
|
||||
*/
|
||||
@Override
|
||||
@@ -505,9 +524,9 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
Map<String, Object> parameters = getPublicParameters(AliTransactionType.TRANS_QUERY);
|
||||
|
||||
Map<String, Object> bizContent = new TreeMap<String, Object>();
|
||||
if (StringUtils.isEmpty(outNo)){
|
||||
if (StringUtils.isEmpty(outNo)) {
|
||||
bizContent.put("order_id", tradeNo);
|
||||
}else {
|
||||
} else {
|
||||
bizContent.put("out_biz_no", outNo);
|
||||
}
|
||||
//设置请求参数的集合
|
||||
@@ -519,32 +538,34 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
|
||||
|
||||
/**
|
||||
* 获取biz_content。请求参数的集合 不包含下载账单
|
||||
* @param tradeNo 支付平台订单号
|
||||
* 获取biz_content。请求参数的集合 不包含下载账单
|
||||
*
|
||||
* @param tradeNo 支付平台订单号
|
||||
* @param outTradeNo 商户单号
|
||||
* @param bizContent 请求参数的集合
|
||||
* @param bizContent 请求参数的集合
|
||||
* @return 请求参数的集合 不包含下载账单
|
||||
*/
|
||||
private Map<String, Object> getBizContent(String tradeNo, String outTradeNo, Map<String, Object> bizContent){
|
||||
if (null == bizContent){
|
||||
bizContent = new TreeMap<>();
|
||||
private Map<String, Object> getBizContent(String tradeNo, String outTradeNo, Map<String, Object> bizContent) {
|
||||
if (null == bizContent) {
|
||||
bizContent = new TreeMap<>();
|
||||
}
|
||||
if (!StringUtils.isEmpty(outTradeNo)){
|
||||
if (!StringUtils.isEmpty(outTradeNo)) {
|
||||
bizContent.put("out_trade_no", outTradeNo);
|
||||
}
|
||||
if (!StringUtils.isEmpty(tradeNo)){
|
||||
if (!StringUtils.isEmpty(tradeNo)) {
|
||||
bizContent.put("trade_no", tradeNo);
|
||||
}
|
||||
return bizContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取biz_content。不包含下载账单
|
||||
* @param tradeNo 支付平台订单号
|
||||
* 获取biz_content。不包含下载账单
|
||||
*
|
||||
* @param tradeNo 支付平台订单号
|
||||
* @param outTradeNo 商户单号
|
||||
* @return 获取biz_content。不包含下载账单
|
||||
* @return 获取biz_content。不包含下载账单
|
||||
*/
|
||||
private String getContentToJson(String tradeNo, String outTradeNo){
|
||||
private String getContentToJson(String tradeNo, String outTradeNo) {
|
||||
|
||||
return JSON.toJSONString(getBizContent(tradeNo, outTradeNo, null));
|
||||
}
|
||||
|
||||
@@ -20,8 +20,14 @@ import com.egzosn.pay.common.bean.TransactionType;
|
||||
public enum AliTransactionType implements TransactionType {
|
||||
/**
|
||||
* 即时到帐
|
||||
* 过时的名称,请换至 {@link #PAGE}
|
||||
*/
|
||||
@Deprecated
|
||||
DIRECT("alipay.trade.page.pay"),
|
||||
/**
|
||||
* 网页支付
|
||||
*/
|
||||
PAGE("alipay.trade.page.pay"),
|
||||
/**
|
||||
* APP支付
|
||||
*/
|
||||
@@ -29,12 +35,12 @@ public enum AliTransactionType implements TransactionType {
|
||||
/**
|
||||
* 手机网站支付
|
||||
*/
|
||||
WAP("alipay.trade.wap.pay")
|
||||
WAP("alipay.trade.wap.pay"),
|
||||
|
||||
/**
|
||||
* 扫码付
|
||||
*/
|
||||
,SWEEPPAY("alipay.trade.precreate"),
|
||||
SWEEPPAY("alipay.trade.precreate"),
|
||||
/**
|
||||
* 条码付
|
||||
*/
|
||||
@@ -42,17 +48,21 @@ public enum AliTransactionType implements TransactionType {
|
||||
/**
|
||||
* 声波付
|
||||
*/
|
||||
WAVE_CODE("alipay.trade.pay")
|
||||
WAVE_CODE("alipay.trade.pay"),
|
||||
//交易辅助接口
|
||||
|
||||
/**
|
||||
* 交易订单查询
|
||||
*/
|
||||
,QUERY("alipay.trade.query"),
|
||||
QUERY("alipay.trade.query"),
|
||||
/**
|
||||
* 交易订单关闭
|
||||
*/
|
||||
CLOSE("alipay.trade.close"),
|
||||
/**
|
||||
* 交易订单撤销
|
||||
*/
|
||||
CANCEL("alipay.trade.cancel "),
|
||||
/**
|
||||
* 退款
|
||||
*/
|
||||
@@ -79,7 +89,7 @@ public enum AliTransactionType implements TransactionType {
|
||||
|
||||
private String method;
|
||||
|
||||
private AliTransactionType(String method) {
|
||||
AliTransactionType(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@@ -88,7 +98,7 @@ public enum AliTransactionType implements TransactionType {
|
||||
return this.name();
|
||||
}
|
||||
|
||||
/* *
|
||||
/**
|
||||
* 获取接口名称
|
||||
* @return 接口名称
|
||||
*/
|
||||
|
||||
@@ -21,6 +21,8 @@ import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
import static com.egzosn.pay.ali.api.AliPayService.SIGN;
|
||||
|
||||
/**
|
||||
* 支付宝支付服务
|
||||
* @author egan
|
||||
@@ -37,8 +39,11 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
|
||||
private static final String HTTPS_REQ_URL = "https://mapi.alipay.com/gateway.do";
|
||||
private static final String QUERY_REQ_URL = "https://openapi.alipay.com/gateway.do";
|
||||
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
|
||||
{
|
||||
public static final String NOTIFY_ID = "notify_id";
|
||||
|
||||
public static final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
static {
|
||||
df.setTimeZone(TimeZone.getTimeZone("GMT+8"));
|
||||
}
|
||||
public AliPayService(AliPayConfigStorage payConfigStorage) {
|
||||
@@ -63,13 +68,13 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
@Override
|
||||
public boolean verify(Map<String, Object> params) {
|
||||
|
||||
if (params.get("sign") == null || params.get("notify_id") == null) {
|
||||
if (params.get(SIGN) == null || params.get(NOTIFY_ID) == null) {
|
||||
LOG.debug("支付宝支付异常:params:" + params);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return signVerify(params, (String) params.get("sign")) && verifySource((String) params.get("notify_id"));
|
||||
return signVerify(params, (String) params.get(SIGN)) && verifySource((String) params.get(NOTIFY_ID));
|
||||
} catch (PayErrorException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
@@ -107,8 +112,8 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
*/
|
||||
private Map<String, Object> setSign(Map<String, Object> parameters){
|
||||
parameters.put("sign_type", payConfigStorage.getSignType());
|
||||
String sign = createSign(SignUtils.parameterText(parameters, "&", "sign", "appId"), payConfigStorage.getInputCharset());
|
||||
parameters.put("sign", sign);
|
||||
String sign = createSign(SignUtils.parameterText(parameters, "&", SIGN, "appId"), payConfigStorage.getInputCharset());
|
||||
parameters.put(SIGN, sign);
|
||||
|
||||
return parameters;
|
||||
}
|
||||
@@ -160,7 +165,7 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
orderInfo.put("sign", sign);
|
||||
orderInfo.put(SIGN, sign);
|
||||
orderInfo.put("sign_type", payConfigStorage.getSignType());
|
||||
return orderInfo;
|
||||
}
|
||||
@@ -220,9 +225,6 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
orderInfo.put("it_b_pay", "30m");
|
||||
// 支付宝处理完请求后,当前页面跳转到商户指定页面的路径,可空
|
||||
orderInfo.put("return_url", payConfigStorage.getReturnUrl());
|
||||
// 调用银行卡支付,需配置此参数,参与签名, 固定值 (需要签约《无线银行卡快捷支付》才能使用)
|
||||
// if (order.getTransactionType().getType())
|
||||
// orderInfo.put("paymethod","expressGateway");
|
||||
|
||||
return orderInfo;
|
||||
}
|
||||
@@ -273,12 +275,12 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
.append( "\" method=\"")
|
||||
.append( method.name().toLowerCase()) .append( "\">");
|
||||
|
||||
for (String key: orderInfo.keySet()) {
|
||||
Object o = orderInfo.get(key);
|
||||
if (null == o ||"null".equals(o) || "".equals(o) ){
|
||||
for (Map.Entry<String, Object> entry : orderInfo.entrySet()) {
|
||||
Object o = entry.getValue();
|
||||
if (null == o || "null".equals(o) || "".equals(o)) {
|
||||
continue;
|
||||
}
|
||||
formHtml.append("<input type=\"hidden\" name=\"" + key + "\" value=\"" + orderInfo.get(key) + "\"/>");
|
||||
formHtml.append("<input type=\"hidden\" name=\"" + entry.getKey() + "\" value=\"" + o + "\"/>");
|
||||
}
|
||||
|
||||
|
||||
@@ -340,6 +342,22 @@ public class AliPayService extends BasePayService<AliPayConfigStorage> {
|
||||
return secondaryInterface(tradeNo, outTradeNo, AliTransactionType.CLOSE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 支付交易返回失败或支付系统超时,调用该接口撤销交易。
|
||||
* 如果此订单用户支付失败,支付宝系统会将此订单关闭;如果用户支付成功,支付宝系统会将此订单资金退还给用户。
|
||||
* 注意:只有发生支付系统超时或者支付结果未知时可调用撤销,其他正常支付的单如需实现相同功能请调用申请退款API。
|
||||
* 提交支付交易后调用【查询订单API】,没有明确的支付结果再调用【撤销订单API】。
|
||||
*
|
||||
* @param tradeNo 支付平台订单号
|
||||
* @param outTradeNo 商户单号
|
||||
* @return 返回支付方交易撤销后的结果
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> cancel(String tradeNo, String outTradeNo) {
|
||||
return secondaryInterface(tradeNo, outTradeNo, AliTransactionType.CANCEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 申请退款接口
|
||||
* 废弃
|
||||
|
||||
@@ -34,7 +34,7 @@ public enum AliTransactionType implements TransactionType {
|
||||
*/
|
||||
WAP("alipay.wap.create.direct.pay.by.user"),
|
||||
|
||||
//交易辅助接口
|
||||
//交易辅助接口,以下属于新版接口
|
||||
|
||||
/**
|
||||
* 交易订单查询
|
||||
@@ -44,6 +44,10 @@ public enum AliTransactionType implements TransactionType {
|
||||
* 交易订单关闭
|
||||
*/
|
||||
CLOSE("alipay.trade.close"),
|
||||
/**
|
||||
* 交易订单撤销
|
||||
*/
|
||||
CANCEL("alipay.trade.cancel "),
|
||||
/**
|
||||
* 退款
|
||||
*/
|
||||
|
||||
@@ -5,20 +5,19 @@ import com.egzosn.pay.common.bean.result.PayException;
|
||||
import com.egzosn.pay.common.exception.PayErrorException;
|
||||
import com.egzosn.pay.common.util.sign.CertDescriptor;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* 支付基础配置存储
|
||||
*
|
||||
* @author: egan
|
||||
* <pre>
|
||||
* email egzosn@gmail.com
|
||||
* date 2017/3/5 20:33
|
||||
* </pre>
|
||||
*/
|
||||
public abstract class BasePayConfigStorage implements PayConfigStorage{
|
||||
public abstract class BasePayConfigStorage implements PayConfigStorage {
|
||||
|
||||
private volatile Object attach;
|
||||
/**
|
||||
@@ -27,39 +26,39 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{
|
||||
private volatile CertDescriptor certDescriptor;
|
||||
|
||||
/**
|
||||
* 应用私钥,rsa_private pkcs8格式 生成签名时使用
|
||||
* 应用私钥,rsa_private pkcs8格式 生成签名时使用
|
||||
*/
|
||||
private volatile String keyPrivate;
|
||||
private volatile String keyPrivate;
|
||||
/**
|
||||
* 应用私钥,rsa_private pkcs8格式 生成签名时使用
|
||||
* 应用私钥,rsa_private pkcs8格式 生成签名时使用
|
||||
*/
|
||||
private volatile String keyPrivateCertPwd;
|
||||
private volatile String keyPrivateCertPwd;
|
||||
/**
|
||||
* 支付平台公钥(签名校验使用)
|
||||
* 支付平台公钥(签名校验使用)
|
||||
*/
|
||||
private volatile String keyPublic;
|
||||
private volatile String keyPublic;
|
||||
/**
|
||||
* 异步回调地址
|
||||
*/
|
||||
private volatile String notifyUrl;
|
||||
private volatile String notifyUrl;
|
||||
/**
|
||||
* 同步回调地址,支付完成后展示的页面
|
||||
*/
|
||||
private volatile String returnUrl;
|
||||
private volatile String returnUrl;
|
||||
/**
|
||||
* 签名加密类型
|
||||
*/
|
||||
private volatile String signType;
|
||||
private volatile String signType;
|
||||
/**
|
||||
* 字符类型
|
||||
*/
|
||||
private volatile String inputCharset;
|
||||
private volatile String inputCharset;
|
||||
|
||||
|
||||
/**
|
||||
* 支付类型 aliPay 支付宝, wxPay微信..等等,扩展支付模块定义唯一。
|
||||
*/
|
||||
private volatile String payType;
|
||||
private volatile String payType;
|
||||
|
||||
/**
|
||||
* 消息来源类型
|
||||
@@ -68,7 +67,7 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{
|
||||
|
||||
|
||||
/**
|
||||
* 访问令牌 每次请求其他方法都要传入的值
|
||||
* 访问令牌 每次请求其他方法都要传入的值
|
||||
*/
|
||||
private volatile String accessToken;
|
||||
/**
|
||||
@@ -105,10 +104,10 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{
|
||||
|
||||
@Override
|
||||
public CertDescriptor getCertDescriptor() {
|
||||
if (!isCertSign){
|
||||
throw new PayErrorException(new PayException("certDescriptor fail", "isCertSign is false"));
|
||||
if (!isCertSign) {
|
||||
throw new PayErrorException(new PayException("certDescriptor fail", "isCertSign is false"));
|
||||
}
|
||||
if(null == certDescriptor){
|
||||
if (null == certDescriptor) {
|
||||
certDescriptor = new CertDescriptor();
|
||||
}
|
||||
return certDescriptor;
|
||||
@@ -265,7 +264,7 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{
|
||||
|
||||
public void setCertSign(boolean certSign) {
|
||||
isCertSign = certSign;
|
||||
if (certSign){
|
||||
if (certSign) {
|
||||
certDescriptor = new CertDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ public abstract class BasePayService<PC extends PayConfigStorage> implements Pay
|
||||
try {
|
||||
base64ClientID = com.egzosn.pay.common.util.sign.encrypt.Base64.encode(String.format("%s:%s", user , password).getBytes("UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
LOG.error(e);
|
||||
}
|
||||
|
||||
return base64ClientID;
|
||||
@@ -132,9 +132,9 @@ public abstract class BasePayService<PC extends PayConfigStorage> implements Pay
|
||||
public Map<String, Object> getParameter2Map (Map<String, String[]> parameterMap, InputStream is) {
|
||||
|
||||
Map<String, Object> params = new TreeMap<String,Object>();
|
||||
for (Iterator iter = parameterMap.keySet().iterator(); iter.hasNext();) {
|
||||
String name = (String) iter.next();
|
||||
String[] values = parameterMap.get(name);
|
||||
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
|
||||
String name = (String) entry.getKey();
|
||||
String[] values = entry.getValue();
|
||||
String valueStr = "";
|
||||
for (int i = 0,len = values.length; i < len; i++) {
|
||||
valueStr += (i == len - 1) ? values[i] : values[i] + ",";
|
||||
@@ -145,7 +145,7 @@ public abstract class BasePayService<PC extends PayConfigStorage> implements Pay
|
||||
valueStr=new String(valueStr.getBytes("iso8859-1"), payConfigStorage.getInputCharset());
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
params.put(name, valueStr);
|
||||
@@ -181,6 +181,31 @@ public abstract class BasePayService<PC extends PayConfigStorage> implements Pay
|
||||
public <T> T close(String tradeNo, String outTradeNo, Callback<T> callback) {
|
||||
return callback.perform(close(tradeNo, outTradeNo));
|
||||
}
|
||||
/**
|
||||
* 交易撤销
|
||||
*
|
||||
* @param tradeNo 支付平台订单号
|
||||
* @param outTradeNo 商户单号
|
||||
* @param callback 处理器
|
||||
* @param <T> 返回类型
|
||||
* @return 返回支付方交易撤销后的结果
|
||||
*/
|
||||
@Override
|
||||
public <T> T cancel(String tradeNo, String outTradeNo, Callback<T> callback) {
|
||||
return callback.perform(close(tradeNo, outTradeNo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 交易交易撤销
|
||||
*
|
||||
* @param tradeNo 支付平台订单号
|
||||
* @param outTradeNo 商户单号
|
||||
* @return 返回支付方交易撤销后的结果
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> cancel(String tradeNo, String outTradeNo) {
|
||||
return Collections.EMPTY_MAP;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款
|
||||
@@ -375,7 +400,9 @@ public abstract class BasePayService<PC extends PayConfigStorage> implements Pay
|
||||
@Override
|
||||
public PayOutMessage payBack(Map<String, String[]> parameterMap, InputStream is) {
|
||||
Map<String, Object> data = getParameter2Map(parameterMap, is);
|
||||
LOG.debug("回调响应:" + JSON.toJSONString(data));
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("回调响应:" + JSON.toJSONString(data));
|
||||
}
|
||||
if (!verify(data)){
|
||||
return getPayOutMessage("fail", "失败");
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.Map;
|
||||
*/
|
||||
public class DefaultPayMessageHandler implements PayMessageHandler {
|
||||
|
||||
protected final Log log = LogFactory.getLog(DefaultPayMessageHandler.class);
|
||||
protected final Log LOG = LogFactory.getLog(DefaultPayMessageHandler.class);
|
||||
/**
|
||||
* @param payMessage 支付消息
|
||||
* @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个
|
||||
@@ -30,7 +30,9 @@ public class DefaultPayMessageHandler implements PayMessageHandler {
|
||||
*/
|
||||
@Override
|
||||
public PayOutMessage handle(PayMessage payMessage, Map<String, Object> context, PayService payService) throws PayErrorException {
|
||||
log.info("回调支付消息处理器,回调消息:" + JSON.toJSONString(payMessage));
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("回调支付消息处理器,回调消息:" + JSON.toJSONString(payMessage));
|
||||
}
|
||||
return payService.successPayOutMessage(payMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,12 @@ import java.util.Map;
|
||||
public interface PayMessageHandler {
|
||||
|
||||
/**
|
||||
* 处理支付回调消息的处理器接口
|
||||
* @param payMessage 支付消息
|
||||
* @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个
|
||||
* @param payService 支付服务
|
||||
* @return xml,text格式的消息,如果在异步规则里处理的话,可以返回null
|
||||
* @throws PayErrorException 支付错误异常
|
||||
*/
|
||||
PayOutMessage handle(PayMessage payMessage,
|
||||
Map<String, Object> context,
|
||||
|
||||
@@ -134,7 +134,7 @@ public class PayMessageRouter {
|
||||
}
|
||||
}
|
||||
|
||||
if (matchRules.size() == 0) {
|
||||
if (matchRules.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -154,7 +154,9 @@ public class PayMessageRouter {
|
||||
} else {
|
||||
res = rule.service(payMessage, payService, exceptionHandler);
|
||||
// 在同步操作结束,session访问结束
|
||||
LOG.debug("End session access: async=false, fromPay=" + payMessage.getFromPay());
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("End session access: async=false, fromPay=" + payMessage.getFromPay());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import java.awt.image.BufferedImage;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -76,7 +75,6 @@ public interface PayService<PC extends PayConfigStorage> {
|
||||
* @param id 业务id, 数据的真实性.
|
||||
* @return true通过
|
||||
*/
|
||||
@Deprecated
|
||||
boolean verifySource(String id);
|
||||
|
||||
|
||||
@@ -187,6 +185,7 @@ public interface PayService<PC extends PayConfigStorage> {
|
||||
*/
|
||||
Map<String, Object> close(String tradeNo, String outTradeNo);
|
||||
|
||||
|
||||
/**
|
||||
* 交易关闭接口
|
||||
*
|
||||
@@ -198,6 +197,26 @@ public interface PayService<PC extends PayConfigStorage> {
|
||||
*/
|
||||
<T>T close(String tradeNo, String outTradeNo, Callback<T> callback);
|
||||
|
||||
/**
|
||||
* 交易交易撤销
|
||||
*
|
||||
* @param tradeNo 支付平台订单号
|
||||
* @param outTradeNo 商户单号
|
||||
* @return 返回支付方交易撤销后的结果
|
||||
*/
|
||||
Map<String, Object> cancel(String tradeNo, String outTradeNo);
|
||||
|
||||
/**
|
||||
* 交易交易撤销
|
||||
*
|
||||
* @param tradeNo 支付平台订单号
|
||||
* @param outTradeNo 商户单号
|
||||
* @param callback 处理器
|
||||
* @param <T> 返回类型
|
||||
* @return 返回支付方交易撤销后的结果
|
||||
*/
|
||||
<T>T cancel(String tradeNo, String outTradeNo, Callback<T> callback);
|
||||
|
||||
/**
|
||||
* 申请退款接口
|
||||
* 废弃
|
||||
@@ -301,7 +320,7 @@ public interface PayService<PC extends PayConfigStorage> {
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* 通用查询接口
|
||||
* @param tradeNoOrBillDate 支付平台订单号或者账单类型, 具体请
|
||||
* 类型为{@link String }或者 {@link Date },类型须强制限制,类型不对应则抛出异常{@link PayErrorException}
|
||||
* @param outTradeNoBillType 商户单号或者 账单类型
|
||||
|
||||
@@ -101,11 +101,10 @@ public class PayMessage implements Serializable {
|
||||
}
|
||||
|
||||
public Number getTotalFee(){
|
||||
String total_fee = (String) payMessage.get("total_fee");
|
||||
if (null == total_fee || "".equals(total_fee)){ return 0; }
|
||||
if (isNumber(total_fee)){
|
||||
BigDecimal totalFee = new BigDecimal(total_fee);
|
||||
return totalFee;
|
||||
String totalFee = (String) payMessage.get("total_fee");
|
||||
if (null == totalFee || "".equals(totalFee)){ return 0; }
|
||||
if (isNumber(totalFee)){
|
||||
return new BigDecimal(totalFee);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -118,19 +117,7 @@ public class PayMessage implements Serializable {
|
||||
return str.matches("^(-?[1-9]\\d*\\.?\\d*)|(-?0\\.\\d*[1-9])|(-?[0])|(-?[0]\\.\\d*)$");
|
||||
}
|
||||
|
||||
public Date parseDate(String str){
|
||||
|
||||
if (null == str || "".equals(str)){
|
||||
return null;
|
||||
}
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
try {
|
||||
return format.parse(str);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
@@ -8,15 +8,5 @@ package com.egzosn.pay.common.bean;
|
||||
*/
|
||||
public interface TransferType extends TransactionType{
|
||||
|
||||
/**
|
||||
* 获取转账类型
|
||||
* @return 转账类型
|
||||
*/
|
||||
String getType();
|
||||
|
||||
/**
|
||||
* 获取接口
|
||||
* @return 接口
|
||||
*/
|
||||
String getMethod();
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ import static com.egzosn.pay.common.http.UriVariables.getMapToParameters;
|
||||
* </pre>
|
||||
*/
|
||||
public class ClientHttpRequest<T> extends HttpEntityEnclosingRequestBase implements org.apache.http.client.ResponseHandler<T>{
|
||||
protected final Log log = LogFactory.getLog(ClientHttpRequest.class);
|
||||
protected static final Log LOG = LogFactory.getLog(ClientHttpRequest.class);
|
||||
public static final ContentType APPLICATION_FORM_URLENCODED_UTF_8 = ContentType.create("application/x-www-form-urlencoded", Consts.UTF_8);;
|
||||
|
||||
|
||||
@@ -157,7 +157,9 @@ public class ClientHttpRequest<T> extends HttpEntityEnclosingRequestBase impleme
|
||||
if (request instanceof HttpHeader){
|
||||
HttpHeader entity = (HttpHeader)request;
|
||||
if (null != entity.getHeaders() ){
|
||||
log.debug("header : " + JSON.toJSONString(entity.getHeaders()));
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("header : " + JSON.toJSONString(entity.getHeaders()));
|
||||
}
|
||||
for (Header header : entity.getHeaders()){
|
||||
addHeader(header);
|
||||
}
|
||||
@@ -168,7 +170,9 @@ public class ClientHttpRequest<T> extends HttpEntityEnclosingRequestBase impleme
|
||||
setEntity(entity);
|
||||
}
|
||||
if (null != entity.getHeaders() ){
|
||||
log.debug("header : " + JSON.toJSONString(entity.getHeaders()));
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("header : " + JSON.toJSONString(entity.getHeaders()));
|
||||
}
|
||||
for (Header header : entity.getHeaders()){
|
||||
addHeader(header);
|
||||
}
|
||||
@@ -177,16 +181,22 @@ public class ClientHttpRequest<T> extends HttpEntityEnclosingRequestBase impleme
|
||||
setEntity((HttpEntity)request);
|
||||
} else if (request instanceof Map) {
|
||||
String parameters = getMapToParameters((Map) request);
|
||||
log.debug("Parameter : " + parameters);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Parameter : " + parameters);
|
||||
}
|
||||
StringEntity entity = new StringEntity(parameters, APPLICATION_FORM_URLENCODED_UTF_8);
|
||||
setEntity(entity);
|
||||
} else if (request instanceof String) {
|
||||
log.debug("Parameter : " + request);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Parameter : " + request);
|
||||
}
|
||||
StringEntity entity = new StringEntity((String) request, APPLICATION_FORM_URLENCODED_UTF_8);
|
||||
setEntity(entity);
|
||||
} else {
|
||||
String body = JSON.toJSONString(request);
|
||||
log.debug("body : " + request);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("body : " + request);
|
||||
}
|
||||
StringEntity entity = new StringEntity(body, ContentType.APPLICATION_JSON);
|
||||
setEntity(entity);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
package com.egzosn.pay.common.http;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.egzosn.pay.common.http.UriVariables.getMapToParameters;
|
||||
|
||||
/**
|
||||
* 请求头
|
||||
@@ -82,8 +75,8 @@ public class HttpHeader{
|
||||
* @param headers 请求头集
|
||||
*/
|
||||
public void setHeaders(Map<String, String> headers) {
|
||||
for (String key : headers.keySet()) {
|
||||
addHeader(new BasicHeader(key, headers.get(key)));
|
||||
for (Map.Entry<String, String> entry : headers.entrySet()) {
|
||||
addHeader(new BasicHeader(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ import java.util.Map;
|
||||
*/
|
||||
public class HttpRequestTemplate {
|
||||
|
||||
protected final Log log = LogFactory.getLog(HttpRequestTemplate.class);
|
||||
protected final Log LOG = LogFactory.getLog(HttpRequestTemplate.class);
|
||||
|
||||
protected CloseableHttpClient httpClient;
|
||||
|
||||
@@ -107,7 +107,7 @@ public class HttpRequestTemplate {
|
||||
try {
|
||||
return new SSLConnectionSocketFactory(SSLContext.getDefault());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,9 +133,9 @@ public class HttpRequestTemplate {
|
||||
|
||||
return sslsf;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
LOG.error(e);
|
||||
} catch (GeneralSecurityException e) {
|
||||
e.printStackTrace();
|
||||
LOG.error(e);
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -175,7 +175,9 @@ public class HttpRequestTemplate {
|
||||
if (0 == configStorage.getMaxTotal() || 0 == configStorage.getDefaultMaxPerRoute()){
|
||||
return null;
|
||||
}
|
||||
log.info(String.format("Initialize the PoolingHttpClientConnectionManager -- maxTotal:%s, defaultMaxPerRoute:%s", configStorage.getMaxTotal(), configStorage.getDefaultMaxPerRoute()));
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info(String.format("Initialize the PoolingHttpClientConnectionManager -- maxTotal:%s, defaultMaxPerRoute:%s", configStorage.getMaxTotal(), configStorage.getDefaultMaxPerRoute()));
|
||||
}
|
||||
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
|
||||
.register("https", createSSL(configStorage))
|
||||
.register("http", new PlainConnectionSocketFactory())
|
||||
@@ -324,7 +326,9 @@ public class HttpRequestTemplate {
|
||||
* @return 类型对象
|
||||
*/
|
||||
public <T>T doExecute(URI uri, Object request, Class<T> responseType, MethodType method){
|
||||
log.debug(String.format("uri:%s, httpMethod:%s ", uri, method.name()));
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(String.format("uri:%s, httpMethod:%s ", uri, method.name()));
|
||||
}
|
||||
ClientHttpRequest<T> httpRequest = new ClientHttpRequest(uri ,method, request);
|
||||
//判断是否有代理设置
|
||||
if (null == httpProxy){
|
||||
|
||||
@@ -175,7 +175,7 @@ public class HttpStringEntity extends StringEntity {
|
||||
public HttpStringEntity(String request, Header... headers) throws UnsupportedEncodingException {
|
||||
super(request);
|
||||
requestIsEmpty(request);
|
||||
if (null == headers) {
|
||||
if (null != headers) {
|
||||
this.headers = Arrays.asList(headers);
|
||||
}
|
||||
}
|
||||
@@ -192,8 +192,8 @@ public class HttpStringEntity extends StringEntity {
|
||||
super(request);
|
||||
requestIsEmpty(request);
|
||||
this.headers = new ArrayList<>();
|
||||
for (String key : headers.keySet()) {
|
||||
this.headers.add(new BasicHeader(key, headers.get(key)));
|
||||
for (Map.Entry<String, String> entry : headers.entrySet()) {
|
||||
addHeader(new BasicHeader(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,8 +233,8 @@ public class HttpStringEntity extends StringEntity {
|
||||
* @param headers 请求头集
|
||||
*/
|
||||
public void setHeaders(Map<String, String> headers) {
|
||||
for (String key : headers.keySet()) {
|
||||
addHeader(new BasicHeader(key, headers.get(key)));
|
||||
for (Map.Entry<String, String> entry : headers.entrySet()) {
|
||||
addHeader(new BasicHeader(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
}
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,7 @@ import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* URL表达式处理器
|
||||
@@ -66,13 +67,13 @@ public class UriVariables {
|
||||
if (null == uriVariables){
|
||||
return uri;
|
||||
}
|
||||
for (String key : uriVariables.keySet()){
|
||||
Object uriVariable = uriVariables.get(key);
|
||||
for (Map.Entry<String, Object> entry : uriVariables.entrySet()) {
|
||||
Object uriVariable = entry.getValue();
|
||||
if (null == uriVariable){
|
||||
continue;
|
||||
}
|
||||
|
||||
uri = uri.replace("{" + key + "}", uriVariable.toString());
|
||||
uri = uri.replace("{" + entry.getKey() + "}", uriVariable.toString());
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
@@ -86,8 +87,8 @@ public class UriVariables {
|
||||
*/
|
||||
public static String getMapToParameters(Map pe){
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Object key : pe.keySet()) {
|
||||
Object o = pe.get(key);
|
||||
for (Map.Entry entry : (Set<Map.Entry>)pe.entrySet()) {
|
||||
Object o = entry.getKey();
|
||||
|
||||
if (null == o) {
|
||||
continue;
|
||||
@@ -107,11 +108,11 @@ public class UriVariables {
|
||||
String value = os[i].toString().trim();
|
||||
valueStr += (i == len - 1) ? value : value + ",";
|
||||
}
|
||||
builder.append(key).append("=").append(URLEncoder.encode(valueStr, "utf-8")).append("&");
|
||||
builder.append(entry.getKey()).append("=").append(URLEncoder.encode(valueStr, "utf-8")).append("&");
|
||||
|
||||
continue;
|
||||
}
|
||||
builder.append(key).append("=").append(URLEncoder.encode( pe.get(key).toString(), "utf-8")).append("&");
|
||||
builder.append(entry.getKey()).append("=").append(URLEncoder.encode( entry.getValue().toString(), "utf-8")).append("&");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public class Util{
|
||||
*/
|
||||
public static byte[] byteConvert32Bytes(BigInteger n)
|
||||
{
|
||||
byte tmpd[] = (byte[])null;
|
||||
byte[] tmpd = (byte[])null;
|
||||
if(n == null)
|
||||
{
|
||||
return null;
|
||||
@@ -166,7 +166,7 @@ public class Util{
|
||||
*/
|
||||
public static byte[] hexStringToBytes(String hexString)
|
||||
{
|
||||
if (hexString == null || hexString.equals(""))
|
||||
if (hexString == null || "".equals(hexString))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -328,15 +328,15 @@ public class Util{
|
||||
* @param content 字符串
|
||||
* @return ASCII字符串
|
||||
*/
|
||||
public static String StringToAsciiString(String content) {
|
||||
String result = "";
|
||||
public static String stringToAsciiString(String content) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
int max = content.length();
|
||||
for (int i = 0; i < max; i++) {
|
||||
char c = content.charAt(i);
|
||||
String b = Integer.toHexString(c);
|
||||
result = result + b;
|
||||
result.append( b);
|
||||
}
|
||||
return result;
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,14 +349,14 @@ public class Util{
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String hexStringToString(String hexString, int encodeType) {
|
||||
String result = "";
|
||||
StringBuilder result = new StringBuilder();
|
||||
int max = hexString.length() / encodeType;
|
||||
for (int i = 0; i < max; i++) {
|
||||
char c = (char) hexStringToAlgorism(hexString
|
||||
.substring(i * encodeType, (i + 1) * encodeType));
|
||||
result += c;
|
||||
result.append( c);
|
||||
}
|
||||
return result;
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -391,60 +391,12 @@ public class Util{
|
||||
*/
|
||||
public static String hexStringToBinary(String hex) {
|
||||
hex = hex.toUpperCase();
|
||||
|
||||
String result = "";
|
||||
int max = hex.length();
|
||||
for (int i = 0; i < max; i++) {
|
||||
char c = hex.charAt(i);
|
||||
switch (c) {
|
||||
case '0':
|
||||
result += "0000";
|
||||
break;
|
||||
case '1':
|
||||
result += "0001";
|
||||
break;
|
||||
case '2':
|
||||
result += "0010";
|
||||
break;
|
||||
case '3':
|
||||
result += "0011";
|
||||
break;
|
||||
case '4':
|
||||
result += "0100";
|
||||
break;
|
||||
case '5':
|
||||
result += "0101";
|
||||
break;
|
||||
case '6':
|
||||
result += "0110";
|
||||
break;
|
||||
case '7':
|
||||
result += "0111";
|
||||
break;
|
||||
case '8':
|
||||
result += "1000";
|
||||
break;
|
||||
case '9':
|
||||
result += "1001";
|
||||
break;
|
||||
case 'A':
|
||||
result += "1010";
|
||||
break;
|
||||
case 'B':
|
||||
result += "1011";
|
||||
break;
|
||||
case 'C':
|
||||
result += "1100";
|
||||
break;
|
||||
case 'D':
|
||||
result += "1101";
|
||||
break;
|
||||
case 'E':
|
||||
result += "1110";
|
||||
break;
|
||||
case 'F':
|
||||
result += "1111";
|
||||
break;
|
||||
}
|
||||
result += Integer.toBinaryString( Character.digit(c,16));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -455,7 +407,7 @@ public class Util{
|
||||
* @param content ASCII字符串
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String AsciiStringToString(String content) {
|
||||
public static String asciiStringToString(String content) {
|
||||
String result = "";
|
||||
int length = content.length() / 2;
|
||||
for (int i = 0; i < length; i++) {
|
||||
@@ -534,7 +486,7 @@ public class Util{
|
||||
String result = "";
|
||||
result = Integer.toHexString(algorism);
|
||||
|
||||
if (result.length() % 2 == 1) {
|
||||
if (result.length() % 2 != 0) {
|
||||
result = "0" + result;
|
||||
|
||||
}
|
||||
@@ -552,15 +504,18 @@ public class Util{
|
||||
* int 补充后十六进制字符串的长度
|
||||
* @return 补充结果
|
||||
*/
|
||||
static public String patchHexString(String str, int maxLength) {
|
||||
String temp = "";
|
||||
public static String patchHexString(String str, int maxLength) {
|
||||
StringBuilder temp = new StringBuilder();
|
||||
for (int i = 0; i < maxLength - str.length(); i++) {
|
||||
temp = "0" + temp;
|
||||
temp.append(0);
|
||||
}
|
||||
str = (temp + str).substring(0, maxLength);
|
||||
return str;
|
||||
temp.append(str);
|
||||
return temp.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 将一个字符串转换为int
|
||||
*
|
||||
@@ -616,7 +571,7 @@ public class Util{
|
||||
for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {
|
||||
String swap = "" + arr[i++] + arr[i];
|
||||
int byteint = Integer.parseInt(swap, 16) & 0xFF;
|
||||
b[j] = new Integer(byteint).byteValue();
|
||||
b[j] = Integer.valueOf(byteint).byteValue();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
@@ -628,22 +583,23 @@ public class Util{
|
||||
* byte[] 需要转换的字节数组
|
||||
* @return String 十六进制字符串
|
||||
*/
|
||||
public static String byteToHex(byte b[]) {
|
||||
public static String byteToHex(byte[] b) {
|
||||
if (b == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Argument b ( byte array ) is null! ");
|
||||
}
|
||||
String hs = "";
|
||||
String stmp = "";
|
||||
StringBuilder hs = new StringBuilder();
|
||||
for (int n = 0; n < b.length; n++) {
|
||||
stmp = Integer.toHexString(b[n] & 0xff);
|
||||
String stmp = Integer.toHexString(b[n] & 0xff);
|
||||
if (stmp.length() == 1) {
|
||||
hs = hs + "0" + stmp;
|
||||
} else {
|
||||
hs.append(0);
|
||||
// hs = hs + "0" + stmp;
|
||||
} /*else {
|
||||
hs = hs + stmp;
|
||||
}
|
||||
}*/
|
||||
hs.append(stmp);
|
||||
}
|
||||
return hs.toUpperCase();
|
||||
return hs.toString().toUpperCase();
|
||||
}
|
||||
|
||||
public static byte[] subByte(byte[] input, int startIndex, int length) {
|
||||
@@ -653,4 +609,5 @@ public class Util{
|
||||
}
|
||||
return bt;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import com.egzosn.pay.common.exception.PayErrorException;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
@@ -174,7 +173,6 @@ public class XML {
|
||||
JSON json = getChildren(children);
|
||||
return json.toJavaObject(clazz);
|
||||
} catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
throw new PayErrorException(new PayException("XML failure", "XML解析失败\n" + e.getMessage()));
|
||||
} finally {
|
||||
in.close();
|
||||
@@ -230,17 +228,17 @@ public class XML {
|
||||
try {
|
||||
document = newDocument();
|
||||
} catch (ParserConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
throw new PayErrorException(new PayException("ParserConfigurationException", e.getLocalizedMessage()));
|
||||
}
|
||||
org.w3c.dom.Element root = document.createElement("xml");
|
||||
document.appendChild(root);
|
||||
for (String key : data.keySet()) {
|
||||
Object value = data.get(key);
|
||||
for (Map.Entry<String, Object> entry : data.entrySet()) {
|
||||
Object value = entry.getValue();
|
||||
if (value == null) {
|
||||
value = "";
|
||||
}
|
||||
value = value.toString().trim();
|
||||
org.w3c.dom.Element filed = document.createElement(key);
|
||||
org.w3c.dom.Element filed = document.createElement(entry.getKey());
|
||||
filed.appendChild(document.createTextNode(value.toString()));
|
||||
root.appendChild(filed);
|
||||
}
|
||||
|
||||
@@ -18,11 +18,10 @@ package com.egzosn.pay.common.util.sign;
|
||||
import com.egzosn.pay.common.util.str.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.math.BigInteger;
|
||||
import java.security.*;
|
||||
import java.security.cert.*;
|
||||
import java.security.spec.RSAPublicKeySpec;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
@@ -32,7 +31,7 @@ import java.util.*;
|
||||
* 声明:以下代码只是为了方便接入方测试而提供的样例代码,商户可以根据自己需要,按照技术文档编写。该代码仅供参考,不提供编码,性能,规范性等方面的保障
|
||||
*/
|
||||
public class CertDescriptor {
|
||||
protected static final Log log = LogFactory.getLog(CertDescriptor.class);
|
||||
protected static final Log LOG = LogFactory.getLog(CertDescriptor.class);
|
||||
/** 证书容器,存储对商户请求报文签名私钥证书. */
|
||||
private KeyStore keyStore = null;
|
||||
|
||||
@@ -57,18 +56,19 @@ public class CertDescriptor {
|
||||
in = new FileInputStream(path);
|
||||
encryptCertTemp = (X509Certificate) cf.generateCertificate(in);
|
||||
// 打印证书加载信息,供测试阶段调试
|
||||
log.warn("[" + path + "][CertId="
|
||||
+ encryptCertTemp.getSerialNumber().toString() + "]");
|
||||
if (LOG.isWarnEnabled()) {
|
||||
LOG.warn("[" + path + "][CertId=" + encryptCertTemp.getSerialNumber().toString() + "]");
|
||||
}
|
||||
} catch (CertificateException e) {
|
||||
log.error("InitCert Error", e);
|
||||
LOG.error("InitCert Error", e);
|
||||
} catch (FileNotFoundException e) {
|
||||
log.error("InitCert Error File Not Found", e);
|
||||
LOG.error("InitCert Error File Not Found", e);
|
||||
}finally {
|
||||
if (null != in) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
log.error(e.toString());
|
||||
LOG.error(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,13 +92,13 @@ public class CertDescriptor {
|
||||
pwd.toCharArray());
|
||||
return privateKey;
|
||||
} catch (KeyStoreException e) {
|
||||
log.error("getSignCertPrivateKey Error", e);
|
||||
LOG.error("getSignCertPrivateKey Error", e);
|
||||
return null;
|
||||
} catch (UnrecoverableKeyException e) {
|
||||
log.error("getSignCertPrivateKey Error", e);
|
||||
LOG.error("getSignCertPrivateKey Error", e);
|
||||
return null;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
log.error("getSignCertPrivateKey Error", e);
|
||||
LOG.error("getSignCertPrivateKey Error", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,7 @@ public class CertDescriptor {
|
||||
.getCertificate(keyAlias);
|
||||
return cert.getSerialNumber().toString();
|
||||
} catch (Exception e) {
|
||||
log.error("getSignCertId Error", e);
|
||||
LOG.error("getSignCertId Error", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -143,12 +143,12 @@ public class CertDescriptor {
|
||||
keyStore = null;
|
||||
}
|
||||
try {
|
||||
keyStore = getKeyInfo(signCertPath,
|
||||
signCertPwd,signCertType);
|
||||
log.info("InitSignCert Successful. CertId=["
|
||||
+ getSignCertId() + "]");
|
||||
keyStore = getKeyInfo(signCertPath, signCertPwd,signCertType);
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("InitSignCert Successful. CertId=[" + getSignCertId() + "]");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("InitSignCert Error", e);
|
||||
LOG.error("InitSignCert Error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,12 +161,15 @@ public class CertDescriptor {
|
||||
* @return 证书对象
|
||||
* @throws IOException
|
||||
*/
|
||||
private KeyStore getKeyInfo(String pfxkeyfile, String keypwd,
|
||||
String type) throws IOException {
|
||||
log.warn("加载签名证书==>" + pfxkeyfile);
|
||||
private KeyStore getKeyInfo(String pfxkeyfile, String keypwd, String type) throws IOException {
|
||||
if (LOG.isWarnEnabled()) {
|
||||
LOG.warn("加载签名证书==>" + pfxkeyfile);
|
||||
}
|
||||
try(FileInputStream fis = new FileInputStream(pfxkeyfile);) {
|
||||
KeyStore ks = KeyStore.getInstance(type);
|
||||
log.warn("Load RSA CertPath=[" + pfxkeyfile + "],Pwd=["+ keypwd + "],type=["+type+"]");
|
||||
if (LOG.isWarnEnabled()) {
|
||||
LOG.warn("Load RSA CertPath=[" + pfxkeyfile + "],Pwd=["+ keypwd + "],type=["+type+"]");
|
||||
}
|
||||
|
||||
char[] nPassword = null;
|
||||
nPassword = null == keypwd || "".equals(keypwd.trim()) ? null: keypwd.toCharArray();
|
||||
@@ -175,7 +178,7 @@ public class CertDescriptor {
|
||||
}
|
||||
return ks;
|
||||
} catch (Exception e) {
|
||||
log.error("getKeyInfo Error", e);
|
||||
LOG.error("getKeyInfo Error", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -198,7 +201,7 @@ public class CertDescriptor {
|
||||
.getCertificate(keyAlias);
|
||||
return cert.getSerialNumber().toString();
|
||||
} catch (KeyStoreException e) {
|
||||
log.error("getCertIdIdByStore Error", e);
|
||||
LOG.error("getCertIdIdByStore Error", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -209,12 +212,14 @@ public class CertDescriptor {
|
||||
* 加载中级证书
|
||||
* @param certPath 证书地址
|
||||
*/
|
||||
public void initPublicCert(String certPath) {
|
||||
public void initPublicCert(String certPath) {
|
||||
if (!StringUtils.isEmpty(certPath)) {
|
||||
publicKeyCert = initCert(certPath);
|
||||
log.info("Load PublicKeyCert Successful");
|
||||
} else {
|
||||
log.info("PublicKeyCert is empty");
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Load PublicKeyCert Successful");
|
||||
}
|
||||
} else if (LOG.isInfoEnabled()) {
|
||||
LOG.info("PublicKeyCert is empty");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,9 +230,11 @@ public class CertDescriptor {
|
||||
public void initRootCert(String certPath) {
|
||||
if (!StringUtils.isEmpty(certPath)) {
|
||||
rootKeyCert = initCert(certPath);
|
||||
log.info("Load RootCert Successful");
|
||||
} else {
|
||||
log.info("RootCert is empty");
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Load RootCert Successful");
|
||||
}
|
||||
} else if (LOG.isInfoEnabled()) {
|
||||
LOG.info("RootCert is empty");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,10 +254,4 @@ public class CertDescriptor {
|
||||
return rootKeyCert;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -62,12 +62,12 @@ public enum SignUtils {
|
||||
*/
|
||||
@Override
|
||||
public String createSign(String content, String key, String characterEncoding) {
|
||||
Mac sha256_HMAC = null;
|
||||
Mac sha256HMAC = null;
|
||||
try {
|
||||
sha256_HMAC = Mac.getInstance("HmacSHA256");
|
||||
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(characterEncoding), "HmacSHA256");
|
||||
sha256_HMAC.init(secret_key);
|
||||
byte[] array = sha256_HMAC.doFinal(content.getBytes(characterEncoding));
|
||||
sha256HMAC = Mac.getInstance("HmacSHA256");
|
||||
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(characterEncoding), "HmacSHA256");
|
||||
sha256HMAC.init(secretKey);
|
||||
byte[] array = sha256HMAC.doFinal(content.getBytes(characterEncoding));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte item : array) {
|
||||
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
|
||||
@@ -197,12 +197,12 @@ public enum SignUtils {
|
||||
}
|
||||
// TODO 2016/11/11 10:14 author: egan 已经排序好处理
|
||||
if (parameters instanceof SortedMap) {
|
||||
for (String k : ((Set<String>) parameters.keySet())) {
|
||||
Object v = parameters.get(k);
|
||||
if (null == v || "".equals(v.toString().trim()) || (null != ignoreKey && Arrays.binarySearch(ignoreKey, k ) >= 0)) {
|
||||
for (Map.Entry<String, Object> entry : (Set<Map.Entry<String, Object>>)parameters.entrySet()) {
|
||||
Object v = entry.getValue();
|
||||
if (null == v || "".equals(v.toString().trim()) || (null != ignoreKey && Arrays.binarySearch(ignoreKey, entry.getKey() ) >= 0)) {
|
||||
continue;
|
||||
}
|
||||
sb.append(k ).append("=").append( v.toString().trim()).append(separator);
|
||||
sb.append(entry.getKey() ).append("=").append( v.toString().trim()).append(separator);
|
||||
}
|
||||
if (sb.length() > 0 && !"".equals(separator)) {
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
@@ -219,9 +219,12 @@ public enum SignUtils {
|
||||
for (String k : keys) {
|
||||
String valueStr = "";
|
||||
Object o = parameters.get(k);
|
||||
if (null == o) {
|
||||
continue;
|
||||
}
|
||||
if (o instanceof String[]) {
|
||||
String[] values = (String[]) o;
|
||||
if (null == values){continue;}
|
||||
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
String value = values[i].trim();
|
||||
if ("".equals(value)){ continue;}
|
||||
|
||||
@@ -312,9 +312,10 @@ public class Base64 {
|
||||
*/
|
||||
public int encode(byte[] src, byte[] dst) {
|
||||
int len = outLength(src.length); // dst array size
|
||||
if (dst.length < len)
|
||||
if (dst.length < len) {
|
||||
throw new IllegalArgumentException(
|
||||
"Output byte array is too small for encoding all input bytes");
|
||||
}
|
||||
return encode0(src, 0, src.length, dst);
|
||||
}
|
||||
|
||||
@@ -409,8 +410,9 @@ public class Base64 {
|
||||
* padding character at the end
|
||||
*/
|
||||
public Encoder withoutPadding() {
|
||||
if (!doPadding)
|
||||
if (!doPadding) {
|
||||
return this;
|
||||
}
|
||||
return new Encoder(isURL, newline, linemax, false);
|
||||
}
|
||||
|
||||
@@ -575,9 +577,10 @@ public class Base64 {
|
||||
* if {@code src} is not in valid Base64 scheme
|
||||
*/
|
||||
public byte[] decode(String src) {
|
||||
if (null != src){
|
||||
src = src.replaceAll("[\r\n]", "");
|
||||
if (null == src){
|
||||
return null;
|
||||
}
|
||||
src = src.replaceAll("[\r\n]", "");
|
||||
return decode(src.getBytes(StandardCharsets.ISO_8859_1));
|
||||
}
|
||||
|
||||
@@ -608,9 +611,10 @@ public class Base64 {
|
||||
*/
|
||||
public int decode(byte[] src, byte[] dst) {
|
||||
int len = outLength(src, 0, src.length);
|
||||
if (dst.length < len)
|
||||
if (dst.length < len) {
|
||||
throw new IllegalArgumentException(
|
||||
"Output byte array is too small for decoding all input bytes");
|
||||
}
|
||||
return decode0(src, 0, src.length, dst);
|
||||
}
|
||||
|
||||
@@ -703,8 +707,9 @@ public class Base64 {
|
||||
len -= (sl - sp + 1);
|
||||
break;
|
||||
}
|
||||
if ((b = base64[b]) == -1)
|
||||
if ((b = base64[b]) == -1) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
len -= n;
|
||||
} else {
|
||||
|
||||
@@ -9,6 +9,10 @@ import static com.egzosn.pay.common.util.str.StringUtils.getContentBytes;
|
||||
|
||||
/**
|
||||
* MD5签名工具
|
||||
* @author egan
|
||||
* <pre>
|
||||
* email egzosn@gmail.com
|
||||
*</pre>
|
||||
*/
|
||||
public class MD5 {
|
||||
|
||||
@@ -17,13 +21,13 @@ public class MD5 {
|
||||
*
|
||||
* @param text 需要签名的字符串
|
||||
* @param key 密钥
|
||||
* @param input_charset 编码格式
|
||||
* @param inputCharset 编码格式
|
||||
* @return 签名结果
|
||||
*/
|
||||
public static String sign(String text, String key, String input_charset) {
|
||||
public static String sign(String text, String key, String inputCharset) {
|
||||
//拼接key
|
||||
text = text + key;
|
||||
return DigestUtils.md5Hex(getContentBytes(text, input_charset));
|
||||
return DigestUtils.md5Hex(getContentBytes(text, inputCharset));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,12 +36,12 @@ public class MD5 {
|
||||
* @param text 需要签名的字符串
|
||||
* @param sign 签名结果
|
||||
* @param key 密钥
|
||||
* @param input_charset 编码格式
|
||||
* @param inputCharset 编码格式
|
||||
* @return 签名结果
|
||||
*/
|
||||
public static boolean verify(String text, String sign, String key, String input_charset) {
|
||||
public static boolean verify(String text, String sign, String key, String inputCharset) {
|
||||
//判断是否一样
|
||||
return StringUtils.equals(sign(text, key, input_charset).toUpperCase(), sign.toUpperCase());
|
||||
return StringUtils.equals(sign(text, key, inputCharset).toUpperCase(), sign.toUpperCase());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,6 +9,13 @@ import java.security.PublicKey;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
|
||||
/**
|
||||
* RSA
|
||||
* @author egan
|
||||
* <pre>
|
||||
* email egzosn@gmail.com
|
||||
*</pre>
|
||||
*/
|
||||
public class RSA{
|
||||
|
||||
private static final String ALGORITHM = "RSA";
|
||||
@@ -221,7 +228,7 @@ public class RSA{
|
||||
* @return 公钥
|
||||
*/
|
||||
public static PublicKey getPublicKey(String key, String signAlgorithms) throws Exception {
|
||||
return getPublicKey(new ByteArrayInputStream(key.getBytes()), signAlgorithms);
|
||||
return getPublicKey(new ByteArrayInputStream(key.getBytes("ISO8859-1")), signAlgorithms);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
|
||||
package com.egzosn.pay.common.util.sign.encrypt;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
|
||||
|
||||
@@ -22,13 +22,13 @@ public class SHA1 {
|
||||
*
|
||||
* @param text 需要签名的字符串
|
||||
* @param key 密钥
|
||||
* @param input_charset 编码格式
|
||||
* @param inputCharset 编码格式
|
||||
* @return 签名结果
|
||||
*/
|
||||
public static String sign(String text, String key, String input_charset) {
|
||||
public static String sign(String text, String key, String inputCharset) {
|
||||
//拼接key
|
||||
text = text + key;
|
||||
return DigestUtils.sha1Hex( StringUtils.getContentBytes(text, input_charset));
|
||||
return DigestUtils.sha1Hex( StringUtils.getContentBytes(text, inputCharset));
|
||||
}
|
||||
|
||||
|
||||
@@ -38,12 +38,12 @@ public class SHA1 {
|
||||
* @param text 需要签名的字符串
|
||||
* @param sign 签名结果
|
||||
* @param key 密钥
|
||||
* @param input_charset 编码格式
|
||||
* @param inputCharset 编码格式
|
||||
* @return 签名结果
|
||||
*/
|
||||
public static boolean verify(String text, String sign, String key, String input_charset) {
|
||||
public static boolean verify(String text, String sign, String key, String inputCharset) {
|
||||
//判断是否一样
|
||||
return StringUtils.equals(sign(text, key, input_charset).toUpperCase(), sign.toUpperCase());
|
||||
return StringUtils.equals(sign(text, key, inputCharset).toUpperCase(), sign.toUpperCase());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,13 +21,13 @@ public class SHA256 {
|
||||
*
|
||||
* @param text 需要签名的字符串
|
||||
* @param key 密钥
|
||||
* @param input_charset 编码格式
|
||||
* @param inputCharset 编码格式
|
||||
* @return 签名结果
|
||||
*/
|
||||
public static String sign(String text, String key, String input_charset) {
|
||||
public static String sign(String text, String key, String inputCharset) {
|
||||
//拼接key
|
||||
text = text + key;
|
||||
return DigestUtils.sha256Hex( StringUtils.getContentBytes(text, input_charset));
|
||||
return DigestUtils.sha256Hex( StringUtils.getContentBytes(text, inputCharset));
|
||||
}
|
||||
|
||||
|
||||
@@ -37,12 +37,12 @@ public class SHA256 {
|
||||
* @param text 需要签名的字符串
|
||||
* @param sign 签名结果
|
||||
* @param key 密钥
|
||||
* @param input_charset 编码格式
|
||||
* @param inputCharset 编码格式
|
||||
* @return 签名结果
|
||||
*/
|
||||
public static boolean verify(String text, String sign, String key, String input_charset) {
|
||||
public static boolean verify(String text, String sign, String key, String inputCharset) {
|
||||
//判断是否一样
|
||||
return StringUtils.equals(sign(text, key, input_charset).toUpperCase(), sign.toUpperCase());
|
||||
return StringUtils.equals(sign(text, key, inputCharset).toUpperCase(), sign.toUpperCase());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,64 +2,54 @@ package com.egzosn.pay.common.util.sign.encrypt.sm3;
|
||||
|
||||
import com.egzosn.pay.common.util.Util;
|
||||
|
||||
public class SM3
|
||||
{
|
||||
public static final byte[] iv = { 0x73, (byte) 0x80, 0x16, 0x6f, 0x49,
|
||||
public class SM3 {
|
||||
public static final byte[] iv = {0x73, (byte) 0x80, 0x16, 0x6f, 0x49,
|
||||
0x14, (byte) 0xb2, (byte) 0xb9, 0x17, 0x24, 0x42, (byte) 0xd7,
|
||||
(byte) 0xda, (byte) 0x8a, 0x06, 0x00, (byte) 0xa9, 0x6f, 0x30,
|
||||
(byte) 0xbc, (byte) 0x16, 0x31, 0x38, (byte) 0xaa, (byte) 0xe3,
|
||||
(byte) 0x8d, (byte) 0xee, 0x4d, (byte) 0xb0, (byte) 0xfb, 0x0e,
|
||||
0x4e };
|
||||
0x4e};
|
||||
|
||||
public static int[] Tj = new int[64];
|
||||
|
||||
static
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
static {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
Tj[i] = 0x79cc4519;
|
||||
}
|
||||
|
||||
for (int i = 16; i < 64; i++)
|
||||
{
|
||||
for (int i = 16; i < 64; i++) {
|
||||
Tj[i] = 0x7a879d8a;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] CF(byte[] V, byte[] B)
|
||||
{
|
||||
public static byte[] CF(byte[] V, byte[] B) {
|
||||
int[] v, b;
|
||||
v = convert(V);
|
||||
b = convert(B);
|
||||
return convert(CF(v, b));
|
||||
}
|
||||
|
||||
private static int[] convert(byte[] arr)
|
||||
{
|
||||
private static int[] convert(byte[] arr) {
|
||||
int[] out = new int[arr.length / 4];
|
||||
byte[] tmp = new byte[4];
|
||||
for (int i = 0; i < arr.length; i += 4)
|
||||
{
|
||||
for (int i = 0; i < arr.length; i += 4) {
|
||||
System.arraycopy(arr, i, tmp, 0, 4);
|
||||
out[i / 4] = bigEndianByteToInt(tmp);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private static byte[] convert(int[] arr)
|
||||
{
|
||||
private static byte[] convert(int[] arr) {
|
||||
byte[] out = new byte[arr.length * 4];
|
||||
byte[] tmp = null;
|
||||
for (int i = 0; i < arr.length; i++)
|
||||
{
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
tmp = bigEndianIntToByte(arr[i]);
|
||||
System.arraycopy(tmp, 0, out, i * 4, 4);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
public static int[] CF(int[] V, int[] B)
|
||||
{
|
||||
public static int[] CF(int[] V, int[] B) {
|
||||
int a, b, c, d, e, f, g, h;
|
||||
int ss1, ss2, tt1, tt2;
|
||||
a = V[0];
|
||||
@@ -75,8 +65,7 @@ public class SM3
|
||||
int[] w = arr[0];
|
||||
int[] w1 = arr[1];
|
||||
|
||||
for (int j = 0; j < 64; j++)
|
||||
{
|
||||
for (int j = 0; j < 64; j++) {
|
||||
ss1 = (bitCycleLeft(a, 12) + e + bitCycleLeft(Tj[j], j));
|
||||
ss1 = bitCycleLeft(ss1, 7);
|
||||
ss2 = ss1 ^ bitCycleLeft(a, 12);
|
||||
@@ -117,91 +106,72 @@ public class SM3
|
||||
return out;
|
||||
}
|
||||
|
||||
private static int[][] expand(int[] B)
|
||||
{
|
||||
int W[] = new int[68];
|
||||
int W1[] = new int[64];
|
||||
for (int i = 0; i < B.length; i++)
|
||||
{
|
||||
private static int[][] expand(int[] B) {
|
||||
int[] W = new int[68];
|
||||
int[] W1 = new int[64];
|
||||
for (int i = 0; i < B.length; i++) {
|
||||
W[i] = B[i];
|
||||
}
|
||||
|
||||
for (int i = 16; i < 68; i++)
|
||||
{
|
||||
for (int i = 16; i < 68; i++) {
|
||||
W[i] = P1(W[i - 16] ^ W[i - 9] ^ bitCycleLeft(W[i - 3], 15))
|
||||
^ bitCycleLeft(W[i - 13], 7) ^ W[i - 6];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
for (int i = 0; i < 64; i++) {
|
||||
W1[i] = W[i] ^ W[i + 4];
|
||||
}
|
||||
|
||||
int arr[][] = new int[][] { W, W1 };
|
||||
int[][] arr = new int[][]{W, W1};
|
||||
return arr;
|
||||
}
|
||||
|
||||
private static byte[] bigEndianIntToByte(int num)
|
||||
{
|
||||
private static byte[] bigEndianIntToByte(int num) {
|
||||
return back(Util.intToBytes(num));
|
||||
}
|
||||
|
||||
private static int bigEndianByteToInt(byte[] bytes)
|
||||
{
|
||||
private static int bigEndianByteToInt(byte[] bytes) {
|
||||
return Util.byteToInt(back(bytes));
|
||||
}
|
||||
|
||||
private static int FFj(int X, int Y, int Z, int j)
|
||||
{
|
||||
if (j >= 0 && j <= 15)
|
||||
{
|
||||
private static int FFj(int X, int Y, int Z, int j) {
|
||||
if (j >= 0 && j <= 15) {
|
||||
return FF1j(X, Y, Z);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return FF2j(X, Y, Z);
|
||||
}
|
||||
}
|
||||
|
||||
private static int GGj(int X, int Y, int Z, int j)
|
||||
{
|
||||
if (j >= 0 && j <= 15)
|
||||
{
|
||||
private static int GGj(int X, int Y, int Z, int j) {
|
||||
if (j >= 0 && j <= 15) {
|
||||
return GG1j(X, Y, Z);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return GG2j(X, Y, Z);
|
||||
}
|
||||
}
|
||||
|
||||
// 逻辑位运算函数
|
||||
private static int FF1j(int X, int Y, int Z)
|
||||
{
|
||||
private static int FF1j(int X, int Y, int Z) {
|
||||
int tmp = X ^ Y ^ Z;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private static int FF2j(int X, int Y, int Z)
|
||||
{
|
||||
private static int FF2j(int X, int Y, int Z) {
|
||||
int tmp = ((X & Y) | (X & Z) | (Y & Z));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private static int GG1j(int X, int Y, int Z)
|
||||
{
|
||||
private static int GG1j(int X, int Y, int Z) {
|
||||
int tmp = X ^ Y ^ Z;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private static int GG2j(int X, int Y, int Z)
|
||||
{
|
||||
private static int GG2j(int X, int Y, int Z) {
|
||||
int tmp = (X & Y) | (~X & Z);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private static int P0(int X)
|
||||
{
|
||||
private static int P0(int X) {
|
||||
int y = rotateLeft(X, 9);
|
||||
y = bitCycleLeft(X, 9);
|
||||
int z = rotateLeft(X, 17);
|
||||
@@ -210,8 +180,7 @@ public class SM3
|
||||
return t;
|
||||
}
|
||||
|
||||
private static int P1(int X)
|
||||
{
|
||||
private static int P1(int X) {
|
||||
int t = X ^ bitCycleLeft(X, 15) ^ bitCycleLeft(X, 23);
|
||||
return t;
|
||||
}
|
||||
@@ -219,15 +188,13 @@ public class SM3
|
||||
/**
|
||||
* 对最后一个分组字节数据padding
|
||||
*
|
||||
* @param in 输入字节
|
||||
* @param bLen 分组个数
|
||||
* @return 分组好的字节
|
||||
* @param in 输入字节
|
||||
* @param bLen 分组个数
|
||||
* @return 分组好的字节
|
||||
*/
|
||||
public static byte[] padding(byte[] in, int bLen)
|
||||
{
|
||||
public static byte[] padding(byte[] in, int bLen) {
|
||||
int k = 448 - (8 * in.length + 1) % 512;
|
||||
if (k < 0)
|
||||
{
|
||||
if (k < 0) {
|
||||
k = 960 - (8 * in.length + 1) % 512;
|
||||
}
|
||||
k += 1;
|
||||
@@ -251,47 +218,39 @@ public class SM3
|
||||
* @param in 输入字节
|
||||
* @return 排序好的字节
|
||||
*/
|
||||
private static byte[] back(byte[] in)
|
||||
{
|
||||
private static byte[] back(byte[] in) {
|
||||
byte[] out = new byte[in.length];
|
||||
for (int i = 0; i < out.length; i++)
|
||||
{
|
||||
for (int i = 0; i < out.length; i++) {
|
||||
out[i] = in[out.length - i - 1];
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
public static int rotateLeft(int x, int n)
|
||||
{
|
||||
public static int rotateLeft(int x, int n) {
|
||||
return (x << n) | (x >> (32 - n));
|
||||
}
|
||||
|
||||
private static int bitCycleLeft(int n, int bitLen)
|
||||
{
|
||||
private static int bitCycleLeft(int n, int bitLen) {
|
||||
bitLen %= 32;
|
||||
byte[] tmp = bigEndianIntToByte(n);
|
||||
int byteLen = bitLen / 8;
|
||||
int len = bitLen % 8;
|
||||
if (byteLen > 0)
|
||||
{
|
||||
if (byteLen > 0) {
|
||||
tmp = byteCycleLeft(tmp, byteLen);
|
||||
}
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
if (len > 0) {
|
||||
tmp = bitSmall8CycleLeft(tmp, len);
|
||||
}
|
||||
|
||||
return bigEndianByteToInt(tmp);
|
||||
}
|
||||
|
||||
private static byte[] bitSmall8CycleLeft(byte[] in, int len)
|
||||
{
|
||||
private static byte[] bitSmall8CycleLeft(byte[] in, int len) {
|
||||
byte[] tmp = new byte[in.length];
|
||||
int t1, t2, t3;
|
||||
for (int i = 0; i < tmp.length; i++)
|
||||
{
|
||||
for (int i = 0; i < tmp.length; i++) {
|
||||
t1 = (byte) ((in[i] & 0x000000ff) << len);
|
||||
t2 = (byte) ((in[(i + 1) % tmp.length] & 0x000000ff) >> (8 - len));
|
||||
t3 = (byte) (t1 | t2);
|
||||
@@ -301,8 +260,7 @@ public class SM3
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private static byte[] byteCycleLeft(byte[] in, int byteLen)
|
||||
{
|
||||
private static byte[] byteCycleLeft(byte[] in, int byteLen) {
|
||||
byte[] tmp = new byte[in.length];
|
||||
System.arraycopy(in, byteLen, tmp, 0, in.length - byteLen);
|
||||
System.arraycopy(in, 0, tmp, in.length - byteLen, byteLen);
|
||||
|
||||
@@ -226,6 +226,16 @@ public class AliPayController {
|
||||
public Map<String, Object> close(QueryOrder order) {
|
||||
return service.close(order.getTradeNo(), order.getOutTradeNo());
|
||||
}
|
||||
/**
|
||||
* 交易c撤销接口
|
||||
*
|
||||
* @param order 订单的请求体
|
||||
* @return 返回支付方交易关闭后的结果
|
||||
*/
|
||||
@RequestMapping("cancel")
|
||||
public Map<String, Object> cancel(QueryOrder order) {
|
||||
return service.cancel(order.getTradeNo(), order.getOutTradeNo());
|
||||
}
|
||||
|
||||
/**
|
||||
* 申请退款接口
|
||||
|
||||
@@ -23,23 +23,40 @@ import java.util.*;
|
||||
*/
|
||||
public class FuiouPayService extends BasePayService<FuiouPayConfigStorage> {
|
||||
|
||||
//正式域名
|
||||
public final static String URL_FuiouBaseDomain = "https://pay.fuiou.com/";
|
||||
//测试域名
|
||||
public final static String DEV_URL_FUIOUBASEDOMAIN = "http://www-1.fuiou.com:8888/wg1_run/";
|
||||
/**
|
||||
* 正式域名
|
||||
*/
|
||||
public static final String URL_FuiouBaseDomain = "https://pay.fuiou.com/";
|
||||
/**
|
||||
* 测试域名
|
||||
*/
|
||||
public static final String DEV_URL_FUIOUBASEDOMAIN = "http://www-1.fuiou.com:8888/wg1_run/";
|
||||
|
||||
/**
|
||||
* B2C/B2B支付
|
||||
*/
|
||||
public static final String URL_FuiouSmpGate = "smpGate.do";
|
||||
/**
|
||||
* B2C/B2B支付(跨境支付)
|
||||
*/
|
||||
public static final String URL_FuiouNewSmpGate = "newSmpGate.do";
|
||||
/**
|
||||
* 订单退款
|
||||
*/
|
||||
public static final String URL_FuiouSmpRefundGate = "newSmpRefundGate.do";
|
||||
/**
|
||||
* 3.2 支付结果查询
|
||||
*/
|
||||
public static final String URL_FuiouSmpQueryGate = "smpQueryGate.do";
|
||||
/**
|
||||
* 3.3 支付结果查询(直接返回)
|
||||
*/
|
||||
public static final String URL_FuiouSmpAQueryGate = "smpAQueryGate.do";
|
||||
/**
|
||||
* 3.4订单退款
|
||||
*/
|
||||
public static final String URL_NewSmpRefundGate = "newSmpRefundGate.do";
|
||||
|
||||
//B2C/B2B支付
|
||||
public final static String URL_FuiouSmpGate = "smpGate.do";
|
||||
//B2C/B2B支付(跨境支付)
|
||||
public final static String URL_FuiouNewSmpGate = "newSmpGate.do";
|
||||
//订单退款
|
||||
public final static String URL_FuiouSmpRefundGate = "newSmpRefundGate.do";
|
||||
//3.2 支付结果查询
|
||||
public final static String URL_FuiouSmpQueryGate = "smpQueryGate.do";
|
||||
//3.3 支付结果查询(直接返回)
|
||||
public final static String URL_FuiouSmpAQueryGate = "smpAQueryGate.do";
|
||||
//3.4订单退款
|
||||
public final static String URL_NewSmpRefundGate = "newSmpRefundGate.do";
|
||||
|
||||
/**
|
||||
* 获取对应的请求地址
|
||||
@@ -141,24 +158,36 @@ public class FuiouPayService extends BasePayService<FuiouPayConfigStorage> {
|
||||
*/
|
||||
private LinkedHashMap<String, Object> getOrderInfo(PayOrder order) {
|
||||
LinkedHashMap<String, Object> parameters = new LinkedHashMap<String, Object>();
|
||||
parameters.put("mchnt_cd", payConfigStorage.getPid());//商户代码
|
||||
parameters.put("order_id", order.getOutTradeNo());//商户订单号
|
||||
parameters.put("order_amt", order.getPrice().multiply(new BigDecimal(100)).setScale( 0, BigDecimal.ROUND_HALF_UP).intValue());//交易金额
|
||||
// parameters.put("cur_type", null == order.getCurType() ? FuiouCurType.CNY:order.getCurType());//交易币种
|
||||
parameters.put("order_pay_type", order.getTransactionType());//支付类型
|
||||
parameters.put("page_notify_url", payConfigStorage.getReturnUrl());//商户接受支付结果通知地址
|
||||
parameters.put("back_notify_url", StringUtils.isBlank(payConfigStorage.getNotifyUrl()) ? "" : payConfigStorage.getNotifyUrl());//商户接受的支付结果后台通知地址 //非必填
|
||||
//商户代码
|
||||
parameters.put("mchnt_cd", payConfigStorage.getPid());
|
||||
//商户订单号
|
||||
parameters.put("order_id", order.getOutTradeNo());
|
||||
//交易金额
|
||||
parameters.put("order_amt", order.getPrice().multiply(new BigDecimal(100)).setScale( 0, BigDecimal.ROUND_HALF_UP).intValue());
|
||||
//交易币种
|
||||
// parameters.put("cur_type", null == order.getCurType() ? FuiouCurType.CNY:order.getCurType());
|
||||
//支付类型
|
||||
parameters.put("order_pay_type", order.getTransactionType());
|
||||
//商户接受支付结果通知地址
|
||||
parameters.put("page_notify_url", payConfigStorage.getReturnUrl());
|
||||
//商户接受的支付结果后台通知地址 //非必填
|
||||
parameters.put("back_notify_url", StringUtils.isBlank(payConfigStorage.getNotifyUrl()) ? "" : payConfigStorage.getNotifyUrl());
|
||||
|
||||
if (null != order.getExpirationTime()){
|
||||
parameters.put("order_valid_time", ((order.getExpirationTime().getTime() - System.currentTimeMillis())/1000/60 + "m"));
|
||||
}else {
|
||||
parameters.put("order_valid_time", "30m");//超时时间 1m-15天,m:分钟、h:小时、d天、1c当天有效,
|
||||
//超时时间 1m-15天,m:分钟、h:小时、d天、1c当天有效,
|
||||
parameters.put("order_valid_time", "30m");
|
||||
}
|
||||
parameters.put("iss_ins_cd", order.getBankType());//银行代码
|
||||
//银行代码
|
||||
parameters.put("iss_ins_cd", order.getBankType());
|
||||
parameters.put("goods_name", order.getSubject());
|
||||
parameters.put("goods_display_url", "");//商品展示网址 //非必填
|
||||
parameters.put("rem", "");//备注 //非必填
|
||||
parameters.put("ver", "1.0.1");//版本号
|
||||
//商品展示网址 //非必填
|
||||
parameters.put("goods_display_url", "");
|
||||
//备注 //非必填
|
||||
parameters.put("rem", "");
|
||||
//版本号
|
||||
parameters.put("ver", "1.0.1");
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@@ -283,9 +312,9 @@ public class FuiouPayService extends BasePayService<FuiouPayConfigStorage> {
|
||||
formHtml.append( "<form name=\"pay\" method=\""+method.name().toLowerCase()+"\" ");
|
||||
formHtml.append( "action=\""+url+"\" id = \"form\">");
|
||||
|
||||
for (String key : param.keySet()) {
|
||||
Object o = param.get(key);
|
||||
formHtml.append("<input type=\"hidden\" value = '"+o+"' name=\""+key+"\"/>");
|
||||
for (Map.Entry entry : param.entrySet()) {
|
||||
Object o = entry.getValue();
|
||||
formHtml.append("<input type=\"hidden\" value = '" + o + "' name=\"" + entry.getKey() + "\"/>");
|
||||
}
|
||||
|
||||
formHtml.append("</form></body></html>");
|
||||
@@ -307,8 +336,6 @@ public class FuiouPayService extends BasePayService<FuiouPayConfigStorage> {
|
||||
params.put("order_id", outTradeNo);
|
||||
params.put("md5", createSign(SignUtils.parameters2MD5Str(params, "|"), payConfigStorage.getInputCharset()));
|
||||
JSONObject resultJson = getHttpRequestTemplate().postForObject(getReqUrl() + URL_FuiouSmpAQueryGate + "?" + UriVariables.getMapToParameters(params), null, JSONObject.class);
|
||||
|
||||
|
||||
return resultJson;
|
||||
}
|
||||
|
||||
@@ -322,11 +349,12 @@ public class FuiouPayService extends BasePayService<FuiouPayConfigStorage> {
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> close(String tradeNo, String outTradeNo) {
|
||||
return null;
|
||||
return Collections.EMPTY_MAP;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 申请退款接口
|
||||
*
|
||||
@@ -351,17 +379,20 @@ public class FuiouPayService extends BasePayService<FuiouPayConfigStorage> {
|
||||
* @return 退款返回结果集
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> refund (RefundOrder refundOrder) {
|
||||
Map<String ,Object> params = new HashMap<>();
|
||||
params.put("mchnt_cd",payConfigStorage.getPid());//商户代码
|
||||
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
|
||||
df.setTimeZone(TimeZone.getTimeZone("GMT+8"));
|
||||
params.put("origin_order_date",refundOrder.getOrderDate());//原交易日期
|
||||
params.put("origin_order_id",refundOrder.getTradeNo());//原订单号
|
||||
params.put("refund_amt",refundOrder.getRefundAmount().multiply(new BigDecimal(100)).setScale( 0, BigDecimal.ROUND_HALF_UP).intValue());//退款金额
|
||||
params.put("rem","");//备注
|
||||
params.put("md5",createSign(SignUtils.parameters2MD5Str(params,"|"),payConfigStorage.getInputCharset()));
|
||||
JSONObject resultJson = getHttpRequestTemplate().postForObject(getReqUrl() + URL_FuiouSmpRefundGate,params,JSONObject.class);
|
||||
public Map<String, Object> refund(RefundOrder refundOrder) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
//商户代码
|
||||
params.put("mchnt_cd", payConfigStorage.getPid());
|
||||
//原交易日期
|
||||
params.put("origin_order_date", refundOrder.getOrderDate());
|
||||
//原订单号
|
||||
params.put("origin_order_id", refundOrder.getTradeNo());
|
||||
//退款金额
|
||||
params.put("refund_amt", refundOrder.getRefundAmount().multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP).intValue());
|
||||
//备注
|
||||
params.put("rem", "");
|
||||
params.put("md5", createSign(SignUtils.parameters2MD5Str(params, "|"), payConfigStorage.getInputCharset()));
|
||||
JSONObject resultJson = getHttpRequestTemplate().postForObject(getReqUrl() + URL_FuiouSmpRefundGate, params, JSONObject.class);
|
||||
return resultJson;
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,10 @@ public class PayoneerPayService extends BasePayService<PayoneerConfigStorage> im
|
||||
//设置 base atuh
|
||||
entity.setHeaders(authHeader());
|
||||
JSONObject response = getHttpRequestTemplate().postForObject(getReqUrl(PayoneerTransactionType.REGISTRATION), entity, JSONObject.class);
|
||||
if (response != null && 0 == response.getIntValue(CODE)) {
|
||||
if (null == response) {
|
||||
return null;
|
||||
}
|
||||
if (0 == response.getIntValue(CODE)) {
|
||||
return response.getString("registration_link");
|
||||
}
|
||||
throw new PayErrorException(new PayException("fail", "Payoneer获取授权页面失败,原因:" + response.getString("hint"), response.toJSONString()));
|
||||
@@ -266,7 +269,7 @@ public class PayoneerPayService extends BasePayService<PayoneerConfigStorage> im
|
||||
if (response != null) {
|
||||
return response;
|
||||
}
|
||||
throw new PayErrorException(new PayException("fail", "Payoneer申请收款失败,原因:" + response.getString("description"), response.toJSONString()));
|
||||
throw new PayErrorException(new PayException("fail", "Payoneer申请收款失败,原因:未有返回值" ));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -296,6 +299,18 @@ public class PayoneerPayService extends BasePayService<PayoneerConfigStorage> im
|
||||
return secondaryInterface(tradeNo, outTradeNo, PayoneerTransactionType.CHARGE_CANCEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 交易交易撤销
|
||||
*
|
||||
* @param tradeNo 支付平台订单号
|
||||
* @param outTradeNo 商户单号
|
||||
* @return 返回支付方交易撤销后的结果
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> cancel(String tradeNo, String outTradeNo) {
|
||||
return secondaryInterface(tradeNo, outTradeNo, PayoneerTransactionType.CHARGE_CANCEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 申请退款接口
|
||||
* 废弃
|
||||
|
||||
@@ -51,8 +51,8 @@ public class UnionPayService extends BasePayService<UnionPayConfigStorage> {
|
||||
private static final String FILE_TRANS_URL= "https://filedownload.%s/";
|
||||
private static final String APP_TRANS_URL= "https://gateway.%s/gateway/api/appTransReq.do";
|
||||
private static final String CARD_TRANS_URL= "https://gateway.%s/gateway/api/cardTransReq.do";
|
||||
public final static DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||
{
|
||||
public static final DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||
static {
|
||||
df.setTimeZone(TimeZone.getTimeZone("GMT+8"));
|
||||
}
|
||||
|
||||
@@ -324,8 +324,7 @@ public class UnionPayService extends BasePayService<UnionPayConfigStorage> {
|
||||
CertPathBuilder builder = CertPathBuilder.getInstance("PKIX");
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
PKIXCertPathBuilderResult result = (PKIXCertPathBuilderResult) builder
|
||||
.build(pkixParams);
|
||||
PKIXCertPathBuilderResult result = (PKIXCertPathBuilderResult) builder.build(pkixParams);
|
||||
return cert;
|
||||
} catch (java.security.cert.CertPathBuilderException e) {
|
||||
LOG.error("verify certificate chain fail.", e);
|
||||
@@ -516,7 +515,7 @@ public class UnionPayService extends BasePayService<UnionPayConfigStorage> {
|
||||
JSONObject response = UriVariables.getParametersToMap(responseStr);
|
||||
if(this.verify(response)){
|
||||
if(SDKConstants.OK_RESP_CODE.equals(response.getString(SDKConstants.param_respCode))){
|
||||
String origRespCode = response.getString(SDKConstants.param_origRespCode);
|
||||
// String origRespCode = response.getString(SDKConstants.param_origRespCode);
|
||||
//交易成功,更新商户订单状态
|
||||
//TODO
|
||||
return response;
|
||||
|
||||
Reference in New Issue
Block a user