增加了bean validation
diff --git a/common/build.gradle b/common/build.gradle
index 3347b79..dcfba9e 100644
--- a/common/build.gradle
+++ b/common/build.gradle
@@ -8,9 +8,16 @@
     implementation 'javax.validation:validation-api:2.0.1.Final'
     implementation 'javax.servlet:javax.servlet-api:4.0.1'
     implementation 'commons-beanutils:commons-beanutils:1.9.3'
+    implementation('org.springframework.boot:spring-boot-starter-validation:2.1.6.RELEASE')
+
+    implementation 'org.hibernate:hibernate-validator:6.0.2.Final'
+    compile 'javax.el:javax.el-api:3.0.0'
+    compile 'org.glassfish.web:javax.el:2.2.6'
 
     compileOnly 'org.projectlombok:lombok:1.18.8'
     annotationProcessor 'org.projectlombok:lombok:1.18.8'
 
     implementation 'org.apache.commons:commons-lang3:3.9'
+
+    testImplementation 'junit:junit:4.12'
 }
\ No newline at end of file
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/annotation/Sex.java b/common/src/main/java/com/supwisdom/dlpay/api/annotation/Sex.java
index 4697807..44fb69e 100644
--- a/common/src/main/java/com/supwisdom/dlpay/api/annotation/Sex.java
+++ b/common/src/main/java/com/supwisdom/dlpay/api/annotation/Sex.java
@@ -1,12 +1,14 @@
 package com.supwisdom.dlpay.api.annotation;
 
-import com.supwisdom.dlpay.api.validator.StatusValidator;
+import com.supwisdom.dlpay.api.util.SexTypes;
+import com.supwisdom.dlpay.api.validator.SexValidator;
+import com.supwisdom.dlpay.api.validator.UserStatusValidator;
 
 import javax.validation.Constraint;
 import javax.validation.Payload;
 import java.lang.annotation.*;
 
-@Constraint(validatedBy = {StatusValidator.class})
+@Constraint(validatedBy = {SexValidator.class})
 @Documented
 @Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
 @Retention(RetentionPolicy.RUNTIME)
@@ -16,4 +18,6 @@
   Class<?>[] groups() default {};
 
   Class<? extends Payload>[] payload() default {};
+
+  SexTypes value() default SexTypes.ALL;
 }
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/annotation/UserStatus.java b/common/src/main/java/com/supwisdom/dlpay/api/annotation/UserStatus.java
index 3b034fb..bbfbc6d 100644
--- a/common/src/main/java/com/supwisdom/dlpay/api/annotation/UserStatus.java
+++ b/common/src/main/java/com/supwisdom/dlpay/api/annotation/UserStatus.java
@@ -1,15 +1,15 @@
 package com.supwisdom.dlpay.api.annotation;
 
 
-import com.supwisdom.dlpay.api.validator.StatusValidator;
+import com.supwisdom.dlpay.api.validator.UserStatusValidator;
 
 import javax.validation.Constraint;
 import javax.validation.Payload;
 import java.lang.annotation.*;
 
-@Constraint(validatedBy = {StatusValidator.class})
+@Constraint(validatedBy = {UserStatusValidator.class})
 @Documented
