前言
再項(xiàng)目開發(fā)中,針對前端傳遞的參數(shù)信息,有些接口中需要寫大量的if
判斷,導(dǎo)致代碼臃腫,不夠優(yōu)雅。
此時,可以使用@Valid
實(shí)現(xiàn)基本的字段校驗(yàn)。
注意實(shí)現(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>
驗(yàn)證自帶的注解
驗(yàn)證自帶的注解,以及實(shí)現(xiàn)原理,可以移步到我的另一篇博客中,本篇博客不做過多的闡述。
做一個優(yōu)雅的接口
自定義valid注解
官方提供的一些常用的注解,有時候并不能適合所有的開發(fā)需求。此時可以采取自定義valid
的方式,實(shí)現(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)校驗(yà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> {
@Override
public void initialize(POrder constraintAnnotation) {
System.out.println("my para order validator init");
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
// 校驗(yàn)邏輯
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 {
@POrder
private 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é)
啟動項(xiàng)目,進(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("字段合法性校驗(yàn)異常:[{}]", e.getMessage());
// getFieldError() 和 getDefaultMessage() 的區(qū)別
return CommonResult.error( Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage(), null);
}
}
重啟項(xiàng)目,再次異常測試:
擴(kuò)展
遞歸參數(shù)下valid不識別的坑
遞歸參數(shù)的意思就是接收對象是一個類,假設(shè)是DataScope
,但是在這個接收類中,還有一個List<User>
這個參數(shù)變量,并且User
中依舊還含有需要valid
校驗(yàn)的字段屬性。
再自定義一個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> {
@Override
public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
System.out.println("校驗(yàn)");
// 故意返回false,觸發(fā)異常
return false;
}
}
然后再請求參數(shù)接收對象中,定義如下格式:
import cn.xj.bi.volid.POrder;
import lombok.Data;
@Data
public class User {
@POrder
private 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;
}
重啟項(xiàng)目,傳遞正常的 order
值,觀察Address 類中的 phoneNum
是否觸發(fā)valid校驗(yàn)。
{
"order": 10,
"address":{
"phoneNum":""
}
}
發(fā)現(xiàn)并未觸發(fā)對應(yīng)的valid校驗(yàn)。
解決方式很簡單,沒有觸發(fā)說明注解無效,接口中定義@Valid User
是對user對象進(jìn)行valid處理,但對象類型的并不在列,只需要在對象類型的變量上增加@Valid
注解即可。文章來源:http://www.zghlxwxcb.cn/news/detail-426139.html
import cn.xj.bi.volid.POrder;
import lombok.Data;
import javax.validation.Valid;
@Data
public class User {
@POrder
private Integer order;
@Valid // 迭代valid
private Address address;
}
重啟項(xiàng)目,繼續(xù)按照上面的傳參,觀察響應(yīng)信息。文章來源地址http://www.zghlxwxcb.cn/news/detail-426139.html
到了這里,關(guān)于Springboot——@valid 做字段校驗(yàn)和自定義注解的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!