重构代码
diff --git a/build.gradle b/build.gradle
index cde386c..9d339e7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -89,6 +89,8 @@
     implementation files('libs/ojdbc6.jar')
     implementation 'commons-dbcp:commons-dbcp:1.4'
 
+    implementation project(':common')
+
     annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
     annotationProcessor 'org.projectlombok:lombok:1.18.8'
     compileOnly 'org.projectlombok:lombok:1.18.8'
diff --git a/common/build.gradle b/common/build.gradle
new file mode 100644
index 0000000..c5ae67d
--- /dev/null
+++ b/common/build.gradle
@@ -0,0 +1,14 @@
+plugins {
+    id 'java'
+}
+
+dependencies {
+    implementation 'org.slf4j:slf4j-parent:1.7.26'
+    implementation 'org.slf4j:slf4j-api:1.7.26'
+    implementation 'javax.validation:validation-api:2.0.1.Final'
+
+    compileOnly 'org.projectlombok:lombok:1.18.8'
+    annotationProcessor 'org.projectlombok:lombok:1.18.8'
+
+    implementation 'org.apache.commons:commons-lang3:3.9'
+}
\ No newline at end of file
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/APIRequestParam.java b/common/src/main/java/com/supwisdom/dlpay/api/APIRequestParam.java
new file mode 100644
index 0000000..75eadc6
--- /dev/null
+++ b/common/src/main/java/com/supwisdom/dlpay/api/APIRequestParam.java
@@ -0,0 +1,165 @@
+package com.supwisdom.dlpay.api;
+
+import com.supwisdom.dlpay.api.annotation.Sign;
+import com.supwisdom.dlpay.api.exception.RequestParamCheckException;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.beans.Introspector;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.*;
+
+public abstract class APIRequestParam {
+  @Sign
+  private String sign;
+  @Sign
+  private String sign_type;
+  @Sign
+  private String version;
+
+  private static final Logger logger = LoggerFactory.getLogger(APIRequestParam.class);
+
+  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 getVersion() {
+    return version;
+  }
+
+  public void setVersion(String version) {
+    this.version = version;
+  }
+
+  private String createLinkString(Map<String, String> params) {
+
+    List<String> keys = new ArrayList<String>(params.keySet());
+    Collections.sort(keys);
+
+    String prestr = "";
+
+    for (int i = 0; i < keys.size(); i++) {
+      String key = keys.get(i);
+      String value = params.get(key);
+
+      if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
+        prestr = prestr + key + "=" + value;
+      } else {
+        prestr = prestr + key + "=" + value + "&";
+      }
+    }
+
+    return prestr;
+  }
+
+  private Map<String, String> paraFilter(Map<String, String> sArray) {
+    Map<String, String> result = new HashMap<String, String>();
+    if (sArray == null || sArray.size() <= 0) {
+      return result;
+    }
+    for (String key : sArray.keySet()) {
+      String value = sArray.get(key);
+      if (null == value || "".equals(value.trim())
+          || "null".equalsIgnoreCase(value.trim())
+          || key.equalsIgnoreCase("sign")
+          || key.equalsIgnoreCase("sign_type")) {
+        continue;
+      }
+      result.put(key, value);
+    }
+    return result;
+  }
+
+  private String md5(String plainText) {
+    //定义一个字节数组
+    byte[] secretBytes = null;
+    try {
+      // 生成一个MD5加密计算摘要
+      MessageDigest md = MessageDigest.getInstance("MD5");
+      //对字符串进行加密
+      md.update(plainText.getBytes());
+      //获得加密后的数据
+      secretBytes = md.digest();
+    } catch (NoSuchAlgorithmException e) {
+      throw new RuntimeException("没有md5这个算法!");
+    }
+    StringBuilder builder = new StringBuilder();
+    for (byte secretByte : secretBytes) {
+      builder.append(String.format("%02X", ((int) secretByte) & 0xFF));
+    }
+    return builder.toString();
+  }
+
+  private boolean calcSignAndCheck(Map<String, String> map, String key) {
+    String sign = map.get("sign");
+    String signType = map.get("sign_type") == null ? "MD5" : map.get("sign_type");
+    if (StringUtils.isEmpty(sign)) return false;
+
+    String signdata = createLinkString(paraFilter(map));
+    logger.info("signdata=[" + signdata + "]");
+
+    String calcSign = null;
+    //fixme: 根据 signType 计算签名
+    if ("MD5".equalsIgnoreCase(signType)) {
+      calcSign = md5(signdata + key); //默认MD5
+    }
+
+    if (sign.equalsIgnoreCase(calcSign)) {
+      return true;
+    }
+    return false;
+  }
+
+  public boolean checkSign(String key) {
+    Class clazz = this.getClass();
+    Map<String, String> paramMap = new HashMap<>();
+    Method[] allGetter = clazz.getMethods();
+
+    for (Method meth : allGetter) {
+      if (meth.getName().startsWith("get") || meth.getName().startsWith("is")) {
+        String fieldName = Introspector.decapitalize(meth.getName().substring(meth.getName().startsWith("get") ? 3 : 2));
+        Field field;
+        try {
+          field = clazz.getDeclaredField(fieldName);
+        } catch (NoSuchFieldException e) {
+          try {
+            field = clazz.getSuperclass().getDeclaredField(fieldName);
+          } catch (NoSuchFieldException e1) {
+            continue;
+          }
+        }
+
+        if (field.isAnnotationPresent(Sign.class)) {
+          Object value;
+          try {
+            value = meth.invoke(this);
+          } catch (Exception e) {
+            e.printStackTrace();
+            continue;
+          }
+          paramMap.put(fieldName, value == null ? null : value.toString());
+        }
+      }
+    }
+    return calcSignAndCheck(paramMap, key);
+  }
+
+  public abstract boolean checkParam() throws RequestParamCheckException;
+}
+
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/annotation/Sign.java b/common/src/main/java/com/supwisdom/dlpay/api/annotation/Sign.java
new file mode 100644
index 0000000..1c9d9ca
--- /dev/null
+++ b/common/src/main/java/com/supwisdom/dlpay/api/annotation/Sign.java
@@ -0,0 +1,12 @@
+package com.supwisdom.dlpay.api.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Sign {
+  int order() default 0;
+}
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/bean/CitizenCardPayfinishParam.java b/common/src/main/java/com/supwisdom/dlpay/api/bean/CitizenCardPayfinishParam.java
new file mode 100644
index 0000000..0b07e7d
--- /dev/null
+++ b/common/src/main/java/com/supwisdom/dlpay/api/bean/CitizenCardPayfinishParam.java
@@ -0,0 +1,21 @@
+package com.supwisdom.dlpay.api.bean;
+
+
+import com.supwisdom.dlpay.api.APIRequestParam;
+import com.supwisdom.dlpay.api.annotation.Sign;
+import com.supwisdom.dlpay.api.exception.RequestParamCheckException;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class CitizenCardPayfinishParam extends APIRequestParam {
+  @Sign
+  @NotNull(message = "交易参考号不能为空")
+  private String refno;
+
+  @Override
+  public boolean checkParam() throws RequestParamCheckException {
+    return true;
+  }
+}
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/bean/CitizenCardPayinitParam.java b/common/src/main/java/com/supwisdom/dlpay/api/bean/CitizenCardPayinitParam.java
new file mode 100644
index 0000000..b31a90a
--- /dev/null
+++ b/common/src/main/java/com/supwisdom/dlpay/api/bean/CitizenCardPayinitParam.java
@@ -0,0 +1,49 @@
+package com.supwisdom.dlpay.api.bean;
+
+import com.supwisdom.dlpay.api.APIRequestParam;
+import com.supwisdom.dlpay.api.annotation.Sign;
+import com.supwisdom.dlpay.api.exception.RequestParamCheckException;
+import com.supwisdom.dlpay.api.util.DateUtil;
+import lombok.Data;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+@Data
+public class CitizenCardPayinitParam extends APIRequestParam {
+  @Sign
+  @NotNull(message = "卡唯一号不能为空")
+  private String cardNo;
+
+  @Sign
+  @NotNull(message = "请指定交易商户")
+  private String shopaccno;
+
+  @Sign
+  @NotNull
+  @Min(value = 0L, message = "交易金额必须大于零")
+  private Integer amount;
+
+  private List<ConsumeFeetype> feelist;
+
+  @Sign
+  @NotNull(message = "对接系统唯一订单号不能为空")
+  private String billno;
+
+  @Sign
+  @NotNull(message = "交易日期不能为空")
+  private String transdate;
+  @Sign
+  @NotNull(message = "交易时间不能为空")
+  private String transtime;
+
+  @Override
+  public boolean checkParam() throws RequestParamCheckException {
+    if (!DateUtil.checkDatetimeValid(transdate, DateUtil.DATE_FMT))
+      throw new RequestParamCheckException("交易日期错误[yyyyMMdd]");
+    if (!DateUtil.checkDatetimeValid(transtime, DateUtil.TIME_FMT))
+      throw new RequestParamCheckException("交易时间错误[HHmmss]");
+    return true;
+  }
+}
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/bean/CommonQueryRechargeResultParam.java b/common/src/main/java/com/supwisdom/dlpay/api/bean/CommonQueryRechargeResultParam.java
new file mode 100644
index 0000000..d76faa8
--- /dev/null
+++ b/common/src/main/java/com/supwisdom/dlpay/api/bean/CommonQueryRechargeResultParam.java
@@ -0,0 +1,24 @@
+package com.supwisdom.dlpay.api.bean;
+
+import com.supwisdom.dlpay.api.APIRequestParam;
+import com.supwisdom.dlpay.api.annotation.Sign;
+import com.supwisdom.dlpay.api.exception.RequestParamCheckException;
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+
+
+@Data
+public class CommonQueryRechargeResultParam extends APIRequestParam {
+  @Sign
+  private String refno;
+  @Sign
+  private String billno;
+
+  @Override
+  public boolean checkParam() throws RequestParamCheckException {
+    if (StringUtils.isEmpty(refno) && StringUtils.isEmpty(billno)) {
+      throw new RequestParamCheckException("流水号不能为空");
+    }
+    return true;
+  }
+}
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/bean/CommonRechargeConfirmParam.java b/common/src/main/java/com/supwisdom/dlpay/api/bean/CommonRechargeConfirmParam.java
new file mode 100644
index 0000000..db748c4
--- /dev/null
+++ b/common/src/main/java/com/supwisdom/dlpay/api/bean/CommonRechargeConfirmParam.java
@@ -0,0 +1,21 @@
+package com.supwisdom.dlpay.api.bean;
+
+
+import com.supwisdom.dlpay.api.APIRequestParam;
+import com.supwisdom.dlpay.api.annotation.Sign;
+import com.supwisdom.dlpay.api.exception.RequestParamCheckException;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+
+@Data
+public class CommonRechargeConfirmParam extends APIRequestParam {
+  @Sign
+  @NotEmpty(message = "流水号不能为空")
+  private String refno;
+
+  @Override
+  public boolean checkParam() throws RequestParamCheckException {
+    return true;
+  }
+}
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/bean/CommonRechargeInitParam.java b/common/src/main/java/com/supwisdom/dlpay/api/bean/CommonRechargeInitParam.java
new file mode 100644
index 0000000..66654d8
--- /dev/null
+++ b/common/src/main/java/com/supwisdom/dlpay/api/bean/CommonRechargeInitParam.java
@@ -0,0 +1,51 @@
+package com.supwisdom.dlpay.api.bean;
+
+import com.supwisdom.dlpay.api.APIRequestParam;
+import com.supwisdom.dlpay.api.annotation.Sign;
+import com.supwisdom.dlpay.api.exception.RequestParamCheckException;
+import com.supwisdom.dlpay.api.util.DateUtil;
+import lombok.Data;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+@Data
+public class CommonRechargeInitParam extends APIRequestParam {
+  @Sign
+  @NotNull(message = "请指定充值用户")
+  private String userid;
+
+  @Sign
+  @NotNull(message = "充值金额必须大于零")
+  @Min(value = 0L, message = "充值金额必须大于零")
+  private Integer amount;
+
+  private List<ConsumeFeetype> feelist;
+
+  @Sign
+  @NotEmpty(message = "请指定充值的支付方式")
+  private String sourcetype;
+
+  @Sign
+  @NotEmpty(message = "对接系统唯一订单号不能为空")
+  private String billno;
+
+  @Sign
+  @NotNull(message = "交易日期不能为空")
+  private String transdate;
+  @Sign
+  @NotNull(message = "交易时间不能为空")
+  private String transtime;
+
+  @Override
+  public boolean checkParam() throws RequestParamCheckException {
+    if (!DateUtil.checkDatetimeValid(transdate, DateUtil.DATE_FMT))
+      throw new RequestParamCheckException("交易日期错误[yyyyMMdd]");
+    if (!DateUtil.checkDatetimeValid(transtime, DateUtil.TIME_FMT))
+      throw new RequestParamCheckException("交易时间错误[HHmmss]");
+
+    return true;
+  }
+}
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/bean/ConsumeFeetype.java b/common/src/main/java/com/supwisdom/dlpay/api/bean/ConsumeFeetype.java
new file mode 100644
index 0000000..d9f75b1
--- /dev/null
+++ b/common/src/main/java/com/supwisdom/dlpay/api/bean/ConsumeFeetype.java
@@ -0,0 +1,14 @@
+package com.supwisdom.dlpay.api.bean;
+
+import lombok.Data;
+
+@Data
+public class ConsumeFeetype {
+  private String feetype;
+  private Integer amount;
+
+  @Override
+  public String toString() {
+    return String.format("feetype='%s', amount=%d", feetype, amount);
+  }
+}
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/bean/ConsumePayCancelParam.java b/common/src/main/java/com/supwisdom/dlpay/api/bean/ConsumePayCancelParam.java
new file mode 100644
index 0000000..b03c75f
--- /dev/null
+++ b/common/src/main/java/com/supwisdom/dlpay/api/bean/ConsumePayCancelParam.java
@@ -0,0 +1,43 @@
+package com.supwisdom.dlpay.api.bean;
+
+import com.supwisdom.dlpay.api.APIRequestParam;
+import com.supwisdom.dlpay.api.annotation.Sign;
+import com.supwisdom.dlpay.api.exception.RequestParamCheckException;
+import com.supwisdom.dlpay.api.util.DateUtil;
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class ConsumePayCancelParam extends APIRequestParam {
+  @Sign
+  @NotNull
+  private String refno;
+  @Sign
+  private String billno;
+  @Sign
+  private String shopaccno;
+  @Sign
+  @NotNull(message = "撤销或退款流水号不能为空")
+  private String requestbillno;
+  @Sign
+  @NotNull(message = "交易日期不能为空")
+  private String transdate;
+  @Sign
+  @NotNull(message = "交易时间不能为空")
+  private String transtime;
+
+  @Override
+  public boolean checkParam() throws RequestParamCheckException {
+    if (StringUtils.isEmpty(refno) && (StringUtils.isEmpty(billno) || StringUtils.isEmpty(shopaccno)))
+      throw new RequestParamCheckException("原流水唯一号不能为空");
+    if (!DateUtil.checkDatetimeValid(transdate, DateUtil.DATE_FMT)) {
+      throw new RequestParamCheckException("交易日期错误[yyyyMMdd]");
+    }
+    if (!DateUtil.checkDatetimeValid(transtime, DateUtil.TIME_FMT)) {
+      throw new RequestParamCheckException("交易时间错误[HHmmss]");
+    }
+    return true;
+  }
+}
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/bean/ConsumePayRefundParam.java b/common/src/main/java/com/supwisdom/dlpay/api/bean/ConsumePayRefundParam.java
new file mode 100644
index 0000000..50948d0
--- /dev/null
+++ b/common/src/main/java/com/supwisdom/dlpay/api/bean/ConsumePayRefundParam.java
@@ -0,0 +1,49 @@
+package com.supwisdom.dlpay.api.bean;
+
+import com.supwisdom.dlpay.api.APIRequestParam;
+import com.supwisdom.dlpay.api.annotation.Sign;
+import com.supwisdom.dlpay.api.exception.RequestParamCheckException;
+import com.supwisdom.dlpay.api.util.DateUtil;
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class ConsumePayRefundParam extends APIRequestParam {
+  @Sign
+  private String refno;
+  @Sign
+  private String billno;
+  @Sign
+  private String shopaccno;
+
+  @Sign
+  @Min(value = 0L, message = "错误的退款金额")
+  private Integer refundAmount;
+
+  @Sign
+  @NotNull(message = "撤销或退款流水号不能为空")
+  private String requestbillno;
+  @Sign
+  @NotNull(message = "交易日期不能为空")
+  private String transdate;
+  @Sign
+  @NotNull(message = "交易时间不能为空")
+  private String transtime;
+
+  @Override
+  public boolean checkParam() throws RequestParamCheckException {
+    if (StringUtils.isEmpty(refno) && (StringUtils.isEmpty(billno) || StringUtils.isEmpty(shopaccno))) {
+      throw new RequestParamCheckException("原流水唯一号不能为空");
+    }
+    if (!DateUtil.checkDatetimeValid(transdate, DateUtil.DATE_FMT)) {
+      throw new RequestParamCheckException("交易日期错误[yyyyMMdd]");
+    }
+    if (!DateUtil.checkDatetimeValid(transtime, DateUtil.TIME_FMT)) {
+      throw new RequestParamCheckException("交易时间错误[HHmmss]");
+    }
+    return true;
+  }
+}
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/bean/QueryDtlResultParam.java b/common/src/main/java/com/supwisdom/dlpay/api/bean/QueryDtlResultParam.java
new file mode 100644
index 0000000..45077bb
--- /dev/null
+++ b/common/src/main/java/com/supwisdom/dlpay/api/bean/QueryDtlResultParam.java
@@ -0,0 +1,50 @@
+package com.supwisdom.dlpay.api.bean;
+
+import com.supwisdom.dlpay.api.APIRequestParam;
+import com.supwisdom.dlpay.api.annotation.Sign;
+import com.supwisdom.dlpay.api.exception.RequestParamCheckException;
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+
+@Data
+public class QueryDtlResultParam extends APIRequestParam {
+  @Sign
+  private String refno;
+  @Sign
+  private String billno;
+  @Sign
+  private String shopaccno;
+
+  public String getRefno() {
+    return refno;
+  }
+
+  public void setRefno(String refno) {
+    this.refno = refno;
+  }
+
+  public String getBillno() {
+    return billno;
+  }
+
+  public void setBillno(String billno) {
+    this.billno = billno;
+  }
+
+  public String getShopaccno() {
+    return shopaccno;
+  }
+
+  public void setShopaccno(String shopaccno) {
+    this.shopaccno = shopaccno;
+  }
+
+  @Override
+  public boolean checkParam() throws RequestParamCheckException {
+    if (StringUtils.isEmpty(refno) && (StringUtils.isEmpty(billno)
+        || StringUtils.isEmpty(shopaccno))) {
+      throw new RequestParamCheckException("流水唯一号不能为空");
+    }
+    return true;
+  }
+}
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/bean/YktCardPayinitParam.java b/common/src/main/java/com/supwisdom/dlpay/api/bean/YktCardPayinitParam.java
new file mode 100644
index 0000000..aa06109
--- /dev/null
+++ b/common/src/main/java/com/supwisdom/dlpay/api/bean/YktCardPayinitParam.java
@@ -0,0 +1,60 @@
+package com.supwisdom.dlpay.api.bean;
+
+import com.supwisdom.dlpay.api.APIRequestParam;
+import com.supwisdom.dlpay.api.annotation.Sign;
+import com.supwisdom.dlpay.api.exception.RequestParamCheckException;
+import com.supwisdom.dlpay.api.util.DateUtil;
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+@Data
+public class YktCardPayinitParam extends APIRequestParam {
+  @Sign
+  private String uid;
+  @Sign
+  @NotEmpty(message = "请指定交易商户")
+  private String shopaccno;
+  @Sign
+  @NotNull(message = "支付金额不能为空")
+  @Min(value = 0, message = "支付金额不能小于 0")
+  private Integer amount;
+
+  private List<ConsumeFeetype> feelist;
+
+  @Sign
+  @NotNull(message = "订单号不能为空")
+  private String billno;
+  @Sign
+  @NotNull(message = "交易日期不能为空")
+  private String transdate;
+  @Sign
+  @NotNull(message = "交易时间不能为空")
+  private String transtime;
+  @Sign
+  @NotNull(message = "一卡通唯一号不能为空")
+  private String stuempno;
+  @Sign
+  private String yktshopid;
+  @Sign
+  private String devphyid;
+
+  @Override
+  public boolean checkParam() throws RequestParamCheckException {
+    if (!DateUtil.checkDatetimeValid(transdate, DateUtil.DATE_FMT)) {
+      throw new RequestParamCheckException("交易日期错误[yyyyMMdd]");
+    }
+    if (!DateUtil.checkDatetimeValid(transtime, DateUtil.TIME_FMT)) {
+      throw new RequestParamCheckException("交易时间错误[HHmmss]");
+    }
+    if (!StringUtils.isEmpty(yktshopid) && !StringUtils.isNumeric(yktshopid))
+      throw new RequestParamCheckException("一卡通商户号非整数");
+
+    return true;
+  }
+}
+
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/exception/RequestParamCheckException.java b/common/src/main/java/com/supwisdom/dlpay/api/exception/RequestParamCheckException.java
new file mode 100644
index 0000000..a58a336
--- /dev/null
+++ b/common/src/main/java/com/supwisdom/dlpay/api/exception/RequestParamCheckException.java
@@ -0,0 +1,14 @@
+package com.supwisdom.dlpay.api.exception;
+
+public class RequestParamCheckException extends Exception {
+  private int errCode;
+
+  public RequestParamCheckException(String message) {
+    super(String.format("Req-%d,%s", 300001, message));
+    this.errCode = errCode;
+  }
+
+  public int getErrCode() {
+    return errCode;
+  }
+}
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/util/DateUtil.java b/common/src/main/java/com/supwisdom/dlpay/api/util/DateUtil.java
new file mode 100644
index 0000000..2e45a7e
--- /dev/null
+++ b/common/src/main/java/com/supwisdom/dlpay/api/util/DateUtil.java
@@ -0,0 +1,345 @@
+package com.supwisdom.dlpay.api.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.Timestamp;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+public class DateUtil {
+  private static final Logger logger = LoggerFactory.getLogger(DateUtil.class);
+  public static final String DATE_FMT = "yyyyMMdd";
+  public static final String TIME_FMT = "HHmmss";
+  public static final String DATETIME_FMT = "yyyyMMddHHmmss";
+
+  /**
+   * Description: 返回一个当前时间 @return String 格式:yyyyMMddHHmmss @exception Modify
+   * History:
+   */
+  public static String getNow() {
+    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
+    return sdf.format(new Date());
+  }
+
+
+  /**
+   * Description: 根据类型返回一个当前时间 @param partten String @return String 格式:partten
+   */
+  public static String getNow(String partten) {
+    SimpleDateFormat sdf = new SimpleDateFormat(partten);
+    return sdf.format(new Date());
+  }
+
+  /**
+   * Description: 得到一个特殊的时间 @param startTime String 格式:yyyyMMddHHmmss @param
+   * interval int 秒 @return String 格式:partten @exception Modify History:
+   */
+  public static String getNewTime(String startTime, int interval) {
+    try {
+      SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
+      Date d = sdf.parse(startTime);
+      Calendar calendar = Calendar.getInstance();
+      calendar.setTimeInMillis(d.getTime());
+      calendar.add(Calendar.SECOND, interval);
+      return sdf.format(calendar.getTime());
+    } catch (ParseException e) {
+      return startTime;
+    }
+  }
+
+  /**
+   * Description: 得到一个特殊的时间 @param startTime String 格式:partten @param
+   * interval int 秒 @return String 格式:partten @exception Modify History:
+   */
+  public static String getNewTime(String startTime, int interval, String partten) {
+    try {
+      SimpleDateFormat sdf = new SimpleDateFormat(partten);
+      Date d = sdf.parse(startTime);
+      Calendar calendar = Calendar.getInstance();
+      calendar.setTimeInMillis(d.getTime());
+      calendar.add(Calendar.SECOND, interval);
+      return sdf.format(calendar.getTime());
+    } catch (ParseException e) {
+      return startTime;
+    }
+  }
+
+  public static String getNewDay(String startDay, int intervalday) {
+    try {
+      SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+      Date d = sdf.parse(startDay);
+      Calendar calendar = Calendar.getInstance();
+      calendar.setTimeInMillis(d.getTime());
+      calendar.add(Calendar.DATE, intervalday);
+      return sdf.format(calendar.getTime());
+    } catch (ParseException e) {
+      return startDay;
+    }
+  }
+
+  /**
+   * 得到两个日期相差的天数 格式 yyyyMMdd @return diffdays = secondDay - firstDay
+   */
+  public static long getIntervalDay(String firstDay, String secondDay) {
+    try {
+      SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+      Date f = sdf.parse(firstDay);
+      Date s = sdf.parse(secondDay);
+      long time = s.getTime() - f.getTime();
+      return time / (24 * 60 * 60 * 1000);
+    } catch (ParseException e) {
+      return 0;
+    }
+  }
+
+  /**
+   * Description: 比较两个时间字符串的前后关系 @param firstTime String 格式:yyyyMMddHHmmss
+   *
+   * @param secondTime String 格式: yyyyMMddHHmmss @return int |
+   *                   firstTime=second int=0 | firstTime>secondTime int>0 |
+   *                   firstTime<secondTime int<0 @exception Modify History:
+   */
+  public static int compareDatetime(String firstTime, String secondTime) {
+    try {
+      SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
+      Date f = sdf.parse(firstTime);
+      Date s = sdf.parse(secondTime);
+      return f.compareTo(s);
+    } catch (ParseException e) {
+      return 0;
+    }
+  }
+
+  /**
+   * Description: 比较两个时间字符串的前后关系 @param firstTime String 格式:pattern
+   *
+   * @param secondTime String 格式: yyyyMMddHHmmss @return int |
+   *                   firstTime=second int=0 | firstTime>secondTime int>0 |
+   *                   firstTime<secondTime int<0 @exception Modify History:
+   */
+  public static int compareDatetime(String firstTime, String secondTime, String pattern) {
+    try {
+      SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+      Date f = sdf.parse(firstTime);
+      Date s = sdf.parse(secondTime);
+      return f.compareTo(s);
+    } catch (ParseException e) {
+      return 0;
+    }
+  }
+
+  /**
+   * Description: 比较两个时间字符串的时间差 @param firstTime String 格式:yyyyMMddHHmmss
+   *
+   * @param secondTime String 格式: yyyyMMddHHmmss @param second int 格式 @return
+   *                   int | firstTime+seconds=secondTime int=0 | firstTime+seconds>secondTime
+   *                   int>0 | firstTime+seconds<secondTime int<0 @exception Modify History:
+   */
+  public static int compareDatetime(String firstTime, String secondTime, int seconds) {
+    try {
+      SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
+      Date f = sdf.parse(firstTime);
+      Date s = sdf.parse(secondTime);
+      Calendar calendar = Calendar.getInstance();
+      calendar.setTimeInMillis(f.getTime());
+      calendar.add(Calendar.SECOND, seconds);
+      Date temp = calendar.getTime();
+      return temp.compareTo(s);
+    } catch (Exception e) {
+      return 0;
+    }
+  }
+
+  /**
+   * Description: 对time重新格式化
+   */
+  public static String reformatDatetime(String time, String fromPattern, String toPattern) {
+    try {
+      SimpleDateFormat sdf = new SimpleDateFormat(fromPattern);
+      Date d = sdf.parse(time);
+      Calendar calendar = Calendar.getInstance();
+      calendar.setTimeInMillis(d.getTime());
+      sdf = new SimpleDateFormat(toPattern);
+      return sdf.format(calendar.getTime());
+    } catch (Exception e) {
+      e.printStackTrace();
+      return time;
+    }
+  }
+
+  /**
+   * 获得两个字符串日期之间的时间差(单位毫秒) 格式 yyyyMMddHHmmss
+   */
+  public static long getInterval(String startTime, String endTime) {
+    long duration = 0;
+    try {
+      SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
+      duration = sdf.parse(endTime).getTime() - sdf.parse(startTime).getTime();
+    } catch (ParseException e) {
+      logger.error("Hi guys,there is an error when you try to parse the date string");
+    }
+    return duration;
+  }
+
+  /**
+   * 获得两个字符串日期之间的时间差(单位毫秒)
+   */
+  public static long getIntervalTime(String startTime, String endTime, String pattern) {
+    long duration = 0;
+    try {
+      SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+      duration = sdf.parse(endTime).getTime() - sdf.parse(startTime).getTime();
+    } catch (ParseException e) {
+      logger.error("Hi guys,there is an error when you try to parse the date string");
+    }
+    return duration;
+  }
+
+  /**
+   * 转换成日期格式
+   * 短格式:20140401 -> 2014-04-01
+   * 中格式:201404011200 -> 2014-04-01 12:00
+   * 长格式:20140401123025 -> 2014-04-01 12:30:25
+   **/
+  public static String parseToDateFormat(String str) {
+    switch (str.length()) {
+      case 8:
+        str = str.substring(0, 4) + "-" + str.substring(4, 6) + "-" + str.substring(6, 8);
+        break;
+      case 12:
+        str = str.substring(0, 4) + "-" + str.substring(4, 6) + "-" + str.substring(6, 8) + " " + str.substring(8, 10) + ":" + str.substring(10, 12);
+        break;
+      case 14:
+        str = str.substring(0, 4) + "-" + str.substring(4, 6) + "-" + str.substring(6, 8) + " " + str.substring(8, 10) + ":" + str.substring(10, 12) + ":" + str.substring(12, 14);
+        break;
+      default:
+        break;
+    }
+    return str;
+  }
+
+  /**
+   * 解日期格式
+   * 短格式:2014-04-01 -> 20140401
+   * 中格式:2014-04-01 12:00 -> 201404011200
+   * 长格式:2014-04-01 12:30:25 -> 20140401123025
+   **/
+  public static String unParseToDateFormat(String str) {
+    return str.replaceAll("-", "").replaceAll(" ", "").replaceAll(":", "");
+  }
+
+  /**
+   * 检验时间格式
+   */
+  public static boolean checkDatetimeValid(String datetime, String pattern) {
+    if (null == datetime) return false;
+    try {
+      SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+      Date d = sdf.parse(datetime);
+      return datetime.trim().equals(sdf.format(d));
+    } catch (Exception e) {
+    }
+    return false;
+  }
+
+  /**
+   * 获取指定日期是星期几 格式 yyyyMMdd
+   * MON|TUE|WED|THU|FRI|SAT|SUN
+   * 1		2		3		4		5		6		7
+   */
+  public static int getWeekday(String datestr) {
+    try {
+      SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+      Calendar calendar = Calendar.getInstance();
+      boolean isFirstSunday = (calendar.getFirstDayOfWeek() == Calendar.SUNDAY); //一周第一天是否为星期天
+      Date d = sdf.parse(datestr);
+      calendar.setTimeInMillis(d.getTime());
+      int weekDay = calendar.get(calendar.DAY_OF_WEEK);
+      if (isFirstSunday) {
+        weekDay = weekDay - 1;
+        if (weekDay == 0) {
+          weekDay = 7;
+        }
+      }
+      return weekDay;
+    } catch (Exception e) {
+      return -1;
+    }
+  }
+
+  /**
+   * 获取指定日期
+   */
+  public static Date getSpecifyDate(String datestr, String pattern) {
+    try {
+      SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+      Date result = sdf.parse(datestr);
+      return result;
+    } catch (Exception e) {
+      return new Date();
+    }
+  }
+
+  public static Integer getLastDayOfMonth(Integer year, Integer month) {
+    Calendar cal = Calendar.getInstance();
+    cal.set(Calendar.YEAR, year);
+    cal.set(Calendar.MONTH, month - 1);
+    cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DATE));
+    String str = new SimpleDateFormat("yyyyMMdd ").format(cal.getTime()).toString();
+    Integer result = Integer.parseInt(str.substring(0, 4) + str.substring(4, 6) + str.substring(6, 8));
+    return result;
+  }
+
+  private static Date set(Date date, int calendarField, int amount) {
+    Calendar c = Calendar.getInstance();
+    c.setLenient(false);
+    c.setTime(date);
+    c.add(calendarField, amount);
+    return c.getTime();
+  }
+
+
+  public static Date setMinutes(Date date, int amount) {
+    return set(date, Calendar.MINUTE, amount);
+  }
+
+
+  public static long getNowSecond() {
+    Calendar calendar = Calendar.getInstance();
+    return calendar.getTimeInMillis() / 1000;
+  }
+
+
+  public static String getUTCTime(Long timeInMillisSecond) {
+    Calendar time = Calendar.getInstance();
+    SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
+    fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
+    time.setTimeInMillis(timeInMillisSecond);
+    return fmt.format(time.getTime());
+  }
+
+  public static String getUTCTime() {
+    return getUTCTime(System.currentTimeMillis());
+  }
+
+  public static int compareDay(Timestamp d1, Timestamp d2) {
+    Calendar cd1 = Calendar.getInstance();
+    cd1.setTimeInMillis(d1.getTime());
+    Calendar cd2 = Calendar.getInstance();
+    cd2.setTimeInMillis(d2.getTime());
+
+    if (cd1.get(Calendar.YEAR) != cd2.get(Calendar.YEAR)) {
+      return cd1.compareTo(cd2);
+    }
+
+    return Integer.compare(cd1.get(Calendar.DAY_OF_YEAR), cd2.get(Calendar.DAY_OF_YEAR));
+  }
+
+  public static Boolean sameDay(Timestamp d1, Timestamp d2) {
+    return (compareDay(d1, d2) == 0);
+  }
+}
diff --git a/payapi-sdk/build.gradle b/payapi-sdk/build.gradle
index 9b201e0..f77566a 100644
--- a/payapi-sdk/build.gradle
+++ b/payapi-sdk/build.gradle
@@ -11,6 +11,9 @@
     implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
     implementation 'org.springframework.boot:spring-boot-starter-data-redis'
 
