1.JSR 303 用于对Java Bean 中的字段的值进行验证,使得验证逻辑从业务代码中脱离出来。
2.是一个运行时的数据验证框架,在验证之后验证的错误信息会被马上返回。
@RequestMapping("/do_Login") @ResponseBody //这个注解有点厉害 可以将返回值 转化为json 格式 输入 也可以转化为json? public Resultdo_Login(HttpServletResponse response, @Valid LoginVo loginVo) { log.info(loginVo.toString()) ;
上图中就是项目中用到的JSR303框架的注解@Valid 打上注解会自动对该Bean 进行参数校验。具体校验规则在该Bean内部实现。本项目是对登陆时候,利用到了参数校验。
好处:避免重复的校验代码,只需在传入的参数上打上注解就可以进行参数校验。项目中对传入Bean参数或多或少会有参数校验的代码,避免代码冗余。
/** 该类用于 接收前端 传来的登陆 数据 * * 关键:1.利用 jsr303 进行 参数校验 避免校验代码的耦合和重复 * @NotNull 为该字段不可为空 * @Length 长度校验 * */ public class LoginVo { @NotNull @IsMobile /*自定义验证*/ private String mobile; @NotNull @Length(min = 32) private String password; @Override public String toString() { return "LoginVo{" + "mobile='" + mobile + '\'' + ", password='" + password + '\'' + '}'; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
空检查
@Null 验证对象是否为null
@NotNull 验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty 检查约束元素是否为NULL或者是EMPTY.
Booelan检查
@AssertTrue 验证 Boolean 对象是否为 true
@AssertFalse 验证 Boolean 对象是否为 false
长度检查
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
@Length(min=, max=) Validates that the annotated string is between min and max included.
日期检查
@Past 验证 Date 和 Calendar 对象是否在当前时间之前,验证成立的话被注释的元素一定是一个过去的日期
@Future 验证 Date 和 Calendar 对象是否在当前时间之后 ,验证成立的话被注释的元素一定是一个将来的日期
@Pattern 验证 String 对象是否符合正则表达式的规则,被注释的元素符合制定的正则表达式,regexp:正则表达式 flags: 指定 Pattern.Flag 的数组,表示正则表达式的相关选项。
JSR常用注解。
@IsMobile()本项目自定义验证注解,用于验证手机好,首先生成注解,获取到传入的参数,绑定校验器。
@javax.validation.Constraint(validatedBy = {IsMobileValidator.class}) /*传入 校验器*/ public @interface IsMobile{ /*默认必须 有值*/ boolean required() default true; /*如果校验不通过 输出 信息*/ java.lang.String message() default "手机号码格式不对啊!"; java.lang.Class>[] groups() default {}; java.lang.Class extends javax.validation.Payload>[] payload() default {}; }
重点是校验器类:即主要用于验证的方法。简单的正在来判断手机号。
/** 工具类: 1.验证手机号是否正确 * */ public class VaildataUtil { //Pattern 类用于创建一个匹配模式 联合Matcher 类使用 达到字符串匹配的效果 private static final Pattern PATTERN = Pattern.compile("1\\d{10}"); /**验证手机号是否正确 * @param input * @return */ public static boolean isMobile(String input) { if (input.isEmpty()) { return false; } Matcher match = PATTERN.matcher(input);//Pattern 返回一个 matcher 对象 return match.matches();//matches 方法 返回值boolean 全字符匹配 } }
全局异常处理
当定义了JSR303校验器后,校验不通过都会产生一个BindException,输出错误信息。若要对异常处理,我们可以定义一个全局异常处理的拦截器。
好处:1.可以实现对项目中所有产生的异常进行拦截,在同一个类中实现统一处理。避免异常漏处理的情况。
2.项目中遇到异常,一般Try catch,这就不可避免在业务代码中加入这部分代码,显得复杂冗余。
/**该注解会 适用所有的@RequestMapper() 结合@ExceptionHander 实现全局异常处理 * */ @ControllerAdvice @ResponseBody public class GlobalExceptionHandler { @ExceptionHandler(value = Exception.class) /*定义拦截 异常的范围 此时 是拦截所有异常*/ public ResultexceptionHandler(HttpServletRequest request,Exception e){ e.printStackTrace(); if (e instanceof GlobalException){ GlobalException globalException = (GlobalException)e; return Result.error(globalException.getCodeMsg()); }else if (e instanceof BindException){ /*注意:此处的BindException 是 Spring 框架抛出的Validation异常*/ BindException ex = (BindException)e; List errors = ex.getAllErrors();/*抛出异常可能不止一个 输出为一个List集合*/ ObjectError error = errors.get(0);/*取第一个异常*/ String errorMsg = error.getDefaultMessage(); /*获取异常信息*/ return Result.error(CodeMsg.BIND_ERROR.fillArgs(errorMsg)); }else { return Result.error(CodeMsg.SERVER_ERROR); } } }
主要用到的是:@ControllerAdvice + @ExceptionHandler (Spring 框架)
@ControllerAdvice
是一个@Component
,用于定义@ExceptionHandler
,@InitBinder
和@ModelAttribute
方法,适用于所有使用@RequestMapping
方法。
意思就是该注解会对所有@RequestMapping方法进行检查,拦截。并进行异常处理。
拦截的范围 可以选定拦截异常范围,最终输出,以Result(CodeMsg)的形式输出。将异常信息放入 msg中。
于是我们的业务异常和运行时的其他异常可以在这个类中一并处理。
目的:1.当参数校验不通过的时候,输出也是Result(CodeMsg),传给前端用于前端显示获取处理
2.当Service 出现业务逻辑错误的时候,这个时候我们可以直接抛出异常,让拦截器来捕捉,捕捉之后,就不需要冗余的代码来return 一个不符合业务逻辑的返回值来作为输出。如下:
public boolean login(HttpServletResponse response, LoginVo loginVo) { /*判断 数据对象是否存在*/ if (loginVo == null ) throw new GlobalException(CodeMsg.SERVER_ERROR); String mobile = loginVo.getMobile(); String password = loginVo.getPassword(); //判断手机号 是否能查到对象 MiaoshaUser miaoshaUser = getById(Long.valueOf(mobile));//从缓存中取 if (miaoshaUser == null){ throw new GlobalException(CodeMsg.LOGIN_ERROR_USER_NOT_ERROR); }返回值应当反映我们业务逻辑,登陆,成功与否,而不是返回一个CodeMSg错误码,所以利用全局异常处理 更简明。
自定义异常类:GlobalException()继承Runtime类,重写构造函数,传入CodeMsg 。
全局异常处理的时候:先检查异常类型,若是我们业务异常,返回即可。业务中发现异常直接抛出我们自定义的异常即可。