SpringMVC 异常


Spring能够较好的处理这种问题,核心如下,文章主要关注前两个:

  • @ExceptionHandler:统一处理某一类异常,从而能够减少代码重复率和复杂度
  • @ResponseStatus:可以将某种异常映射为HTTP状态码
  • @ControllerAdvice:异常集中处理,更好的使业务逻辑与异常处理剥离开

一、@ExceptionHandler

统一处理某一类异常,从而能够减少代码重复率和复杂度

该注解作用 对象、方法,参数value 可以指定一个或者多个异常类

源码:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExceptionHandler {
	
	Class<? extends Throwable>[] value() default {};
}

二、@ResponseStatus:

用在类、方法上,用于指定 异常的 HTTP 状态码和异常原因。

有两个参数:value 、reason。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseStatus {

	@AliasFor("code")
	HttpStatus value() default HttpStatus.INTERNAL_SERVER_ERROR;
	
	@AliasFor("value")
	HttpStatus code() default HttpStatus.INTERNAL_SERVER_ERROR;
	
	String reason() default "";
}

带有 @ResponseStatus 注解的异常类会被 ResponseStatusExceptionResolver 解析

@ResponseStatus 可以实现自定义异常HTTP状态码,同时在页面上进行显示。具体的使用方法如下:

2.1、指定异常的状态码

@ResponseStatus(value = HttpStatus.FORBIDDEN,reason = "用户名和密码不匹配!")
public class UserNameNotMatchPasswordException extends RuntimeException{
        
}

带有@ResponseStatus注解的异常类会被ResponseStatusExceptionResolver 解析

2.2、在Controller中抛出自定义的异常

@RequestMapping("/testResponseStatusExceptionResolver")
public String testResponseStatusExceptionResolver(@RequestParam("i") int i){
    if (i==13){
        throw new UserNameNotMatchPasswordException();
    }
    System.out.println("testResponseStatusExceptionResolver....");
    return "success";
}

2.3、测试

输入如下额路径:http://localhost:8090/testResponseStatusExceptionResolver?i=13

显示了 上面定义好的异常的状态码和异常原因

2.4、直接在方法上进行修饰:

@ResponseStatus(reason = "测试",value = HttpStatus.NOT_FOUND)
@RequestMapping("/testResponseStatusExceptionResolver")
public String testResponseStatusExceptionResolver(@RequestParam("i") int i){
    if (i==13){
        throw new UserNameNotMatchPasswordException();
    }
    System.out.println("testResponseStatusExceptionResolver....");
    return "success";
}

2.5、再次测试

三、@ControllerAdvice

异常集中处理,更好的使业务逻辑与异常处理剥离开

该注解作用对象为TYPE,包括类、接口和枚举等,
在运行时有效,
可以通过Spring扫描为bean组件。

其可以包含由@ExceptionHandler@InitBinder@ModelAttribute 标注的方法,可以处理多个Controller类,这样所有控制器的异常可以在一个地方进行处理。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {

    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

    Class<?>[] assignableTypes() default {};

    Class<? extends Annotation>[] annotations() default {};
}

定义全局异常处理类:

@ControllerAdvice
public class GlobalExceptionHandler  {

	static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler .class);

    @ExceptionHandler(CustomGenericException.class)//可以直接写@ExceptionHandler,不指明异常类,会自动映射
    public ModelAndView customGenericExceptionHnadler(CustomGenericException exception){ //还可以声明接收其他任意参数
        ModelAndView modelAndView = new ModelAndView("generic_error");
        modelAndView.addObject("errCode",exception.getErrCode());
        modelAndView.addObject("errMsg",exception.getErrMsg());
        return modelAndView;
    }

    @ExceptionHandler(Exception.class)//可以直接写@EceptionHandler,IOExeption继承于Exception
    public ModelAndView allExceptionHandler(Exception exception){
        ModelAndView modelAndView = new ModelAndView("generic_error");
        modelAndView.addObject("errMsg", "this is Exception.class");
        return modelAndView;
    }

	/**
	 *
	 *  使用  @ResponseBod ,返回不同类型数据
	 */
	@ExceptionHandler(BusinessException.class)
    @ResponseBody
    public LuoblogResult<Object> handle(BusinessException e) {
        logger.warn("GloabalExceptionHandler handing a Exception: " + e.getMessage());
        // 业务失败返回
        return new LuoblogResult<Object>(false, e.getDescription());
    }
}

如果 @ExceptionHandler 注解中未声明要处理的异常类型,则默认为参数列表中的异常类型。
返回值可以是任何数据类型的,如:ModelAndView,String,Map,List ,自定义的JavaBean等。

所以还可以写成这样:

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler()
    @ResponseBody
    public String handleException(Exception e){
        return "Exception Deal! " + e.getMessage();
    }
}

猜你喜欢

转载自blog.csdn.net/xiaojin21cen/article/details/83477058