JSR303
* 1)、给Bean添加校验注解:javax.validation.constraints,并定义自己的message提示
* 2)、开启校验功能@Valid
* 效果:校验错误以后会有默认的响应;
* 3)、给校验的bean后紧跟一个BindingResult,就可以获取到校验的结果
* 4)、分组校验(多场景的复杂校验)
* 1)、 @NotBlank(message = "品牌名必须提交",groups = {AddGroup.class,UpdateGroup.class})
* 给校验注解标注什么情况需要进行校验
* 2)、@Validated({AddGroup.class})
* 3)、默认没有指定分组的校验注解@NotBlank,在分组校验情况@Validated({AddGroup.class})下不生效,只会在@Validated生效;
*
* 5)、自定义校验
* 1)、编写一个自定义的校验注解
* 2)、编写一个自定义的校验器 ConstraintValidator
* 3)、关联自定义的校验器和自定义的校验注解
* @Documented
* @Constraint(validatedBy = { ListValueConstraintValidator.class【可以指定多个不同的校验器,适配不同类型的校验】 })
* @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
* @Retention(RUNTIME)
* public @interface ListValue {
*
* 4、统一的异常处理
* @ControllerAdvice
* 1)、编写异常处理类,使用@ControllerAdvice。
* 2)、使用@ExceptionHandler标注方法可以处理的异常。
1.导入maven依赖
<dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency>
2.controller层
@RestController public class BrandController { /** * 保存 */ @RequestMapping("/save") public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand){ return R.ok(); } /** * 修改 */ @RequestMapping("/update") public R update(@Validated({UpdateGroup.class}) @RequestBody BrandEntity brand){ return R.ok(); } /** * 修改状态 */ @RequestMapping("/update/status") public R updateStatus(@Validated(UpdateStatusGroup.class) @RequestBody BrandEntity brand){ return R.ok(); } }
3.全局捕获异常
/** * 集中处理所有异常 */ @Slf4j @RestControllerAdvice public class MyExceptionControllerAdvice { @ExceptionHandler(value= MethodArgumentNotValidException.class) public R handleVaildException(MethodArgumentNotValidException e){ log.error("数据校验出现问题{},异常类型:{}",e.getMessage(),e.getClass()); BindingResult bindingResult = e.getBindingResult(); Map<String,String> errorMap = new HashMap<>(); bindingResult.getFieldErrors().forEach((fieldError)->{ errorMap.put(fieldError.getField(),fieldError.getDefaultMessage()); }); return R.error(BizCodeEnume.VAILD_EXCEPTION.getCode(),BizCodeEnume.VAILD_EXCEPTION.getMsg()).put("data",errorMap); } @ExceptionHandler(value = Throwable.class) public R handleException(Throwable throwable){ log.error("错误:",throwable); return R.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(),BizCodeEnume.UNKNOW_EXCEPTION.getMsg()); }
public enum BizCodeEnume { UNKNOW_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; } }
4.自定义返回的结果集
/** * 返回数据 * * @author Mark sunlightcs@gmail.com */ public class R extends HashMap<String, Object> { private static final long serialVersionUID = 1L; public R() { put("code", 0); put("msg", "success"); } public static R error() { return error(40001, "未知异常,请联系管理员"); } public static R error(String msg) { return error(40001, msg); } public static R error(int code, String msg) { R r = new R(); r.put("code", code); r.put("msg", msg); return r; } public static R ok(String msg) { R r = new R(); r.put("msg", msg); return r; } public static R ok(Map<String, Object> map) { R r = new R(); r.putAll(map); return r; } public static R ok() { return new R(); } public R put(String key, Object value) { super.put(key, value); return this; } public Integer getCode() { return (Integer) this.get("code"); } }
5.javabean对象
@Data public class BrandEntity implements Serializable { private static final long serialVersionUID = 1L; @NotNull(message = "修改必须指定品牌id",groups = {UpdateGroup.class}) @Null(message = "新增不能指定id",groups = {AddGroup.class}) private Long brandId; /** * 品牌名 */ @NotBlank(message = "品牌名必须提交") private String name; /** * 品牌logo地址 */ @URL(message = "logo必须是一个合法的url地址") private String logo; /** * 介绍 */ private String descript; /** * 显示状态[0-不显示;1-显示] */ @NotNull(groups = {AddGroup.class, UpdateStatusGroup.class}) @ListValue(vals={0,1},groups = {AddGroup.class, UpdateStatusGroup.class}) private Integer showStatus; /** * 检索首字母 */ @NotEmpty(message = "首字母不允许为空") @Pattern(regexp="^[a-zA-Z]$",message = "检索首字母必须是一个字母") private String firstLetter; /** * 排序 */ @NotNull @Min(value = 0,message = "排序必须大于等于0") @Max(value = 100,message = "排序必须小于等于100") private Integer sort; }
6.校验的类
public interface AddGroup { }
public interface UpdateGroup { }
public interface UpdateStatusGroup { }
7.自定义校验器
@Documented @Constraint(validatedBy = { ListValueConstraintValidator.class }) @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) @Retention(RUNTIME) public @interface ListValue { String message() default "{com.hourui.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); } } //判断是否校验成功 /** * * @param value 需要校验的值 * @param context * @return */ @Override public boolean isValid(Integer value, ConstraintValidatorContext context) { return set.contains(value); } }
ValidationMessages.properties
com.hourui.valid.ListValue.message=必须提交指定的值