java 异常以及springmvc全局异常处理

一、Throwable

所有异常类的父类,下面分为Error和Exception两个子类
Error表示系统错误或资源耗尽,由Java系统自己使用,应用程序不应抛出和处理
Exception表示应用程序错误,它有很多子类,应用程序也可以通过继承Exception或其子类创建自定义异常

二、 异常分类

未受检异常:运行时异常RunningTimeException、Error及其子类也是未受检异常

受检异常:Exception的其他子类和Exception自身,
受检异常,java会强制要求程序员进行处理,否则会编译错误,而对于未受检异常则没有这个要求。

三、自定义异常

一般是继承Exception或者它的某个子类。

四、捕获异常

1、try、catch、finally

try代码块:可能抛出异常的代码块
catch代码块:要处理的异常信息,
1)catch可以有多个,每条对应一种异常类型;
2)找到第一个匹配的catch块后,执行catch块内的代码,不在执行其他catch块,如果没有找到,会继续到上层方法中查找。
fianlly:finally 内的代码不管有无异常发生,都会执行。
如果异常没有发生,在try内的代码执行结束后执行;
如果发生异常且被catch捕获,在catch内的代码执行结束后执行
如果有异常发生但没有被捕获,在异常被抛给上层之前执行。
如果try或者catch语句内有return语句,则return语句在finally语句执行结束后执行,但finally并不能改变返回值。

    public static int test(){
        int ret=10;
        try{
            return ret;
        }finally {
            ret=2;
        }
    }

这里函数的返回值为10,而不是2,。执行过程:在执行到try的return语句时,会将返回值ret保存在一个临时变量中,然后执行finally语句,最后再返回那个临时变量,finally中对ret的修改不会被返回。
如果finally中有return语句,try和catch内的return会丢失,实际返回finally中的返回值。finally有return不仅会覆盖try和catch内的返回值,还会掩盖try和catch内的异常,就当异常没有发生一样。
所以应该避免在finally中使用return语句或者抛出异常。

2、try-with-resources语句

对于文件关闭、资源释放等涉及资源场景,java1.7支持try-with-resources语句,资源的声明和初始化放在try语句内,不用在调用finally,在执行完try语句后,会自动调用资源的close()方法。
对于多个资源,以分号分隔。

try(File file=new File("a.txt")){
//使用资源
}
3、throw与throws

throw:用于声明一个方法可能抛出的异常。
throws:跟在方法的括号后面,可以声明多个异常,以逗号分隔。

对于未受检异常,不要求使用throws进行声明,但对于受检异常,则必须进行声明,换句话说,如果没有声明,则不能抛出。
对于受检异常,不可以抛出而不声明,但可以声明抛出但实际不抛出。主要用于父类方法中声明,父类方法内可能没有抛出,但子类重写方法可能就抛出了,子类不能抛出父类方法中没有声明的受检异常,所以就将所有可能抛出的异常都写在父类上。
一个方法内调用了另一个声明抛出受检异常的方法,则必须处理这个受检异常,可以是catch,也可以继续使用throws。

四、springmvc全局异常处理

全局异常处理,是为了在发生异常时由统一的类进行处理,能够与应用业务代码解耦。

1、声明异常类

需要继承Exception

public class ParamsException extends Exception{
    private String code;
    private String message;

    public ParamsException(String code, String message) {
        this.code = code;
        this.message = message;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

2、异常处理类

@ControllerAdvice
使用@ControllerAdvice声明类,标识该类是一个异常处理类, @ExceptionHandler:作用在方法上,标识要处理的异常类型。

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ParamsException.class)
    @ResponseBody
    public  BaseRes<Object> doParamsException(ParamsException exception){
        final BaseRes<Object> objectBaseRes = new BaseRes<>();
        objectBaseRes.setCode(exception.getCode());
        objectBaseRes.setMsg(exception.getMessage());
        return objectBaseRes;
    }

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseBody
    public  BaseRes<Object> doMediaTypeException(){
        final BaseRes<Object> objectBaseRes = new BaseRes<>();
        objectBaseRes.setCode("60000");
        objectBaseRes.setMsg("请求方式不正确");
        return objectBaseRes;
    }
}
3、控制层异常抛出
    @RequestMapping(path = {"/test9"}, method = RequestMethod.GET)
    @ResponseBody
    public String test9(@RequestParam String msg) throws ParamsException {
        if ("00".equals(msg)) {
            throw new ParamsException("000001", "参数异常处理");
        }
        //访问外部资源
        return "success";
    }