+
+    implementation project(':common')
+
     implementation 'org.springframework.cloud:spring-cloud-dependencies:Finchley.SR3'
     implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:2.1.2.RELEASE'
 }
\ No newline at end of file
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/CitizenCardPay.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/CitizenCardPay.java
index 1700dc6..f815fe1 100644
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/CitizenCardPay.java
+++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/CitizenCardPay.java
@@ -1,8 +1,17 @@
 package com.supwisdom.dlpay.paysdk;
 
+import com.supwisdom.dlpay.api.bean.CitizenCardPayfinishParam;
+import com.supwisdom.dlpay.api.bean.CitizenCardPayinitParam;
 import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 
-@FeignClient(value = "citizenCardPay", url = "${payapi.url}/api")
+@FeignClient(value = "citizenCardPay", url = "${payapi.url}")
 public interface CitizenCardPay {
-  
+  @PostMapping("/api/consume/citizencard/payinit")
+  ResponseEntity citizencardPayinit(@RequestBody CitizenCardPayinitParam param);
+
+  @PostMapping("/api/consume/citizencard/payfinish")
+  ResponseEntity citizencardPayinit(@RequestBody CitizenCardPayfinishParam param);
 }
diff --git a/settings.gradle b/settings.gradle
index 4e2ae1c..60cb130 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,2 +1,2 @@
 rootProject.name = 'payapi'
