From e49a408a275464cfb4718f8af35604f13767f585 Mon Sep 17 00:00:00 2001
From: xiaoyong931011 <15274802129@163.com>
Date: Thu, 25 Aug 2022 15:38:48 +0800
Subject: [PATCH] 20220822

---
 src/main/java/cc/mrbird/febs/pay/model/Request.java                             |   91 +++
 src/main/java/cc/mrbird/febs/pay/util/HEXUtil.java                              |   85 +++
 src/test/java/cc/mrbird/febs/ProfitTest.java                                    |   45 +
 src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallOrderInfoServiceImpl.java |   30 +
 src/main/java/cc/mrbird/febs/pay/model/AgreementSignDto.java                    |   15 
 src/main/java/cc/mrbird/febs/pay/util/JsonUtil.java                             |   71 ++
 src/main/java/cc/mrbird/febs/pay/util/RandomUtil.java                           |   29 +
 src/main/java/cc/mrbird/febs/pay/model/AgreeMentPaySmsDto.java                  |   31 +
 src/main/java/cc/mrbird/febs/pay/model/SignTypeEnum.java                        |   22 
 src/main/java/cc/mrbird/febs/pay/util/HttpClientUtil.java                       |   39 +
 src/main/java/cc/mrbird/febs/pay/util/MD5Util.java                              |   44 +
 src/main/java/cc/mrbird/febs/pay/model/Response.java                            |   86 +++
 src/main/java/cc/mrbird/febs/pay/service/UnipayService.java                     |   25 
 src/main/java/cc/mrbird/febs/pay/model/AgreementPayDto.java                     |   26 +
 src/main/java/cc/mrbird/febs/pay/model/CommonConst.java                         |   12 
 src/main/java/cc/mrbird/febs/pay/util/RSAUtil.java                              |  211 ++++++++
 src/main/java/cc/mrbird/febs/pay/model/RequestParam.java                        |   22 
 src/main/java/cc/mrbird/febs/pay/service/impl/UnipayServiceImpl.java            |  275 ++++++++++
 src/main/java/cc/mrbird/febs/pay/controller/UnipayController.java               |   12 
 src/main/java/cc/mrbird/febs/pay/util/SignUtil.java                             |  109 ++++
 src/main/java/cc/mrbird/febs/pay/util/Base64Util.java                           |  118 ++++
 src/main/java/cc/mrbird/febs/common/exception/JPException.java                  |   12 
 src/main/java/cc/mrbird/febs/pay/util/CodeUtil.java                             |   17 
 src/main/java/cc/mrbird/febs/pay/util/AESUtil.java                              |   71 ++
 src/main/java/cc/mrbird/febs/pay/model/Algorithm.java                           |   14 
 25 files changed, 1,500 insertions(+), 12 deletions(-)

diff --git a/src/main/java/cc/mrbird/febs/common/exception/JPException.java b/src/main/java/cc/mrbird/febs/common/exception/JPException.java
new file mode 100644
index 0000000..ce4c79e
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/common/exception/JPException.java
@@ -0,0 +1,12 @@
+package cc.mrbird.febs.common.exception;
+
+public class JPException extends RuntimeException {
+
+    public JPException(String message) {
+        super(message);
+    }
+
+    public JPException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallOrderInfoServiceImpl.java b/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallOrderInfoServiceImpl.java
index cb72f74..2f2ff02 100644
--- a/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallOrderInfoServiceImpl.java
+++ b/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallOrderInfoServiceImpl.java
@@ -17,6 +17,7 @@
 import cc.mrbird.febs.mall.vo.OrderDetailVo;
 import cc.mrbird.febs.mall.vo.OrderListVo;
 import cc.mrbird.febs.mall.vo.OrderRefundVo;
+import cc.mrbird.febs.pay.model.AgreementSignDto;
 import cc.mrbird.febs.pay.model.UnipayDto;
 import cc.mrbird.febs.pay.service.IPayService;
 import cc.mrbird.febs.pay.service.UnipayService;
@@ -329,6 +330,35 @@
 
                 mallMoneyFlowService.addMoneyFlow(member.getId(), orderInfo.getAmount().negate(), MoneyFlowTypeEnum.PAY.getValue(), orderInfo.getOrderNo(),  FlowTypeEnum.PRIZE_SCORE.getValue());
                 break;
+            case "5":
+                AgreementSignDto agreementSignDto = new AgreementSignDto();
+                agreementSignDto.setOrderNo(orderInfo.getOrderNo());
+                unipayService.agreementSign(agreementSignDto);
+//                UnipayDto unipayDto = new UnipayDto();
+////                unipayDto.setAmount(new BigDecimal("0.01"));
+//                unipayDto.setAmount(orderInfo.getAmount());
+//                unipayDto.setFrpCode("ALIPAY_H5");
+//                unipayDto.setTradeMerchantNo("777180800385820");
+//                unipayDto.setOrderNo(orderInfo.getOrderNo());
+//                List<MallOrderItem> items = orderInfo.getItems();
+//                if(CollUtil.isEmpty(items)){
+//                    unipayDto.setProductName("商品");
+//                }else{
+//                    unipayDto.setProductName(items.get(0).getGoodsName());
+//                }
+//                String agreementSignStr = "";
+//                if("fail" == unipayStr){
+//                    throw new FebsException("支付失败");
+//                }else{
+//                    JSONUtil.parseObj(unipayStr);
+//                    JSONObject jsonObject = JSONUtil.parseObj(unipayStr);
+//                    payResultStr = (String) jsonObject.get("r7_TrxNo");
+//                    rcResult = (String) jsonObject.get("rc_Result");
+//                }
+                orderInfo.setPayOrderNo(payResultStr);
+                orderInfo.setPayMethod("支付宝支付");
+//                agentProducer.sendOrderReturn(orderInfo.getId());
+                break;
             default:
 
         }
diff --git a/src/main/java/cc/mrbird/febs/pay/controller/UnipayController.java b/src/main/java/cc/mrbird/febs/pay/controller/UnipayController.java
index 58321a5..2a7eada 100644
--- a/src/main/java/cc/mrbird/febs/pay/controller/UnipayController.java
+++ b/src/main/java/cc/mrbird/febs/pay/controller/UnipayController.java
@@ -150,12 +150,12 @@
 //        System.out.println(orderNo);
 //    }
 
-//    @ApiOperation(value = "获取协议支付签约短信", notes = "获取协议支付签约短信")
-//    @PostMapping(value = "getAgreeMentPaySms")
-//    public FebsResponse getAgreeMentPaySms(@RequestBody AgreeMentPaySmsDto agreeMentPaySmsDto) {
-//        unipayService.getAgreeMentPaySms(agreeMentPaySmsDto);
-//        return new FebsResponse().success().message("申请成功");
-//    }
+    @ApiOperation(value = "获取协议支付签约短信", notes = "获取协议支付签约短信")
+    @PostMapping(value = "getAgreeMentPaySms")
+    public FebsResponse getAgreeMentPaySms(@RequestBody AgreeMentPaySmsDto agreeMentPaySmsDto) {
+        unipayService.getAgreeMentPaySms(agreeMentPaySmsDto);
+        return new FebsResponse().success().message("申请成功");
+    }
 
 //    public static void main(String[] args) {
 //        String data = "{\\\"bank_trx_no\\\":\\\"0825144603229910\\\",\\\"jp_order_no\\\":\\\"100120220825446322447537651712\\\",\\\"mch_order_no\\\":\\\"2022082514435329133\\\",\\\"order_amount\\\":0.10,\\\"order_desc\\\":\\\"测试\\\",\\\"order_status\\\":\\\"P1000\\\",\\\"pay_success_time\\\":\\\"2022-08-25 14:46:04\\\"}";
