• @valid和自定义异常


    @valid和自定义异常

    问题的产生:

    当有很多参数需要校验时,比如name,age,email等很多参数都需要判空,或者有长度限制时,如果后端写很多if-else就有很多代码,不美观,不优雅.前端每个参数都效验的话工作量也很大

    本文旨在解决这个问题,本文使用@valid 注解来解决这个问题.

    首先定义一个

    统一结果返回

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    public class Result<T> {
    
        private String msg;
        private Integer code;
        private T data;
        private static final Integer successCode = 200;
        private static Integer errorCode = 500;
        private static final String successMsg = "成功";
        private static final Object resultNoData = null;
    
        public static Result successNoResult() {
            return new Result(successMsg, successCode, resultNoData);
        }
    
        public static <T> Result<T> successWithResult(T data) {
            return new Result(successMsg, successCode, data);
        }
    
        public static Result successWithCodeAndMsg(Integer code, String msg) {
            return new Result(msg, code, resultNoData);
        }
    
        public static Result errorNoResult(String msg) {
            return new Result(msg, errorCode, resultNoData);
        }
    
        public static Result errorWithResult(String msg, Object data) {
            return new Result(msg, errorCode, data);
        }
    
        public static Result errorWithCodeAndMsg(Integer code, String msg) {
            return new Result(msg, code, resultNoData);
        }
    
    }
    

    @valid 注解简单使用

    先看下简单使用,复杂的自己查api吧

    首先在控制层的参数上加上该注解

    import javax.validation.Valid;
    import java.util.*;
    
    @RestController
    @RequestMapping("/test")
    public class Test2 {
    
        @RequestMapping("test2")
        public Result<User> test2(@Valid User user){
            return Result.successWithResult(user);
        }
    }
    

    然后在实体类中加上如下注解

    import javax.validation.constraints.NotBlank;
    import javax.validation.constraints.NotNull;
    import javax.validation.constraints.Size;
    
    public class User {
        
        /**
         * @NotEmpty:不能为null,而且长度必须大于0
         * @NotBlank:只用在String上,表示传进来的值不能为null,而且调用trim()后,长度必须大于0
         * @NotNull:不能为null,但可以为empty
         * @Length(message = "名称不能超过个 {max} 字符", max = 10)
         * @Range(message = "年龄范围为 {min} 到 {max} 之间", min = 1, max = 100)
         */
        @NotNull( message = "ID不能为空")
        private Integer id;
    
        @NotBlank( message = "昵称不能为空")
        @Size( min = 2,max = 5,message ="昵称的字数个数必须在0和5之间" )
        private String name;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    

    请求该接口

    http://localhost:8080/test/test2?id=5&name=xxwwwww
    

    查看效果,如下

    image

    可以看到,已经能表示该请求参数错误

    但是还有个问题,我们不能直接这样子直接返回给前端,需要返回统一的结果

    全局异常处理

    Spring-boot对于异常的处理也做了不错的支持,

    它提供了一个 @ControllerAdvice注解以及 @ExceptionHandler注解,

    前者是用来开启全局的异常捕获,后者则是说明捕获哪些异常,对那些异常进行处理。如下

    自定义异常

    import lombok.Data;
    
    @Data
    public class DefinitionException extends RuntimeException {
        private Integer errorCode;
        private String errorMsg;
    
        public DefinitionException(){
    
        }
        public DefinitionException(Integer errorCode, String errorMsg) {
            this.errorCode = errorCode;
            this.errorMsg = errorMsg;
        }
    
    }
    

    异常处理

    @ControllerAdvice
    public class GlobalExceptionHandler {
    
        /**
         * 处理自定义异常
         */
        @ExceptionHandler(value = DefinitionException.class)
        @ResponseBody
        public Result bizExceptionHandler(DefinitionException definitionException) {
            Result result=new Result();
            result.setCode(definitionException.getErrorCode());
            result.setMsg(definitionException.getErrorMsg());
            return result;
        }
    
        /**
         * 处理异常
         */
        @ExceptionHandler(value = Exception.class)
        @ResponseBody
        public Result runtimeExceptionHandler(Exception exception) {
            Result result=new Result();
            result.setCode(500);
            result.setMsg(exception.getMessage());
            return result;
        }
    }
    

    测试代码

    @RequestMapping("test3")
    public Result<String> test3(){
    int i=1/0;
    return Result.successWithResult("test3");
    }
    
    @RequestMapping("test4")
    public Result<String> test4(){
    throw new DefinitionException(500,"啊哦,报错了");
    }
    

    查看结果

    image

    image

    将@valid注解抛的异常也返回统一格式

    我们再请求一下这个接口

    http://localhost:8080/test/test2?id=5&name=xxwwwww
    

    看下结果

    image

    返回格式是统一的格式了,但是返回的信息不太友好,我们看看怎么优化

    debug一下,看看这个是什么异常

    image

    我们看到,这个异常是org.springframework.validation.BindException类的,

    我们看下这个类的具体内容,我们只要我们想要的信息就行

    image

    这里,我们只要这个信息就可以了我们改动后如下

        /**
         * 处理异常
         */
        @ExceptionHandler(value = Exception.class)
        @ResponseBody
        public Result runtimeExceptionHandler(Exception exception) {
            Result result=new Result();
            if(exception instanceof BindException){//注解类异常
                StringBuilder sb = new StringBuilder();
                BindException bindException= (BindException) exception;
                BindingResult bindingResult = bindException.getBindingResult();
                List<ObjectError> allErrors = bindingResult.getAllErrors();
                for (ObjectError item : allErrors) {
                    sb
                            .append(item.getDefaultMessage())
                            .append(',');
                }
                sb.deleteCharAt(sb.length()-1);
                result.setCode(500);
                result.setMsg(sb.toString());
    
            }
            return result;
        }
    

    再请求该接口,得到结果

    image

    到此为止,我们已经得到了我们想要的结果

    优化代码

    最后,我们在优化一下全局异常处理代码如下

    import com.yoocar.util.Result;
    import org.springframework.validation.BindException;
    import org.springframework.validation.BindingResult;
    import org.springframework.validation.ObjectError;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    import java.util.List;
    
    @ControllerAdvice
    public class GlobalExceptionHandler {
    
        /**
         * 处理自定义异常
         */
        @ExceptionHandler(value = Exception.class)
        @ResponseBody
        public Result exceptionHandler(Exception exception) {
            Result result=new Result();
            //自定义类型异常
            if(exception instanceof DefinitionException){
                DefinitionException definitionException= (DefinitionException) exception;
                result.setCode(definitionException.getErrorCode());
                result.setMsg(definitionException.getErrorMsg());
            }else if(exception instanceof BindException){//@valid注解抛出的异常
                //使用StringBuilder来拼接错误信息,减少对象开销
                StringBuilder stringBuilder = new StringBuilder();
                //获取并拼接所有错误信息
                BindException bindException= (BindException) exception;
                BindingResult bindingResult = bindException.getBindingResult();
                List<ObjectError> allErrors = bindingResult.getAllErrors();
                for (ObjectError item : allErrors) {
                    stringBuilder.append(item.getDefaultMessage())
                            .append(',');
                }
                //删除最后一个逗号
                stringBuilder.deleteCharAt(stringBuilder.length()-1);
                result.setCode(600);//这里自定义了600用于表示参数有误
                result.setMsg(stringBuilder.toString());
            }else {//其他异常
                result.setCode(500);
                result.setMsg(exception.getMessage());
            }
            return result;
        }
    
    }
    

    至此,本文结束.文章中若有错误和疏漏之处,还请各位大佬不吝指出,谢谢大家!

  • 相关阅读:
    Javascript面向对象编程:非构造函数的继承
    JavaScript中this 详解
    构造函数与 new 命令
    JavaScript数组去重的6个方法
    初学Java Web(9)——学生管理系统(简易版)总结
    初学Java Web(8)——过滤器和监听器
    初学Java Web(7)——文件的上传和下载
    初学Java Web(6)——JSP学习总结
    初学Java Web(5)——cookie-session学习
    初学Java Web(4)——Servlet学习总结
  • 原文地址:https://www.cnblogs.com/lusaisai/p/14698334.html
Copyright © 2020-2023  润新知