-include 'payapi-sdk'
+include 'payapi-sdk', 'common'
diff --git a/src/main/java/com/supwisdom/dlpay/exception/RequestParamCheckException.java b/src/main/java/com/supwisdom/dlpay/exception/RequestParamCheckException.java
deleted file mode 100644
index 328a08d..0000000
--- a/src/main/java/com/supwisdom/dlpay/exception/RequestParamCheckException.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.supwisdom.dlpay.exception;
-
-public class RequestParamCheckException extends Exception {
-  private int errCode;
-
-  public RequestParamCheckException(int errCode, String message) {
-    super(String.format("Req-%d,%s", errCode, message));
-    this.errCode = errCode;
-  }
-
-  public int getErrCode() {
-    return errCode;
-  }
-}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/APIRequestParam.java b/src/main/java/com/supwisdom/dlpay/framework/util/APIRequestParam.java
deleted file mode 100644
index 14fc1d7..0000000
--- a/src/main/java/com/supwisdom/dlpay/framework/util/APIRequestParam.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package com.supwisdom.dlpay.framework.util;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.beans.Introspector;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-
-public abstract class APIRequestParam {
-  @Sign
-  private String sign;
-  @Sign
-  private String sign_type;
-  @Sign
-  private String version;
-
-  private static final Logger logger = LoggerFactory.getLogger(APIRequestParam.class);
-
-  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 getVersion() {
-    return version;
-  }
-
-  public void setVersion(String version) {
-    this.version = version;
-  }
-
-  private boolean calcSignAndCheck(Map<String, String> map, String key) {
-    String sign = map.get("sign");
-    String signType = map.get("sign_type") == null ? "MD5" : map.get("sign_type");
-    if (StringUtil.isEmpty(sign)) return false;
-
-    String signdata = StringUtil.createLinkString(StringUtil.paraFilter(map));
-    logger.info("signdata=[" + signdata + "]");
-
-    String calcSign = null;
-    //fixme: 根据 signType 计算签名
-    if ("MD5".equalsIgnoreCase(signType)) {
-      calcSign = MD5.encodeByMD5(signdata + key); //默认MD5
-    }
-
-    if (sign.equalsIgnoreCase(calcSign)) {
-      return true;
-    }
-    return false;
-  }
-
-  public boolean checkSign(String key){
-    Class clazz = this.getClass();
-    Map<String, String> paramMap = new HashMap<>();
-    Method[] allGetter = clazz.getMethods();
-
-    for (Method meth : allGetter) {
-      if (meth.getName().startsWith("get") || meth.getName().startsWith("is")) {
-        String fieldName = Introspector.decapitalize(meth.getName().substring(meth.getName().startsWith("get") ? 3 : 2));
-        Field field;
-        try {
-          field = clazz.getDeclaredField(fieldName);
-        } catch (NoSuchFieldException e) {
-          try {
-            field = clazz.getSuperclass().getDeclaredField(fieldName);
-          } catch (NoSuchFieldException e1) {
-//            e1.printStackTrace();
-            continue;
-          }
-        }
-
-        if (field.isAnnotationPresent(Sign.class)) {
-          Object value;
-          try {
-            value = meth.invoke(this);
-          } catch (Exception e) {
-            e.printStackTrace();
-            continue;
-          }
-          paramMap.put(fieldName, value == null ? null : value.toString());
-        }
-      }
-    }
-    return calcSignAndCheck(paramMap,key);
-  }
-
-  public abstract boolean checkParam();
-}
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/bean/api_request_param.kt b/src/main/kotlin/com/supwisdom/dlpay/api/bean/api_request_param.kt
index 5568b6f..87573a0 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/bean/api_request_param.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/bean/api_request_param.kt
@@ -2,7 +2,8 @@
 
 import com.google.gson.Gson
 import com.google.gson.reflect.TypeToken