diff --git a/src/main/java/cc/mrbird/febs/pay/model/AgreeMentPaySmsDto.java b/src/main/java/cc/mrbird/febs/pay/model/AgreeMentPaySmsDto.java
new file mode 100644
index 0000000..c166a1a
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/model/AgreeMentPaySmsDto.java
@@ -0,0 +1,31 @@
+package cc.mrbird.febs.pay.model;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@ApiModel(value = "AgreeMentPaySmsDto", description = "汇聚支付快捷支付-协议支付短信接收参数类")
+public class AgreeMentPaySmsDto {
+
+    // 商户订单号
+    private String orderNo;
+    // 订单金额;金额保留两位小数
+    private BigDecimal orderAmount;
+    //创建时间
+//    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private String createdTime;
+    // 姓名
+    private String name;
+    //证件类型
+    private String idType;
+    //证件号码
+    private String idCardNum;
+    // 银行卡号
+    private String bankNo;
+    // 手机号
+    private String phone;
+}
diff --git a/src/main/java/cc/mrbird/febs/pay/model/AgreementPayDto.java b/src/main/java/cc/mrbird/febs/pay/model/AgreementPayDto.java
new file mode 100644
index 0000000..51308b4
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/model/AgreementPayDto.java
@@ -0,0 +1,26 @@
+package cc.mrbird.febs.pay.model;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@ApiModel(value = "AgreementPayDto", description = "汇聚支付快捷支付-协议支付接收参数类")
+public class AgreementPayDto {
+
+    // 商户订单号
+    private String orderNo;
+    // 订单金额;金额保留两位小数
+    private BigDecimal orderAmount;
+    //订单时间 格式 yyyy-MM-dd HH:mm:ss
+//    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private String orderTime;
+    // 商品名称
+    private String orderDesc;
+    // 银行卡号
+    private String bankNo;
+
+}
diff --git a/src/main/java/cc/mrbird/febs/pay/model/AgreementSignDto.java b/src/main/java/cc/mrbird/febs/pay/model/AgreementSignDto.java
new file mode 100644
index 0000000..cbcb103
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/model/AgreementSignDto.java
@@ -0,0 +1,15 @@
+package cc.mrbird.febs.pay.model;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+@Data
+@ApiModel(value = "AgreementSignDto", description = "汇聚支付快捷支付-协议支付签约接收参数类")
+public class AgreementSignDto {
+
+    // 商户订单号
+    private String orderNo;
+    // 签约短信验证码
+    private String smsCode;
+
+}
diff --git a/src/main/java/cc/mrbird/febs/pay/model/Algorithm.java b/src/main/java/cc/mrbird/febs/pay/model/Algorithm.java
new file mode 100644
index 0000000..7323f6f
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/model/Algorithm.java
@@ -0,0 +1,14 @@
+package cc.mrbird.febs.pay.model;
+
+/**
+ * 加解密运算时的逻辑算法名常量类
+ * @author: chenyf
+ * @Date: 2018-12-15
+ */
+public class Algorithm {
+    public final static String MD5 = "MD5";
+    public final static String AES = "AES";
+    public final static String RSA = "RSA";
+
+
+}
diff --git a/src/main/java/cc/mrbird/febs/pay/model/CommonConst.java b/src/main/java/cc/mrbird/febs/pay/model/CommonConst.java
new file mode 100644
index 0000000..364a196
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/model/CommonConst.java
@@ -0,0 +1,12 @@
+package cc.mrbird.febs.pay.model;
+
+/**
+ * 公共常量类
+ * @author: chenyf
+ * @Date: 2018-12-15
+ */
+public class CommonConst {
+    public static final String ENCODING_UTF_8 = "UTF-8";
+
+    public static final String AES_KEY_SEPARATOR = ":";
+}
diff --git a/src/main/java/cc/mrbird/febs/pay/model/Request.java b/src/main/java/cc/mrbird/febs/pay/model/Request.java
new file mode 100644
index 0000000..c9ecb27
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/model/Request.java
@@ -0,0 +1,91 @@
+package cc.mrbird.febs.pay.model;
+
+import com.alibaba.fastjson.annotation.JSONField;
+
+/**
+ * 商户请求的VO
+ */
+public class Request {
+    private String method;
+    private String version;
+    @JSONField(jsonDirect = true)
+    private String data;
+    private String rand_str;
+    private String sign_type;
+    private String mch_id;
+    private String sign;
+    private String aes_key;
+
+    public String getMethod() {
+        return method;
+    }
+
+    public void setMethod(String method) {
+        this.method = method;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String getData() {
+        return data;
+    }
+
+    public void setData(String data) {
+        this.data = data;
+    }
+
+    public String getRand_str() {
+        return rand_str;
+    }
+
+    public void setRand_str(String rand_str) {
+        this.rand_str = rand_str;
+    }
+
+    public String getSign_type() {
+        return sign_type;
+    }
+
+    public void setSign_type(String sign_type) {
+        this.sign_type = sign_type;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getAes_key() {
+        return aes_key;
+    }
+
+    public void setAes_key(String aes_key) {
+        this.aes_key = aes_key;
+    }
+
+    /**
+     * 拼接aes_key
+     * @param aes_key
+     * @param iv
+     */
+    public void joinAesKey(String aes_key, String iv){
+        this.aes_key = aes_key + CommonConst.AES_KEY_SEPARATOR + iv;
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/pay/model/RequestParam.java b/src/main/java/cc/mrbird/febs/pay/model/RequestParam.java
new file mode 100644
index 0000000..ca43bbb
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/model/RequestParam.java
@@ -0,0 +1,22 @@
+package cc.mrbird.febs.pay.model;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+/**
+ * 用户的请求参数
+ */
+@Data
+@ApiModel(value = "RequestParam", description = "接收参数类")
+public class RequestParam {
+    private String method;
+    private String version;
+ //  @JSONField(jsonDirect=true)
+    private String data;
+    private String rand_str;
+    private String sign_type;
+    private String mch_no;
+    private String sign;
+    private String sec_key;
+}
diff --git a/src/main/java/cc/mrbird/febs/pay/model/Response.java b/src/main/java/cc/mrbird/febs/pay/model/Response.java
new file mode 100644
index 0000000..e08fbc6
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/model/Response.java
@@ -0,0 +1,86 @@
+package cc.mrbird.febs.pay.model;
+
+import com.alibaba.fastjson.annotation.JSONField;
+
+/**
+ * 响应给商户的VO
+ */
+public class Response {
+    private String biz_code;
+    private String biz_msg;
+    @JSONField(jsonDirect = true)
+    private String data;
+    private String mch_no;
+    private String rand_str;
+    private String sign;
+    private String sign_type;
+    private String sec_key;
+
+    public String[] splitAesKey(){
+        return sec_key.split(CommonConst.AES_KEY_SEPARATOR);
+    }
+
+    public String getBiz_code() {
+        return biz_code;
+    }
+
+    public void setBiz_code(String biz_code) {
+        this.biz_code = biz_code;
+    }
+
+    public String getBiz_msg() {
+        return biz_msg;
+    }
+
+    public void setBiz_msg(String biz_msg) {
+        this.biz_msg = biz_msg;
+    }
+
+    public String getData() {
+        return data;
+    }
+
+    public void setData(String data) {
+        this.data = data;
+    }
+
+    public String getMch_no() {
+        return mch_no;
+    }
+
+    public void setMch_no(String mch_no) {
+        this.mch_no = mch_no;
+    }
+
+    public String getRand_str() {
+        return rand_str;
+    }
+
+    public void setRand_str(String rand_str) {
+        this.rand_str = rand_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getSign_type() {
+        return sign_type;
+    }
+
+    public void setSign_type(String sign_type) {
+        this.sign_type = sign_type;
+    }
+
+    public String getSec_key() {
+        return sec_key;
+    }
+
+    public void setSec_key(String sec_key) {
+        this.sec_key = sec_key;
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/pay/model/SignTypeEnum.java b/src/main/java/cc/mrbird/febs/pay/model/SignTypeEnum.java
new file mode 100644
index 0000000..916e2b9
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/model/SignTypeEnum.java
@@ -0,0 +1,22 @@
+package cc.mrbird.febs.pay.model;
+
+public enum SignTypeEnum {
+    MD5("1"),
+    RSA("2"),
+    RSA2("3");
+
+    /** 枚举值 */
+    private String value;
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    private SignTypeEnum(String value) {
+        this.value = value;
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/pay/service/UnipayService.java b/src/main/java/cc/mrbird/febs/pay/service/UnipayService.java
index 0069323..549ced2 100644
--- a/src/main/java/cc/mrbird/febs/pay/service/UnipayService.java
+++ b/src/main/java/cc/mrbird/febs/pay/service/UnipayService.java
@@ -1,10 +1,33 @@
 package cc.mrbird.febs.pay.service;
 
+import cc.mrbird.febs.pay.model.AgreeMentPaySmsDto;
+import cc.mrbird.febs.pay.model.AgreementPayDto;
+import cc.mrbird.febs.pay.model.AgreementSignDto;
 import cc.mrbird.febs.pay.model.UnipayDto;
-import com.sun.org.apache.xpath.internal.operations.Bool;
 
 public interface UnipayService {
 
     String unipay(UnipayDto unipayDto);
 
+    /**
+     * 快捷协议支付-签约短信接口
+     * @param agreeMentPaySmsDto
+     * @return
+     */
+    String getAgreeMentPaySms(AgreeMentPaySmsDto agreeMentPaySmsDto);
+
+    /**
+     *快捷协议支付-签约接口
+     * @param agreementSignDto
+     * @return
+     */
+    String agreementSign(AgreementSignDto agreementSignDto);
+
+    /**
+     * 快捷协议支付-无短支付接口
+     * @param agreementPayDto
+     * @return
+     */
+    String agreementPay(AgreementPayDto agreementPayDto);
+
 }
diff --git a/src/main/java/cc/mrbird/febs/pay/service/impl/UnipayServiceImpl.java b/src/main/java/cc/mrbird/febs/pay/service/impl/UnipayServiceImpl.java
index 0aad1b6..65e9a09 100644
--- a/src/main/java/cc/mrbird/febs/pay/service/impl/UnipayServiceImpl.java
+++ b/src/main/java/cc/mrbird/febs/pay/service/impl/UnipayServiceImpl.java
@@ -1,10 +1,10 @@
 package cc.mrbird.febs.pay.service.impl;
 
-import cc.mrbird.febs.common.entity.FebsResponse;
-import cc.mrbird.febs.pay.model.UnipayDto;
+import cc.mrbird.febs.pay.model.*;
 import cc.mrbird.febs.pay.service.UnipayService;
-import cc.mrbird.febs.pay.util.HttpRequester;
-import cc.mrbird.febs.pay.util.HttpRespons;
+import cc.mrbird.febs.pay.util.*;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import lombok.extern.slf4j.Slf4j;
@@ -13,13 +13,37 @@
 import org.springframework.transaction.annotation.Transactional;
 
 import java.io.IOException;
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.text.DecimalFormat;
 import java.util.*;
 
 @Slf4j
 @Service
 public class UnipayServiceImpl implements UnipayService {
 
+    //汇聚支付平台公钥
+    public static final String platformPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwSAEXsiC0IYh" +
+            "a6a94imKq8VfOkk7WjDRAQWMBRnoKOZeEUeMrHYiblcrqeMYXGpV13288iUOkuyKwkPXkYXyIQK8emvJIbQOhtB5bS" +
+            "lAbodsPgncM9Ney1GFiz+7ogBxyt58mP8AA9UHtMw7u78zZoQ1+dUWwUUowVXml3Q0cVQIDAQAB";
+    //本地生成的公钥
+    public static final String paySecretKey =
+            "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJSsoLHAy4P+H76l4i6IMZ/JKKTVphvrJBSB777N8h" +
+                    "gzN38M+66IqazRQLNjjyn2UZxm4eSfuJ4OBxCTGLJgDOw8B9l9lVo+0bzhNxsy5ae20EOlQa3h8xfCjCCU" +
+                    "Xb8VP8yknG43Wk1WtwLX5VYWmJFTwA1I0dWQR4RlbHH2q2aVAgMBAAECgYBZNyoK4JV/tFwaTHLo12Nn7g" +
+                    "9MssRGFpmFEN/sEKuJKBrSS9kvx+SBxuPbgg/j72LTxs0hI1NmzSYiJRL53zeBFM0wM2/D2zW0pZfogUPN" +
+                    "7Mb3FkFOoE0CxFwn7pjjBkvAsZQJS2fZFY6cf/WYhVI+XCMzjiQWJSQUXKEfWzUflQJBAMpLzinyAsBHKe" +
+                    "6lmAkSh/yaQX76cnxNZGmfc/gj62qM5YDzpt3+Za5Y4NSq5kYu36NAgorf2ipJPRwpgS13fK8CQQC8JKVP" +
+                    "2YgZ39fa+xVJu3yTT48k9EnYIEfsv/Bc7AVdpaZKDeEBuGpBb0JQzuIg3Zd6yNQCzH3oBqp8l6l/fgn7Ak" +
+                    "EAtFluvHB4yWjoVk0lRPlTaP0w5P5ssKrimVPBtPh4+a4RMayHGKSjjBLKpm6SCwHg+Q8bEqpNOqO+qmvK" +
+                    "MXm0GwJAZd4Bk8ZYJopIOUyRLibRQIFnI78Q7HAuAUW7QtSX4yh5bMcu+Nt8zIkNAuvBC8Ju7hAmmo1V7n" +
+                    "cNgAAtydXYWQJALLOFCjCkRgeRVL8YE8bVi4U16b8ltAN1DlbWEzui6VFy2vIga3IryesNVAOOdornyAwf" +
+                    "1huqB2lYfuQwtrIBKg==";
     public static final String notifyUrl = "http://47.111.90.145:8800/api/unipay/unipayCallBack";
+    public static final String agreementPayNotifyUrl = "http://47.111.90.145:8800/api/unipay/agreementPayCallBack";
+    public static final String p1MerchantNo = "888118000001971";/** 商户编号 */
+    public static final String aesKey = "1234567891234567";/** 商户编号 */
 
     @Override
     @Transactional
@@ -27,7 +51,7 @@
         String key = "2e95f6a3e11e47fa8a4386d6aefe1735";/** md5密钥商户后台-商户中心-商户设置-密钥管理获取 必填!*/
         Map<String, String> map = new HashMap<String, String>();
         map.put("p0_Version", "1.0");/** 版本号 */
-        map.put("p1_MerchantNo", "888118000001971");/** 商户编号 */
+        map.put("p1_MerchantNo", p1MerchantNo);/** 商户编号 */
         map.put("p2_OrderNo", unipayDto.getOrderNo()); /**商户订单号*/
         map.put("p3_Amount", unipayDto.getAmount().toString());/**订单金额*/
         map.put("p4_Cur", "1"); /**交易币种 */
@@ -131,4 +155,245 @@
 
     }
 
+
+
+    @Override
+    @Transactional
+    public String agreementPay(AgreementPayDto agreementPayDto) {
+
+        String secretKey =paySecretKey;
+        String key = aesKey;//敏感信息加密key
+
+        Map<String, Object> map = new HashMap<>();
+        RequestParam requestParam = new RequestParam();
+        requestParam.setMch_no(p1MerchantNo);// 商户编号
+        requestParam.setMethod("fastPay.agreement.pay");// 固定方法名
+        requestParam.setVersion("1.0");// 版本号
+        requestParam.setRand_str("12345678901234567890123456789012");// 随机字符串
+        requestParam.setSign_type("2");// 签名类型
+        try {
+            requestParam.setSec_key(RSAUtil.encryptByPublicKey(platformPublicKey,aesKey));//加密密钥
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        map.put("mch_order_no",agreementPayDto.getOrderNo()); // 商户订单号
+        map.put("order_amount", agreementPayDto.getOrderAmount()); // 订单金额;金额保留两位小数
+        map.put("mch_req_time", agreementPayDto.getOrderTime()); // 订单时间
+        map.put("order_desc", agreementPayDto.getOrderDesc()); // 订单时间
+        map.put("callback_url", agreementPayNotifyUrl); // 异步通知地址
+        map.put("bank_card_no",  AESUtil.Aes256Encode(agreementPayDto.getBankNo(),aesKey)); // 签约银行卡号
+
+        requestParam.setData(JsonUtil.toString(map));
+
+        String signStr = null;
+        try {
+            signStr = getSortedString(requestParam);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        System.out.println("待签名字符串:"+signStr);// 待签名字符串
+
+        // 签名
+        if (SignTypeEnum.RSA.getValue().equals(requestParam.getSign_type())) {
+            try {
+                signStr =(RSAUtil.sign(signStr, secretKey, false));
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        } else {
+            signStr = "";
+            System.out.println("未预期的签名类型:" + requestParam.getSign_type());
+        }
+        requestParam.setSign(signStr);
+
+        // Map转json字符串
+        String reqBodyJson = JSON.toJSONString(requestParam);
+        System.out.println(reqBodyJson);
+        String httpResponseJson = null;
+        try {
+            httpResponseJson = HttpClientUtil.sendHttpPost("https://api.joinpay.com/fastpay", reqBodyJson);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        System.out.println(httpResponseJson);
+
+        if(StrUtil.isNotBlank(httpResponseJson)){
+            return httpResponseJson;
+        }else{
+            return "fail";
+        }
+    }
+
+    public static void main(String[] args) {
+//        BigDecimal value = new BigDecimal("0.10858").setScale(2,BigDecimal.ROUND_HALF_UP);
+        BigDecimal value = new BigDecimal("1231.1").setScale(2, BigDecimal.ROUND_DOWN);
+        DecimalFormat decimalFormat = new DecimalFormat("0.00#");
+        String strVal = decimalFormat.format(value);
+        System.out.println(strVal);
+    }
+
+    @Override
+    public String getAgreeMentPaySms(AgreeMentPaySmsDto agreeMentPaySmsDto) {
+        String secretKey = paySecretKey;
+
+        Map<String, Object> map = new HashMap<>();
+        RequestParam requestParam = new RequestParam();
+        requestParam.setMch_no(p1MerchantNo);// 商户编号
+        requestParam.setMethod("fastPay.agreement.signSms");// 固定方法名
+        requestParam.setVersion("1.0");// 版本号
+        requestParam.setRand_str("12345678901234567890123456789012");// 随机字符串
+        requestParam.setSign_type("2");// 签名类型
+        try {
+            requestParam.setSec_key(RSAUtil.encryptByPublicKey(platformPublicKey,aesKey));//加密密钥
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        map.put("mch_order_no", "NO_"+agreeMentPaySmsDto.getOrderNo()); // 商户订单号
+        map.put("order_amount", agreeMentPaySmsDto.getOrderAmount()); // 订单金额
+        map.put("mch_req_time", agreeMentPaySmsDto.getCreatedTime()); // 下单时间
+        map.put("payer_name",AESUtil.Aes256Encode(agreeMentPaySmsDto.getName(),aesKey)); // 姓名
+        map.put("id_type", agreeMentPaySmsDto.getIdType()); // 证件类型
+        map.put("id_no", AESUtil.Aes256Encode(agreeMentPaySmsDto.getIdCardNum(),aesKey)); // 证件号码
+        map.put("bank_card_no", AESUtil.Aes256Encode(agreeMentPaySmsDto.getBankNo(),aesKey)); // 银行卡号
+        map.put("mobile_no", AESUtil.Aes256Encode(agreeMentPaySmsDto.getPhone(), aesKey)); // 手机号
+
+        requestParam.setData(JsonUtil.toString(map));
+
+        String signStr = null;
+        try {
+            signStr = getSortedString(requestParam);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        System.out.println("待签名字符串:"+signStr);// 待签名字符串
+
+        // 签名
+        if (SignTypeEnum.RSA.getValue().equals(requestParam.getSign_type())) {
+            try {
+                signStr =(RSAUtil.sign(signStr, secretKey, false));
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        } else {
+            signStr = "";
+            System.out.println("未预期的签名类型:" + requestParam.getSign_type());
+        }
+        requestParam.setSign(signStr);
+
+
+        // Map转json字符串
+        String reqBodyJson = JSON.toJSONString(requestParam);
+        System.out.println(reqBodyJson);
+        String httpResponseJson = null;
+        try {
+            httpResponseJson = HttpClientUtil.sendHttpPost("https://api.joinpay.com/fastpay", reqBodyJson);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        System.out.println(httpResponseJson);
+        if(StrUtil.isNotBlank(httpResponseJson)){
+            cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(httpResponseJson);
+            System.out.println(jsonObject);
+            String biz_code = jsonObject.get("biz_code").toString();
+            if("JS000000" == biz_code){
+                return httpResponseJson;
+            }
+            return "fail";
+        }else{
+            return "fail";
+        }
+    }
+
+    @Override
+    public String agreementSign(AgreementSignDto agreementSignDto) {
+        String secretKey = paySecretKey;
+
+        Map<String, Object> map = new HashMap<>();
+        RequestParam requestParam = new RequestParam();
+        requestParam.setMch_no(p1MerchantNo);// 商户编号
+        requestParam.setMethod("fastPay.agreement.smsSign");// 固定方法名
+        requestParam.setVersion("1.0");// 版本号
+        requestParam.setRand_str("12345678901234567890123456789012");// 随机字符串
+        requestParam.setSign_type("2");// 签名类型
+        try {
+            requestParam.setSec_key(RSAUtil.encryptByPublicKey(platformPublicKey,aesKey));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        map.put("mch_order_no", agreementSignDto.getOrderNo()); // 商户订单号
+        map.put("sms_code", agreementSignDto.getSmsCode()); // 签约短信验证码
+
+        requestParam.setData(JsonUtil.toString(map));
+
+        String signStr = null;
+        try {
+            signStr = getSortedString(requestParam);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        System.out.println(signStr);// 待签名字符串
+
+        // 签名
+        if (SignTypeEnum.RSA.getValue().equals(requestParam.getSign_type())) {
+            try {
+                signStr =(RSAUtil.sign(signStr, secretKey, false));
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        } else {
+            signStr = "";
+            System.out.println("未预期的签名类型:" + requestParam.getSign_type());
+        }
+        requestParam.setSign(signStr);
+
+
+        // Map转json字符串
+        String reqBodyJson = JSON.toJSONString(requestParam);
+        System.out.println(reqBodyJson);
+        String httpResponseJson = null;
+        try {
+            httpResponseJson = HttpClientUtil.sendHttpPost("https://api.joinpay.com/fastpay", reqBodyJson);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        System.out.println(httpResponseJson);
+
+        if(StrUtil.isNotBlank(httpResponseJson)){
+            return httpResponseJson;
+        }else{
+            return "fail";
+        }
+    }
+
+    protected static String getSortedString(Object obj) throws Exception {
+        Field[] fields = obj.getClass().getDeclaredFields();
+
+        Map<String, String> map = new HashMap<String, String>();
+        for (int i = 0; i < fields.length; i++) {
+            Field filed = fields[i];
+            String name = filed.getName();
+            if (SignUtil.NOT_SIGN_PARAM.contains(name)) {// 不参与签名或验签的参数直接跳过
+                continue;
+            }
+            filed.setAccessible(true);
+            map.put(name, String.valueOf(filed.get(obj)));
+        }
+        StringBuffer content = new StringBuffer();
+        List<String> keys = new ArrayList(map.keySet());
+        Collections.sort(keys); // 排序map
+        for (int i = 0; i < keys.size(); i++) {
+            String key = keys.get(i);
+            String value = map.get(key);
+
+            if (i != 0) {
+                content.append(SignUtil.SIGN_SEPARATOR);
+            }
+            content.append(key).append(SignUtil.SIGN_EQUAL).append(value);
+        }
+        return content.toString();
+    }
+
 }
diff --git a/src/main/java/cc/mrbird/febs/pay/util/AESUtil.java b/src/main/java/cc/mrbird/febs/pay/util/AESUtil.java
new file mode 100644
index 0000000..e1e69b8
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/util/AESUtil.java
@@ -0,0 +1,71 @@
+package cc.mrbird.febs.pay.util;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.Security;
+import java.util.Base64;
+
+/**
+ * AES加解密工具类
+ * @author chenyf
+ * @date 2018-12-15
+ */
+public class AESUtil {
+	//   private static final Logger logger = LoggerFactory.getLogger(AesUtils.class);
+	    public static final String ALGORITHM = "AES/ECB/PKCS5Padding";
+	    public static final String UTF_8 = "UTF-8";
+	    public static final String AES = "AES";
+	    public static final String BC = "BC";
+
+
+	    static {
+	        //仅加载一次,不要多次加载,可能会导致内存溢出
+	        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+	    }
+
+	    /**
+	     * 网联敏感字段AES加密
+	     *
+	     * @param str 敏感字段原文
+	     * @param key AES密钥 必须是8位、16位、24位
+	     * @return
+	     */
+	    public static String Aes256Encode(String str, String key) {
+	      //  if(StringUtil.isNotBlank(str)) {
+	            try {
+	                Cipher cipher = Cipher.getInstance(ALGORITHM, BC);
+	                SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(UTF_8), AES); // 生成加密解密需要的Key
+	                cipher.init(Cipher.ENCRYPT_MODE, keySpec);
+	                byte[] result = cipher.doFinal(str.getBytes(UTF_8));
+	                return Base64.getEncoder().encodeToString(result);
+	            } catch (Exception e) {
+	               // logger.error("Aes256Encode error:", e);
+	                return null;
+	            }
+
+	    }
+
+	    /**
+	     * 网联敏感字段密文解密
+	     *
+	     * @param base64Str 要被解密的密文.做了base64编码 base64Str
+	     * @param key       AES密钥 必须是8位、16位、24位
+	     * @return 解密后的字符串
+	     */
+	    public static String Aes256Decode(String base64Str, String key) {
+	       // if (StringUtil.isNotBlank(base64Str)) {
+	            String result = null;
+	            try {
+	                Cipher cipher = Cipher.getInstance(ALGORITHM, BC);
+	                SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(UTF_8), AES); // 生成加密解密需要的Key
+	                cipher.init(Cipher.DECRYPT_MODE, keySpec);
+	                byte[] decoded = cipher.doFinal(Base64Util.decode(base64Str));
+	                result = new String(decoded, "UTF-8");
+	            } catch (Exception e) {
+	                e.printStackTrace();
+	            }
+	            return result;
+	    }
+
+
+	}
diff --git a/src/main/java/cc/mrbird/febs/pay/util/Base64Util.java b/src/main/java/cc/mrbird/febs/pay/util/Base64Util.java
new file mode 100644
index 0000000..a2cab85
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/util/Base64Util.java
@@ -0,0 +1,118 @@
+package cc.mrbird.febs.pay.util;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * base64 format encoding & decoding
+ */
+public class Base64Util {
+	private static char[] base64EncodeChars = new char[] { 'A', 'B', 'C', 'D',
+			'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
+			'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
+			'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
+			'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3',
+			'4', '5', '6', '7', '8', '9', '+', '/' };
+
+	private static byte[] base64DecodeChars = new byte[] { -1, -1, -1, -1, -1,
+			-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+			-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+			-1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59,
+			60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+			10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1,
+			-1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+			38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1,
+			-1, -1 };
+
+	private Base64Util(){
+	}
+
+	public static String encode(byte[] data){
+		StringBuffer sb = new StringBuffer();
+		int len = data.length;
+		int i = 0;
+		int b1, b2, b3;
+
+		while (i < len) {
+			b1 = data[i++] & 0xff;
+			if (i == len) {
+				sb.append(base64EncodeChars[b1 >>> 2]);
+				sb.append(base64EncodeChars[(b1 & 0x3) << 4]);
+				sb.append("==");
+				break;
+			}
+			b2 = data[i++] & 0xff;
+			if (i == len) {
+				sb.append(base64EncodeChars[b1 >>> 2]);
+				sb.append(base64EncodeChars[((b1 & 0x03) << 4)
+						| ((b2 & 0xf0) >>> 4)]);
+				sb.append(base64EncodeChars[(b2 & 0x0f) << 2]);
+				sb.append("=");
+				break;
+			}
+			b3 = data[i++] & 0xff;
+			sb.append(base64EncodeChars[b1 >>> 2]);
+			sb.append(base64EncodeChars[((b1 & 0x03) << 4)
+					| ((b2 & 0xf0) >>> 4)]);
+			sb.append(base64EncodeChars[((b2 & 0x0f) << 2)
+					| ((b3 & 0xc0) >>> 6)]);
+			sb.append(base64EncodeChars[b3 & 0x3f]);
+		}
+		return sb.toString();
+	}
+
+	public static byte[] decode(String str){
+		byte[] data = str.getBytes();
+		int len = data.length;
+		ByteArrayOutputStream buf = new ByteArrayOutputStream(len);
+		int i = 0;
+		int b1, b2, b3, b4;
+
+		while (i < len) {
+
+			/* b1 */
+			do {
+				b1 = base64DecodeChars[data[i++]];
+			} while (i < len && b1 == -1);
+			if (b1 == -1) {
+				break;
+			}
+
+			/* b2 */
+			do {
+				b2 = base64DecodeChars[data[i++]];
+			} while (i < len && b2 == -1);
+			if (b2 == -1) {
+				break;
+			}
+			buf.write(((b1 << 2) | ((b2 & 0x30) >>> 4)));
+
+			/* b3 */
+			do {
+				b3 = data[i++];
+				if (b3 == 61) {
+					return buf.toByteArray();
+				}
+				b3 = base64DecodeChars[b3];
+			} while (i < len && b3 == -1);
+			if (b3 == -1) {
+				break;
+			}
+			buf.write((((b2 & 0x0f) << 4) | ((b3 & 0x3c) >>> 2)));
+
+			/* b4 */
+			do {
+				b4 = data[i++];
+				if (b4 == 61) {
+					return buf.toByteArray();
+				}
+				b4 = base64DecodeChars[b4];
+			} while (i < len && b4 == -1);
+			if (b4 == -1) {
+				break;
+			}
+			buf.write((((b3 & 0x03) << 6) | b4));
+		}
+		return buf.toByteArray();
+	}
+
+}
diff --git a/src/main/java/cc/mrbird/febs/pay/util/CodeUtil.java b/src/main/java/cc/mrbird/febs/pay/util/CodeUtil.java
new file mode 100644
index 0000000..638cb3f
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/util/CodeUtil.java
@@ -0,0 +1,17 @@
+package cc.mrbird.febs.pay.util;
+
+/**
+ * 编解码工具类
+ * @author chenyf
+ * @date 2018-12-15
+ */
+public class CodeUtil {
+
+    public static String base64Encode(byte[] value) {
+        return Base64Util.encode(value);
+    }
+
+    public static byte[] base64Decode(String value) {
+        return Base64Util.decode(value);
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/pay/util/HEXUtil.java b/src/main/java/cc/mrbird/febs/pay/util/HEXUtil.java
new file mode 100644
index 0000000..73028b4
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/util/HEXUtil.java
@@ -0,0 +1,85 @@
+package cc.mrbird.febs.pay.util;
+
+import cc.mrbird.febs.common.exception.JPException;
+import cc.mrbird.febs.pay.model.CommonConst;
+
+/**
+ * 16进制工具类
+ * @author chenyf
+ * @date 2018-12-15
+ */
+public class HEXUtil {
+    private static final char[] DIGITS_LOWER =
+            {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+    private static final char[] DIGITS_UPPER =
+            {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+
+    public static String encode(String str){
+        try{
+            return encode(str.getBytes(CommonConst.ENCODING_UTF_8), true);
+        }catch (Exception e){
+            throw new JPException("16进制转换失败", e);
+        }
+    }
+
+    public static String encode(byte[] data, final boolean toUpperCase){
+        return bytes2Hex(data, toUpperCase ? DIGITS_UPPER : DIGITS_LOWER);
+    }
+
+    public static String decode(String str){
+        try{
+            byte[] date = hex2Bytes(str);
+            return new String(date, CommonConst.ENCODING_UTF_8);
+        }catch (Exception e){
+            throw new JPException("16进制转换失败", e);
+        }
+    }
+
+    private static String bytes2Hex(final byte[] data, final char[] toDigits) {
+        final int l = data.length;
+        final char[] out = new char[l << 1];
+        // two characters form the hex value.
+        for (int i = 0, j = 0; i < l; i++) {
+            out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
+            out[j++] = toDigits[0x0F & data[i]];
+        }
+        return new String(out);
+    }
+
+    private static byte[] hex2Bytes(final String data) throws Exception {
+        final int len = data.length();
+
+        if ((len & 0x01) != 0) {
+            throw new Exception("Odd number of characters.");
+        }
+
+        final byte[] out = new byte[len >> 1];
+
+        // two characters form the hex value.
+        for (int i = 0, j = 0; j < len; i++) {
+            int f = toDigit(data.charAt(j), j) << 4;
+            j++;
+            f = f | toDigit(data.charAt(j), j);
+            j++;
+            out[i] = (byte) (f & 0xFF);
+        }
+        return out;
+    }
+
+    /**
+     * 16转化为数字
+     * @param ch 16进制
+     * @param index 索引
+     * @return 转化结果
+     * @throws Exception 转化失败异常
+     */
+    private static int toDigit(final char ch, final int index) throws Exception {
+        final int digit = Character.digit(ch, 16);
+        if (digit == -1) {
+            throw new Exception("Illegal hexadecimal character " + ch + " at index " + index);
+        }
+        return digit;
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/pay/util/HttpClientUtil.java b/src/main/java/cc/mrbird/febs/pay/util/HttpClientUtil.java
new file mode 100644
index 0000000..2dcb734
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/util/HttpClientUtil.java
@@ -0,0 +1,39 @@
+package cc.mrbird.febs.pay.util;
+
+/**
+ * 类HttpClientUtil
+ * 
+ * @author Lori 2018年6月04日 下午16:10:04
+ */
+
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;  
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+
+public class HttpClientUtil {
+	public static String sendHttpPost(String url, String body) throws Exception {
+		CloseableHttpClient httpClient = HttpClients.createDefault();
+		HttpPost httpPost = new HttpPost(url);
+		httpPost.addHeader("Content-Type","application/json;charset=UTF-8");
+		//UrlEncodedFormEntity setEntity = new UrlEncodedFormEntity(body, HTTP.UTF_8);
+		StringEntity setEntity = new StringEntity(body,"utf-8");
+		setEntity.setContentType("application/json");
+		setEntity.setContentEncoding("UTF-8");
+		httpPost.setEntity(setEntity);
+		
+
+		CloseableHttpResponse response = httpClient.execute(httpPost);
+		//System.out.println(response.getStatusLine().getStatusCode() + "\n");
+		HttpEntity entity = response.getEntity();
+		String responseContent = EntityUtils.toString(entity, "UTF-8"); 
+		//System.out.println(responseContent);
+
+		response.close();
+		httpClient.close();
+		return responseContent;
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/pay/util/JsonUtil.java b/src/main/java/cc/mrbird/febs/pay/util/JsonUtil.java
new file mode 100644
index 0000000..406f1ab
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/util/JsonUtil.java
@@ -0,0 +1,71 @@
+package cc.mrbird.febs.pay.util;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.PropertyNamingStrategy;
+import com.alibaba.fastjson.serializer.SerializeConfig;
+
+import java.lang.reflect.Type;
+import java.util.List;
+
+/**
+ * JSON转换工具类
+ * @author chenyf
+ * @date 2018-12-15
+ */
+public class JsonUtil {
+
+    /**
+     * 将一个对像转成一个json字符串
+     */
+    public static final String toString(Object obj) {
+        return JSON.toJSONString(obj);
+    }
+
+    /**
+     * 把json字符串转换成指定Class的对象
+     * @param text
+     * @param clazz
+     * @param <T>
+     * @return
+     */
+    public static <T> T toBean(String text, Class<T> clazz) {
+        return JSON.parseObject(text, clazz);
+    }
+
+    /**
+     * 把json字节转换成指定Class的对象
+     * @param text
+     * @param clazz
+     * @param <T>
+     * @return
+     */
+    public static <T> T toBean(byte[] text, Class<T> clazz) {
+        return JSON.parseObject(text, clazz);
+    }
+
+    /**
+     * 把json字符串转换成指定类型的对象
+     * @param text
+     * @param type
+     * @param <T>
+     * @return
+     */
+    public static <T> T toBean(String text, Type type) {
+        return JSON.parseObject(text, type);
+    }
+
+    /**
+     * 把json字符串转换为指定Class的List
+     * @param obj
+     * @param clazz
+     * @param <T>
+     * @return
+     */
+    public static final <T> List<T> toList(Object obj, Class<T> clazz) {
+        if (obj == null) {
+            return null;
+        }
+        return JSONArray.parseArray(obj.toString(), clazz);
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/pay/util/MD5Util.java b/src/main/java/cc/mrbird/febs/pay/util/MD5Util.java
new file mode 100644
index 0000000..290a33e
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/util/MD5Util.java
@@ -0,0 +1,44 @@
+package cc.mrbird.febs.pay.util;
+
+import cc.mrbird.febs.common.exception.JPException;
+import cc.mrbird.febs.pay.model.Algorithm;
+import cc.mrbird.febs.pay.model.CommonConst;
+import cn.hutool.core.util.StrUtil;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * MD5工具类
+ * @author chenyf
+ * @date 2018-12-15
+ */
+public class MD5Util {
+
+    /**
+     * 生成16进制的MD5字符串
+     * @param str
+     * @return
+     */
+    public static String getMD5Hex(String str) {
+        return HEXUtil.encode(getMD5(str), true);
+    }
+
+    public static byte[] getMD5(String str) {
+        MessageDigest messageDigest;
+        try {
+            messageDigest = MessageDigest.getInstance(Algorithm.MD5);
+            messageDigest.reset();
+            if (StrUtil.isNotEmpty(str)) {
+                messageDigest.update(str.getBytes(CommonConst.ENCODING_UTF_8));
+            }
+        } catch (NoSuchAlgorithmException e) {
+            throw new JPException("生成MD5信息时异常", e);
+        } catch (UnsupportedEncodingException e) {
+            throw new JPException("生成MD5信息时异常", e);
+        }
+
+        return messageDigest.digest();
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/pay/util/RSAUtil.java b/src/main/java/cc/mrbird/febs/pay/util/RSAUtil.java
new file mode 100644
index 0000000..bf96fac
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/util/RSAUtil.java
@@ -0,0 +1,211 @@
+package cc.mrbird.febs.pay.util;
+
+
+
+import org.apache.commons.codec.binary.Base64;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+import javax.crypto.Cipher;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.*;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * RSA加解密的工具类
+ */
+public class RSAUtil {
+//    private static final Logger logger = LoggerFactory.getLogger(RSAUtil.class);
+    public static final String SIGNATURE_ALGORITHM_SHA1 = "SHA1withRSA";
+    public static final String SIGNATURE_ALGORITHM_MD5 = "MD5withRSA";
+    public static final String RSA = "RSA";
+
+    public static final String ANDROID_ENCRYPT_ALGORITHM = "RSA/ECB/NoPadding";
+    public static final String DEFAULT_ENCRYPT_ALGORITHM = "RSA/ECB/PKCS1Padding";
+
+    public static final String PUBLIC_KEY = "publicKey";
+    public static final String PRIVATE_KEY = "privateKey";
+
+    /** */
+    /**
+     * RSA最大加密明文大小
+     */
+    private static final int MAX_ENCRYPT_BLOCK = 116;
+
+    /** */
+    /**
+     * RSA最大解密密文大小
+     */
+    private static final int MAX_DECRYPT_BLOCK = 128;
+
+    /**
+     * 初始化BC提供者,RSA算法必须要先初始化BC才能进行加密解密和签名验签
+     */
+    private static void initProvider() {
+        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+            Security.addProvider(new BouncyCastleProvider());
+        }
+    }
+
+    /**
+     * 生成RSA签名串
+     *
+     * @param data       需要生成签名串的数据
+     * @param privateKey 私钥
+     * @return
+     * @throws BizException
+     */
+    public static String sign(String data, String privateKey, boolean isSha) throws Exception {
+        try {
+            initProvider();
+            byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
+            byte[] keyBytes = CodeUtil.base64Decode(privateKey);
+            String algorithm = isSha ? SIGNATURE_ALGORITHM_SHA1 : SIGNATURE_ALGORITHM_MD5;
+
+            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
+            PrivateKey priKey = KeyFactory.getInstance(RSA).generatePrivate(pkcs8KeySpec);
+            Signature signature = Signature.getInstance(algorithm);
+            signature.initSign(priKey);
+            signature.update(dataBytes);
+            return CodeUtil.base64Encode(signature.sign());
+        }catch (Throwable e){
+//            logger.error("==>sign err:", e);
+            throw new Exception("生成RSA签名失败", e);
+        }
+    }
+
+    /**
+     * 验证RSA签名串
+     *
+     * @param data      需要验签的数据
+     * @param publicKey 公钥
+     * @param sign      用户传过来的签名串
+     * @return
+     * @throws BizException
+     */
+    public static boolean verify(String data, String publicKey, String sign, boolean isSha) throws Exception {
+        try {
+            initProvider();
+            byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
+            byte[] signBytes = CodeUtil.base64Decode(sign);
+            String algorithm = isSha ? SIGNATURE_ALGORITHM_SHA1 : SIGNATURE_ALGORITHM_MD5;
+            PublicKey publicK = getPublicKey(publicKey);
+
+            Signature signature = Signature.getInstance(algorithm);
+            signature.initVerify(publicK);
+            signature.update(dataBytes);
+            return signature.verify(signBytes);
+        } catch (Throwable e) {
+//            logger.error("==>verify err:", e);
+            throw new Exception("RSA验签失败", e);
+        }
+    }
+
+    /**
+     * 对称密钥公钥加密
+     *
+     * @param publicKeyStr 公钥Str
+     * @param content      密钥原文
+     * @return 加密密文
+     */
+    public static String encryptByPublicKey(String publicKeyStr, String content) throws Exception {
+       
+            byte[] dataBytes = content.getBytes(StandardCharsets.UTF_8);
+            dataBytes = doCipher(dataBytes, publicKeyStr, true, false);
+            return CodeUtil.base64Encode(dataBytes);
+       
+    }
+
+    /**
+     * 对称密钥密文解密
+     *
+     * @param privateKeyStr 私钥字符串
+     * @param content       对称密钥密文
+     * @return 对称密钥明文
+     * @throws Exception
+     */
+    public static String decryptByPrivateKey(String privateKeyStr, String content) throws Exception{
+            byte[] dataBytes = CodeUtil.base64Decode(content);
+            dataBytes = doCipher(dataBytes, privateKeyStr, false, false);
+            return new String(dataBytes, StandardCharsets.UTF_8);
+       
+    }
+
+    private static byte[] doCipher(byte[] dataBytes, String keyStr, boolean isEncrypt, boolean isAndroid) throws Exception {
+
+        initProvider();
+
+        Key key;
+        Cipher cipher;
+        int maxBlock;
+
+        if (isEncrypt) {
+            maxBlock = MAX_ENCRYPT_BLOCK;
+            key = getPublicKey(keyStr);
+            if (isAndroid) {
+                cipher = Cipher.getInstance(ANDROID_ENCRYPT_ALGORITHM);// 如果是安卓机
+            } else {
+                cipher = Cipher.getInstance(DEFAULT_ENCRYPT_ALGORITHM);
+            }
+            cipher.init(Cipher.ENCRYPT_MODE, key);
+        } else {
+            maxBlock = MAX_DECRYPT_BLOCK;
+            byte[] keyBytes = Base64.decodeBase64(keyStr);
+            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
+            KeyFactory keyFactory = KeyFactory.getInstance(RSA);
+            Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
+            cipher = Cipher.getInstance(keyFactory.getAlgorithm());
+            cipher.init(Cipher.DECRYPT_MODE, privateK);
+        }
+
+        int offSet = 0, i = 0, inputLen = dataBytes.length;
+        byte[] cache;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        try {
+            // 对数据分段加密/解密
+            while (inputLen - offSet > 0) {
+                if (inputLen - offSet > maxBlock) {
+                    cache = cipher.doFinal(dataBytes, offSet, maxBlock);
+                } else {
+                    cache = cipher.doFinal(dataBytes, offSet, inputLen - offSet);
+                }
+                out.write(cache, 0, cache.length);
+                i++;
+                offSet = i * maxBlock;
+            }
+            return out.toByteArray();
+        } finally {
+            out.close();
+        }
+    }
+
+    /**
+     * 生成公私密钥对
+     * @return
+     */
+    public static Map<String, String> genKeyPair() throws Exception {
+        try {
+            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA);
+            keyPairGen.initialize(1024);
+            KeyPair keyPair = keyPairGen.generateKeyPair();
+
+            Map<String, String> keyMap = new HashMap<>(2);
+            keyMap.put(PUBLIC_KEY, CodeUtil.base64Encode(keyPair.getPublic().getEncoded()));
+            keyMap.put(PRIVATE_KEY, CodeUtil.base64Encode(keyPair.getPrivate().getEncoded()));
+            return keyMap;
+        }catch (Throwable e){
+            throw new Exception("生成RSA密钥对出现异常", e);
+        }
+    }
+
+    private static PublicKey getPublicKey(String publicKey) throws Exception {
+        byte[] keyBytes = CodeUtil.base64Decode(publicKey);
+        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
+        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
+        return keyFactory.generatePublic(x509KeySpec);
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/pay/util/RandomUtil.java b/src/main/java/cc/mrbird/febs/pay/util/RandomUtil.java
new file mode 100644
index 0000000..3450ad2
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/util/RandomUtil.java
@@ -0,0 +1,29 @@
+package cc.mrbird.febs.pay.util;
+
+import java.util.Random;
+import java.util.UUID;
+
+/**
+ * 获取一些随机数的工具类
+ * @author chenyf
+ * @date 2018-12-15
+ */
+public class RandomUtil {
+
+    public static String get16LenStr(){
+        if(getInt(2) == 0){
+            return MD5Util.getMD5Hex(UUID.randomUUID().toString()).substring(16);
+        }else{
+            return MD5Util.getMD5Hex(UUID.randomUUID().toString()).substring(1, 17);
+        }
+    }
+
+    public static String get32LenStr(){
+        return MD5Util.getMD5Hex(UUID.randomUUID().toString());
+    }
+
+    public static int getInt(int max){
+        Random random = new Random();
+        return random.nextInt(max);
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/pay/util/SignUtil.java b/src/main/java/cc/mrbird/febs/pay/util/SignUtil.java
new file mode 100644
index 0000000..702d515
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/util/SignUtil.java
@@ -0,0 +1,109 @@
+package cc.mrbird.febs.pay.util;
+
+import cc.mrbird.febs.common.exception.JPException;
+import cc.mrbird.febs.pay.model.Request;
+import cc.mrbird.febs.pay.model.Response;
+import cc.mrbird.febs.pay.model.SignTypeEnum;
+import cn.hutool.core.util.ObjectUtil;
+import com.alipay.service.schema.util.StringUtil;
+
+import java.lang.reflect.Field;
+import java.util.*;
+
+/**
+ * 签名、验签的工具类
+ * @author chenyf
+ * @date 2018-12-15
+ */
+public class SignUtil {
+    public final static String SIGN_SEPARATOR = "&";//分隔符
+    public final static String SIGN_EQUAL = "=";//等于号
+    public final static String SIGN_KEY_PARAM_NAME = "key";
+    public final static List<String> NOT_SIGN_PARAM = Arrays.asList(new String[]{"sign","aesKey","aes_key","sec_key"});//不参与签名/验签的参数
+
+    /**
+     * 验证签名
+     * @param response
+     * @param key
+     * @return
+     */
+    public static boolean verify(Response response, String key) throws Exception {
+        String signStr = getSortedString(response);
+        if(SignTypeEnum.MD5.getValue().equals(response.getSign_type())){
+            signStr = HEXUtil.encode(genMD5Sign(signStr, key), true);
+            if(signStr.equals(response.getSign())){
+                return true;
+            }else{
+                return false;
+            }
+        }else if(SignTypeEnum.RSA.getValue().equals(response.getSign_type())){
+            return RSAUtil.verify(signStr, key, HEXUtil.decode(response.getSign()), true);
+        }else{
+            return false;
+        }
+    }
+
+    /**
+     * 生成签名
+     * @param request
+     * @param key
+     * @return
+     */
+    public static void sign(Request request, String key) throws Exception {
+        if(ObjectUtil.isEmpty(request)){
+            return;
+        }else if(StringUtil.isEmpty(request.getMch_id()) || StringUtil.isEmpty(request.getSign_type())){
+            request.setSign("");
+            return;
+        }
+
+        if(StringUtil.isEmpty(request.getRand_str())){
+            request.setRand_str(RandomUtil.get32LenStr());
+        }
+
+        String signStr = getSortedString(request);
+
+        if(SignTypeEnum.MD5.getValue().equals(request.getSign_type())){
+            signStr = HEXUtil.encode(genMD5Sign(signStr, key), true);
+        }else if(SignTypeEnum.RSA.getValue().equals(request.getSign_type())){
+            signStr = HEXUtil.encode(RSAUtil.sign(signStr, key, true));
+        }else{
+            //抛出签名失败的异常
+            throw new JPException("签名失败,未预期的签名类型:"+request.getSign_type());
+        }
+        request.setSign(signStr);
+    }
+
+    protected static String getSortedString(Object obj) throws Exception {
+        Field[] fields = obj.getClass().getDeclaredFields();
+
+        Map<String, String> map = new HashMap<String, String>();
+        for(int i=0; i<fields.length; i++){
+            Field filed = fields[i];
+            String name = filed.getName();
+            if(NOT_SIGN_PARAM.contains(name)){//不参与签名或验签的参数直接跳过
+                continue;
+            }
+            filed.setAccessible(true);
+            map.put(name, String.valueOf(filed.get(obj)));
+        }
+
+        StringBuffer content = new StringBuffer();
+        List<String> keys = new ArrayList(map.keySet());
+        Collections.sort(keys); // 排序map
+        for (int i = 0; i < keys.size(); i++) {
+            String key = keys.get(i);
+            String value = map.get(key);
+
+            if(i != 0){
+                content.append(SIGN_SEPARATOR);
+            }
+            content.append(key).append(SIGN_EQUAL).append(value);
+        }
+        return content.toString();
+    }
+
+    private static byte[] genMD5Sign(String signStr, String key){
+        return MD5Util.getMD5(signStr + SIGN_SEPARATOR + SIGN_KEY_PARAM_NAME + SIGN_EQUAL + key);
+    }
+}
diff --git a/src/test/java/cc/mrbird/febs/ProfitTest.java b/src/test/java/cc/mrbird/febs/ProfitTest.java
index 816d535..0656a84 100644
--- a/src/test/java/cc/mrbird/febs/ProfitTest.java
+++ b/src/test/java/cc/mrbird/febs/ProfitTest.java
@@ -7,14 +7,19 @@
 import cc.mrbird.febs.mall.service.IAgentService;
 import cc.mrbird.febs.mall.service.IMallAchieveService;
 import cc.mrbird.febs.mall.service.IMemberProfitService;
+import cc.mrbird.febs.pay.model.AgreeMentPaySmsDto;
+import cc.mrbird.febs.pay.model.AgreementPayDto;
+import cc.mrbird.febs.pay.model.AgreementSignDto;
 import cc.mrbird.febs.pay.model.UnipayDto;
 import cc.mrbird.febs.pay.service.UnipayService;
 import cc.mrbird.febs.rabbit.consumer.AgentConsumer;
+import cn.hutool.core.date.DateUtil;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 
 import java.math.BigDecimal;
+import java.text.DecimalFormat;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -130,4 +135,44 @@
         unipayDto.setProductName("洗护套装");
         unipayService.unipay(unipayDto);
     }
+    @Test
+    public void getAgreeMentPaySms(){
+        AgreeMentPaySmsDto agreeMentPaySmsDto = new AgreeMentPaySmsDto();
+        agreeMentPaySmsDto.setOrderNo("NO_2022082514435329133");
+
+        BigDecimal value = new BigDecimal("0.1").setScale(2, BigDecimal.ROUND_DOWN);
+        DecimalFormat decimalFormat = new DecimalFormat("0.00#");
+        String strVal = decimalFormat.format(value);
+        agreeMentPaySmsDto.setOrderAmount(new BigDecimal(strVal));
+        agreeMentPaySmsDto.setName("肖永");
+        agreeMentPaySmsDto.setCreatedTime(DateUtil.now());
+        agreeMentPaySmsDto.setIdType("1");
+        agreeMentPaySmsDto.setIdCardNum("430321199310113713");
+        agreeMentPaySmsDto.setBankNo("6222031901002389639");
+        agreeMentPaySmsDto.setPhone("15274802129");
+        unipayService.getAgreeMentPaySms(agreeMentPaySmsDto);
+    }
+
+    @Test
+    public void agreementSign(){
+        AgreementSignDto agreementSignDto = new AgreementSignDto();
+        agreementSignDto.setOrderNo("NO_2022082514435329133");
+        agreementSignDto.setSmsCode("464439");
+        unipayService.agreementSign(agreementSignDto);
+    }
+
+    @Test
+    public void agreementPay(){
+        AgreementPayDto agreementPayDto = new AgreementPayDto();
+        agreementPayDto.setOrderNo("2022082514435329133");
+
+        BigDecimal value = new BigDecimal("0.1").setScale(2, BigDecimal.ROUND_DOWN);
+        DecimalFormat decimalFormat = new DecimalFormat("0.00#");
+        String strVal = decimalFormat.format(value);
+        agreementPayDto.setOrderAmount(new BigDecimal(strVal));
+        agreementPayDto.setOrderTime(DateUtil.now());
+        agreementPayDto.setOrderDesc("测试");
+        agreementPayDto.setBankNo("6222031901002389639");
+        unipayService.agreementPay(agreementPayDto);
+    }
 }

--
Gitblit v1.9.1