-@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
+@Target({ElementType.METHOD, ElementType.FIELD})
 @Retention(RetentionPolicy.RUNTIME)
 public @interface UserStatus {
   String message() default "不正确的状态 , 应该是 'open', 'closed', 'losed' 其中之一";
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
index 79c5160..5b0e7dc 100644
--- a/common/src/main/java/com/supwisdom/dlpay/api/bean/CitizenCardPayinitParam.java
+++ b/common/src/main/java/com/supwisdom/dlpay/api/bean/CitizenCardPayinitParam.java
@@ -7,8 +7,8 @@
 import lombok.Getter;
 import lombok.Setter;
 
-import javax.validation.constraints.Min;
 import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Positive;
 import java.util.List;
 
 @Getter
@@ -23,8 +23,8 @@
   private String shopaccno;
 
   @Sign
-  @NotNull
-  @Min(value = 0L, message = "交易金额必须大于零")
+  @NotNull(message = "交易金额不能为空")
+  @Positive(message = "交易金额必须大于零")
   private Integer amount;
 
   private List<ConsumeFeetype> feelist;
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/util/SexTypes.java b/common/src/main/java/com/supwisdom/dlpay/api/util/SexTypes.java
new file mode 100644
index 0000000..380110f
--- /dev/null
+++ b/common/src/main/java/com/supwisdom/dlpay/api/util/SexTypes.java
@@ -0,0 +1,22 @@
+package com.supwisdom.dlpay.api.util;
+
+public enum SexTypes {
+  MALE("male"),
+  FEMALE("female"),
+  UNKNOWN("unknown"),
+  ALL(new SexTypes[]{MALE, FEMALE, UNKNOWN});
+
+  SexTypes(Object data) {
+    this.data = data;
+  }
+
+  public String value() {
+    return this.data.toString();
+  }
+
+  public Object getData() {
+    return this.data;
+  }
+
+  private Object data;
+}
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/validator/MobileNumberValidator.java b/common/src/main/java/com/supwisdom/dlpay/api/validator/MobileNumberValidator.java
index 0be737f..8fc1a26 100644
--- a/common/src/main/java/com/supwisdom/dlpay/api/validator/MobileNumberValidator.java
+++ b/common/src/main/java/com/supwisdom/dlpay/api/validator/MobileNumberValidator.java
@@ -10,6 +10,9 @@
 
   @Override
   public boolean isValid(String value, ConstraintValidatorContext context) {
+    if (value == null) {
+      return true;
+    }
     return MobileNumberCheck.isPhone(value);
   }
 
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/validator/SexValidator.java b/common/src/main/java/com/supwisdom/dlpay/api/validator/SexValidator.java
index 5a38bb4..22aba88 100644
--- a/common/src/main/java/com/supwisdom/dlpay/api/validator/SexValidator.java
+++ b/common/src/main/java/com/supwisdom/dlpay/api/validator/SexValidator.java
@@ -2,21 +2,31 @@
 
 
 import com.supwisdom.dlpay.api.annotation.Sex;
+import com.supwisdom.dlpay.api.util.SexTypes;
 
 import javax.validation.ConstraintValidator;
 import javax.validation.ConstraintValidatorContext;
-import java.util.Collections;
+import java.util.Arrays;
 
 
 public class SexValidator implements ConstraintValidator<Sex, String> {
-  private final String[] ALL_TYPE = {"male", "female", "unknown"};
+  private String[] sexTypes;
 
   @Override
   public boolean isValid(String value, ConstraintValidatorContext context) {
-    return Collections.singletonList(ALL_TYPE).contains(value);
+    return Arrays.asList(sexTypes).contains(value);
   }
 
   @Override
   public void initialize(Sex constraintAnnotation) {
+    if (constraintAnnotation.value().getData() instanceof SexTypes[]) {
+      SexTypes[] arrays = (SexTypes[]) constraintAnnotation.value().getData();
+      sexTypes = new String[arrays.length];
+      for (int i = 0; i < arrays.length; i++) {
+        sexTypes[i] = arrays[i].value();
+      }
+    } else {
+      sexTypes = new String[]{constraintAnnotation.value().value()};
+    }
   }
 }
diff --git a/common/src/main/java/com/supwisdom/dlpay/api/validator/StatusValidator.java b/common/src/main/java/com/supwisdom/dlpay/api/validator/UserStatusValidator.java
similarity index 86%
rename from common/src/main/java/com/supwisdom/dlpay/api/validator/StatusValidator.java
rename to common/src/main/java/com/supwisdom/dlpay/api/validator/UserStatusValidator.java
index 84b8e5b..b124f65 100644
--- a/common/src/main/java/com/supwisdom/dlpay/api/validator/StatusValidator.java
+++ b/common/src/main/java/com/supwisdom/dlpay/api/validator/UserStatusValidator.java
@@ -6,7 +6,7 @@
 import javax.validation.ConstraintValidatorContext;
 import java.util.Arrays;
 
-public class StatusValidator implements ConstraintValidator<UserStatus, String> {
+public class UserStatusValidator implements ConstraintValidator<UserStatus, String> {
   private final String[] ALL_STATUS = {"open", "closed", "losed"};
 
   @Override
diff --git a/common/src/test/java/com/supwisdom/dlpay/api/bean/CitizenCardPayinitParamTest.java b/common/src/test/java/com/supwisdom/dlpay/api/bean/CitizenCardPayinitParamTest.java
new file mode 100644
index 0000000..f39af2e
--- /dev/null
+++ b/common/src/test/java/com/supwisdom/dlpay/api/bean/CitizenCardPayinitParamTest.java
@@ -0,0 +1,47 @@
+package com.supwisdom.dlpay.api.bean;
+
+import org.junit.Test;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+import java.util.Set;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class CitizenCardPayinitParamTest {
+
+  private Validator validator;
+
+  @org.junit.Before
+  public void setUp() throws Exception {
+    ValidatorFactory factor = Validation.buildDefaultValidatorFactory();
+    validator = factor.getValidator();
+  }
+
+  @Test
+  public void testCitizenPay() {
+    CitizenCardPayinitParam param = new CitizenCardPayinitParam();
+
+    Set<ConstraintViolation<CitizenCardPayinitParam>> violations = validator.validate(param);
+    StringBuilder message = new StringBuilder();
+    for (ConstraintViolation<CitizenCardPayinitParam> item : violations) {
+      message.append(item.getMessage()).append("\n");
+    }
+    assertFalse(message.toString(), violations.isEmpty());
+  }
+
+  @Test
+  public void testOpenUserParam() {
+    OpenUserParam param = new OpenUserParam();
+    param.setIdtype("12323");
+    Set<ConstraintViolation<OpenUserParam>> violations = validator.validate(param);
+    StringBuilder message = new StringBuilder();
+    for (ConstraintViolation<OpenUserParam> item : violations) {
+      message.append(item.getMessage()).append("\n");
+    }
+    assertFalse(message.toString(), violations.isEmpty());
+  }
+}
\ No newline at end of file
diff --git a/payapi-sdk/build.gradle b/payapi-sdk/build.gradle
index 3523c69..e0f0d0d 100644
--- a/payapi-sdk/build.gradle
+++ b/payapi-sdk/build.gradle
@@ -59,6 +59,7 @@
     implementation 'javax.servlet:javax.servlet-api:4.0.1'
     compileOnly 'org.projectlombok:lombok:1.18.8'
     annotationProcessor 'org.projectlombok:lombok:1.18.8'
+    compile 'com.github.mwiede:feign-validation:1.0'
 
     testImplementation 'org.springframework:spring-test'
     testImplementation 'org.springframework.boot:spring-boot-test'
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/CitizenCardPayProxy.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/CitizenCardPayProxy.java
index e46d5f7..e2042d9 100644
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/CitizenCardPayProxy.java
+++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/CitizenCardPayProxy.java
@@ -8,9 +8,12 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 
+import javax.validation.Valid;
+
 @FeignClient(value = "citizenCardPay", url = "${payapi.url}")
 public interface CitizenCardPayProxy {
   @RequestMapping(value = "/api/consume/citizencard/payinit", method = RequestMethod.GET)
+  @Valid
   CitizenPayResponse citizencardPayinit(@RequestBody CitizenCardPayinitParam param);
 
   @RequestMapping(value = "/api/consume/citizencard/payfinish", method = RequestMethod.GET)
diff --git a/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/CitizenCardPayProxyTest.java b/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/CitizenCardPayProxyTest.java
index 6a1037c..812930d 100644
--- a/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/CitizenCardPayProxyTest.java
+++ b/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/CitizenCardPayProxyTest.java
@@ -61,10 +61,11 @@
 
     CitizenCardPayinitParam initParam = new CitizenCardPayinitParam();
     initParam.setBillno("20190708172756000001");
-    initParam.setCardNo("1231231213");
-    initParam.setAmount(100);
+    initParam.setCardNo("20190619001");
+    initParam.setAmount(0);
     initParam.setTransdate("20190708");
     initParam.setTranstime("172713");
+    initParam.setShopaccno("2000000038");
     CitizenPayResponse payInit = citizenCardPayProxy.citizencardPayinit(initParam);
     assertThat("pay initialized " + payInit.getRetmsg() + payInit.getException(),
         payInit.getRetcode(), equalTo(0));
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/advices.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/advices.kt
index b2ff84d..9fab5f0 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/advices.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/advices.kt
@@ -13,6 +13,8 @@
 import org.aspectj.lang.annotation.Pointcut
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.beans.factory.annotation.Value
+import org.springframework.http.HttpHeaders
+import org.springframework.http.HttpStatus
 import org.springframework.http.ResponseEntity
 import org.springframework.security.core.context.SecurityContextHolder
 import org.springframework.stereotype.Component
@@ -20,6 +22,13 @@
 import org.springframework.web.bind.annotation.RestControllerAdvice
 import java.lang.reflect.UndeclaredThrowableException
 import javax.servlet.http.HttpServletRequest
+import java.util.stream.Collectors
+import org.springframework.validation.BindingResultUtils.getBindingResult
+import java.util.LinkedHashMap
+import org.springframework.web.context.request.WebRequest
+import org.springframework.web.bind.MethodArgumentNotValidException
+import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
+import org.springframework.web.bind.annotation.ControllerAdvice
 
 
 @RestControllerAdvice("com.supwisdom.dlpay.api")
@@ -43,6 +52,22 @@
     }
 }
 
+@ControllerAdvice
+class CustomGlobalExceptionHandler : ResponseEntityExceptionHandler() {
+
+    // error handle for @Valid
+    override fun handleMethodArgumentNotValid(ex: MethodArgumentNotValidException,
+                                              headers: HttpHeaders,
+                                              status: HttpStatus, request: WebRequest): ResponseEntity<Any> {
+        val msg = ex.bindingResult.fieldErrors.joinToString(",") {
+            it?.defaultMessage ?: ""
+        }
+        return ResponseEntity.ok(ResponseBodyBuilder.create()
+                .fail(300001, msg))
+
+    }
+}
+
 @Component
 @Aspect
 class RestControllerAspect {
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt
index 9479e50..0b726b7 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt
@@ -18,6 +18,7 @@
 import org.springframework.web.bind.annotation.RequestBody
 import org.springframework.web.bind.annotation.RequestMapping
 import org.springframework.web.bind.annotation.RestController
+import javax.validation.Valid
 
 @RestController
 @RequestMapping("/api/consume")
@@ -39,7 +40,7 @@
      * ============================================================================
      * */
     @PostMapping("/queryresult")
-    fun queryDtlResult(@RequestBody param: QueryDtlResultParam): ResponseEntity<Any> {
+    fun queryDtlResult(@Valid @RequestBody param: QueryDtlResultParam): ResponseEntity<Any> {
         consumePayService.getTransactionMainDtl(param.refno, param.billno, param.shopaccno)?.let {
             return ResponseEntity.ok(ResponseBodyBuilder.create()
                     .success(QueryTransDtlResponse(it.refno, it.outTradeNo, it.shopDtl.amount,
@@ -126,7 +127,7 @@
      * ============================================================================
      * */
     @PostMapping("/citizencard/payinit")
-    fun citizencardPayinit(@RequestBody param: CitizenCardPayinitParam): ResponseEntity<Any> {
+    fun citizencardPayinit(@Valid @RequestBody param: CitizenCardPayinitParam): ResponseEntity<Any> {
         val person = userService.findPersonByIdentityCheckStatus(param.cardNo)
         if (consumePayService.checkShopPaytype(param.shopaccno, TradeDict.PAYTYPE_CITIZEN_CARD)) {
 
@@ -197,7 +198,7 @@
      * ============================================================================
      * */
     @PostMapping("/citizencard/payfinish")
-    fun citizencardPayinit(@RequestBody param: CitizenCardPayfinishParam): ResponseEntity<Any> {
+    fun citizencardPayinit(@Valid @RequestBody param: CitizenCardPayfinishParam): ResponseEntity<Any> {
         val code = transactionService.wip(param.refno).let {
             CallService.CallCitizenCardPay(
                     consumePayService.getPaytypeConfig(TradeDict.PAYTYPE_CITIZEN_CARD, it.shopDtl.shopaccno),
@@ -225,7 +226,7 @@
      * ============================================================================
      * */
     @PostMapping("/paycancel")
-    fun payCancel(@RequestBody param: ConsumePayCancelParam): ResponseEntity<Any> {
+    fun payCancel(@Valid @RequestBody param: ConsumePayCancelParam): ResponseEntity<Any> {
         consumePayService.getTransactionMainDtl(param.refno, param.billno, param.shopaccno)?.let {
             val builder = TransactionBuilder().apply {
                 setTransInfo(param.transdate, param.transtime, it.transCode, it.sourceType)
@@ -249,7 +250,7 @@
      * ============================================================================
      * */
     @PostMapping("/payrefund")
-    fun payRefund(@RequestBody param: ConsumePayRefundParam): ResponseEntity<Any> {
+    fun payRefund(@Valid @RequestBody param: ConsumePayRefundParam): ResponseEntity<Any> {
         consumePayService.getTransactionMainDtl(param.refno, param.billno, param.shopaccno)?.let {
             val builder = TransactionBuilder().apply {
                 setTransInfo(param.transdate, param.transtime, it.transCode, it.sourceType)