如何在建設(shè)教育協(xié)會網(wǎng)站注冊考試智能營銷系統(tǒng)
文章目錄
- 前言
- 注意實現(xiàn)
- 測試環(huán)境
- 驗證自帶的注解
- 自定義valid注解
- 自定義注解和處理類
- 創(chuàng)建參數(shù)接收類,并增加字段注解
- 接口中使用
- 自測環(huán)節(jié)
- 正常測試
- 異常測試
- 自定義全局異常監(jiān)聽
- 擴(kuò)展
- 遞歸參數(shù)下valid不識別的坑
前言
再項目開發(fā)中,針對前端傳遞的參數(shù)信息,有些接口中需要寫大量的if
判斷,導(dǎo)致代碼臃腫,不夠優(yōu)雅。
此時,可以使用@Valid
實現(xiàn)基本的字段校驗。
注意實現(xiàn)
- springboot 2.3之前 ,直接進(jìn)行開發(fā)即可,無需引用額外的依賴
集成在spring-boot-starter-web
中。 - springboot 2.3之后 需要額外引入
spring-boot-starter-validation
依賴信息
測試環(huán)境
springboot 2.1.4
如果你的springboot版本高于 2.3
,需要額外引入下列依賴:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency>
驗證自帶的注解
驗證自帶的注解,以及實現(xiàn)原理,可以移步到我的另一篇博客中,本篇博客不做過多的闡述。
做一個優(yōu)雅的接口
自定義valid注解
官方提供的一些常用的注解,有時候并不能適合所有的開發(fā)需求。此時可以采取自定義valid
的方式,實現(xiàn)其應(yīng)有的功能。
自定義注解和處理類
創(chuàng)建一個自定義的注解
檢查排序號是否輸入,以及是否滿足要求。
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Constraint(validatedBy = POrderParse.class) // 注解對應(yīng)的處理類
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface POrder {// 默認(rèn)提示語句String message() default "排序號不允許為空,且只允許是1到20的數(shù)字!";// 默認(rèn)校驗正則表達(dá)式String regexp() default "^([1-9])|([1]\\d)|20$";Class<?>[] groups() default { };Class<? extends Payload>[] payload() default { };}
定義注解后,還需要定義其指定的處理類
,如下所示:
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;@Component
public class POrderParse implements ConstraintValidator<POrder,Object> {@Overridepublic void initialize(POrder constraintAnnotation) {System.out.println("my para order validator init");}@Overridepublic boolean isValid(Object value, ConstraintValidatorContext context) {// 校驗邏輯ConstraintValidatorContextImpl con = (ConstraintValidatorContextImpl) context;// 獲取注解中的屬性值Map<String, Object> maps = con.getConstraintDescriptor().getAttributes();// 獲取設(shè)置的或者默認(rèn)的正則表達(dá)式String regexp = (String) maps.get("regexp");// 獲取數(shù)據(jù)值String param = String.valueOf(value);// 正則判斷Pattern regexpVo = Pattern.compile(regexp);Matcher matcher = regexpVo.matcher(param);return matcher.matches();}
}
創(chuàng)建參數(shù)接收類,并增加字段注解
import cn.xj.bi.volid.MyPhone;
import cn.xj.bi.volid.POrder;
import lombok.Data;@Data
public class User {@POrderprivate Integer order;
}
接口中使用
創(chuàng)建一個測試接口,進(jìn)行應(yīng)用測試。
需要使用到
@Valid
注解標(biāo)識
@RestController
@RequestMapping("/test1")
@Api(tags = "測試")
public class TestController {@PostMapping("/demo4")@ApiOperation(value = "demo4")public CommonResult<String> test4(@RequestBody @Valid User user){return CommonResult.success("6666");}
)
自測環(huán)節(jié)
啟動項目,進(jìn)入swagger進(jìn)行請求測試。
正常測試
傳遞滿足正則要求
的值,查看返回結(jié)果信息。
{"order": 10
}
異常測試
參數(shù)中傳遞一個不滿足正則
表達(dá)式的值,觀察返回信息。
{"order": 0
}
自定義全局異常監(jiān)聽
每次返回這樣的報錯信息不夠直觀,此時可以自定義全局異常監(jiān)聽,如下所示:
import cn.xj.bi.vo.CommonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.Objects;@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(MethodArgumentNotValidException.class)public CommonResult handleScopeFiledException(MethodArgumentNotValidException e) {log.error("字段合法性校驗異常:[{}]", e.getMessage());// getFieldError() 和 getDefaultMessage() 的區(qū)別return CommonResult.error( Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage(), null);}
}
重啟項目,再次異常測試:
擴(kuò)展
遞歸參數(shù)下valid不識別的坑
遞歸參數(shù)的意思就是接收對象是一個類,假設(shè)是DataScope
,但是在這個接收類中,還有一個List<User>
這個參數(shù)變量,并且User
中依舊還含有需要valid
校驗的字段屬性。
再自定義一個valid注解,如下所示:
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Constraint(validatedBy = {MyPhoneValidtor.class})
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyPhone {String message();Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};}
valid注解具體處理類:
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;public class MyPhoneValidtor implements ConstraintValidator<MyPhone,Object> {@Overridepublic boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {System.out.println("校驗");// 故意返回false,觸發(fā)異常return false;}
}
然后再請求參數(shù)接收對象中,定義如下格式:
import cn.xj.bi.volid.POrder;
import lombok.Data;@Data
public class User {@POrderprivate Integer order;private Address address;
}
import cn.xj.bi.volid.MyPhone;
import lombok.Data;
import java.io.Serializable;@Data
public class Address implements Serializable {@MyPhone(message = "這只是一個測試")private String phoneNum;
}
重啟項目,傳遞正常的 order
值,觀察Address 類中的 phoneNum
是否觸發(fā)valid校驗。
{"order": 10,"address":{"phoneNum":""}
}
發(fā)現(xiàn)并未觸發(fā)對應(yīng)的valid校驗。
解決方式很簡單,沒有觸發(fā)說明注解無效,接口中定義@Valid User
是對user對象進(jìn)行valid處理,但對象類型的并不在列,只需要在對象類型的變量上增加@Valid
注解即可。
import cn.xj.bi.volid.POrder;
import lombok.Data;import javax.validation.Valid;@Data
public class User {@POrderprivate Integer order;@Valid // 迭代validprivate Address address;
}
重啟項目,繼續(xù)按照上面的傳參,觀察響應(yīng)信息。