真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Java中怎么實(shí)現(xiàn)接口數(shù)據(jù)校驗(yàn)

今天就跟大家聊聊有關(guān)Java中怎么實(shí)現(xiàn)接口數(shù)據(jù)校驗(yàn),可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

孟州網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應(yīng)式網(wǎng)站等網(wǎng)站項(xiàng)目制作,到程序開發(fā),運(yùn)營維護(hù)。創(chuàng)新互聯(lián)成立于2013年到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)

Controller接口層數(shù)據(jù)綁定校驗(yàn)

實(shí)際上在Java開發(fā)中目前普通使用的Bean數(shù)據(jù)校驗(yàn)工具是"hibernate-validator",它是一個hibernete獨(dú)立的jar包,所以使用這個jar包并不需要一定要集成Hibernete框架。該jar包主要實(shí)現(xiàn)并擴(kuò)展了javax.validation(是一個基于JSR-303標(biāo)準(zhǔn)開發(fā)出來的Bean校驗(yàn)規(guī)范)接口。

由于Spring Boot在內(nèi)部默認(rèn)集成了"hibernate-validator",所以使用Spring  Boot構(gòu)建的Java工程可以直接使用相關(guān)注解來實(shí)現(xiàn)Bean的數(shù)據(jù)校驗(yàn)。例如我們最常編寫的Controller層接口參數(shù)對象,可以在定義Bean類時直接編寫這樣的代碼:

@Data public class CreateOrderDTO {      @NotNull(message = "訂單號不能為空")     private String orderId;     @NotNull(message = "訂單金額不能為空")     @Min(value = 1, message = "訂單金額不能小于0")     private Integer amount;     @Pattern(regexp = "^1[3|4|5|7|8][0-9]{9}$", message = "用戶手機(jī)號不合法")     private String mobileNo;     private String orderType;     private String status; }

如上所示代碼,我們可以使用@NotNull注解來約束該字段必須不能為空,也可以使用@Min注解來約束字段的最小取值,或者還可以通過@Pattern注解來使用正則表達(dá)式來約束字段的格式(如手機(jī)號格式)等等。

以上這些注解都是“hibernate-validator”依賴包默認(rèn)提供的,更多常用的注解還有很多,例如:

Java中怎么實(shí)現(xiàn)接口數(shù)據(jù)校驗(yàn)

利用這些約束注解,我們就可以很輕松的搞定接口數(shù)據(jù)校驗(yàn),而不需要在業(yè)務(wù)邏輯中編寫大量的if-else來進(jìn)行數(shù)據(jù)合法性校驗(yàn)。而定義好Bean參數(shù)對象并使用相關(guān)注解實(shí)現(xiàn)參數(shù)值約束后,在Controller層接口定義中只需要使用@Validated注解就可以實(shí)現(xiàn)在接收參數(shù)后自動進(jìn)行數(shù)據(jù)綁定校驗(yàn)了,具體代碼如下:

@PostMapping("/createOrder") public CreateOrderBO validationTest(@Validated CreateOrderDTO createOrderDTO) {     return orderServiceImpl.createOrder(createOrderDTO); }

如上所示,在Controller層中通過Spring提供的@Validated注解可以自動實(shí)現(xiàn)數(shù)據(jù)Bean的綁定校驗(yàn),如果數(shù)據(jù)異常則會統(tǒng)一拋出校驗(yàn)異常!

約束性注解擴(kuò)展

在“hibernate-validator”依賴jar包中,雖然提供了很多很方便的約束注解,但是也有不滿足某些實(shí)際需要的情況,例如我們想針對參數(shù)中的某個值約定其值的枚舉范圍,如orderType訂單類型只允許傳“pay”、“refund”兩種值,那么現(xiàn)有的約束注解可能就沒有特別適用的了。此外,如果對這樣的枚舉值,我們還想在約束定義中直接匹配代碼中的枚舉定義,以更好地統(tǒng)一接口參數(shù)與業(yè)務(wù)邏輯的枚舉定義。那么這種情況下,我們還可以自己擴(kuò)展定義相應(yīng)地約束注解邏輯。

