谷粒商城--品牌管理
前端表单校验
品牌新增
品牌修改
校验规则
javascript"> dataRule: {name: [{ required: true, message: "品牌名不能为空", trigger: "blur" }],logo: [{ required: true, message: "品牌logo地址不能为空", trigger: "blur" },],descript: [{ required: true, message: "介绍不能为空", trigger: "blur" },],showStatus: [{required: true,message: "显示状态[0-不显示;1-显示]不能为空",trigger: "blur",},],firstLetter: [{ validator: (rule, value, callback) => {if (value == '') {callback(new Error("检索首字母不能为空"));} else if (!/^[a-zA-Z]$/.test(value)) {callback(new Error("检索首字母必须为a-zA-Z的字母"));} else {callback();}},trigger: "blur" },],sort: [{validator: (rule, value, callback) => {if (value === '') {callback(new Error("排序不能为空"));} else if (!Number.isInteger(value) || value < 0) {callback(new Error("排序必须是一个大于0的整数"));} else {callback();}},trigger: "blur",},],},
require是否必填;message校验提示;triggeer:“”blur“聚焦时校验
validator自定义校验器,value为校验值,callback回调函数
服务端数据校验
防止用户绕过前端,直接向服务端发送数据。
JSR303是Java EE 6中的一项子规范,主要用于定义Java对象的校验规则。
1.给Bean添加校验注解,并定义message提示
java">@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})@TableIdprivate Long brandId;/*** 品牌名*/@NotBlank(message = "品牌名不能为空",groups = {AddGroup.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-显示]*/@SpecifiedInteger(vals={0,1},groups = {AddGroup.class, UpdateGroup.class})private Integer showStatus;/*** 检索首字母*/@NotEmpty(groups = {AddGroup.class})@Pattern(regexp = "^[a-zA-Z]$",message = "检索首字母必须是一个字母",groups = {AddGroup.class, UpdateGroup.class})private String firstLetter;/*** 排序*/@NotNull(groups = {AddGroup.class})@Min(value = 0,message = "排序必须大于 等于0",groups = {AddGroup.class, UpdateGroup.class})private Integer sort;}
2.开启校验功能@Valid
BindingResult获取校验的结果
java"> @RequestMapping("/save")//@RequiresPermissions("product:brand:save")public R save(@Validated(value = {AddGroup.class}) @RequestBody BrandEntity brand /*,BindingResult result*/){
// if(result.hasErrors()){
// Map<String,String> map=new HashMap<>();
// result.getFieldErrors().forEach(item->{
// map.put(item.getField(),item.getDefaultMessage());
// });
// return R.error(400,"提交的数据不合法").put("data",map);
// }else {
// brandService.save(brand);
// }brandService.save(brand);return R.ok();}/*** 修改*/@RequestMapping("/update")//@RequiresPermissions("product:brand:update")public R update(@Validated(value = {UpdateGroup.class}) @RequestBody BrandEntity brand){brandService.updateById(brand);return R.ok();}
3.分组校验
指定分组
groups = {AddGroup.class,UpdateGroup.class})
@Validated({AddGroup.class})
默认没有指定分组的校验注解,在分组校验情况下不生效,只会在@Validated生效;
4. 自定义校验
1)自定义校验注解
元注解
@Target
可以定义Annotation
能够被应用于源码的哪些位置ElementType.FIELD 字段
@Retention
定义了Annotation
的生命周期RetentionPolicy.RUNTIME
运行时生效
java">@Documented
@Constraint(validatedBy = {SpecifiedIntegerConstraintValidator.class}
)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SpecifiedInteger {String message() default "{com.elysia.common.validator.valid.SpecifiedInteger.message}";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};int[] vals() default {};
}
@Constraint(validatedBy = {SpecifiedIntegerConstraintValidator.class})
【可以指定多个不同的校验器,适配不同类型的校验】
2)自定义的校验器 ConstraintValidator
java">ConstraintValidator<A extends Annotation, T>
ConstraintValidator接口,A为注解,T为校验数据类型
java">public class SpecifiedIntegerConstraintValidator implements ConstraintValidator<SpecifiedInteger,Integer>{private Set<Integer> set=new HashSet<>();@Overridepublic void initialize(SpecifiedInteger constraintAnnotation) {int[] values=constraintAnnotation.vals();for (int value:values) {set.add(value);}}/**** @param integer 想要校验的值* @param constraintValidatorContext* @return*/@Overridepublic boolean isValid(Integer integer, ConstraintValidatorContext constraintValidatorContext) {return set.contains(integer);}
}
获取注解中的value,校验数据是否合法
5.自定义异常处理类
@RestControllerAdvice=@ControllerAdvice+@ResponseBody
@ControllerAdvice为控制器(Controller)添加全局的操作或处理逻辑。这些操作或处理逻辑可以包括异常处理、数据绑定、数据预处理等。
basePackages限制@ControllerAdvice的作用范围,只应用于指定包或注解的控制器。
@ExceptionHandler(value = MethodArgumentNotValidException.class)处理某类异常
java">@Slf4j
@RestControllerAdvice(basePackages = "com.elysia.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {@ExceptionHandler(value = MethodArgumentNotValidException.class)public R handleValidException(MethodArgumentNotValidException e){log.error("数据校验出现异常{},异常类型{}",e.getMessage(),e.getClass());Map<String,String> errorMap=new HashMap<>();e.getBindingResult().getFieldErrors().forEach(fieldError -> {errorMap.put(fieldError.getField(),fieldError.getDefaultMessage());});return R.error(BizCodeEnum.VAILD_EXCEPTION.getCode(), BizCodeEnum.VAILD_EXCEPTION.getMsg()).put("data",errorMap);}@ExceptionHandler(value = Throwable.class)public R handleException(Throwable throwable){log.error("未知错误 ",throwable);return R.error(BizCodeEnum.UNKNOW_EXCEPTION.getCode(), BizCodeEnum.UNKNOW_EXCEPTION.getMsg());}
}
6.错误码和错误信息定义类
枚举类,将构造器私有化,创建和初始化UNKNOW_EXCEPTION和VAILD_EXCEPTION这两个枚举常量。
java">/**** 错误码和错误信息定义类* 1. 错误码定义规则为5为数字* 2. 前两位表示业务场景,最后三位表示错误码。例如:100001。10:通用 001:系统未知异常* 3. 维护错误码后需要维护错误描述,将他们定义为枚举形式* 错误码列表:* 10: 通用* 001:参数格式校验* 11: 商品* 12: 订单* 13: 购物车* 14: 物流***/
public enum BizCodeEnum {UNKNOW_EXCEPTION(10000,"系统未知异常"),VAILD_EXCEPTION(10001,"参数格式校验失败");private int code;private String msg;BizCodeEnum(int code,String msg){this.code = code;this.msg = msg;}public int getCode() {return code;}public String getMsg() {return msg;}
}