-import com.supwisdom.dlpay.exception.RequestParamCheckException
+import com.supwisdom.dlpay.api.APIRequestParam
+import com.supwisdom.dlpay.api.exception.RequestParamCheckException
 import com.supwisdom.dlpay.framework.util.*
 import com.supwisdom.dlpay.util.ConstantUtil
 import com.supwisdom.dlpay.util.DESedeUtil
@@ -31,14 +32,14 @@
     var zipcode: String? = null
 
     override fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(uid)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "用户唯一号不能为空")
-        if (StringUtil.isEmpty(name)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "姓名不能为空")
-        if (!StringUtil.isEmpty(sex) && ConstantUtil.SEX_MALE != sex && ConstantUtil.SEX_FEMALE != sex) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "性别非法[male|female]")
-        if (StringUtil.isEmpty(idtype) || !ConstantUtil.IDTYPE_DICTS.contains(idtype)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "证件类型非法")
-        if (StringUtil.isEmpty(idno) || !StringUtil.isCharAndNum(idno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "证件号不能为空,且仅支持数字和字母")
-        if (ConstantUtil.IDTYPE_IDENTITY == idtype && !StringUtil.isIdentity(idno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "身份证格式错误")
-        if (!StringUtil.isEmpty(mobile) && !StringUtil.isMobile(mobile)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "手机号格式错误")
-        if (!StringUtil.isEmpty(email) && !StringUtil.isEmail(email)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "邮箱格式错误")
+        if (StringUtil.isEmpty(uid)) throw RequestParamCheckException("用户唯一号不能为空")
+        if (StringUtil.isEmpty(name)) throw RequestParamCheckException("姓名不能为空")
+        if (!StringUtil.isEmpty(sex) && ConstantUtil.SEX_MALE != sex && ConstantUtil.SEX_FEMALE != sex) throw RequestParamCheckException("性别非法[male|female]")
+        if (StringUtil.isEmpty(idtype) || !ConstantUtil.IDTYPE_DICTS.contains(idtype)) throw RequestParamCheckException("证件类型非法")
+        if (StringUtil.isEmpty(idno) || !StringUtil.isCharAndNum(idno)) throw RequestParamCheckException("证件号不能为空,且仅支持数字和字母")
+        if (ConstantUtil.IDTYPE_IDENTITY == idtype && !StringUtil.isIdentity(idno)) throw RequestParamCheckException("身份证格式错误")
+        if (!StringUtil.isEmpty(mobile) && !StringUtil.isMobile(mobile)) throw RequestParamCheckException("手机号格式错误")
+        if (!StringUtil.isEmpty(email) && !StringUtil.isEmail(email)) throw RequestParamCheckException("邮箱格式错误")
 
         return true
     }
@@ -51,7 +52,7 @@
     var uid: String? = null    // 用户ID二选一
 
     override fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(userid) && StringUtil.isEmpty(uid)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "用户唯一号不能为空")
