JRS303 做后端数据校验
1. 引入springboot整合jrs依赖
<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
;
@Null(message
= "新增不能指定ID")
@NotNull(message
= "修改必须指定ID")
@TableId
private Long brandId
;
@NotBlank(message
= "品牌名必须提交")
private String name
;
@NotBlank(message
= "品牌logo地址必须提交")
@URL(message
= "logo必须是一个合法的URL地址")
private String logo
;
private String descript
;
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
){
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
;
@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
;
@NotBlank(message
= "品牌logo地址必须提交" ,groups
= {AddGroup
.class})
@URL(message
= "logo必须是一个合法的URL地址" ,groups
= {AddGroup
.class,UpdateGroup
.class})
private String logo
;
private String descript
;
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
;
@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 {
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 {