SpringBoot学习 -JRS303 做后端数据校验整合

tech2025-06-17  2

JRS303 做后端数据校验

1. 引入springboot整合jrs依赖

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>

2. 普通校验

1、给bean添加校验注解

@Data @TableName("pms_brand") public class BrandEntity implements Serializable { private static final long serialVersionUID = 1L; /** * 品牌id */ @Null(message = "新增不能指定ID") @NotNull(message = "修改必须指定ID") @TableId private Long brandId; /** * 品牌名 */ @NotBlank(message = "品牌名必须提交") private String name; /** * 品牌logo地址 */ @NotBlank(message = "品牌logo地址必须提交") @URL(message = "logo必须是一个合法的URL地址") private String logo; /** * 介绍 */ private String descript; /** * 显示状态[0-不显示;1-显示] */ //自定义注解 private Integer showStatus; /** * 检索首字母 */ @NotBlank(message = "检索首字母必须提交") @Pattern(regexp = "^[a-zA-Z]$",message = "检索首字母必须是一个字母") private String firstLetter; /** * 排序 */ @NotNull(message = "排序必须提交") @Min(value = 0,message = "排序必须大于等于0") private Integer sort; }

2、在controller层方法的参数上开启校验功能

可以给校验的参数bean在controller的方法参数紧跟一个BindResult参数 可以自定义错误处理

@RequestMapping("/save") public R save(@Valid @RequestBody BrandEntity brand,BindingResult bindingResult){ if(bindingResult.hasErrors()){ //获取校验的错误结果 Map<String,String > map = new HashMap<>(); bindingResult.getFieldErrors().forEach(item ->{ String message = item.getDefaultMessage(); String field = item.getField(); map.put(field,message); }); return R.error(400,"提交的数据不合法").put("data",map); }else{ brandService.save(brand); return R.ok(); } brandService.save(brand); return R.ok(); }

3、统一异常处理

避免在controller层处理异常,使用统一异常处理@RestControllerAdvice

@RequestMapping("/save") public R save(@Valid @RequestBody BrandEntity brand){ //不添加bindingresult时异常会抛出 brandService.save(brand); return R.ok(); }

新建异常处理类捕获处理异常

/** * 集中处理所有异常 */ @Slf4j @RestControllerAdvice(basePackages = "com.rwp.gulimail.product.controller") public class GulimailExceptionControllerAdvice { @ExceptionHandler(value = MethodArgumentNotValidException.class) public R handleVaildException(MethodArgumentNotValidException e){ log.error("数据校验出现问题:"+e.getMessage()+e.getClass()); BindingResult bindingResult = e.getBindingResult(); //获取校验的错误结果 Map<String,String > map = new HashMap<>(); bindingResult.getFieldErrors().forEach(item ->{ String message = item.getDefaultMessage(); String field = item.getField(); map.put(field,message); }); return R.error(BizCodeEnume.VALID_EXCEPTION.getCode(),BizCodeEnume.VALID_EXCEPTION.getMessage()).put("data",map); } //全局异常 @ExceptionHandler(value = Throwable.class) public R handleException(Throwable throwable){ return R.error(BizCodeEnume.UNKONW_EXCEPTION.getCode(),BizCodeEnume.UNKONW_EXCEPTION.getMessage()); } }

3. 分组校验(多场景复杂校验)

1、新建场景接口作为标志(不做任何处理)

public interface AddGroup {} public interface UpdateGroup {}

2、实体类的校验标签添加groups属性

@Data @TableName("pms_brand") public class BrandEntity implements Serializable { private static final long serialVersionUID = 1L; /** * 品牌id */ @Null(message = "新增不能指定ID",groups = {AddGroup.class}) @NotNull(message = "修改必须指定ID",groups = {UpdateGroup.class}) @TableId private Long brandId; /** * 品牌名 */ @NotBlank(message = "品牌名必须提交",groups = {AddGroup.class,UpdateGroup.class}) private String name; /** * 品牌logo地址 */ @NotBlank(message = "品牌logo地址必须提交" ,groups = {AddGroup.class}) @URL(message = "logo必须是一个合法的URL地址" ,groups = {AddGroup.class,UpdateGroup.class}) private String logo; /** * 介绍 */ private String descript; /** * 显示状态[0-不显示;1-显示] */ private Integer showStatus; /** * 检索首字母 */ @NotBlank(message = "检索首字母必须提交" ,groups = {AddGroup.class}) @Pattern(regexp = "^[a-zA-Z]$",message = "检索首字母必须是一个字母" ,groups = {AddGroup.class,UpdateGroup.class}) private String firstLetter; /** * 排序 */ @NotNull(message = "排序必须提交",groups = {AddGroup.class}) @Min(value = 0,message = "排序必须大于等于0" ,groups = {AddGroup.class,UpdateGroup.class}) private Integer sort; }

3、controller的方法参数指定属于哪一个groups @Validated

默认没有指定分组的校验注解 在分组的校验情况下不生效,只会在@Valid生效

@RequestMapping("/save") public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand){ brandService.save(brand); return R.ok(); }

4. 自定义校验

引入依赖

<dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency>

效果

给BrandEntity的showstatus属性添加自定义校验,目的:showstatus的值只能为0或1

@Data @TableName("pms_brand") public class BrandEntity implements Serializable { private static final long serialVersionUID = 1L; /** * .............. */ /** * 显示状态[0-不显示;1-显示] */ //自定义注解 @ListValue(values={0,1},groups = {AddGroup.class}) private Integer showStatus; /** * .......... */ }

1、编写一个自定义的检验注解

@Documented @Constraint( validatedBy = {ListValueConstraintValidator.class} ) @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE}) @Retention(RetentionPolicy.RUNTIME) public @interface ListValue { //前三个是jrs303的规范 String message() default "{com.rwp.common.valid.ListValue.message}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; int[] values() default {}; //自己添加的属性 }

2、编写一个自定义的校验器

public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer>{ //泛型第一个为注解类型,第二个为注解标注的属性的类型 private Set<Integer> set = new HashSet<>(); //初始化方法 @Override public void initialize(ListValue constraintAnnotation) { int[] values = constraintAnnotation.values(); for (int value: values ) { set.add(value); } } //判断是否校验成功 @Override public boolean isValid(Integer integer, ConstraintValidatorContext constraintValidatorContext) { if(set.contains(integer)){ return true; }else { return false; } } }

3、关联自定义的校验器和自定义的校验注解

1、校验器实现的接口泛型指明注解属性

public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer>{

2、注解使用@Constraint添加校验器

@Documented @Constraint( validatedBy = {ListValueConstraintValidator.class} ) @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE}) @Retention(RetentionPolicy.RUNTIME) public @interface ListValue {
最新回复(0)