+        if (StringUtil.isEmpty(userid) && StringUtil.isEmpty(uid)) throw RequestParamCheckException("用户唯一号不能为空")
 
         return true
     }
@@ -82,14 +83,14 @@
     var zipcode: String? = null
 
     override fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(userid) && StringUtil.isEmpty(uid)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "用户唯一号不能为空")
-        if (!StringUtil.isEmpty(sex) && ConstantUtil.SEX_MALE != sex && ConstantUtil.SEX_FEMALE != sex) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "性别非法[male|female]")
-        if (!StringUtil.isEmpty(idtype) && !ConstantUtil.IDTYPE_DICTS.contains(idtype)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "证件类型非法")
-        if (!StringUtil.isEmpty(idno) && !StringUtil.isCharAndNum(idno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "证件号不能为空,且仅支持数字和字母")
-        if (!StringUtil.isEmpty(idno) && StringUtil.isEmpty(idtype)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "证件号不能为空时,请指定证件类型")
-        if (!StringUtil.isEmpty(idno) && ConstantUtil.IDTYPE_IDENTITY == idtype && !StringUtil.isIdentity(idno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "身份证格式错误")
-        if (!StringUtil.isEmpty(mobile) && !StringUtil.isMobile(mobile)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "手机号格式错误")
-        if (!StringUtil.isEmpty(email) && !StringUtil.isEmail(email)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "邮箱格式错误")
+        if (StringUtil.isEmpty(userid) && StringUtil.isEmpty(uid)) throw RequestParamCheckException("用户唯一号不能为空")
+        if (!StringUtil.isEmpty(sex) && ConstantUtil.SEX_MALE != sex && ConstantUtil.SEX_FEMALE != sex) throw RequestParamCheckException("性别非法[male|female]")
+        if (!StringUtil.isEmpty(idtype) && !ConstantUtil.IDTYPE_DICTS.contains(idtype)) throw RequestParamCheckException("证件类型非法")
+        if (!StringUtil.isEmpty(idno) && !StringUtil.isCharAndNum(idno)) throw RequestParamCheckException("证件号不能为空,且仅支持数字和字母")
+        if (!StringUtil.isEmpty(idno) && StringUtil.isEmpty(idtype)) throw RequestParamCheckException("证件号不能为空时,请指定证件类型")
+        if (!StringUtil.isEmpty(idno) && ConstantUtil.IDTYPE_IDENTITY == idtype && !StringUtil.isIdentity(idno)) throw RequestParamCheckException("身份证格式错误")
+        if (!StringUtil.isEmpty(mobile) && !StringUtil.isMobile(mobile)) throw RequestParamCheckException("手机号格式错误")
+        if (!StringUtil.isEmpty(email) && !StringUtil.isEmail(email)) throw RequestParamCheckException("邮箱格式错误")
 
         return true
     }
@@ -122,14 +123,14 @@
     var zipcode: String? = null
 
     override fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(shopUniqueId)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "商户唯一号不能为空")
