重构代码
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);
+  }
+}