省住房与城乡建设厅网站,聊城网站建设聊城,旅游网页设计页面 模板html,dw做网站的导航栏文章目录前言注意实现测试环境验证自带的注解自定义valid注解自定义注解和处理类创建参数接收类#xff0c;并增加字段注解接口中使用自测环节正常测试异常测试自定义全局异常监听扩展递归参数下valid不识别的坑前言
再项目开发中#xff0c;针对前端传递的参数信息#xf…
文章目录前言注意实现测试环境验证自带的注解自定义valid注解自定义注解和处理类创建参数接收类并增加字段注解接口中使用自测环节正常测试异常测试自定义全局异常监听扩展递归参数下valid不识别的坑前言
再项目开发中针对前端传递的参数信息有些接口中需要写大量的if判断导致代码臃肿不够优雅。
此时可以使用Valid实现基本的字段校验。
注意实现
springboot 2.3之前 直接进行开发即可无需引用额外的依赖 集成在spring-boot-starter-web中。springboot 2.3之后 需要额外引入spring-boot-starter-validation依赖信息
测试环境
springboot 2.1.4
如果你的springboot版本高于 2.3需要额外引入下列依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-validation/artifactId
/dependency验证自带的注解
验证自带的注解以及实现原理可以移步到我的另一篇博客中本篇博客不做过多的阐述。 做一个优雅的接口 自定义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 POrderParse.class) // 注解对应的处理类
Target({ElementType.METHOD, ElementType.FIELD})
Retention(RetentionPolicy.RUNTIME)
public interface POrder {// 默认提示语句String message() default 排序号不允许为空且只允许是1到20的数字;// 默认校验正则表达式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 ConstraintValidatorPOrder,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;// 获取注解中的属性值MapString, Object maps con.getConstraintDescriptor().getAttributes();// 获取设置的或者默认的正则表达式String regexp (String) maps.get(regexp);// 获取数据值String param String.valueOf(value);// 正则判断Pattern regexpVo Pattern.compile(regexp);Matcher matcher regexpVo.matcher(param);return matcher.matches();}
}创建参数接收类并增加字段注解
import cn.xj.bi.volid.MyPhone;
import cn.xj.bi.volid.POrder;
import lombok.Data;Data
public class User {POrderprivate Integer order;
}接口中使用
创建一个测试接口进行应用测试。 需要使用到Valid注解标识 RestController
RequestMapping(/test1)
Api(tags 测试)
public class TestController {PostMapping(/demo4)ApiOperation(value demo4)public CommonResultString test4(RequestBody Valid User user){return CommonResult.success(6666);}
)自测环节
启动项目进入swagger进行请求测试。
正常测试
传递满足正则要求的值查看返回结果信息。
{order: 10
}异常测试
参数中传递一个不满足正则表达式的值观察返回信息。
{order: 0
}自定义全局异常监听
每次返回这样的报错信息不够直观此时可以自定义全局异常监听如下所示
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() 的区别return CommonResult.error( Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage(), null);}
}重启项目再次异常测试
扩展
递归参数下valid不识别的坑
递归参数的意思就是接收对象是一个类假设是DataScope但是在这个接收类中还有一个ListUser这个参数变量并且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 ConstraintValidatorMyPhone,Object {Overridepublic boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {System.out.println(校验);// 故意返回false触发异常return false;}
}然后再请求参数接收对象中定义如下格式
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 是否触发valid校验。
{order: 10,address:{phoneNum:}
}发现并未触发对应的valid校验。
解决方式很简单没有触发说明注解无效接口中定义Valid User 是对user对象进行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;
}重启项目继续按照上面的传参观察响应信息。