-        if (ConstantUtil.SHOPTYPE_GROUP != shoptype && ConstantUtil.SHOPTYPE_LEAF != shoptype) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "请指定商户类型")
-        if (StringUtil.isEmpty(shopname)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "商户名称不能为空")
-        if (!StringUtil.isEmpty(idtype) && !ConstantUtil.IDTYPE_DICTS.contains(idtype)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "证件类型非法")
-        if (!StringUtil.isEmpty(idno) && !StringUtil.isCharAndNum(idno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "证件号不能为空,且仅支持数字和字母")
-        if (!StringUtil.isEmpty(idno) && StringUtil.isEmpty(idtype)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "证件号不能为空时,请指定证件类型")
-        if (!StringUtil.isEmpty(mobile) && !StringUtil.isMobile(mobile)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "手机号格式错误")
-        if (!StringUtil.isEmpty(email) && !StringUtil.isEmail(email)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "邮箱格式错误")
+        if (StringUtil.isEmpty(shopUniqueId)) throw RequestParamCheckException("商户唯一号不能为空")
+        if (ConstantUtil.SHOPTYPE_GROUP != shoptype && ConstantUtil.SHOPTYPE_LEAF != shoptype) throw RequestParamCheckException("请指定商户类型")
+        if (StringUtil.isEmpty(shopname)) throw RequestParamCheckException("商户名称不能为空")
+        if (!StringUtil.isEmpty(idtype) && !ConstantUtil.IDTYPE_DICTS.contains(idtype)) throw RequestParamCheckException("证件类型非法")
+        if (!StringUtil.isEmpty(idno) && !StringUtil.isCharAndNum(idno)) throw RequestParamCheckException("证件号不能为空,且仅支持数字和字母")
+        if (!StringUtil.isEmpty(idno) && StringUtil.isEmpty(idtype)) throw RequestParamCheckException("证件号不能为空时,请指定证件类型")
+        if (!StringUtil.isEmpty(mobile) && !StringUtil.isMobile(mobile)) throw RequestParamCheckException("手机号格式错误")
+        if (!StringUtil.isEmpty(email) && !StringUtil.isEmail(email)) throw RequestParamCheckException("邮箱格式错误")
 
         return true
     }
