From decbace4434917a9631d3932e680c3a710bbf7f9 Mon Sep 17 00:00:00 2001 From: zzs Date: Fri, 24 Feb 2017 10:51:50 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9A=E4=B9=89=E6=9F=A5=E8=B4=A6=EF=BC=8C?= =?UTF-8?q?=E9=80=80=E6=AC=BE=E7=AD=89=E6=8E=A5=E5=8F=A3=EF=BC=8C=E5=BC=80?= =?UTF-8?q?=E5=8F=91=E6=96=B0=E7=89=88=E6=9C=AC=E6=94=AF=E4=BB=98=E5=AE=9D?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=EF=BC=8C=E6=96=B0=E5=A2=9ERSA2=E7=AD=BE?= =?UTF-8?q?=E5=90=8D=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../egan/pay/ali/api/AliPayConfigStorage.java | 40 +- .../in/egan/pay/ali/api/AliPayService.java | 158 ++++---- .../egan/pay/ali/bean/AliTransactionType.java | 7 +- .../pay/ali/before/api/AliPayService.java | 343 ++++++++++++++++++ .../ali/before/bean/AliTransactionType.java | 27 ++ .../pay/common/api/BasePayConfigStorage.java | 8 +- .../egan/pay/common/api/PayConfigStorage.java | 7 + .../in/egan/pay/common/api/PayService.java | 45 ++- .../egan/pay/common/api/RequestExecutor.java | 3 +- .../in/egan/pay/common/bean/PayOrder.java | 51 ++- .../pay/common/util/sign/encrypt/RSA.java | 133 +++---- .../pay/common/util/sign/encrypt/RSA2.java | 53 +++ .../pay/demo/dao/ApyAccountRepository.java | 4 +- .../java/in/egan/pay/demo/entity/PayType.java | 2 +- .../egan/pay/fuiou/api/FuiouPayService.java | 25 ++ .../wx/youdian/api/WxYouDianPayService.java | 26 ++ .../java/in/egan/pay/wx/api/WxPayService.java | 29 +- 17 files changed, 791 insertions(+), 170 deletions(-) create mode 100644 pay-java-ali/src/main/java/in/egan/pay/ali/before/api/AliPayService.java create mode 100644 pay-java-ali/src/main/java/in/egan/pay/ali/before/bean/AliTransactionType.java create mode 100644 pay-java-common/src/main/java/in/egan/pay/common/util/sign/encrypt/RSA2.java diff --git a/pay-java-ali/src/main/java/in/egan/pay/ali/api/AliPayConfigStorage.java b/pay-java-ali/src/main/java/in/egan/pay/ali/api/AliPayConfigStorage.java index 69081d1..ea6ea7a 100644 --- a/pay-java-ali/src/main/java/in/egan/pay/ali/api/AliPayConfigStorage.java +++ b/pay-java-ali/src/main/java/in/egan/pay/ali/api/AliPayConfigStorage.java @@ -11,7 +11,12 @@ import in.egan.pay.common.api.BasePayConfigStorage; public class AliPayConfigStorage extends BasePayConfigStorage { // 商户PID - public volatile String partner ; + public volatile String appId ; + // 商户签约拿到的pid,partner_id的简称,合作伙伴身份等同于 partner + public volatile String pid ; + //partner_id的简称,合作伙伴身份 +// public volatile String partner ; + // 商户收款账号 public volatile String seller; //公钥 @@ -33,20 +38,41 @@ public class AliPayConfigStorage extends BasePayConfigStorage { } + public void setAppId(String appId) { + this.appId = appId; + } @Override public String getAppid() { - return null; + return appId; + } + + /** + * @see #getPid() + * @return 合作者id + */ + @Deprecated + @Override + public String getPartner() { + return pid; + } + + /** + * @see #setPid() + * @return 合作者id + */ + @Deprecated + public void setPartner(String partner) { + this.pid = partner; } @Override - public String getPartner() { - return partner; + public String getPid() { + return pid; } - - public void setPartner(String partner) { - this.partner = partner; + public void setPid(String pid) { + this.pid = pid; } public String getSeller() { diff --git a/pay-java-ali/src/main/java/in/egan/pay/ali/api/AliPayService.java b/pay-java-ali/src/main/java/in/egan/pay/ali/api/AliPayService.java index 44d758e..f3c3266 100644 --- a/pay-java-ali/src/main/java/in/egan/pay/ali/api/AliPayService.java +++ b/pay-java-ali/src/main/java/in/egan/pay/ali/api/AliPayService.java @@ -1,10 +1,10 @@ package in.egan.pay.ali.api; +import com.alibaba.fastjson.JSONObject; import in.egan.pay.ali.bean.AliTransactionType; import in.egan.pay.ali.util.SimpleGetRequestExecutor; import in.egan.pay.common.api.BasePayService; import in.egan.pay.common.api.PayConfigStorage; -import in.egan.pay.common.api.PayService; import in.egan.pay.common.api.RequestExecutor; import in.egan.pay.common.bean.MethodType; import in.egan.pay.common.bean.PayOrder; @@ -12,39 +12,28 @@ import in.egan.pay.common.bean.PayOutMessage; import in.egan.pay.common.bean.result.PayError; import in.egan.pay.common.exception.PayErrorException; import in.egan.pay.common.util.sign.SignUtils; -import in.egan.pay.common.util.str.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.http.HttpHost; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; - import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.net.URLEncoder; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.TreeMap; +import java.text.DateFormat; +import java.util.*; /** * 支付宝支付通知 * @author egan * @email egzosn@gmail.com - * @date 2016-5-18 14:09:01 + * @date 2017-2-22 20:09 */ public class AliPayService extends BasePayService { protected final Log log = LogFactory.getLog(AliPayService.class); - private String httpsReqUrl = "https://mapi.alipay.com/gateway.do"; + private String httpsReqUrl = "https://openapi.alipay.com/gateway.do"; public String getHttpsVerifyUrl() { @@ -149,69 +138,6 @@ public class AliPayService extends BasePayService { } - /** - * 支付宝创建订单信息 - * create the order info - * - * @param order 支付订单 - * @return - * @see in.egan.pay.common.bean.PayOrder - */ - @Deprecated - private String getOrderInfo(PayOrder order) { - StringBuilder orderInfo = new StringBuilder(); - // 签约合作者身份ID - orderInfo.append( "partner=").append( "\"").append( payConfigStorage.getPartner() ).append("\""); - - // 签约卖家支付宝账号 - orderInfo.append("&seller_id=" ) .append("\"" ) .append(payConfigStorage.getSeller() ) .append("\""); - - // 商户网站唯一订单号 - orderInfo.append("&out_trade_no=" ) .append("\"" ).append(order.getTradeNo() ) .append("\""); - - // 商品名称 - orderInfo.append("&subject=" ) .append("\"" ) .append(order.getSubject() ) .append("\""); - - // 商品详情 - orderInfo.append("&body=" ) .append("\"" ) .append(order.getBody() ) .append("\""); - - // 商品金额 - orderInfo.append("&total_fee=" ) .append("\"" ) .append(order.getPrice().setScale(2, BigDecimal.ROUND_HALF_UP) ) .append("\""); - - // 服务器异步通知页面路径 - orderInfo.append("¬ify_url=" ) .append("\"" ).append( payConfigStorage.getNotifyUrl() ) .append("\""); - - // 服务接口名称, 固定值 - orderInfo.append("&service=\"" ).append( order.getTransactionType().getType() ).append("\""); - - // 支付类型, 固定值 - orderInfo.append("&payment_type=\"1\""); - - // 参数编码, 固定值 - orderInfo.append("&_input_charset=\"utf-8\""); - - // 设置未付款交易的超时时间 - // 默认30分钟,一旦超时,该笔交易就会自动被关闭。 - // 取值范围:1m~15d。 - // m-分钟,h-小时,d-天,1c-当天(无论交易何时创建,都在0点关闭)。 - // 该参数数值不接受小数点,如1.5h,可转换为90m。 - orderInfo.append("&it_b_pay=\"30m\""); - - // extern_token为经过快登授权获取到的alipay_open_id,带上此参数用户将使用授权的账户进行支付 - // orderInfo.append("&extern_token=" ) .append("\"" ) extern_token ) .append("\""); - - // 支付宝处理完请求后,当前页面跳转到商户指定页面的路径,可空 - if (AliTransactionType.APP == order.getTransactionType()){ - orderInfo.append("&return_url=\"m.alipay.com\""); - } - - // 调用银行卡支付,需配置此参数,参与签名, 固定值 (需要签约《无线银行卡快捷支付》才能使用) -// if (order.getTransactionType().getType()) -// orderInfo.append("&paymethod=\"expressGateway\""); - - return orderInfo.toString(); - } - /** * 支付宝创建订单信息 * create the order info @@ -221,7 +147,52 @@ public class AliPayService extends BasePayService { * @see in.egan.pay.common.bean.PayOrder */ private Map getOrder(PayOrder order) { - Map orderInfo = new HashMap<>(); + + //兼容上一版本的即时到账 + if (AliTransactionType.DIRECT == order.getTransactionType()){ + return getOrderDirect(order); + } + + Map orderInfo = new TreeMap<>(); + orderInfo.put("app_id", payConfigStorage.getAppid()); + orderInfo.put("method", order.getTransactionType().getType()); + orderInfo.put("charset", payConfigStorage.getInputCharset()); + DateFormat formatter = DateFormat.getDateTimeInstance(); + orderInfo.put("timestamp", formatter.format( new Date())); + orderInfo.put("version", "1.0"); + orderInfo.put("notify_url", payConfigStorage.getNotifyUrl()); + + JSONObject bizContent = new JSONObject(); + if ("alipay.trade.pay".equals(order.getTransactionType().getType())){ + bizContent.put("scene", order.getTransactionType().toString().toLowerCase()); + bizContent.put("product_code", "FACE_TO_FACE_PAYMENT"); + bizContent.put("auth_code", order.getAuthCode()); + }else { + bizContent.put("product_code", "QUICK_MSECURITY_PAY"); + } + bizContent.put("body", order.getBody()); + bizContent.put("seller_id", payConfigStorage.getPid()); + 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()); + orderInfo.put("biz_content", bizContent.toJSONString()); + + + + return orderInfo; + } + + + /** + * 支付宝创建订单信息 + * create the order info + * + * @param order 支付订单 + * @return + * @see in.egan.pay.common.bean.PayOrder + */ + private Map getOrderDirect(PayOrder order) { + Map orderInfo = new TreeMap<>(); // StringBuilder orderInfo = new StringBuilder(); // 签约合作者身份ID orderInfo.put("partner", payConfigStorage.getPartner()); @@ -286,6 +257,8 @@ public class AliPayService extends BasePayService { return orderInfo; } + + @Override public String createSign(String content, String characterEncoding) { @@ -358,6 +331,31 @@ public class AliPayService extends BasePayService { throw new UnsupportedOperationException(); } + @Override + public Map query(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Map close(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Map refund(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Map refundquery(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Object downloadbill(Date billDate, String billType) { + return null; + } + /** * * @param executor diff --git a/pay-java-ali/src/main/java/in/egan/pay/ali/bean/AliTransactionType.java b/pay-java-ali/src/main/java/in/egan/pay/ali/bean/AliTransactionType.java index 56f6900..981f75b 100644 --- a/pay-java-ali/src/main/java/in/egan/pay/ali/bean/AliTransactionType.java +++ b/pay-java-ali/src/main/java/in/egan/pay/ali/bean/AliTransactionType.java @@ -9,8 +9,11 @@ import in.egan.pay.common.bean.TransactionType; * @date 2016/10/19 22:58 */ public enum AliTransactionType implements TransactionType { - //即时到帐 //移动支付 //手机网站支付 - DIRECT("create_direct_pay_by_user"),APP("mobile.securitypay.pay"),WAP("alipay.wap.create.direct.pay.by.user"); + //即时到帐 //移动支付 //手机网站支付 + DIRECT("create_direct_pay_by_user"),APP("alipay.trade.app.pay"),WAP("alipay.trade.wap.pay") + // TODO 2017/2/23 20:26 author: egan 以下三个为主动交易类型 暂未测试, + //扫码付 //条码付 // 声波付 + ,SWEEPPAY("alipay.trade.precreate"),BAR_CODE("alipay.trade.pay"),WAVE_CODE("alipay.trade.pay"),; private String type; diff --git a/pay-java-ali/src/main/java/in/egan/pay/ali/before/api/AliPayService.java b/pay-java-ali/src/main/java/in/egan/pay/ali/before/api/AliPayService.java new file mode 100644 index 0000000..276bc1e --- /dev/null +++ b/pay-java-ali/src/main/java/in/egan/pay/ali/before/api/AliPayService.java @@ -0,0 +1,343 @@ +package in.egan.pay.ali.before.api; + +import in.egan.pay.ali.util.SimpleGetRequestExecutor; +import in.egan.pay.common.api.BasePayService; +import in.egan.pay.common.api.PayConfigStorage; +import in.egan.pay.common.api.RequestExecutor; +import in.egan.pay.common.bean.MethodType; +import in.egan.pay.common.bean.PayOrder; +import in.egan.pay.common.bean.PayOutMessage; +import in.egan.pay.common.bean.result.PayError; +import in.egan.pay.common.exception.PayErrorException; +import in.egan.pay.common.util.sign.SignUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.net.URLEncoder; +import java.util.*; + +/** + * 支付宝支付通知 + * @author egan + * @email egzosn@gmail.com + * @date 2016-5-18 14:09:01 + * @see in.egan.pay.ali.api.AliPayService + */ +@Deprecated +public class AliPayService extends BasePayService { + protected final Log log = LogFactory.getLog(AliPayService.class); + + + private String httpsReqUrl = "https://mapi.alipay.com/gateway.do"; + + + public String getHttpsVerifyUrl() { + return httpsReqUrl + "?service=notify_verify"; + } + + @Override + public boolean verify(Map params) { + + + if (params.get("sign") == null || params.get("notify_id") == null) { + log.debug("支付宝支付异常:params:" + params); + return false; + } + + try { + return getSignVerify(params, params.get("sign")) && "true".equals(verifyUrl(params.get("notify_id"))); + } catch (PayErrorException e) { + e.printStackTrace(); + } + + return false; + } + + + /** + * 根据反馈回来的信息,生成签名结果 + * @param params 通知返回来的参数数组 + * @param sign 比对的签名结果 + * @return 生成的签名结果 + */ + public boolean getSignVerify(Map params, String sign) { + + return SignUtils.valueOf(payConfigStorage.getSignType()).verify(params, sign, payConfigStorage.getKeyPublic(), payConfigStorage.getInputCharset()); + } + + + @Override + public String verifyUrl(String notify_id) throws PayErrorException { + return execute(new SimpleGetRequestExecutor(), getHttpsVerifyUrl(), "partner=" + payConfigStorage.getPartner() + "¬ify_id=" + notify_id); + } + + + /** + * 向支付宝端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 + * + * @param executor + * @param uri + * @param data + * @return + * @throws PayErrorException + * @source chanjarster/weixin-java-tools + */ + @Override + public T execute(RequestExecutor executor, String uri, E data) throws PayErrorException { + int retryTimes = 0; + do { + try { + return executeInternal(executor, uri, data); + } catch (PayErrorException e) { + PayError error = e.getError(); + if (error.getErrorCode() == 404) { + int sleepMillis = retrySleepMillis * (1 << retryTimes); + try { + log.debug(String.format("支付宝系统繁忙,(%s)ms 后重试(第%s次)", sleepMillis, retryTimes + 1)); + Thread.sleep(sleepMillis); + } catch (InterruptedException e1) { + throw new RuntimeException(e1); + } + } else { + throw e; + } + } + } while (++retryTimes < maxRetryTimes); + + throw new RuntimeException("支付宝服务端异常,超出重试次数"); + } + + + /** + * 返回创建的订单信息 + * + * @param order 支付订单 + * @return + * @see PayOrder + */ + @Override + public Map orderInfo(PayOrder order) { + + Map orderInfo = getOrder(order); + + String sign = createSign( SignUtils.parameterText(orderInfo, "&"), "UTF-8"); + + try { + sign = URLEncoder.encode(sign, "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + orderInfo.put("sign", sign); + orderInfo.put("sign_type", payConfigStorage.getSignType()); + return orderInfo; + } + + /** + * 支付宝创建订单信息 + * create the order info + * + * @param order 支付订单 + * @return + * @see in.egan.pay.common.bean.PayOrder + */ + private Map getOrder(PayOrder order) { + Map orderInfo = new TreeMap<>(); +// StringBuilder orderInfo = new StringBuilder(); + // 签约合作者身份ID + orderInfo.put("partner", payConfigStorage.getPartner()); +// orderInfo.append( "partner=").append( "\"").append( payConfigStorage.getPartner() ).append("\""); + + // 签约卖家支付宝账号 + orderInfo.put("seller_id", payConfigStorage.getSeller()); +// orderInfo.append("&seller_id=" ) .append("\"" ) .append(payConfigStorage.getSeller() ) .append("\""); + + // 商户网站唯一订单号 + orderInfo.put("out_trade_no", order.getTradeNo()); +// orderInfo.append("&out_trade_no=" ) .append("\"" ).append(order.getTradeNo() ) .append("\""); + + // 商品名称 + orderInfo.put("subject", order.getSubject()); +// orderInfo.append("&subject=" ) .append("\"" ) .append(order.getSubject() ) .append("\""); + + // 商品详情 + orderInfo.put("body", order.getBody()); +// orderInfo.append("&body=" ) .append("\"" ) .append(order.getBody() ) .append("\""); + + // 商品金额 + orderInfo.put("total_fee", order.getPrice().setScale(2, BigDecimal.ROUND_HALF_UP).toString() ); +// orderInfo.append("&total_fee=" ) .append("\"" ) .append(order.getPrice().setScale(2, BigDecimal.ROUND_HALF_UP) ) .append("\""); + + // 服务器异步通知页面路径 + orderInfo.put("notify_url", payConfigStorage.getNotifyUrl() ); +// orderInfo.append("¬ify_url=" ) .append("\"" ).append( payConfigStorage.getNotifyUrl() ) .append("\""); + + // 服务接口名称, 固定值 + orderInfo.put("service", order.getTransactionType().getType() ); +// orderInfo.append("&service=\"" ).append( order.getTransactionType().getType() ).append("\""); + + // 支付类型, 固定值 + orderInfo.put("payment_type", "1" ); +// orderInfo.append("&payment_type=\"1\""); + + // 参数编码, 固定值 + orderInfo.put("_input_charset", payConfigStorage.getInputCharset()); +// orderInfo.append("&_input_charset=\"utf-8\""); + + // 设置未付款交易的超时时间 + // 默认30分钟,一旦超时,该笔交易就会自动被关闭。 + // 取值范围:1m~15d。 + // m-分钟,h-小时,d-天,1c-当天(无论交易何时创建,都在0点关闭)。 + // 该参数数值不接受小数点,如1.5h,可转换为90m。 + // TODO 2017/2/6 11:05 author: egan 目前写死,这一块建议配置 + orderInfo.put("it_b_pay", "30m"); +// orderInfo.append("&it_b_pay=\"30m\""); + + // extern_token为经过快登授权获取到的alipay_open_id,带上此参数用户将使用授权的账户进行支付 + // orderInfo.append("&extern_token=" ) .append("\"" ) extern_token ) .append("\""); + + // 支付宝处理完请求后,当前页面跳转到商户指定页面的路径,可空 + orderInfo.put("return_url", payConfigStorage.getReturnUrl()); +// orderInfo.append("&return_url=\"m.alipay.com\""); + + // 调用银行卡支付,需配置此参数,参与签名, 固定值 (需要签约《无线银行卡快捷支付》才能使用) +// if (order.getTransactionType().getType()) +// orderInfo.append("&paymethod=\"expressGateway\""); + + return orderInfo; + } + + + @Override + public String createSign(String content, String characterEncoding) { + + return SignUtils.valueOf(payConfigStorage.getSignType()).createSign(content, payConfigStorage.getKeyPrivate(),characterEncoding); + } + + + @Override + 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); + String valueStr = ""; + for (int i = 0,len = values.length; i < len; i++) { + valueStr += (i == len - 1) ? values[i] + : values[i] + ","; + } + //乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化 + //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk"); + params.put(name, valueStr); + } + + return params; + } + + @Override + public PayOutMessage getPayOutMessage(String code, String message) { + return PayOutMessage.TEXT().content(code.toLowerCase()).build(); + } + + @Override + public String buildRequest(Map orderInfo, MethodType method) { + + StringBuffer formHtml = new StringBuffer(); + + formHtml.append("
"); + + for (String key: orderInfo.keySet()) { + Object o = orderInfo.get(key); + if (null == o ||"null".equals(o) || "".equals(o) ){ + continue; + } + formHtml.append(""); + } + + + //submit按钮控件请不要含有name属性 +// formHtml.append(""); + formHtml.append("
"); + formHtml.append(""); + + return formHtml.toString(); + } + + /** + * 生成二维码支付 + * 暂未实现或无此功能 + * @param orderInfo 发起支付的订单信息 + * @return + */ + @Override + public BufferedImage genQrPay(Map orderInfo) { + throw new UnsupportedOperationException(); + } + + @Override + public Map query(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Map close(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Map refund(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Map refundquery(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Object downloadbill(Date billDate, String billType) { + return null; + } + + /** + * + * @param executor + * @param uri + * @param data + * @param + * @param + * @return + * @throws PayErrorException + */ + protected T executeInternal(RequestExecutor executor, String uri, E data) throws PayErrorException { + + try { + return executor.execute(getHttpClient(), httpProxy, uri, data); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + + + @Override + public PayConfigStorage getPayConfigStorage() { + return payConfigStorage; + } + + public AliPayService() { + } + + public AliPayService(PayConfigStorage payConfigStorage) { + setPayConfigStorage(payConfigStorage); + } +} diff --git a/pay-java-ali/src/main/java/in/egan/pay/ali/before/bean/AliTransactionType.java b/pay-java-ali/src/main/java/in/egan/pay/ali/before/bean/AliTransactionType.java new file mode 100644 index 0000000..dd1b5d2 --- /dev/null +++ b/pay-java-ali/src/main/java/in/egan/pay/ali/before/bean/AliTransactionType.java @@ -0,0 +1,27 @@ +package in.egan.pay.ali.before.bean; + +import in.egan.pay.common.bean.TransactionType; + +/** + * 阿里交易类型 + * @author egan + * @email egzosn@gmail.com + * @date 2016/10/19 22:58 + * @see in.egan.pay.ali.bean.AliTransactionType + */ +@Deprecated +public enum AliTransactionType implements TransactionType { + //即时到帐 //移动支付 //手机网站支付 + DIRECT("create_direct_pay_by_user"),APP("mobile.securitypay.pay"),WAP("alipay.wap.create.direct.pay.by.user"); + + private String type; + + private AliTransactionType(String type) { + this.type = type; + } + + @Override + public String getType() { + return type; + } +} diff --git a/pay-java-common/src/main/java/in/egan/pay/common/api/BasePayConfigStorage.java b/pay-java-common/src/main/java/in/egan/pay/common/api/BasePayConfigStorage.java index 9c793f3..62732dc 100644 --- a/pay-java-common/src/main/java/in/egan/pay/common/api/BasePayConfigStorage.java +++ b/pay-java-common/src/main/java/in/egan/pay/common/api/BasePayConfigStorage.java @@ -54,7 +54,13 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{ protected volatile String httpProxyPassword; - + /** + * 合作商唯一标识 + * @see #getPartner 代替者 + */ + public String getPid(){ + throw null; + } @Override public String getInputCharset() { diff --git a/pay-java-common/src/main/java/in/egan/pay/common/api/PayConfigStorage.java b/pay-java-common/src/main/java/in/egan/pay/common/api/PayConfigStorage.java index 71aed52..ff9d74f 100644 --- a/pay-java-common/src/main/java/in/egan/pay/common/api/PayConfigStorage.java +++ b/pay-java-common/src/main/java/in/egan/pay/common/api/PayConfigStorage.java @@ -20,7 +20,14 @@ import java.util.concurrent.locks.Lock; /** * 合作商唯一标识 */ + @Deprecated String getPartner(); + /** + * 合作商唯一标识 + * @see #getPartner 代替者 + */ + String getPid(); + /** * 获取收款账号 */ diff --git a/pay-java-common/src/main/java/in/egan/pay/common/api/PayService.java b/pay-java-common/src/main/java/in/egan/pay/common/api/PayService.java index d3f142b..1df174f 100644 --- a/pay-java-common/src/main/java/in/egan/pay/common/api/PayService.java +++ b/pay-java-common/src/main/java/in/egan/pay/common/api/PayService.java @@ -8,6 +8,7 @@ import in.egan.pay.common.exception.PayErrorException; import java.awt.image.BufferedImage; import java.io.InputStream; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.Map; @@ -19,6 +20,7 @@ import java.util.Map; * @date 2016-5-18 14:09:01 */ public interface PayService { + /** * 回调校验URL * @return @@ -93,7 +95,6 @@ import java.util.Map; /** * 将请求参数或者请求流转化为 Map - * * @param parameterMap 请求参数 * @param is 请求流 * @return @@ -123,4 +124,46 @@ import java.util.Map; * @return */ BufferedImage genQrPay(Map orderInfo); + + /** + * 交易查询接口 + * @param tradeNo 支付平台订单号 + * @param outTradeNo 商户单号 + * @return + */ + Map query(String tradeNo, String outTradeNo); + + /** + * 交易关闭接口 + * @param tradeNo 支付平台订单号 + * @param outTradeNo 商户单号 + * @return + */ + Map close(String tradeNo, String outTradeNo); + + /** + * 交易关闭接口 + * @param tradeNo 支付平台订单号 + * @param outTradeNo 商户单号 + * @return + */ + Map refund(String tradeNo, String outTradeNo); + + /** + * 查询退款 + * @param tradeNo 支付平台订单号 + * @param outTradeNo 商户单号 + * @return + */ + Map refundquery(String tradeNo, String outTradeNo); + + /** + * 下载对账单 + * @param billDate 支付平台订单号 + * @param billType 商户单号 + * @return + */ + Object downloadbill(Date billDate, String billType); + + } diff --git a/pay-java-common/src/main/java/in/egan/pay/common/api/RequestExecutor.java b/pay-java-common/src/main/java/in/egan/pay/common/api/RequestExecutor.java index b76422b..5812f4b 100644 --- a/pay-java-common/src/main/java/in/egan/pay/common/api/RequestExecutor.java +++ b/pay-java-common/src/main/java/in/egan/pay/common/api/RequestExecutor.java @@ -24,9 +24,8 @@ public interface RequestExecutor { * @param uri uri * @param data 数据 * @return - * @throws ClientProtocolException * @throws java.io.IOException */ - public T execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, E data) throws PayErrorException, ClientProtocolException,IOException; + public T execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, E data) throws PayErrorException, IOException; } diff --git a/pay-java-common/src/main/java/in/egan/pay/common/bean/PayOrder.java b/pay-java-common/src/main/java/in/egan/pay/common/bean/PayOrder.java index fd84d7f..c6f5f6d 100644 --- a/pay-java-common/src/main/java/in/egan/pay/common/bean/PayOrder.java +++ b/pay-java-common/src/main/java/in/egan/pay/common/bean/PayOrder.java @@ -16,12 +16,14 @@ public class PayOrder { private String body; //价格 private BigDecimal price; - //商户单号 - private String tradeNo; + //商户订单号 + private String outTradeNo; //银行卡类型 private String bankType; //设备号 private String deviceInfo; + //付款条码串 与设备号类似??? + private String authCode; //交易类型 private TransactionType transactionType; //支付币种 @@ -60,12 +62,38 @@ public class PayOrder { this.price = price; } + /** + * 获取商户订单号 + * @return + * @see #getOutTradeNo() + */ + @Deprecated public String getTradeNo() { - return tradeNo; + return outTradeNo; } + /** + * 设置商户订单号 + * @see #setOutTradeNo(String) + */ + @Deprecated public void setTradeNo(String tradeNo) { - this.tradeNo = tradeNo; + this.outTradeNo = tradeNo; + } + + /** + * 获取商户订单号 + * @return + */ + public String getOutTradeNo() { + return outTradeNo; + } + /** + * 设置商户订单号 + * @return + */ + public void setOutTradeNo(String outTradeNo) { + this.outTradeNo = outTradeNo; } public TransactionType getTransactionType() { @@ -84,6 +112,14 @@ public class PayOrder { this.bankType = bankType; } + public String getAuthCode() { + return authCode; + } + + public void setAuthCode(String authCode) { + this.authCode = authCode; + } + public String getDeviceInfo() { return deviceInfo; } @@ -96,15 +132,16 @@ public class PayOrder { } - public PayOrder(String subject, String body, BigDecimal price, String tradeNo, TransactionType transactionType) { - + public PayOrder(String subject, String body, BigDecimal price, String outTradeNo, TransactionType transactionType) { this.subject = subject; this.body = body; this.price = price; - this.tradeNo = tradeNo; + this.outTradeNo = outTradeNo; this.transactionType = transactionType; } + + } diff --git a/pay-java-common/src/main/java/in/egan/pay/common/util/sign/encrypt/RSA.java b/pay-java-common/src/main/java/in/egan/pay/common/util/sign/encrypt/RSA.java index e7e45a5..fa04438 100644 --- a/pay-java-common/src/main/java/in/egan/pay/common/util/sign/encrypt/RSA.java +++ b/pay-java-common/src/main/java/in/egan/pay/common/util/sign/encrypt/RSA.java @@ -12,9 +12,42 @@ import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; public class RSA{ - - public static final String SIGN_ALGORITHMS = "SHA1WithRSA"; - + + private static final String ALGORITHM = "RSA"; + + private static final String SIGN_ALGORITHMS = "SHA1WithRSA"; + + + /** + * RSA签名 + * @param content 待签名数据 + * @param privateKey 私钥 + * @param signAlgorithms 签名算法 + * @param characterEncoding 编码格式 + * @return 签名值 + */ + public static String sign(String content, String privateKey, String signAlgorithms, String characterEncoding) { + try { + PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec( Base64.decode(privateKey)); + KeyFactory keyf = KeyFactory.getInstance(ALGORITHM); + PrivateKey priKey = keyf.generatePrivate(priPKCS8); + + java.security.Signature signature = java.security.Signature.getInstance(signAlgorithms); + + signature.initSign(priKey); + signature.update(content.getBytes(characterEncoding)); + + byte[] signed = signature.sign(); + + return Base64.encode(signed); + } catch (Exception e) { + e.printStackTrace(); + } + + return null; + } + + /** * RSA签名 * @param content 待签名数据 @@ -22,32 +55,33 @@ public class RSA{ * @param characterEncoding 编码格式 * @return 签名值 */ - public static String sign(String content, String privateKey ,String characterEncoding) - { - try - { - PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec( Base64.decode(privateKey) ); - KeyFactory keyf = KeyFactory.getInstance("RSA"); - PrivateKey priKey = keyf.generatePrivate(priPKCS8); - - java.security.Signature signature = java.security.Signature - .getInstance(SIGN_ALGORITHMS); - - signature.initSign(priKey); - signature.update( content.getBytes(characterEncoding) ); - - byte[] signed = signature.sign(); - - return Base64.encode(signed); - } - catch (Exception e) - { - e.printStackTrace(); - } - - return null; + public static String sign(String content, String privateKey ,String characterEncoding){ + return sign(content, privateKey, SIGN_ALGORITHMS, characterEncoding); } - + + /** + * RSA验签名检查 + * @param content 待签名数据 + * @param sign 签名值 + * @param publicKey 公钥 + * @param signAlgorithms 签名算法 + * @param characterEncoding 编码格式 + * @return 布尔值 + */ + public static boolean verify(String content, String sign, String publicKey, String signAlgorithms, String characterEncoding){ + try { + KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM); + byte[] encodedKey = Base64.decode(publicKey); + PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey)); + java.security.Signature signature = java.security.Signature.getInstance(signAlgorithms); + signature.initVerify(pubKey); + signature.update( content.getBytes(characterEncoding) ); + return signature.verify( Base64.decode(sign) ); + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } /** * RSA验签名检查 * @param content 待签名数据 @@ -56,31 +90,9 @@ public class RSA{ * @param characterEncoding 编码格式 * @return 布尔值 */ - public static boolean verify(String content, String sign, String publicKey, String characterEncoding) - { - try - { - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - byte[] encodedKey = Base64.decode(publicKey); - PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey)); + public static boolean verify(String content, String sign, String publicKey, String characterEncoding){ - - java.security.Signature signature = java.security.Signature - .getInstance(SIGN_ALGORITHMS); - - signature.initVerify(pubKey); - signature.update( content.getBytes(characterEncoding) ); - - boolean bverify = signature.verify( Base64.decode(sign) ); - return bverify; - - } - catch (Exception e) - { - e.printStackTrace(); - } - - return false; + return verify(content, sign, publicKey, SIGN_ALGORITHMS, characterEncoding); } /** @@ -91,17 +103,14 @@ public class RSA{ * @return 解密后的字符串 */ public static String decrypt(String content, String privateKey, String characterEncoding) throws Exception { - PrivateKey prikey = getPrivateKey(privateKey); - - Cipher cipher = Cipher.getInstance("RSA"); + PrivateKey prikey = getPrivateKey(privateKey); + Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, prikey); - - InputStream ins = new ByteArrayInputStream(Base64.decode(content)); + InputStream ins = new ByteArrayInputStream(Base64.decode(content)); ByteArrayOutputStream writer = new ByteArrayOutputStream(); //rsa解密的字节大小最多是128,将需要解密的内容,按128位拆开解密 byte[] buf = new byte[128]; int bufl; - while ((bufl = ins.read(buf)) != -1) { byte[] block = null; @@ -113,7 +122,6 @@ public class RSA{ block[i] = buf[i]; } } - writer.write(cipher.doFinal(block)); } @@ -129,15 +137,10 @@ public class RSA{ public static PrivateKey getPrivateKey(String key) throws Exception { byte[] keyBytes; - keyBytes = Base64.decode(key); - PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); - - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - + KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM); PrivateKey privateKey = keyFactory.generatePrivate(keySpec); - return privateKey; } } diff --git a/pay-java-common/src/main/java/in/egan/pay/common/util/sign/encrypt/RSA2.java b/pay-java-common/src/main/java/in/egan/pay/common/util/sign/encrypt/RSA2.java new file mode 100644 index 0000000..8f1e7de --- /dev/null +++ b/pay-java-common/src/main/java/in/egan/pay/common/util/sign/encrypt/RSA2.java @@ -0,0 +1,53 @@ + +package in.egan.pay.common.util.sign.encrypt; + +import java.security.PrivateKey; + +public class RSA2 { + + private static final String SIGN_SHA256RSA_ALGORITHMS = "SHA256WithRSA"; + + + + public static String sign(String content, String privateKey, String characterEncoding) { + + return RSA.sign(content, privateKey, SIGN_SHA256RSA_ALGORITHMS, characterEncoding); + } + + + + + /** + * RSA验签名检查 + * @param content 待签名数据 + * @param sign 签名值 + * @param publicKey 公钥 + * @param characterEncoding 编码格式 + * @return 布尔值 + */ + public static boolean verify(String content, String sign, String publicKey, String characterEncoding){ + + return RSA.verify(content, sign, publicKey, SIGN_SHA256RSA_ALGORITHMS, characterEncoding ); + } + + /** + * 解密 + * @param content 密文 + * @param privateKey 商户私钥 + * @param characterEncoding 编码格式 + * @return 解密后的字符串 + */ + public static String decrypt(String content, String privateKey, String characterEncoding) throws Exception { + return RSA.decrypt(content, privateKey, characterEncoding); + } + + + /** + * 得到私钥 + * @param key 密钥字符串(经过base64编码) + * @throws Exception + */ + public static PrivateKey getPrivateKey(String key) throws Exception { + return RSA.getPrivateKey(key); + } +} diff --git a/pay-java-demo/src/main/java/in/egan/pay/demo/dao/ApyAccountRepository.java b/pay-java-demo/src/main/java/in/egan/pay/demo/dao/ApyAccountRepository.java index 7d98566..aa6f61a 100644 --- a/pay-java-demo/src/main/java/in/egan/pay/demo/dao/ApyAccountRepository.java +++ b/pay-java-demo/src/main/java/in/egan/pay/demo/dao/ApyAccountRepository.java @@ -28,8 +28,8 @@ public class ApyAccountRepository { { ApyAccount apyAccount1 = new ApyAccount(); apyAccount1.setPayId(1); - apyAccount1.setPartner("12******01"); - apyAccount1.setAppid("wxa**********ba9e9"); + apyAccount1.setPartner("2088911944978307"); + apyAccount1.setAppid("2016052301431829"); // TODO 2017/2/9 16:20 author: egan sign_type只有单一key时public_key与private_key相等,比如sign_type=MD5的情况 apyAccount1.setPublicKey("48gf0iwuhr***********r9weh9eiut9"); apyAccount1.setPrivateKey("48gf0iwuhr***********r9weh9eiut9"); diff --git a/pay-java-demo/src/main/java/in/egan/pay/demo/entity/PayType.java b/pay-java-demo/src/main/java/in/egan/pay/demo/entity/PayType.java index d87570c..a868527 100644 --- a/pay-java-demo/src/main/java/in/egan/pay/demo/entity/PayType.java +++ b/pay-java-demo/src/main/java/in/egan/pay/demo/entity/PayType.java @@ -26,7 +26,7 @@ public enum PayType implements BasePayType { @Override public PayService getPayService(ApyAccount apyAccount) { AliPayConfigStorage aliPayConfigStorage = new AliPayConfigStorage(); - aliPayConfigStorage.setPartner(apyAccount.getPartner()); + aliPayConfigStorage.setPid(apyAccount.getPartner()); aliPayConfigStorage.setAliPublicKey(apyAccount.getPublicKey()); aliPayConfigStorage.setKeyPrivate(apyAccount.getPrivateKey()); aliPayConfigStorage.setNotifyUrl(apyAccount.getNotifyUrl()); diff --git a/pay-java-fuiou/src/main/java/in/egan/pay/fuiou/api/FuiouPayService.java b/pay-java-fuiou/src/main/java/in/egan/pay/fuiou/api/FuiouPayService.java index def9b9d..eaa8811 100644 --- a/pay-java-fuiou/src/main/java/in/egan/pay/fuiou/api/FuiouPayService.java +++ b/pay-java-fuiou/src/main/java/in/egan/pay/fuiou/api/FuiouPayService.java @@ -272,5 +272,30 @@ public class FuiouPayService extends BasePayService { throw new UnsupportedOperationException(); } + @Override + public Map query(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Map close(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Map refund(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Map refundquery(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Object downloadbill(Date billDate, String billType) { + return null; + } + } diff --git a/pay-java-wx-youdian/src/main/java/in/egan/pay/wx/youdian/api/WxYouDianPayService.java b/pay-java-wx-youdian/src/main/java/in/egan/pay/wx/youdian/api/WxYouDianPayService.java index 9aa12cc..a0b2da9 100644 --- a/pay-java-wx-youdian/src/main/java/in/egan/pay/wx/youdian/api/WxYouDianPayService.java +++ b/pay-java-wx-youdian/src/main/java/in/egan/pay/wx/youdian/api/WxYouDianPayService.java @@ -19,6 +19,7 @@ import org.apache.commons.logging.LogFactory; import java.awt.image.BufferedImage; import java.io.InputStream; import java.math.BigDecimal; +import java.util.Date; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; @@ -354,6 +355,31 @@ public class WxYouDianPayService extends BasePayService { return MatrixToImageWriter.writeInfoToJpgBuff((String) orderInfo.get("code_url")); } + @Override + public Map query(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Map close(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Map refund(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Map refundquery(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Object downloadbill(Date billDate, String billType) { + return null; + } + public WxYouDianPayService(PayConfigStorage payConfigStorage) { setPayConfigStorage(payConfigStorage); } diff --git a/pay-java-wx/src/main/java/in/egan/pay/wx/api/WxPayService.java b/pay-java-wx/src/main/java/in/egan/pay/wx/api/WxPayService.java index ad3428f..e872eca 100644 --- a/pay-java-wx/src/main/java/in/egan/pay/wx/api/WxPayService.java +++ b/pay-java-wx/src/main/java/in/egan/pay/wx/api/WxPayService.java @@ -164,13 +164,13 @@ public class WxPayService implements PayService { parameters.put("nonce_str", SignUtils.randomStr()); parameters.put("body", order.getSubject());// 购买支付信息 parameters.put("notify_url", payConfigStorage.getNotifyUrl()); - parameters.put("out_trade_no", order.getTradeNo());// 订单号 + parameters.put("out_trade_no", order.getOutTradeNo());// 订单号 parameters.put("spbill_create_ip", "192.168.1.150"); parameters.put("total_fee", order.getPrice().multiply(new BigDecimal(100)).intValue());// 总金额单位为分 parameters.put("trade_type", order.getTransactionType().getType()); parameters.put("attach", order.getBody()); if (WxTransactionType.NATIVE == order.getTransactionType()){ - parameters.put("product_id", order.getTradeNo()); + parameters.put("product_id", order.getOutTradeNo()); } String sign = createSign(SignUtils.parameterText(parameters), payConfigStorage.getInputCharset()); parameters.put("sign", sign); @@ -270,6 +270,31 @@ public class WxPayService implements PayService { return MatrixToImageWriter.writeInfoToJpgBuff((String) orderInfo.get("code_url")); } + @Override + public Map query(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Map close(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Map refund(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Map refundquery(String tradeNo, String outTradeNo) { + return null; + } + + @Override + public Object downloadbill(Date billDate, String billType) { + return null; + } + protected T executeInternal(RequestExecutor executor, String uri, E data) throws PayErrorException {