aop+注解实现对实体类的字段校验_SpringBoot中处理校验逻
辑的两种⽅式,真的很机智!
Hibernate Validator
Hibernate Validator是SpringBoot内置的校验框架,只要集成了SpringBoot就⾃动集成了它,我们可以通过在对象上⾯使⽤它提供的注解来完成参数校验。
常⽤注解
我们先来了解下常⽤的注解,对Hibernate Validator所提供的校验功能有个印象。
@Null:被注释的属性必须为null;
@NotNull:被注释的属性不能为null;
@AssertTrue:被注释的属性必须为true;
@AssertFalse:被注释的属性必须为false;
@Min:被注释的属性必须⼤于等于其value值;
@Max:被注释的属性必须⼩于等于其value值;
@Size:被注释的属性必须在其min和max值之间;
@Pattern:被注释的属性必须符合其regexp所定义的正则表达式;
@NotBlank:被注释的字符串不能为空字符串;
@NotEmpty:被注释的属性不能为空;
@Email:被注释的属性必须符合邮箱格式。
使⽤⽅式
接下来我们以添加品牌接⼝的参数校验为例来讲解下Hibernate Validator的使⽤⽅法,其中涉及到⼀些AOP的知识,不了解的朋友可以参考下《SpringBoot应⽤中使⽤AOP记录接⼝访问⽇志》。
⾸先我们需要在添加品牌接⼝的参数PmsBrandParam中添加校验注解,⽤于确定属性的校验规则及校验失败后需要返回的信息;
* 品牌传递参数
* Created by macro on 2018/4/26.
*/
public class PmsBrandParam {
@ApiModelProperty(value = "品牌名称",required = true)
@NotEmpty(message = "名称不能为空")
private String name;
@ApiModelProperty(value = "品牌⾸字母")
private String firstLetter;
@ApiModelProperty(value = "排序字段")
@Min(value = 0, message = "排序最⼩为0")
private Integer sort;
@ApiModelProperty(value = "是否为⼚家制造商")
@FlagValidator(value = {"0","1"}, message = "⼚家状态不正确")
private Integer factoryStatus;
@ApiModelProperty(value = "是否进⾏显⽰")
@FlagValidator(value = {"0","1"}, message = "显⽰状态不正确")
private Integer showStatus;
@ApiModelProperty(value = "品牌logo",required = true)
@NotEmpty(message = "品牌logo不能为空")
private String logo;
@ApiModelProperty(value = "品牌⼤图")
private String bigPic;
@ApiModelProperty(value = "品牌故事")
private String brandStory;
//省略若⼲Getter和Setter⽅法...
}
然后在添加品牌的接⼝中添加@Validated注解,并注⼊⼀个BindingResult参数;
/**
* 品牌功能Controller
* Created by macro on 2018/4/26.
*/
@Controller
@Api(tags = "PmsBrandController", description = "商品品牌管理")
@RequestMapping("/brand")
public class PmsBrandController {
@Autowired
private PmsBrandService brandService;
@ApiOperation(value = "添加品牌")
@RequestMapping(value = "/create", method = RequestMethod.POST)
@ResponseBody
public CommonResult create(@Validated @RequestBody PmsBrandParam pmsBrand, BindingResult result) {
CommonResult commonResult;
int count = ateBrand(pmsBrand);
if (count == 1) {
commonResult = CommonResult.success(count);
} else {
commonResult = CommonResult.failed();
}
return commonResult;
}
}
然后在整个Controller层创建⼀个切⾯,在其环绕通知中获取到注⼊的BindingResult对象,通过hasErrors⽅法判断校验是否通过,如果有错误信息直接返回错误信息,验证通过则放⾏;
* HibernateValidator错误结果处理切⾯
* Created by macro on 2018/4/26.
*/
@Aspect
@Component
@Order(2)
public class BindingResultAspect {
@Pointcut("execution(public * com.ller.*.*(..))")
public void BindingResult() {
}
@Around("BindingResult()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = Args();
for (Object arg : args) {
if (arg instanceof BindingResult) {
BindingResult result = (BindingResult) arg;
if (result.hasErrors()) {
FieldError fieldError = FieldError();
if(fieldError!=null){
return CommonResult.DefaultMessage());
}else{
return CommonResult.validateFailed();
}
}
}
}
return joinPoint.proceed();
}
}
此时我们访问添加品牌的接⼝,不传⼊name字段,就会返回名称不能为空的错误信息;
⾃定义注解
有时候框架提供的校验注解并不能满⾜我们的需要,此时我们就需要⾃定义校验注解。⽐如还是上⾯的添加品牌,此时有个参数showStatus,我们希望它只能是0或者1,不能是其他数字,此时可以使⽤⾃定义注解来实现该功能。
⾸先⾃定义⼀个校验注解类FlagValidator,然后添加@Constraint注解,使⽤它的validatedBy属性指定校验逻辑的具体实现类;
springboot aop* ⽤户验证状态是否在指定范围内的注解
* Created by macro on 2018/4/26.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.PARAMETER})
@Constraint(validatedBy = FlagValidatorClass.class)
public @interface FlagValidator {
String[] value() default {};
String message() default "flag is not found";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
然后创建FlagValidatorClass作为校验逻辑的具体实现类,实现ConstraintValidator接⼝,这⾥需要指定两个泛型参数,第⼀个需要指定为你⾃定义的校验注解类,第⼆个指定为你要校验属性的类型,isValid⽅法中就是具体的校验逻辑。
/**
* 状态标记校验器
* Created by macro on 2018/4/26.
*/
public class FlagValidatorClass implements ConstraintValidator<FlagValidator,Integer> {
private String[] values;
@Override
public void initialize(FlagValidator flagValidator) {
this.values = flagValidator.value();
}
@Override
public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
boolean isValid = false;
if(value==null){
//当状态为空时使⽤默认值
return true;
}
for(int i=0;i<values.length;i++){
if(values[i].equals(String.valueOf(value))){
isValid = true;
break;
}
}
return isValid;
}
}
接下来我们就可以在传参对象中使⽤该注解了;
* 品牌传递参数
* Created by macro on 2018/4/26.
*/
public class PmsBrandParam {
@ApiModelProperty(value = "是否进⾏显⽰")
@FlagValidator(value = {"0","1"}, message = "显⽰状态不正确")
private Integer showStatus;
//省略若⼲Getter和Setter⽅法...
}
最后我们测试下该注解,调⽤接⼝是传⼊showStatus=3,会返回显⽰状态不正确的错误信息。
优缺点
这种⽅式的优点是可以使⽤注解来实现参数校验,不需要⼀些重复的校验逻辑,但是也有⼀些缺点,⽐如需要在Controller的⽅法中额外注⼊⼀个BindingResult对象,只⽀持⼀些简单的校验,涉及到要查
询数据库的校验就⽆法满⾜了。
全局异常处理
使⽤全局异常处理来处理校验逻辑的思路很简单,⾸先我们需要通过@ControllerAdvice注解定义⼀个全局异常的处理类,然后⾃定义⼀个校验异常,当我们在Controller中校验失败时,直接抛出该异常,这样就可以达到校验失败返回错误信息的⽬的了。
使⽤到的注解
@ControllerAdvice:类似于@Component注解,可以指定⼀个组件,这个组件主要⽤于增强@Controller注解修饰的类的功能,⽐如说进⾏全局异常处理。
@ExceptionHandler:⽤来修饰全局异常处理的⽅法,可以指定异常的类型。
使⽤⽅式
⾸先我们需要⾃定义⼀个异常类ApiException,当我们校验失败时抛出该异常:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。