From 34a974bc28ff885eec1e541dd8ca681aa973fb11 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 21 Dec 2017 00:33:07 +0800 Subject: [PATCH] =?UTF-8?q?#392=20=E5=BE=AE=E4=BF=A1=E6=94=AF=E4=BB=98?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BC=81=E4=B8=9A=E4=BB=98=E6=AC=BE=E5=88=B0?= =?UTF-8?q?=E9=93=B6=E8=A1=8C=E5=8D=A1=E7=9A=84=E7=9B=B8=E5=85=B3=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- weixin-java-pay/pom.xml | 5 + .../wxpay/bean/entpay/EntPayBankRequest.java | 112 ++++++++++++++++++ .../wxpay/bean/entpay/EntPayBankResult.java | 49 ++++++++ .../wxpay/bean/entpay/GetPublicKeyResult.java | 31 +++++ .../wxpay/bean/request/BaseWxPayRequest.java | 28 +++-- .../request/WxPayQueryCommentRequest.java | 5 + .../bean/request/WxPayRefundRequest.java | 4 +- .../request/WxPayUnifiedOrderRequest.java | 4 +- .../wxpay/service/EntPaySerivce.java | 45 ------- .../wxpay/service/EntPayService.java | 72 +++++++++++ .../wxpay/service/WxPayService.java | 10 +- .../service/impl/BaseWxPayServiceImpl.java | 54 ++++----- .../wxpay/service/impl/EntPayServiceImpl.java | 106 +++++++++++++++-- .../service/impl/EntPayServiceImplTest.java | 24 +++- 14 files changed, 449 insertions(+), 100 deletions(-) create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayBankRequest.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayBankResult.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/GetPublicKeyResult.java delete mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EntPaySerivce.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EntPayService.java diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index c78208c9..a988be00 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -39,6 +39,11 @@ commons-beanutils 1.9.3 + + org.bouncycastle + bcprov-jdk16 + 1.46 + ch.qos.logback diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayBankRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayBankRequest.java new file mode 100644 index 00000000..6a277d71 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayBankRequest.java @@ -0,0 +1,112 @@ +package com.github.binarywang.wxpay.bean.entpay; + +import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import me.chanjar.weixin.common.annotation.Required; + +/** + *
+ *  企业付款到银行卡的请求对象类
+ *  Created by BinaryWang on 2017/12/20.
+ * 
+ * + * @author Binary Wang + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Builder +@XStreamAlias("xml") +public class EntPayBankRequest extends BaseWxPayRequest { + + /** + *
+   * 字段名:商户企业付款单号
+   * 变量名:partner_trade_no
+   * 是否必填:是
+   * 示例值:1212121221227
+   * 类型:string(32)
+   * 描述:商户订单号,需保持唯一(只允许数字[0~9]或字母[A~Z]和[a~z],最短8位,最长32位)
+   */
+  @Required
+  @XStreamAlias("partner_trade_no")
+  private String partnerTradeNo;
+
+  /**
+   * 
+   * 字段名:收款方银行卡号
+   * 变量名:enc_bank_no
+   * 是否必填:是
+   * 示例值:8609cb22e1774a50a930e414cc71eca06121bcd266335cda230d24a7886a8d9f
+   * 类型:string(64)
+   * 描述:收款方银行卡号(采用标准RSA算法,公钥由微信侧提供),详见获取RSA加密公钥API
+   */
+  @Required
+  @XStreamAlias("enc_bank_no")
+  private String encBankNo;
+
+  /**
+   * 
+   * 字段名:收款方用户名
+   * 变量名:enc_true_name
+   * 是否必填:是
+   * 示例值:ca775af5f841bdf424b2e6eb86a6e21e
+   * 类型:string(64)
+   * 描述:收款方用户名(采用标准RSA算法,公钥由微信侧提供)详见获取RSA加密公钥API
+   */
+  @Required
+  @XStreamAlias("enc_true_name")
+  private String encTrueName;
+
+  /**
+   * 
+   * 字段名:收款方开户行
+   * 变量名:bank_code
+   * 是否必填:是
+   * 示例值:1001
+   * 类型:string(64)
+   * 描述:银行卡所在开户行编号,详见银行编号列表
+   */
+  @Required
+  @XStreamAlias("bank_code")
+  private String bankCode;
+
+  /**
+   * 
+   * 字段名:付款金额
+   * 变量名:amount
+   * 是否必填:是
+   * 示例值:100000
+   * 类型:int
+   * 描述:付款金额:RMB分(支付总额,不含手续费) 注:大于0的整数
+   */
+  @Required
+  @XStreamAlias("amount")
+  private Integer amount;
+
+  /**
+   * 
+   * 字段名:付款说明
+   * 变量名:desc
+   * 是否必填:否
+   * 示例值:理财
+   * 类型:string
+   * 描述:企业付款到银行卡付款说明,即订单备注(UTF8编码,允许100个字符以内)
+   */
+  @Required
+  @XStreamAlias("desc")
+  private String description;
+
+  @Override
+  protected void checkConstraints() throws WxPayException {
+
+  }
+
+  @Override
+  protected boolean ignoreAppid() {
+    return true;
+  }
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayBankResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayBankResult.java
new file mode 100644
index 00000000..6cddaab6
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayBankResult.java
@@ -0,0 +1,49 @@
+package com.github.binarywang.wxpay.bean.entpay;
+
+import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+/**
+ * 
+ * 企业付款到银行卡的响应结果
+ * Created by Binary Wang on 2017/12/21.
+ * 
+ * + * @author Binary Wang + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@XStreamAlias("xml") +public class EntPayBankResult extends BaseWxPayResult { + /** + * 代付金额. + */ + @XStreamAlias("amount") + private Integer amount; + + /** + * 商户企业付款单号. + */ + @XStreamAlias("partner_trade_no") + private String partnerTradeNo; + + //############以下字段在return_code 和result_code都为SUCCESS的时候有返回############## + /** + * 微信企业付款单号. + * 代付成功后,返回的内部业务单号 + */ + @XStreamAlias("payment_no") + private String paymentNo; + + /** + * 手续费金额. + * RMB:分 + */ + @XStreamAlias("cmms_amt") + private String cmmsAmount; + +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/GetPublicKeyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/GetPublicKeyResult.java new file mode 100644 index 00000000..f7f62afb --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/GetPublicKeyResult.java @@ -0,0 +1,31 @@ +package com.github.binarywang.wxpay.bean.entpay; + +import com.github.binarywang.wxpay.bean.result.BaseWxPayResult; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + *
+ *  企业付款获取RSA加密公钥接口返回结果类
+ *  Created by BinaryWang on 2017/12/20.
+ * 
+ * + * @author Binary Wang + */ +@Data +@EqualsAndHashCode(callSuper = true) +@XStreamAlias("xml") +public class GetPublicKeyResult extends BaseWxPayResult { + /** + * 商户号. + */ + @XStreamAlias("mch_id") + private String mchId; + + /** + * 密钥 + */ + @XStreamAlias("pub_key") + private String pubKey; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java index 805517ee..9534aeb8 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java @@ -182,6 +182,20 @@ public abstract class BaseWxPayRequest { return xstream.toXML(this); } + /** + * 签名时,是否忽略signType + */ + protected boolean ignoreSignType() { + return false; + } + + /** + * 签名时,是否忽略appid + */ + protected boolean ignoreAppid() { + return false; + } + /** *
    * 检查参数,并设置签名
@@ -190,14 +204,15 @@ public abstract class BaseWxPayRequest {
    * 3、生成签名,并设置进去
    * 
* - * @param config 支付配置对象,用于读取相应系统配置信息 - * @param isIgnoreSignType 签名时,是否忽略signType + * @param config 支付配置对象,用于读取相应系统配置信息 */ - public void checkAndSign(WxPayConfig config, boolean isIgnoreSignType) throws WxPayException { + public void checkAndSign(WxPayConfig config) throws WxPayException { this.checkFields(); - if (StringUtils.isBlank(getAppid())) { - this.setAppid(config.getAppId()); + if (!ignoreAppid()) { + if (StringUtils.isBlank(getAppid())) { + this.setAppid(config.getAppId()); + } } if (StringUtils.isBlank(getMchId())) { @@ -229,7 +244,6 @@ public abstract class BaseWxPayRequest { //设置签名字段的值 this.setSign(SignUtils.createSign(this, this.getSignType(), config.getMchKey(), - isIgnoreSignType)); + this.ignoreSignType())); } - } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayQueryCommentRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayQueryCommentRequest.java index 33e2a212..d052a26e 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayQueryCommentRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayQueryCommentRequest.java @@ -20,6 +20,11 @@ import me.chanjar.weixin.common.annotation.Required; @AllArgsConstructor @XStreamAlias("xml") public class WxPayQueryCommentRequest extends BaseWxPayRequest { + @Override + protected boolean ignoreSignType() { + return true; + } + /** *
    * 字段名:开始时间
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java
index d5510b6c..4a2c7571 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java
@@ -157,12 +157,12 @@ public class WxPayRefundRequest extends BaseWxPayRequest {
   private String refundDesc;
 
   @Override
-  public void checkAndSign(WxPayConfig config, boolean isIgnoreSignType) throws WxPayException {
+  public void checkAndSign(WxPayConfig config) throws WxPayException {
     if (StringUtils.isBlank(this.getOpUserId())) {
       this.setOpUserId(config.getMchId());
     }
 
-    super.checkAndSign(config, isIgnoreSignType);
+    super.checkAndSign(config);
   }
 
   @Override
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java
index de299928..f5a5067d 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java
@@ -349,7 +349,7 @@ public class WxPayUnifiedOrderRequest extends BaseWxPayRequest {
   }
 
   @Override
-  public void checkAndSign(WxPayConfig config, boolean isIgnoreSignType) throws WxPayException {
+  public void checkAndSign(WxPayConfig config) throws WxPayException {
     if (StringUtils.isBlank(this.getNotifyURL())) {
       this.setNotifyURL(config.getNotifyUrl());
     }
@@ -358,7 +358,7 @@ public class WxPayUnifiedOrderRequest extends BaseWxPayRequest {
       this.setTradeType(config.getTradeType());
     }
 
-    super.checkAndSign(config, isIgnoreSignType);
+    super.checkAndSign(config);
   }
 
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EntPaySerivce.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EntPaySerivce.java
deleted file mode 100644
index d398042b..00000000
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EntPaySerivce.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.github.binarywang.wxpay.service;
-
-import com.github.binarywang.wxpay.bean.entpay.EntPayQueryResult;
-import com.github.binarywang.wxpay.bean.entpay.EntPayRequest;
-import com.github.binarywang.wxpay.bean.entpay.EntPayResult;
-import com.github.binarywang.wxpay.bean.request.WxEntPayRequest;
-import com.github.binarywang.wxpay.bean.result.WxEntPayQueryResult;
-import com.github.binarywang.wxpay.bean.result.WxEntPayResult;
-import com.github.binarywang.wxpay.exception.WxPayException;
-
-/**
- * 
- *     企业付款相关服务类
- *  Created by BinaryWang on 2017/12/19.
- * 
- * - * @author Binary Wang - */ -public interface EntPaySerivce { - /** - *
-   * 企业付款业务是基于微信支付商户平台的资金管理能力,为了协助商户方便地实现企业向个人付款,针对部分有开发能力的商户,提供通过API完成企业付款的功能。
-   * 比如目前的保险行业向客户退保、给付、理赔。
-   * 企业付款将使用商户的可用余额,需确保可用余额充足。查看可用余额、充值、提现请登录商户平台“资金管理”https://pay.weixin.qq.com/进行操作。
-   * 注意:与商户微信支付收款资金并非同一账户,需要单独充值。
-   * 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
-   * 接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers
-   * 
- * - * @param request 请求对象 - */ - EntPayResult entPay(EntPayRequest request) throws WxPayException; - - /** - *
-   * 查询企业付款API
-   * 用于商户的企业付款操作进行结果查询,返回付款操作详细结果。
-   * 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_3
-   * 接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo
-   * 
- * - * @param partnerTradeNo 商户订单号 - */ - EntPayQueryResult queryEntPay(String partnerTradeNo) throws WxPayException; -} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EntPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EntPayService.java new file mode 100644 index 00000000..f68f7d37 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EntPayService.java @@ -0,0 +1,72 @@ +package com.github.binarywang.wxpay.service; + +import com.github.binarywang.wxpay.bean.entpay.*; +import com.github.binarywang.wxpay.exception.WxPayException; + +/** + *
+ *  企业付款相关服务类.
+ *  Created by BinaryWang on 2017/12/19.
+ * 
+ * + * @author Binary Wang + */ +public interface EntPayService { + /** + *
+   * 企业付款API.
+   * 企业付款业务是基于微信支付商户平台的资金管理能力,为了协助商户方便地实现企业向个人付款,针对部分有开发能力的商户,提供通过API完成企业付款的功能。
+   * 比如目前的保险行业向客户退保、给付、理赔。
+   * 企业付款将使用商户的可用余额,需确保可用余额充足。查看可用余额、充值、提现请登录商户平台“资金管理”https://pay.weixin.qq.com/进行操作。
+   * 注意:与商户微信支付收款资金并非同一账户,需要单独充值。
+   * 文档详见: https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
+   * 接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers
+   * 
+ * + * @param request 请求对象 + */ + EntPayResult entPay(EntPayRequest request) throws WxPayException; + + /** + *
+   * 查询企业付款API.
+   * 用于商户的企业付款操作进行结果查询,返回付款操作详细结果。
+   * 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_3
+   * 接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo
+   * 
+ * + * @param partnerTradeNo 商户订单号 + */ + EntPayQueryResult queryEntPay(String partnerTradeNo) throws WxPayException; + + /** + *
+   * 获取RSA加密公钥API.
+   * RSA算法使用说明(非对称加密算法,算法采用RSA/ECB/OAEPPadding模式)
+   * 1、 调用获取RSA公钥API获取RSA公钥,落地成本地文件,假设为public.pem
+   * 2、 确定public.pem文件的存放路径,同时修改代码中文件的输入路径,加载RSA公钥
+   * 3、 用标准的RSA加密库对敏感信息进行加密,选择RSA_PKCS1_OAEP_PADDING填充模式
+   * (eg:Java的填充方式要选 " RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING")
+   * 4、 得到进行rsa加密并转base64之后的密文
+   * 5、 将密文传给微信侧相应字段,如付款接口(enc_bank_no/enc_true_name)
+   *
+   * 接口默认输出PKCS#1格式的公钥,商户需根据自己开发的语言选择公钥格式
+   * 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_7&index=4
+   * 接口链接:https://fraud.mch.weixin.qq.com/risk/getpublickey
+   * 
+ */ + String getPublicKey() throws WxPayException; + + /** + * 企业付款到银行卡. + *
+   * 用于企业向微信用户银行卡付款
+   * 目前支持接口API的方式向指定微信用户的银行卡付款。
+   * 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_2
+   * 接口链接:https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank
+   * 
+ * + * @param request 请求对象 + */ + EntPayBankResult payToBankCard(EntPayBankRequest request) throws WxPayException; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java index 628170ca..a653612e 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java @@ -2,9 +2,7 @@ package com.github.binarywang.wxpay.service; import com.github.binarywang.wxpay.bean.WxPayApiData; import com.github.binarywang.wxpay.bean.coupon.*; -import com.github.binarywang.wxpay.bean.entpay.EntPayQueryResult; import com.github.binarywang.wxpay.bean.entpay.EntPayRequest; -import com.github.binarywang.wxpay.bean.entpay.EntPayResult; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; import com.github.binarywang.wxpay.bean.request.*; @@ -54,12 +52,12 @@ public interface WxPayService { /** * 获取企业付款服务类 */ - EntPaySerivce getEntPaySerivce(); + EntPayService getEntPayService(); /** * 设置企业付款服务类,允许开发者自定义实现类 */ - void setEntPaySerivce(EntPaySerivce entPaySerivce); + void setEntPayService(EntPayService entPayService); /** *
@@ -211,13 +209,13 @@ public interface WxPayService {
   WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxPayException;
 
   /**
-   * 请使用this.getEntPayService().entPay()方法{@link EntPaySerivce#entPay(EntPayRequest)}
+   * 请使用this.getEntPayService().entPay()方法{@link EntPayService#entPay(EntPayRequest)}
    */
   @Deprecated
   WxEntPayResult entPay(WxEntPayRequest request) throws WxPayException;
 
   /**
-   * 请使用this.getEntPayService().queryEntPay()方法 {@link EntPaySerivce#queryEntPay(String)}
+   * 请使用this.getEntPayService().queryEntPay()方法 {@link EntPayService#queryEntPay(String)}
    */
   @Deprecated
   WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxPayException;
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
index 3c8b59d0..c4343f5a 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
@@ -3,8 +3,6 @@ package com.github.binarywang.wxpay.service.impl;
 import com.github.binarywang.utils.qrcode.QrcodeUtils;
 import com.github.binarywang.wxpay.bean.WxPayApiData;
 import com.github.binarywang.wxpay.bean.coupon.*;
-import com.github.binarywang.wxpay.bean.entpay.EntPayQueryResult;
-import com.github.binarywang.wxpay.bean.entpay.EntPayResult;
 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
 import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
 import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult;
@@ -17,7 +15,7 @@ import com.github.binarywang.wxpay.constant.WxPayConstants.BillType;
 import com.github.binarywang.wxpay.constant.WxPayConstants.SignType;
 import com.github.binarywang.wxpay.constant.WxPayConstants.TradeType;
 import com.github.binarywang.wxpay.exception.WxPayException;
-import com.github.binarywang.wxpay.service.EntPaySerivce;
+import com.github.binarywang.wxpay.service.EntPayService;
 import com.github.binarywang.wxpay.service.WxPayService;
 import com.github.binarywang.wxpay.util.SignUtils;
 import com.google.common.base.Joiner;
@@ -52,18 +50,18 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
   protected final Logger log = LoggerFactory.getLogger(this.getClass());
   protected static ThreadLocal wxApiData = new ThreadLocal<>();
 
-  private EntPaySerivce entPaySerivce = new EntPayServiceImpl(this);
+  private EntPayService entPayService = new EntPayServiceImpl(this);
 
   protected WxPayConfig config;
 
   @Override
-  public EntPaySerivce getEntPaySerivce() {
-    return entPaySerivce;
+  public EntPayService getEntPayService() {
+    return entPayService;
   }
 
   @Override
-  public void setEntPaySerivce(EntPaySerivce entPaySerivce) {
-    this.entPaySerivce = entPaySerivce;
+  public void setEntPayService(EntPayService entPayService) {
+    this.entPayService = entPayService;
   }
 
   @Override
@@ -87,7 +85,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
 
   @Override
   public WxPayRefundResult refund(WxPayRefundRequest request) throws WxPayException {
-    request.checkAndSign(this.getConfig(), false);
+    request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/secapi/pay/refund";
     String responseContent = this.post(url, request.toXML(), true);
@@ -105,7 +103,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
     request.setOutRefundNo(StringUtils.trimToNull(outRefundNo));
     request.setRefundId(StringUtils.trimToNull(refundId));
 
-    request.checkAndSign(this.getConfig(), false);
+    request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/pay/refundquery";
     String responseContent = this.post(url, request.toXML(), false);
@@ -153,7 +151,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
 
   @Override
   public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxPayException {
-    request.checkAndSign(this.getConfig(), false);
+    request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/mmpaymkttransfers/sendredpack";
     if (request.getAmtType() != null) {
@@ -171,7 +169,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
     WxPayRedpackQueryRequest request = new WxPayRedpackQueryRequest();
     request.setMchBillNo(mchBillNo);
     request.setBillType(BillType.MCHT);
-    request.checkAndSign(this.getConfig(), false);
+    request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/mmpaymkttransfers/gethbinfo";
     String responseContent = this.post(url, request.toXML(), true);
@@ -185,7 +183,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
     WxPayOrderQueryRequest request = new WxPayOrderQueryRequest();
     request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
     request.setTransactionId(StringUtils.trimToNull(transactionId));
-    request.checkAndSign(this.getConfig(), false);
+    request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/pay/orderquery";
     String responseContent = this.post(url, request.toXML(), false);
@@ -207,7 +205,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
 
     WxPayOrderCloseRequest request = new WxPayOrderCloseRequest();
     request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
-    request.checkAndSign(this.getConfig(), false);
+    request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/pay/closeorder";
     String responseContent = this.post(url, request.toXML(), false);
@@ -289,7 +287,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
 
   @Override
   public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxPayException {
-    request.checkAndSign(this.getConfig(), false);
+    request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/pay/unifiedorder";
     String responseContent = this.post(url, request.toXML(), false);
@@ -350,13 +348,13 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
   @Override
   @Deprecated
   public WxEntPayResult entPay(WxEntPayRequest request) throws WxPayException {
-    return WxEntPayResult.createFrom(this.getEntPaySerivce().entPay(request));
+    return WxEntPayResult.createFrom(this.getEntPayService().entPay(request));
   }
 
   @Override
   @Deprecated
   public WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxPayException {
-    return WxEntPayQueryResult.createFrom(this.getEntPaySerivce().queryEntPay(partnerTradeNo));
+    return WxEntPayQueryResult.createFrom(this.getEntPayService().queryEntPay(partnerTradeNo));
   }
 
   @Override
@@ -403,7 +401,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
 
   @Override
   public void report(WxPayReportRequest request) throws WxPayException {
-    request.checkAndSign(this.getConfig(), false);
+    request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/payitil/report";
     String responseContent = this.post(url, request.toXML(), false);
@@ -423,7 +421,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
     request.setTarType(tarType);
     request.setDeviceInfo(deviceInfo);
 
-    request.checkAndSign(this.getConfig(), false);
+    request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/pay/downloadbill";
 
@@ -547,7 +545,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
 
   @Override
   public WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxPayException {
-    request.checkAndSign(this.getConfig(), false);
+    request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/pay/micropay";
     String responseContent = this.post(url, request.toXML(), false);
@@ -558,7 +556,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
 
   @Override
   public WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) throws WxPayException {
-    request.checkAndSign(this.getConfig(), false);
+    request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/secapi/pay/reverse";
     String responseContent = this.post(url, request.toXML(), true);
@@ -569,7 +567,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
 
   @Override
   public String shorturl(WxPayShorturlRequest request) throws WxPayException {
-    request.checkAndSign(this.getConfig(), false);
+    request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/tools/shorturl";
     String responseContent = this.post(url, request.toXML(), false);
@@ -585,7 +583,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
 
   @Override
   public String authcode2Openid(WxPayAuthcode2OpenidRequest request) throws WxPayException {
-    request.checkAndSign(this.getConfig(), false);
+    request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/tools/authcodetoopenid";
     String responseContent = this.post(url, request.toXML(), false);
@@ -602,7 +600,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
   @Override
   public String getSandboxSignKey() throws WxPayException {
     WxPayDefaultRequest request = new WxPayDefaultRequest();
-    request.checkAndSign(this.getConfig(), false);
+    request.checkAndSign(this.getConfig());
 
     String url = "https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey";
     String responseContent = this.post(url, request.toXML(), false);
@@ -613,7 +611,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
 
   @Override
   public WxPayCouponSendResult sendCoupon(WxPayCouponSendRequest request) throws WxPayException {
-    request.checkAndSign(this.getConfig(), false);
+    request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/mmpaymkttransfers/send_coupon";
     String responseContent = this.post(url, request.toXML(), true);
@@ -624,7 +622,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
 
   @Override
   public WxPayCouponStockQueryResult queryCouponStock(WxPayCouponStockQueryRequest request) throws WxPayException {
-    request.checkAndSign(this.getConfig(), false);
+    request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/mmpaymkttransfers/query_coupon_stock";
     String responseContent = this.post(url, request.toXML(), false);
@@ -635,7 +633,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
 
   @Override
   public WxPayCouponInfoQueryResult queryCouponInfo(WxPayCouponInfoQueryRequest request) throws WxPayException {
-    request.checkAndSign(this.getConfig(), false);
+    request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/mmpaymkttransfers/querycouponsinfo";
     String responseContent = this.post(url, request.toXML(), false);
@@ -664,7 +662,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
     request.setLimit(limit);
     request.setSignType(SignType.HMAC_SHA256);
 
-    request.checkAndSign(this.getConfig(), true);
+    request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/billcommentsp/batchquerycomment";
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImpl.java
index 92b5a730..5ab4c187 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImpl.java
@@ -1,13 +1,25 @@
 package com.github.binarywang.wxpay.service.impl;
 
-import com.github.binarywang.wxpay.bean.entpay.EntPayQueryRequest;
-import com.github.binarywang.wxpay.bean.entpay.EntPayQueryResult;
-import com.github.binarywang.wxpay.bean.entpay.EntPayRequest;
-import com.github.binarywang.wxpay.bean.entpay.EntPayResult;
+import com.github.binarywang.wxpay.bean.entpay.*;
+import com.github.binarywang.wxpay.bean.request.WxPayDefaultRequest;
 import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
 import com.github.binarywang.wxpay.exception.WxPayException;
-import com.github.binarywang.wxpay.service.EntPaySerivce;
+import com.github.binarywang.wxpay.service.EntPayService;
 import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.util.SignUtils;
+import org.apache.commons.codec.binary.Base64;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.provider.JCERSAPublicKey;
+import org.bouncycastle.openssl.PEMReader;
+import org.bouncycastle.openssl.PasswordFinder;
+
+import javax.crypto.Cipher;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.Security;
 
 /**
  * 
@@ -16,7 +28,7 @@ import com.github.binarywang.wxpay.service.WxPayService;
  *
  * @author Binary Wang
  */
-public class EntPayServiceImpl implements EntPaySerivce {
+public class EntPayServiceImpl implements EntPayService {
   private WxPayService payService;
 
   public EntPayServiceImpl(WxPayService payService) {
@@ -25,7 +37,7 @@ public class EntPayServiceImpl implements EntPaySerivce {
 
   @Override
   public EntPayResult entPay(EntPayRequest request) throws WxPayException {
-    request.checkAndSign(this.payService.getConfig(), false);
+    request.checkAndSign(this.payService.getConfig());
     String url = this.payService.getPayBaseUrl() + "/mmpaymkttransfers/promotion/transfers";
 
     String responseContent = this.payService.post(url, request.toXML(), true);
@@ -38,7 +50,7 @@ public class EntPayServiceImpl implements EntPaySerivce {
   public EntPayQueryResult queryEntPay(String partnerTradeNo) throws WxPayException {
     EntPayQueryRequest request = new EntPayQueryRequest();
     request.setPartnerTradeNo(partnerTradeNo);
-    request.checkAndSign(this.payService.getConfig(), false);
+    request.checkAndSign(this.payService.getConfig());
 
     String url = this.payService.getPayBaseUrl() + "/mmpaymkttransfers/gettransferinfo";
     String responseContent = this.payService.post(url, request.toXML(), true);
@@ -47,4 +59,82 @@ public class EntPayServiceImpl implements EntPaySerivce {
     return result;
   }
 
+  @Override
+  public String getPublicKey() throws WxPayException {
+    WxPayDefaultRequest request = new WxPayDefaultRequest();
+    request.setMchId(this.payService.getConfig().getMchId());
+    request.setNonceStr(String.valueOf(System.currentTimeMillis()));
+    request.setSign(SignUtils.createSign(request, null, this.payService.getConfig().getMchKey(),
+      true));
+
+    String url = "https://fraud.mch.weixin.qq.com/risk/getpublickey";
+    String responseContent = this.payService.post(url, request.toXML(), true);
+    GetPublicKeyResult result = BaseWxPayResult.fromXML(responseContent, GetPublicKeyResult.class);
+    result.checkResult(this.payService, request.getSignType(), true);
+    return result.getPubKey();
+  }
+
+  @Override
+  public EntPayBankResult payToBankCard(EntPayBankRequest request) throws WxPayException {
+    File publicKeyFile = this.buildPublicKeyFile();
+    request.setEncBankNo(this.encryptRSA(publicKeyFile, request.getEncBankNo()));
+    request.setEncTrueName(this.encryptRSA(publicKeyFile, request.getEncTrueName()));
+    publicKeyFile.deleteOnExit();
+
+    request.checkAndSign(this.payService.getConfig());
+
+    String url = this.payService.getPayBaseUrl() + "/mmpaysptrans/pay_bank";
+    String responseContent = this.payService.post(url, request.toXML(), true);
+    EntPayBankResult result = BaseWxPayResult.fromXML(responseContent, EntPayBankResult.class);
+    result.checkResult(this.payService, request.getSignType(), true);
+    return result;
+  }
+
+  private String encryptRSA(File publicKeyFile, String srcString) throws WxPayException {
+    try {
+      Security.addProvider(new BouncyCastleProvider());
+      Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
+      PasswordFinder passwordFinder = new PasswordFinder() {
+        @Override
+        public char[] getPassword() {
+          return "".toCharArray();
+        }
+      };
+
+      try (PEMReader reader = new PEMReader(new FileReader(publicKeyFile), passwordFinder)) {
+        JCERSAPublicKey publicKey = (JCERSAPublicKey) reader.readObject();
+        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+        byte[] encrypt = cipher.doFinal(srcString.getBytes());
+        return Base64.encodeBase64String(encrypt);
+      }
+    } catch (Exception e) {
+      throw new WxPayException("加密出错", e);
+    }
+  }
+
+  private File buildPublicKeyFile() throws WxPayException {
+    try {
+      String publicKeyStr = this.getPublicKey();
+      Path tmpFile = Files.createTempFile("payToBank", ".pem");
+      Files.write(tmpFile, publicKeyStr.getBytes());
+      return tmpFile.toFile();
+    } catch (Exception e) {
+      throw new WxPayException("生成加密公钥文件时发生异常", e);
+    }
+  }
+
+  public static void main(String[] args) throws WxPayException, IOException {
+    String key = "-----BEGIN RSA PUBLIC KEY-----\n" +
+      "MIIBCgKCAQEAtEeUSop/YGqZ53Y++R9NapFSZmorj+SL/brmJUU7+hyClEnPOeG/\n" +
+      "v6/ZrX9qo25JAojrBDbqaW9L+HtzI141vusarRYIGPvVqTV30L5db0Yq7AmX7Hs9\n" +
+      "s+nEtoMAwMWUzQPXLUs2mt6rpu85HwAIK3F4Xb+OFIbXCJTbDvWYtQssn07lr+IY\n" +
+      "jPA00sON71egmuRrCoQClkhf0vgrhj7eHUCRZRJ2zf4UU31fHv+kO441hVD5TTP8\n" +
+      "bjJvFm6TW3sgQE8aCDbomtu+syk4Tv/4ONCqxG8d/kF1TlU+idGWEU179uR/KSjP\n" +
+      "p7kM7BoaY2goFgYAe4DsI8Fh33dCOiKyVwIDAQAB\n" +
+      "-----END RSA PUBLIC KEY-----";
+    Path tmpFile = Files.createTempFile("payToBank", ".pem");
+    Files.write(tmpFile, key.getBytes());
+    System.out.println(new EntPayServiceImpl(null).encryptRSA(tmpFile.toFile(), "111111"));
+  }
+
 }
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImplTest.java
index 2707090b..8e35db8c 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImplTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImplTest.java
@@ -1,5 +1,7 @@
 package com.github.binarywang.wxpay.service.impl;
 
+import com.github.binarywang.wxpay.bean.entpay.EntPayBankRequest;
+import com.github.binarywang.wxpay.bean.entpay.EntPayBankResult;
 import com.github.binarywang.wxpay.bean.entpay.EntPayRequest;
 import com.github.binarywang.wxpay.bean.request.WxEntPayRequest;
 import com.github.binarywang.wxpay.constant.WxPayConstants;
@@ -51,7 +53,7 @@ public class EntPayServiceImplTest {
       .description("描述信息")
       .build();
 
-    this.logger.info(this.payService.getEntPaySerivce().entPay(request).toString());
+    this.logger.info(this.payService.getEntPayService().entPay(request).toString());
   }
 
   @Test
@@ -61,6 +63,24 @@ public class EntPayServiceImplTest {
 
   @Test
   public void testQueryEntPay() throws WxPayException {
-    this.logger.info(this.payService.getEntPaySerivce().queryEntPay("11212121").toString());
+    this.logger.info(this.payService.getEntPayService().queryEntPay("11212121").toString());
+  }
+
+  @Test
+  public void testGetPublicKey() throws Exception {
+    this.logger.info(this.payService.getEntPayService().getPublicKey());
+  }
+
+  @Test
+  public void testPayToBankCard() throws Exception {
+    EntPayBankResult result = this.payService.getEntPayService().payToBankCard(EntPayBankRequest.builder()
+      .bankCode("aa")
+      .amount(1)
+      .encBankNo("1")
+      .encTrueName("2")
+      .partnerTradeNo("3")
+      .description("11")
+      .build());
+    this.logger.info(result.toString());
   }
 }