diff --git a/pay-java-ali/README.md b/pay-java-ali/README.md index 110b94c..7f32460 100644 --- a/pay-java-ali/README.md +++ b/pay-java-ali/README.md @@ -167,6 +167,12 @@ Map result = service.close("支付宝单号", "我方系统单号"); ``` +#### 交易撤销接口 + ```java + + Map result = service.cancel("支付宝单号", "我方系统单号"); + +``` #### 申请退款接口 diff --git a/pay-java-ali/src/main/java/com/egzosn/pay/ali/api/AliPayService.java b/pay-java-ali/src/main/java/com/egzosn/pay/ali/api/AliPayService.java index 06d5ce7..b01628e 100644 --- a/pay-java-ali/src/main/java/com/egzosn/pay/ali/api/AliPayService.java +++ b/pay-java-ali/src/main/java/com/egzosn/pay/ali/api/AliPayService.java @@ -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 + *

+ * email egzosn@gmail.com + * date 2017-2-22 20:09 */ public class AliPayService extends BasePayService { - + /** * 正式测试环境 */ - 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 { @Override public boolean verify(Map 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 params, String sign) { - if (params instanceof JSONObject){ - for (String key : params.keySet()){ - if ("sign".equals(key)){ + if (params instanceof JSONObject) { + for (Map.Entry entry : params.entrySet()) { + if (SIGN.equals(entry.getKey())) { continue; } - TreeMap response = new TreeMap((Map) params.get(key)); + TreeMap response = new TreeMap((Map )entry.getValue()); LinkedHashMap 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 { */ @Override public boolean verifySource(String id) { - return true; } /** - * 生成并设置签名 + * 生成并设置签名 + * * @param parameters 请求参数 * @return 请求参数 */ - private Map setSign(Map parameters){ + private Map setSign(Map 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 { } - /** + /** * 支付宝创建订单信息 * create the order info * @@ -159,7 +161,7 @@ public class AliPayService extends BasePayService { * @return 返回支付宝预下单信息 * @see PayOrder 支付订单信息 */ - private Map getOrder(PayOrder order) { + private Map getOrder(PayOrder order) { Map orderInfo = getPublicParameters(order.getTransactionType()); @@ -174,7 +176,8 @@ public class AliPayService extends BasePayService { 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 { 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 { /** * 获取公共请求参数 + * * @param transactionType 交易类型 * @return 放回公共请求参数 */ - private Map getPublicParameters(TransactionType transactionType ){ + private Map getPublicParameters(TransactionType transactionType) { Map orderInfo = new TreeMap<>(); orderInfo.put("app_id", payConfigStorage.getAppid()); orderInfo.put("method", transactionType.getMethod()); @@ -215,14 +219,14 @@ public class AliPayService extends BasePayService { 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 { /** * 获取成功输出消息,用户返回给支付端 * 主要用于拦截器中返回 + * * @param payMessage 支付回调消息 * @return 返回输出消息 */ @@ -243,19 +248,18 @@ public class AliPayService extends BasePayService { } /** - * * @param orderInfo 发起支付的订单信息 * @param method 请求方式 "post" "get", - * @return 获取输出消息,用户返回给支付端, 针对于web端 + * @return 获取输出消息,用户返回给支付端, 针对于web端 */ @Override public String buildRequest(Map orderInfo, MethodType method) { StringBuffer formHtml = new StringBuffer(); formHtml.append("

"); - formHtml.append(""); + .append("\" method=\"").append(method.name().toLowerCase()).append("\">"); + formHtml.append(""); formHtml.append("
"); formHtml.append(""); @@ -264,6 +268,7 @@ public class AliPayService extends BasePayService { /** * 生成二维码支付 + * * @param order 发起支付的订单信息 * @return 返回图片信息,支付时需要的 */ @@ -276,15 +281,16 @@ public class AliPayService extends BasePayService { //预订单 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 { //预订单 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 { } - /** * 交易关闭接口 * @@ -323,18 +329,34 @@ public class AliPayService extends BasePayService { */ @Override public Map 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 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 { /** * 申请退款接口 * - * @param refundOrder 退款订单信息 + * @param refundOrder 退款订单信息 * @return 返回支付方申请退款后的结果 */ @Override @@ -355,7 +377,7 @@ public class AliPayService extends BasePayService { Map parameters = getPublicParameters(AliTransactionType.REFUND); Map 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 { 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 { /** * 查询退款 * - * @param refundOrder 退款订单单号信息 + * @param refundOrder 退款订单单号信息 * @return 返回支付方查询退款后的结果 */ @Override - public Map refundquery(RefundOrder refundOrder){ + public Map refundquery(RefundOrder refundOrder) { //获取公共参数 Map parameters = getPublicParameters(AliTransactionType.REFUNDQUERY); Map 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 { } - /** - * - * @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 secondaryInterface(Object tradeNoOrBillDate, String outTradeNoBillType, TransactionType transactionType){ + public Map 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 { 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 { 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 { * * @param outNo 商户转账订单号 * @param tradeNo 支付平台转账订单号 - * * @return 对应的转账订单 */ @Override @@ -505,9 +524,9 @@ public class AliPayService extends BasePayService { Map parameters = getPublicParameters(AliTransactionType.TRANS_QUERY); Map bizContent = new TreeMap(); - 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 { /** - * 获取biz_content。请求参数的集合 不包含下载账单 - * @param tradeNo 支付平台订单号 + * 获取biz_content。请求参数的集合 不包含下载账单 + * + * @param tradeNo 支付平台订单号 * @param outTradeNo 商户单号 - * @param bizContent 请求参数的集合 + * @param bizContent 请求参数的集合 * @return 请求参数的集合 不包含下载账单 */ - private Map getBizContent(String tradeNo, String outTradeNo, Map bizContent){ - if (null == bizContent){ - bizContent = new TreeMap<>(); + private Map getBizContent(String tradeNo, String outTradeNo, Map 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)); } diff --git a/pay-java-ali/src/main/java/com/egzosn/pay/ali/bean/AliTransactionType.java b/pay-java-ali/src/main/java/com/egzosn/pay/ali/bean/AliTransactionType.java index b7b5c6b..3c0b6b7 100644 --- a/pay-java-ali/src/main/java/com/egzosn/pay/ali/bean/AliTransactionType.java +++ b/pay-java-ali/src/main/java/com/egzosn/pay/ali/bean/AliTransactionType.java @@ -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 接口名称 */ diff --git a/pay-java-ali/src/main/java/com/egzosn/pay/ali/before/api/AliPayService.java b/pay-java-ali/src/main/java/com/egzosn/pay/ali/before/api/AliPayService.java index e2cd01d..3a50dd7 100644 --- a/pay-java-ali/src/main/java/com/egzosn/pay/ali/before/api/AliPayService.java +++ b/pay-java-ali/src/main/java/com/egzosn/pay/ali/before/api/AliPayService.java @@ -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 { 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 { @Override public boolean verify(Map 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 { */ private Map setSign(Map 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 { } 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 { 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 { .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 entry : orderInfo.entrySet()) { + Object o = entry.getValue(); + if (null == o || "null".equals(o) || "".equals(o)) { continue; } - formHtml.append(""); + formHtml.append(""); } @@ -340,6 +342,22 @@ public class AliPayService extends BasePayService { return secondaryInterface(tradeNo, outTradeNo, AliTransactionType.CLOSE); } + + /** + * 支付交易返回失败或支付系统超时,调用该接口撤销交易。 + * 如果此订单用户支付失败,支付宝系统会将此订单关闭;如果用户支付成功,支付宝系统会将此订单资金退还给用户。 + * 注意:只有发生支付系统超时或者支付结果未知时可调用撤销,其他正常支付的单如需实现相同功能请调用申请退款API。 + * 提交支付交易后调用【查询订单API】,没有明确的支付结果再调用【撤销订单API】。 + * + * @param tradeNo 支付平台订单号 + * @param outTradeNo 商户单号 + * @return 返回支付方交易撤销后的结果 + */ + @Override + public Map cancel(String tradeNo, String outTradeNo) { + return secondaryInterface(tradeNo, outTradeNo, AliTransactionType.CANCEL); + } + /** * 申请退款接口 * 废弃 diff --git a/pay-java-ali/src/main/java/com/egzosn/pay/ali/before/bean/AliTransactionType.java b/pay-java-ali/src/main/java/com/egzosn/pay/ali/before/bean/AliTransactionType.java index 0570aa3..6dcf1d1 100644 --- a/pay-java-ali/src/main/java/com/egzosn/pay/ali/before/bean/AliTransactionType.java +++ b/pay-java-ali/src/main/java/com/egzosn/pay/ali/before/bean/AliTransactionType.java @@ -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 "), /** * 退款 */ diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/api/BasePayConfigStorage.java b/pay-java-common/src/main/java/com/egzosn/pay/common/api/BasePayConfigStorage.java index b5b7740..397cd73 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/api/BasePayConfigStorage.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/api/BasePayConfigStorage.java @@ -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 *
  *     email egzosn@gmail.com
  *     date 2017/3/5 20:33
  *  
*/ -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(); } } diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/api/BasePayService.java b/pay-java-common/src/main/java/com/egzosn/pay/common/api/BasePayService.java index 7ad72c3..87f6364 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/api/BasePayService.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/api/BasePayService.java @@ -91,7 +91,7 @@ public abstract class BasePayService 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 implements Pay public Map getParameter2Map (Map parameterMap, InputStream is) { Map params = new TreeMap(); - for (Iterator iter = parameterMap.keySet().iterator(); iter.hasNext();) { - String name = (String) iter.next(); - String[] values = parameterMap.get(name); + for (Map.Entry 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 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 implements Pay public T close(String tradeNo, String outTradeNo, Callback callback) { return callback.perform(close(tradeNo, outTradeNo)); } + /** + * 交易撤销 + * + * @param tradeNo 支付平台订单号 + * @param outTradeNo 商户单号 + * @param callback 处理器 + * @param 返回类型 + * @return 返回支付方交易撤销后的结果 + */ + @Override + public T cancel(String tradeNo, String outTradeNo, Callback callback) { + return callback.perform(close(tradeNo, outTradeNo)); + } + + /** + * 交易交易撤销 + * + * @param tradeNo 支付平台订单号 + * @param outTradeNo 商户单号 + * @return 返回支付方交易撤销后的结果 + */ + @Override + public Map cancel(String tradeNo, String outTradeNo) { + return Collections.EMPTY_MAP; + } /** * 退款 @@ -375,7 +400,9 @@ public abstract class BasePayService implements Pay @Override public PayOutMessage payBack(Map parameterMap, InputStream is) { Map data = getParameter2Map(parameterMap, is); - LOG.debug("回调响应:" + JSON.toJSONString(data)); + if (LOG.isDebugEnabled()) { + LOG.debug("回调响应:" + JSON.toJSONString(data)); + } if (!verify(data)){ return getPayOutMessage("fail", "失败"); } diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/api/DefaultPayMessageHandler.java b/pay-java-common/src/main/java/com/egzosn/pay/common/api/DefaultPayMessageHandler.java index 4af551c..a963720 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/api/DefaultPayMessageHandler.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/api/DefaultPayMessageHandler.java @@ -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 context, PayService payService) throws PayErrorException { - log.info("回调支付消息处理器,回调消息:" + JSON.toJSONString(payMessage)); + if (LOG.isInfoEnabled()) { + LOG.info("回调支付消息处理器,回调消息:" + JSON.toJSONString(payMessage)); + } return payService.successPayOutMessage(payMessage); } } diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/api/PayMessageHandler.java b/pay-java-common/src/main/java/com/egzosn/pay/common/api/PayMessageHandler.java index c0bab6a..5485d84 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/api/PayMessageHandler.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/api/PayMessageHandler.java @@ -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 context, diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/api/PayMessageRouter.java b/pay-java-common/src/main/java/com/egzosn/pay/common/api/PayMessageRouter.java index 01b1754..4675b71 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/api/PayMessageRouter.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/api/PayMessageRouter.java @@ -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()); + } } } diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/api/PayService.java b/pay-java-common/src/main/java/com/egzosn/pay/common/api/PayService.java index de6b5bb..1936364 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/api/PayService.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/api/PayService.java @@ -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 { * @param id 业务id, 数据的真实性. * @return true通过 */ - @Deprecated boolean verifySource(String id); @@ -187,6 +185,7 @@ public interface PayService { */ Map close(String tradeNo, String outTradeNo); + /** * 交易关闭接口 * @@ -198,6 +197,26 @@ public interface PayService { */ T close(String tradeNo, String outTradeNo, Callback callback); + /** + * 交易交易撤销 + * + * @param tradeNo 支付平台订单号 + * @param outTradeNo 商户单号 + * @return 返回支付方交易撤销后的结果 + */ + Map cancel(String tradeNo, String outTradeNo); + + /** + * 交易交易撤销 + * + * @param tradeNo 支付平台订单号 + * @param outTradeNo 商户单号 + * @param callback 处理器 + * @param 返回类型 + * @return 返回支付方交易撤销后的结果 + */ + T cancel(String tradeNo, String outTradeNo, Callback callback); + /** * 申请退款接口 * 废弃 @@ -301,7 +320,7 @@ public interface PayService { /** - * + * 通用查询接口 * @param tradeNoOrBillDate 支付平台订单号或者账单类型, 具体请 * 类型为{@link String }或者 {@link Date },类型须强制限制,类型不对应则抛出异常{@link PayErrorException} * @param outTradeNoBillType 商户单号或者 账单类型 diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/bean/PayMessage.java b/pay-java-common/src/main/java/com/egzosn/pay/common/bean/PayMessage.java index 8ae04f1..cff3dc2 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/bean/PayMessage.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/bean/PayMessage.java @@ -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() { diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/bean/TransferType.java b/pay-java-common/src/main/java/com/egzosn/pay/common/bean/TransferType.java index bacea65..867acf9 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/bean/TransferType.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/bean/TransferType.java @@ -8,15 +8,5 @@ package com.egzosn.pay.common.bean; */ public interface TransferType extends TransactionType{ - /** - * 获取转账类型 - * @return 转账类型 - */ - String getType(); - /** - * 获取接口 - * @return 接口 - */ - String getMethod(); } diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/http/ClientHttpRequest.java b/pay-java-common/src/main/java/com/egzosn/pay/common/http/ClientHttpRequest.java index 6b37c42..500839f 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/http/ClientHttpRequest.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/http/ClientHttpRequest.java @@ -32,7 +32,7 @@ import static com.egzosn.pay.common.http.UriVariables.getMapToParameters; * */ public class ClientHttpRequest extends HttpEntityEnclosingRequestBase implements org.apache.http.client.ResponseHandler{ - 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 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 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 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); } diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/http/HttpHeader.java b/pay-java-common/src/main/java/com/egzosn/pay/common/http/HttpHeader.java index 18c03f7..2063441 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/http/HttpHeader.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/http/HttpHeader.java @@ -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 headers) { - for (String key : headers.keySet()) { - addHeader(new BasicHeader(key, headers.get(key))); + for (Map.Entry entry : headers.entrySet()) { + addHeader(new BasicHeader(entry.getKey(), entry.getValue())); } } diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/http/HttpRequestTemplate.java b/pay-java-common/src/main/java/com/egzosn/pay/common/http/HttpRequestTemplate.java index 2673b7c..f361535 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/http/HttpRequestTemplate.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/http/HttpRequestTemplate.java @@ -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 socketFactoryRegistry = RegistryBuilder. create() .register("https", createSSL(configStorage)) .register("http", new PlainConnectionSocketFactory()) @@ -324,7 +326,9 @@ public class HttpRequestTemplate { * @return 类型对象 */ public T doExecute(URI uri, Object request, Class 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 httpRequest = new ClientHttpRequest(uri ,method, request); //判断是否有代理设置 if (null == httpProxy){ diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/http/HttpStringEntity.java b/pay-java-common/src/main/java/com/egzosn/pay/common/http/HttpStringEntity.java index a3e702d..828c9be 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/http/HttpStringEntity.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/http/HttpStringEntity.java @@ -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 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 headers) { - for (String key : headers.keySet()) { - addHeader(new BasicHeader(key, headers.get(key))); + for (Map.Entry entry : headers.entrySet()) { + addHeader(new BasicHeader(entry.getKey(), entry.getValue())); } } /** diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/http/UriVariables.java b/pay-java-common/src/main/java/com/egzosn/pay/common/http/UriVariables.java index d34a41c..e5be3f2 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/http/UriVariables.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/http/UriVariables.java @@ -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 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)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(); } diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/util/Util.java b/pay-java-common/src/main/java/com/egzosn/pay/common/util/Util.java index 88d0d2e..e815768 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/util/Util.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/util/Util.java @@ -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; } + } \ No newline at end of file diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/util/XML.java b/pay-java-common/src/main/java/com/egzosn/pay/common/util/XML.java index 6b29f92..0569cc5 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/util/XML.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/util/XML.java @@ -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 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); } diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/CertDescriptor.java b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/CertDescriptor.java index 3d762db..c98a620 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/CertDescriptor.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/CertDescriptor.java @@ -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; } - - - - - - } diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/SignUtils.java b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/SignUtils.java index 7f1ce19..fdafda4 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/SignUtils.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/SignUtils.java @@ -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) parameters.keySet())) { - Object v = parameters.get(k); - if (null == v || "".equals(v.toString().trim()) || (null != ignoreKey && Arrays.binarySearch(ignoreKey, k ) >= 0)) { + for (Map.Entry entry : (Set>)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;} diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/Base64.java b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/Base64.java index 586a0b6..0d40b16 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/Base64.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/Base64.java @@ -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 { diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/MD5.java b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/MD5.java index 05237fc..ddcb9f3 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/MD5.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/MD5.java @@ -9,6 +9,10 @@ import static com.egzosn.pay.common.util.str.StringUtils.getContentBytes; /** * MD5签名工具 + * @author egan + *
+ * email egzosn@gmail.com
+ *
*/ 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()); } diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/RSA.java b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/RSA.java index 6269ec9..859ba95 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/RSA.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/RSA.java @@ -9,6 +9,13 @@ import java.security.PublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; +/** + * RSA + * @author egan + *
+ * email egzosn@gmail.com
+ *
+ */ 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); } diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/RSA2.java b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/RSA2.java index 745364e..680b7b0 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/RSA2.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/RSA2.java @@ -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; diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/SHA1.java b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/SHA1.java index 36a99cb..52db2bb 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/SHA1.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/SHA1.java @@ -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()); } } diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/SHA256.java b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/SHA256.java index 663c0c7..4334392 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/SHA256.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/SHA256.java @@ -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()); } } diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/sm3/SM3.java b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/sm3/SM3.java index 934a7bb..09f319b 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/sm3/SM3.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/encrypt/sm3/SM3.java @@ -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); diff --git a/pay-java-demo/src/main/java/com/egzosn/pay/demo/controller/AliPayController.java b/pay-java-demo/src/main/java/com/egzosn/pay/demo/controller/AliPayController.java index 39e03b8..ea391da 100644 --- a/pay-java-demo/src/main/java/com/egzosn/pay/demo/controller/AliPayController.java +++ b/pay-java-demo/src/main/java/com/egzosn/pay/demo/controller/AliPayController.java @@ -226,6 +226,16 @@ public class AliPayController { public Map close(QueryOrder order) { return service.close(order.getTradeNo(), order.getOutTradeNo()); } + /** + * 交易c撤销接口 + * + * @param order 订单的请求体 + * @return 返回支付方交易关闭后的结果 + */ + @RequestMapping("cancel") + public Map cancel(QueryOrder order) { + return service.cancel(order.getTradeNo(), order.getOutTradeNo()); + } /** * 申请退款接口 diff --git a/pay-java-fuiou/src/main/java/com/egzosn/pay/fuiou/api/FuiouPayService.java b/pay-java-fuiou/src/main/java/com/egzosn/pay/fuiou/api/FuiouPayService.java index 836e5b9..03ad0b3 100644 --- a/pay-java-fuiou/src/main/java/com/egzosn/pay/fuiou/api/FuiouPayService.java +++ b/pay-java-fuiou/src/main/java/com/egzosn/pay/fuiou/api/FuiouPayService.java @@ -23,23 +23,40 @@ import java.util.*; */ public class FuiouPayService extends BasePayService { - //正式域名 - 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 { */ private LinkedHashMap getOrderInfo(PayOrder order) { LinkedHashMap parameters = new LinkedHashMap(); - 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 { formHtml.append( "
"); - for (String key : param.keySet()) { - Object o = param.get(key); - formHtml.append(""); + for (Map.Entry entry : param.entrySet()) { + Object o = entry.getValue(); + formHtml.append(""); } formHtml.append("
"); @@ -307,8 +336,6 @@ public class FuiouPayService extends BasePayService { 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 { */ @Override public Map close(String tradeNo, String outTradeNo) { - return null; + return Collections.EMPTY_MAP; } + /** * 申请退款接口 * @@ -351,17 +379,20 @@ public class FuiouPayService extends BasePayService { * @return 退款返回结果集 */ @Override - public Map refund (RefundOrder refundOrder) { - Map 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 refund(RefundOrder refundOrder) { + Map 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; } diff --git a/pay-java-payoneer/src/main/java/com/egzosn/pay/payoneer/api/PayoneerPayService.java b/pay-java-payoneer/src/main/java/com/egzosn/pay/payoneer/api/PayoneerPayService.java index 014307b..548327f 100644 --- a/pay-java-payoneer/src/main/java/com/egzosn/pay/payoneer/api/PayoneerPayService.java +++ b/pay-java-payoneer/src/main/java/com/egzosn/pay/payoneer/api/PayoneerPayService.java @@ -84,7 +84,10 @@ public class PayoneerPayService extends BasePayService 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 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 im return secondaryInterface(tradeNo, outTradeNo, PayoneerTransactionType.CHARGE_CANCEL); } + /** + * 交易交易撤销 + * + * @param tradeNo 支付平台订单号 + * @param outTradeNo 商户单号 + * @return 返回支付方交易撤销后的结果 + */ + @Override + public Map cancel(String tradeNo, String outTradeNo) { + return secondaryInterface(tradeNo, outTradeNo, PayoneerTransactionType.CHARGE_CANCEL); + } + /** * 申请退款接口 * 废弃 diff --git a/pay-java-union/src/main/java/com/egzosn/pay/union/api/UnionPayService.java b/pay-java-union/src/main/java/com/egzosn/pay/union/api/UnionPayService.java index b560bc0..1d8d274 100644 --- a/pay-java-union/src/main/java/com/egzosn/pay/union/api/UnionPayService.java +++ b/pay-java-union/src/main/java/com/egzosn/pay/union/api/UnionPayService.java @@ -51,8 +51,8 @@ public class UnionPayService extends BasePayService { 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 { 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 { 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;