@@ -144,214 +145,7 @@
     var shopUniqueId: String? = null //注册传的商户唯一号
 
     override fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(shopUniqueId) && null == shopid && StringUtil.isEmpty(shopaccno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "商户唯一标志不能为空")
-
-        return true
-    }
-}
-
-
-// ============================ CONSUME ============================ //
-class ConsumeFeetype {
-    var feetype: String = ""
-    var amount: Int = 0
-
-    override fun toString(): String {
-        return "{feetype='$feetype', amount=$amount}"
-    }
-}
-
-class QueryDtlResultParam : APIRequestParam() {
-    @Sign
-    var refno: String? = null //二选一
-    @Sign
-    var billno: String? = null //二选一 (billno+shopaccno) 传billno时,shopaccno必传
-    @Sign
-    var shopaccno: String? = null
-
-    override fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(refno) && (StringUtil.isEmpty(billno) || StringUtil.isEmpty(shopaccno))) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "流水唯一号不能为空")
-
-        return true
-    }
-}
-
-class CitizenCardPayinitParam : APIRequestParam() {
-    @Sign
-    var cardNo: String = "" //必传
-    @Sign
-    var shopaccno: String = "" //必传
-    @Sign
-    var amount: Int = 0 //必传
-
-    var feelist: List<ConsumeFeetype>? = null //TODO: 怎么拼接签名字符串??
-    @Sign
-    var billno: String = "" //必传
-    @Sign
-    var transdate: String = "" //必传
-    @Sign
-    var transtime: String = "" //必传
-
-    override fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(cardNo)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "卡唯一号不能为空")
-        if (StringUtil.isEmpty(shopaccno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "请指定交易商户")
-        if (amount <= 0) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易金额必须大于零")
-        if (StringUtil.isEmpty(billno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "对接系统唯一订单号不能为空")
-        if (!DateUtil.checkDatetimeValid(transdate, DateUtil.DATE_FMT)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易日期错误[yyyyMMdd]")
-        if (!DateUtil.checkDatetimeValid(transtime, DateUtil.TIME_FMT)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易时间错误[HHmmss]")
-
-        return true
-    }
-}
-
-class CitizenCardPayfinishParam : APIRequestParam() {
-    @Sign
-    var refno: String = ""
-
-    override fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(refno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易参考号不能为空")
-
-        return true
-    }
-}
-
-class YktCardPayinitParam : APIRequestParam() {
-    @Sign
-    var uid: String? = null //未注册,可能不传
-    @Sign
-    var shopaccno: String = "" //必传
-    @Sign
-    var amount: Int = 0 //必传
-
-    var feelist: List<ConsumeFeetype>? = null //TODO: 怎么拼接签名字符串??
-    @Sign
-    var billno: String = "" //必传
-    @Sign
-    var transdate: String = "" //必传
-    @Sign
-    var transtime: String = "" //必传
-    @Sign
-    var stuempno: String = "" //必传
-    @Sign
-    var yktshopid: String? = null
-    @Sign
-    var devphyid: String? = null
-
-    override fun checkParam(): Boolean {
-
-        if (StringUtil.isEmpty(shopaccno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "请指定交易商户")
-        if (amount <= 0) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易金额必须大于零")
-        if (StringUtil.isEmpty(billno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "对接系统唯一订单号不能为空")
-        if (!DateUtil.checkDatetimeValid(transdate, DateUtil.DATE_FMT)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易日期错误[yyyyMMdd]")
-        if (!DateUtil.checkDatetimeValid(transtime, DateUtil.TIME_FMT)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易时间错误[HHmmss]")
-        if (StringUtil.isEmpty(stuempno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "一卡通唯一号不能为空")
-        if (!StringUtil.isEmpty(yktshopid) && !NumberUtil.isDigits(yktshopid)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "一卡通商户号非整数")
-
-        return true
-    }
-}
-
-class ConsumePayCancelParam : APIRequestParam() {
-    @Sign
-    var refno: String? = null //流水号
-    @Sign
-    var billno: String? = null //订单号
-    @Sign
-    var shopaccno: String? = null //商户号
-    @Sign
-    var requestbillno: String = "" //退款请求唯一标识
-    @Sign
-    var transdate: String = "" //必传
-    @Sign
-    var transtime: String = "" //必传
-
-    override fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(refno) && (StringUtil.isEmpty(billno) || StringUtil.isEmpty(shopaccno))) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "原流水唯一号不能为空")
-        if (StringUtil.isEmpty(requestbillno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "撤销或退款流水号不能为空")
-        if (!DateUtil.checkDatetimeValid(transdate, DateUtil.DATE_FMT)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易日期错误[yyyyMMdd]")
-        if (!DateUtil.checkDatetimeValid(transtime, DateUtil.TIME_FMT)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易时间错误[HHmmss]")
-
-        return true
-    }
-}
-
-class ConsumePayRefundParam : APIRequestParam() {
-    @Sign
-    var refno: String? = null //流水号
-    @Sign
-    var billno: String? = null //订单号
-    @Sign
-    var shopaccno: String? = null //商户号
-
-    @Sign
-    var refundAmount: Int = 0 // 退款金额
-
-    @Sign
-    var requestbillno: String = "" //退款请求唯一标识
-    @Sign
-    var transdate: String = "" //必传
-    @Sign
-    var transtime: String = "" //必传
-
-    override fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(refno) && (StringUtil.isEmpty(billno) || StringUtil.isEmpty(shopaccno))) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "原流水唯一号不能为空")
-        if (StringUtil.isEmpty(requestbillno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "撤销或退款流水号不能为空")
-        if (!DateUtil.checkDatetimeValid(transdate, DateUtil.DATE_FMT)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易日期错误[yyyyMMdd]")
-        if (!DateUtil.checkDatetimeValid(transtime, DateUtil.TIME_FMT)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易时间错误[HHmmss]")
-
-        return true
-    }
-}
-
-
-// ============================ RECHARGE ============================ //
-class CommonRechargeInitParam : APIRequestParam() {
-    @Sign
-    var userid: String = "" //用户ID
-    @Sign
-    var amount: Int = 0 //必传
-
-    var feelist: List<ConsumeFeetype>? = null //TODO: 怎么拼接签名字符串??
-    @Sign
-    var sourcetype: String = "" //必传,充值方式
-    @Sign
-    var billno: String = "" //必传
-    @Sign
-    var transdate: String = "" //必传
-    @Sign
-    var transtime: String = "" //必传
-
-    override fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(userid)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "请指定充值用户")
-        if (amount <= 0) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "充值金额必须大于零")
-        if (StringUtil.isEmpty(sourcetype)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "请指定充值的支付方式")
-        if (StringUtil.isEmpty(billno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "对接系统唯一订单号不能为空")
-        if (!DateUtil.checkDatetimeValid(transdate, DateUtil.DATE_FMT)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易日期错误[yyyyMMdd]")
-        if (!DateUtil.checkDatetimeValid(transtime, DateUtil.TIME_FMT)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易时间错误[HHmmss]")
-
-        return true
-    }
-}
-
-class CommonRechargeConfirmParam : APIRequestParam() {
-    @Sign
-    var refno: String = "" //流水号
-
-    override fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(refno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "流水号不能为空")
-
-        return true
-    }
-}
-
-class CommonQueryRechargeResultParam : APIRequestParam() {
-    @Sign
-    var refno: String? = null //流水号
-    @Sign
-    var billno: String? = null
-
-    override fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(refno) && StringUtil.isEmpty(billno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "流水号不能为空")
+        if (StringUtil.isEmpty(shopUniqueId) && null == shopid && StringUtil.isEmpty(shopaccno)) throw RequestParamCheckException("商户唯一标志不能为空")
 
         return true
     }
@@ -367,12 +161,23 @@
     var sign: String = ""
 
     fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(app_id)) throw RequestParamCheckException(2000, "请求参数错误[应用ID为空]")
-        if (StringUtil.isEmpty(data)) throw RequestParamCheckException(2000, "请求参数错误[业务参数报文为空]")
-        if (null == count || count < 1) throw RequestParamCheckException(2000, "请求参数错误[业务明细至少有一条]")
-        if (!DateUtil.checkDatetimeValid(timestamp, DateUtil.DATETIME_FMT)) throw RequestParamCheckException(2000, "请求参数错误[时间戳]")
-        if (StringUtil.isEmpty(sign_type) || !"HmacSHA256".equals(sign_type, true)) throw RequestParamCheckException(2000, "请求参数错误[签名算法]")
-        if (StringUtil.isEmpty(sign)) throw RequestParamCheckException(2000, "请求参数错误[签名为空]")
+        if (StringUtil.isEmpty(app_id)) {
+            throw RequestParamCheckException("请求参数错误[应用ID为空]")
+        }
+        if (StringUtil.isEmpty(data)) {
+            throw RequestParamCheckException("请求参数错误[业务参数报文为空]")
+        }
+        if (count < 1) throw RequestParamCheckException("请求参数错误[业务明细至少有一条]")
+        if (!DateUtil.checkDatetimeValid(timestamp, DateUtil.DATETIME_FMT)) {
+            throw RequestParamCheckException("请求参数错误[时间戳]")
+        }
+        if (StringUtil.isEmpty(sign_type)
+                || !"HmacSHA256".equals(sign_type, true)) {
+            throw RequestParamCheckException("请求参数错误[签名算法]")
+        }
+        if (StringUtil.isEmpty(sign)) {
+            throw RequestParamCheckException("请求参数错误[签名为空]")
+        }
 
         return true
     }
@@ -388,7 +193,7 @@
             val decstr = DESedeUtil.getInstance(deskey).decode(data)
             return Gson().fromJson(decstr, listType)
         } catch (e: Exception) {
-            throw RequestParamCheckException(1001, "数据解密失败!")
+            throw RequestParamCheckException("数据解密失败!")
         }
     }
 
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt b/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt
index 9e0ebd5..4ecb7df 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt
@@ -1,8 +1,6 @@
 package com.supwisdom.dlpay.api.controller
 
-import com.supwisdom.dlpay.api.AccountProxy
-import com.supwisdom.dlpay.api.CallService
-import com.supwisdom.dlpay.api.TransactionBuilder
+import com.supwisdom.dlpay.api.*
 import com.supwisdom.dlpay.api.bean.*
 import com.supwisdom.dlpay.api.service.AccountUtilServcie
 import com.supwisdom.dlpay.api.service.ConsumePayService
diff --git a/src/main/kotlin/com/supwisdom/dlpay/framework/service/impl/framework_service_impl.kt b/src/main/kotlin/com/supwisdom/dlpay/framework/service/impl/framework_service_impl.kt
index 32c6d92..d5a13dd 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/framework/service/impl/framework_service_impl.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/framework/service/impl/framework_service_impl.kt
@@ -1,10 +1,6 @@
 package com.supwisdom.dlpay.framework.service.impl
 
-import com.google.gson.Gson
-import com.google.gson.reflect.TypeToken
 import com.jcabi.manifests.Manifests
-import com.supwisdom.dlpay.api.bean.ConsumeFeetype
-import com.supwisdom.dlpay.exception.RequestParamCheckException
 import com.supwisdom.dlpay.exception.TransactionProcessException
 import com.supwisdom.dlpay.framework.core.JwtConfig
 import com.supwisdom.dlpay.framework.core.JwtTokenUtil