接下來我們定義新的約束注解@EnumValue,來實(shí)現(xiàn)上面我們所說的效果,具體代碼如下:

@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER}) @Retention(RUNTIME) @Documented @Constraint(validatedBy = {EnumValueValidator.class}) public @interface EnumValue {      //默認(rèn)錯誤消息     String message() default "必須為指定值";      //支持string數(shù)組驗(yàn)證     String[] strValues() default {};      //支持int數(shù)組驗(yàn)證     int[] intValues() default {};      //支持枚舉列表驗(yàn)證     Class[] enumValues() default {};      //分組     Class[] groups() default {};      //負(fù)載     Class[] payload() default {};      //指定多個時使用     @Target({FIELD, METHOD, PARAMETER, ANNOTATION_TYPE})     @Retention(RUNTIME)     @Documented     @interface List {         EnumValue[] value();     }      /**      * 校驗(yàn)類邏輯定義      */     class EnumValueValidator implements ConstraintValidator {          //字符串類型數(shù)組         private String[] strValues;         //int類型數(shù)組         private int[] intValues;         //枚舉類         private Class[] enumValues;          /**          * 初始化方法          *          * @param constraintAnnotation          */         @Override         public void initialize(EnumValue constraintAnnotation) {             strValues = constraintAnnotation.strValues();             intValues = constraintAnnotation.intValues();             enumValues = constraintAnnotation.enumValues();         }          /**          * 校驗(yàn)方法          *          * @param value          * @param context          * @return          */         @SneakyThrows         @Override         public boolean isValid(Object value, ConstraintValidatorContext context) {             //針對字符串?dāng)?shù)組的校驗(yàn)匹配             if (strValues != null && strValues.length > 0) {                 if (value instanceof String) {                     for (String s : strValues) {//判斷值類型是否為Integer類型                         if (s.equals(value)) {                             return true;                         }                     }                 }             }             //針對整型數(shù)組的校驗(yàn)匹配             if (intValues != null && intValues.length > 0) {                 if (value instanceof Integer) {//判斷值類型是否為Integer類型                     for (Integer s : intValues) {                         if (s == value) {                             return true;                         }                     }                 }             }             //針對枚舉類型的校驗(yàn)匹配             if (enumValues != null && enumValues.length > 0) {                 for (Class cl : enumValues) {                     if (cl.isEnum()) {                         //枚舉類驗(yàn)證                         Object[] objs = cl.getEnumConstants();                         //這里需要注意,定義枚舉時,枚舉值名稱統(tǒng)一用value表示                         Method method = cl.getMethod("getValue");                         for (Object obj : objs) {                             Object code = method.invoke(obj, null);                             if (value.equals(code.toString())) {                                 return true;                             }                         }                     }                 }             }             return false;         }     } }

如上所示的@EnumValue約束注解,是一個非常實(shí)用的擴(kuò)展,通過該注解我們可以實(shí)現(xiàn)對參數(shù)取值范圍(不是大小范圍)的約束,它支持對int、string以及enum三種數(shù)據(jù)類型的約束,具體使用方式如下:

/**  * 定制化注解,支持參數(shù)值與指定類型數(shù)組列表值進(jìn)行匹配(缺點(diǎn)是需要將枚舉值寫死在字段定義的注解中)  */ @EnumValue(strValues = {"pay", "refund"}, message = "訂單類型錯誤") private String orderType; /**  * 定制化注解,實(shí)現(xiàn)參數(shù)值與枚舉列表的自動匹配校驗(yàn)(能更好地與實(shí)際業(yè)務(wù)開發(fā)匹配)  */ @EnumValue(enumValues = Status.class, message = "狀態(tài)值不在指定范圍") private String status;

如上所示代碼,該擴(kuò)展注解既可以使用strValues或intValues屬性來編程列舉取值范圍,也可以直接通過enumValues來綁定枚舉定義。但是需要注意,處于通用考慮,具體枚舉定義的屬性的名稱要統(tǒng)一匹配為value、desc,例如Status枚舉定義如下:

public enum Status {     PROCESSING(1, "處理中"),     SUCCESS(2, "訂單已完成");     Integer value;     String desc;      Status(Integer value, String desc) {         this.value = value;         this.desc = desc;     }      public Integer getValue() {         return value;     }      public String getDesc() {         return desc;     } }

通過注解擴(kuò)展,就能實(shí)現(xiàn)更多方便的約束性注解!

更加靈活的數(shù)據(jù)校驗(yàn)工具類封裝

除了上面直接在Controller層使用@Validated進(jìn)行綁定數(shù)據(jù)校驗(yàn)外,在有些情況,例如你的參數(shù)對象中的某個字段是一個復(fù)合對象,或者業(yè)務(wù)層的某個方法所定義的入?yún)ο笠残枰M(jìn)行數(shù)據(jù)合法性校驗(yàn),那么這種情況下如何實(shí)現(xiàn)像Controller層一樣的校驗(yàn)效果呢?

