JSR303参数校验+全局异常处理

 JSR303

1.JSR 303 用于对Java Bean 中的字段的值进行验证,使得验证逻辑从业务代码中脱离出来。

 2.是一个运行时的数据验证框架,在验证之后验证的错误信息会被马上返回。

@RequestMapping("/do_Login")
@ResponseBody //这个注解有点厉害  可以将返回值 转化为json 格式 输入 也可以转化为json?
public Result do_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.Classextends 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 Result exceptionHandler(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 。

全局异常处理的时候:先检查异常类型,若是我们业务异常,返回即可。业务中发现异常直接抛出我们自定义的异常即可。

你可能感兴趣的:(Sanno限时秒杀商城项目)