实验结果:
在这里插入图片描述

4、参数校验异常统一处理

开发中一般碰到参数异常,需要统一处理可以使用一下方法处理:
导入依赖:

 <!--        JSR-303 需要的依赖-->
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.2.1.Final</version>
        </dependency>

实例类使用@NotNull、@NotBlank、@Length、@Size声明
@NotNull:适用于基本数据类型(Integer,Long,Double等等),当 @NotNull 注解被使用在 String 类型的数据上,则表示该数据不能为 Null(但是可以为 Empty);
@NotBlank:适用于 String 类型的数据上,加了@NotBlank 注解的参数不能为 Null 且 trim() 之后 size > 0;
@NotEmpty:适用于 String、Collection集合、Map、数组等等,加了@NotEmpty 注解的参数不能为 Null 或者 长度为 0;
@Length:适用于String;
@Size:适用于集合、数组、字符序列长度,
实体类

public class User implements Serializable {
    @NotNull(message="id不能为空")
    private int id;
    @NotBlank(message="name不能为空")
    private String name;
    //@Size(min = 0,max = 2,message="长度应该在0和2位之间")
    @Max(value = 99,message="age小于99")
    @Min(value = 0,message="age大于0")
    private int age;

    public User() {
    }

    public User(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

controller方法

       @RequestMapping(path = {"/test8"}, produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.POST)
    @ResponseBody
    public BaseRes test7(@Valid @RequestBody User user, BindingResult bindingResult) throws ParamsException {
        logger.info("user:{}", user);
        if (bindingResult.hasErrors()) {
            final StringBuilder stringBuilder = new StringBuilder();
            bindingResult.getAllErrors().forEach((item) -> stringBuilder.append(item.getDefaultMessage()).append(","));
            logger.warn("参数异常:{}", bindingResult.getFieldError().getDefaultMessage());
            throw new ParamsException("000001", stringBuilder.substring(0,stringBuilder.length()-1).toString());
        }
        return BaseRes.success();
    }

@Valid:这个需要添加到参数上,
BindingResult :用于接收错误信息
结果展示:
在这里插入图片描述

5、自定义校验类

自定义一个检验整数大小的类,代替@Min和@Max

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Constraint(validatedBy = MyConstrainValidator.class)
public @interface MyConstraint {
    int min() default 0;
    int max() default Integer.MAX_VALUE;

    String message() default "{com.riant.annotation.message}";
    Class<?> [] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
public class MyConstrainValidator implements ConstraintValidator<MyConstraint, Object> {
    private int min;
    private int max;
    @Override
    public void initialize(MyConstraint constraintAnnotation) {
        this.max = constraintAnnotation.max();
        this.min = constraintAnnotation.min();
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        if (!(value instanceof Integer)) {
            return false;
        }
        int temp = (Integer) value;
        if (temp < min || temp > max) {
            return false;
        }
        return true;
    }
}

实验结果:
在这里插入图片描述

五、@ControllerAdvice 原理

该注解原理是与springmvc的DispatcherServlet有关,
在对DispatcherServlet进行初始化时,会执行initHandlerAdapters(context)和initHandlerExceptionResolvers(context)这两个方法,用于实例处理器适配器和HandlerExceptionResolver,
处理器适配器会实例化RequestMappingHandlerAdapter的bean,该bean和@RequestMapping有关联,
HandlerExceptionResolver用于在处理器映射和执行过程中抛出的异常处理,在controller层抛出异常后,HandlerExceptionResolver会去解决异常,它会根据抛出的一张去找@ExceptionHandler注解的方法,默认会查找当前的controller,如果没有找到会在@ControllerAdvice的切面查找。

参考:@NotEmpty、@NotBlank、@NotNull 区别和使用
springboot 统一异常处理
代码:springmvc-demo01

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值