需要說明在這種情況下@Validated已經(jīng)無法直接使用了,因?yàn)锧Validated注解發(fā)揮作用主要是Spring  MVC在接收參數(shù)的過程中實(shí)現(xiàn)了自動數(shù)據(jù)綁定校驗(yàn),而在普通的業(yè)務(wù)方法或者復(fù)合參數(shù)對象中是沒有辦法直接綁定校驗(yàn)的。這種情況下,我們可以通過定義ValidateUtils工具類來實(shí)現(xiàn)一樣的校驗(yàn)效果,具體代碼如下:

public class ValidatorUtils {      private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator();      /**      * bean整體校驗(yàn),有不合規(guī)范,拋出第1個違規(guī)異常      */     public static void validate(Object obj, Class... groups) {         Set> resultSet = validator.validate(obj, groups);         if (resultSet.size() > 0) {             //如果存在錯誤結(jié)果,則將其解析并進(jìn)行拼湊后異常拋出             List errorMessageList = resultSet.stream().map(o -> o.getMessage()).collect(Collectors.toList());             StringBuilder errorMessage = new StringBuilder();             errorMessageList.stream().forEach(o -> errorMessage.append(o + ";"));             throw new IllegalArgumentException(errorMessage.toString());         }     } }

如上所示,我們定義了一個基于"javax.validation"接口的工具類實(shí)現(xiàn),這樣就可以在非@Validated直接綁定校驗(yàn)的場景中通過校驗(yàn)工具類來實(shí)現(xiàn)對Bean對象約束注解的校驗(yàn)處理,具體使用代碼如下:

public boolean orderCheck(OrderCheckBO orderCheckBO) {     //對參數(shù)對象進(jìn)行數(shù)據(jù)校驗(yàn)     ValidatorUtils.validate(orderCheckBO);     return true; }

而方法入?yún)ο髣t還是可以繼續(xù)使用前面我們介紹的約束性注解進(jìn)行約定,例如上述方法的入?yún)ο蠖x如下:

@Data @Builder public class OrderCheckBO {      @NotNull(message = "訂單號不能為空")     private String orderId;     @Min(value = 1, message = "訂單金額不能小于0")     private Integer orderAmount;     @NotNull(message = "創(chuàng)建人不能為空")     private String operator;     @NotNull(message = "操作時間不能為空")     private String operatorTime; }

這樣在編程體驗(yàn)上就可以整體上保持一致!

數(shù)據(jù)合法性校驗(yàn)結(jié)果異常統(tǒng)一處理

通過前面我們所講的各種約束注解,我們實(shí)現(xiàn)了對Controller層接口以及業(yè)務(wù)方法參數(shù)對象的統(tǒng)一數(shù)據(jù)校驗(yàn)。而為了保持校驗(yàn)異常處理的統(tǒng)一處理和錯誤報(bào)文統(tǒng)一輸出,我們還可以定義通用的異常處理機(jī)制,來保證各類數(shù)據(jù)校驗(yàn)錯誤都能以統(tǒng)一錯誤格式反饋給調(diào)用方。具體代碼如下:

@Slf4j @ControllerAdvice public class GlobalExceptionHandler {     /**      * 統(tǒng)一處理參數(shù)校驗(yàn)錯誤異常(非Spring接口數(shù)據(jù)綁定驗(yàn)證)      *      * @param response      * @param e      * @return      */     @ExceptionHandler(BindException.class)     @ResponseBody     public ResponseResult processValidException(HttpServletResponse response, BindException e) {         response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());         //獲取校驗(yàn)錯誤結(jié)果信息,并將信息組裝         List errorStringList = e.getBindingResult().getAllErrors()                 .stream().map(ObjectError::getDefaultMessage).collect(Collectors.toList());         String errorMessage = String.join("; ", errorStringList);         response.setContentType("application/json;charset=UTF-8");         log.error(e.toString() + "_" + e.getMessage(), e);         return ResponseResult.systemException(GlobalCodeEnum.GL_FAIL_9998.getCode(),                 errorMessage);     }      /**      * 統(tǒng)一處理參數(shù)校驗(yàn)錯誤異常      *      * @param response      * @param e      * @return      */     @ExceptionHandler(IllegalArgumentException.class)     @ResponseBody     public ResponseResult processValidException(HttpServletResponse response, IllegalArgumentException e) {         response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());         String errorMessage = String.join("; ", e.getMessage());         response.setContentType("application/json;charset=UTF-8");         log.error(e.toString() + "_" + e.getMessage(), e);         return ResponseResult.systemException(GlobalCodeEnum.GL_FAIL_9998.getCode(),                 errorMessage);     }      ... }

如上所示,我們定義了針對前面兩種數(shù)據(jù)校驗(yàn)方式的統(tǒng)一異常處理機(jī)制,這樣數(shù)據(jù)校驗(yàn)的錯誤信息就能通過統(tǒng)一的報(bào)文格式反饋給調(diào)用端,從而實(shí)現(xiàn)接口數(shù)據(jù)報(bào)文的統(tǒng)一返回!

其中通用的接口參數(shù)對象ResponseResult的代碼定義如下:

@Data @Builder @NoArgsConstructor @AllArgsConstructor @JsonPropertyOrder({"code", "message", "data"}) public class ResponseResult implements Serializable {      private static final long serialVersionUID = 1L;      /**      * 返回的對象      */     @JsonInclude(JsonInclude.Include.NON_NULL)     private T data;     /**      * 返回的編碼      */     private Integer code;     /**      * 返回的信息      */     private String message;      /**      * @param data 返回的數(shù)據(jù)      * @param   返回的數(shù)據(jù)類型      * @return 響應(yīng)結(jié)果      */     public static  ResponseResult OK(T data) {         return packageObject(data, GlobalCodeEnum.GL_SUCC_0);     }      /**      * 自定義系統(tǒng)異常信息      *      * @param code      * @param message 自定義消息      * @param       * @return      */     public static  ResponseResult systemException(Integer code, String message) {         return packageObject(null, code, message);     } }

當(dāng)然,這樣的統(tǒng)一報(bào)文格式也不僅僅只處理異常返回,正常的數(shù)據(jù)報(bào)文格式也可以通過該對象來進(jìn)行統(tǒng)一封裝!

看完上述內(nèi)容,你們對Java中怎么實(shí)現(xiàn)接口數(shù)據(jù)校驗(yàn)有進(jìn)一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。


當(dāng)前標(biāo)題:Java中怎么實(shí)現(xiàn)接口數(shù)據(jù)校驗(yàn)
URL地址:http://weahome.cn/article/gijocj.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部