添加统一异常处理类注解@RestControllerAdvice 添加日志注解@Slf4j 添加异常处理方法注解@ExceptionHandler
开启校验注解 JSR303
导包
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
javax.validation.constraints
(1)在实体类中
@NotEmpty //不能为空
private String name;
(1)controller 开启校验@Valid
public R save(@Valid @RequestBody BrandEntity brand)
应用 自定义校验(单个处理)
@NotEmpty(message = "品牌名不能为空") //不能为空
private String name;
@NotEmpty
@URL(message = "logo必须是有效的URL")
private String logo;
private String descript;
private Integer showStatus;
@NotEmpty
@Pattern(regexp="/^[a-zA-Z]$/",message = "检索首字母必须是一个字母")//自定义正则表达式
private String firstLetter;
@NotNull
@Min(value = 0,message = "排序必须必须最大于等于0")//最小是0
private Integer sort;
@RequestMapping("/save")//校验后面加一个女BindingResult 可以获取校验结构
public R save(@Valid @RequestBody BrandEntity brand, BindingResult result) {
if (result.hasErrors()) {
Map<Object, Object> map = new HashMap<>();
//获取校验结果
result.getFieldErrors().forEach((item) -> {
//获取错误提示
String message = item.getDefaultMessage();
//获取错误属性名
String field = item.getField();
map.put(field,message);
});
//返回R错误提示,并put给map用data封装
return R.error(400, "提交数据不合法").put("data",map);
} else {
brandService.save(brand);
}
return R.ok();
}
自定义校验(全局处理) 抽取全局异常类exception
//GulimallExceptionControllerAdvice
@Slf4j
//RestControllerAdvice包含@ControllerAdvice和@ResponseBody
//集中全局处理异常注解并说明处理哪个包
@RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {
//通过打印日志定位到异常类型的MethodArgumentNotValidException
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public R handleVaildExeption(MethodArgumentNotValidException e){
//一一对应
log.error("数据校验出错{},异常类型:{}",e.getMessage(),e.getClass());
//校验结果 forEach 给errorMap集合
BindingResult bindingResult = e.getBindingResult();
Map<String, String> errorMap = new HashMap<>();
bindingResult.getFieldErrors().forEach((fieldError)->{
errorMap.put(fieldError.getField(),fieldError.getDefaultMessage());
});
//返回输出错误信息
return R.error(400,"数据校验出错").put("data",errorMap);
}
}
抽取枚举类处理异常 定义
package com.atguigu.common.exception;
//定义状态码枚举
public enum BizCodeEnume {
UNKONOW_EXCEPTION(10000,"系统格式校验失败"),
VAILD_EXCEPTION(10001,"参数格式校验失败");
private int code;
private String msg;
BizCodeEnume(int code,String msg){
this.code=code;
this.msg=msg;
}
public int getCode(){
return code;
}
public String getMsg(){
return msg;
}
}
应用
@ExceptionHandler(value = Throwable.class)
public R handleException(Throwable throwable){
return R.error(BizCodeEnume.UNKONOW_EXCEPTION.getCode(),BizCodeEnume.UNKONOW_EXCEPTION.getMsg());
}
多场景分组校验
- 设置实体类分组校验分组判断时候校验 groups ={UpdateGroup.class,AddGroup.class}
- controller 设置@Validated({AddGroup.class}) 属于哪一个组
- 默认没有指定分组的校验注解
//新建两个接口(无需写其他 只是空接口)
common.valid.AddGroup;
common.valid.UpdateGroup;
//实体类groups
public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L;
@NotNull(message = "修改必须指定ID",groups ={UpdateGroup.class})
@Null(message = "新增不能指定ID",groups ={AddGroup.class})
@TableId
private Long brandId;
//修改和新增 都不能为空
@NotEmpty(message = "品牌名不能为空",groups ={UpdateGroup.class,AddGroup.class})
private String name;
//新增不能为空 修改或新增必须是有效的地址
@NotEmpty(message = "logo必须是有效的URL",groups ={AddGroup.class})
@URL(message = "logo必须是有效的URL",groups ={UpdateGroup.class,AddGroup.class})
private String logo;
private String descript;
private Integer showStatus;
@NotEmpty(groups ={AddGroup.class})
@Pattern(regexp="/^[a-zA-Z]$/",message = "检索首字母必须是一个字母",groups ={UpdateGroup.class,AddGroup.class})//自定义正则表达式
private String firstLetter;
@NotNull(groups ={AddGroup.class})
@Min(value = 0,message = "排序必须必须最大于等于0",groups ={UpdateGroup.class,AddGroup.class})//最小是0
private Integer sort;
}
//controller层 @Validated
//新增校验分组@Validated({AddGroup.class})
public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand)
//修改校验分组@Validated({UpdateGroup.class})
public R update(@Validated({UpdateGroup.class})@RequestBody BrandEntity brand)
自定义value
ListValue ListValueConstraintValidator ValidationMessages.properties
@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.atguigu.common.valid.ListValue.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int[] vals() default {};;
}
public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer>{
private Set<Integer> set =new HashSet<>();
//初始化方法
@Override
public void initialize(ListValue constraintAnnotation) {
int[] vals = constraintAnnotation.vals();
for (int val :vals) {
set.add(val);
}
}
//判断是否校验成功
@Override
public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
return set.contains(value);
}
}
//ValidationMessages.properties
com.atguigu.common.valid.ListValue.message=必须提交正确数
实体类
@ListValue(vals={0,1,},groups = {AddGroup.class, UpdateStatuesGroup.class})
private Integer showStatus;