统一异常处理_学习笔记

SpringMVC提供了@ControllerAdvice功能

  1. 抽取一个异常处理类,在类上添加@ControllerAdvice注解,并且通过basePackages属性指定它要处理那些类抛出的异常;
@ControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {
    
}
  1. 编写处理异常的方法,并且在方法上添加@ExceptionHandler注解,来告诉Springmvc这个方法能处理哪些异常;
    在方法参数中传入响应的异常类型
@Slf4j
@ControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {

    @ResponseBody
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handleValidException(MethodArgumentNotValidException e){
      log.info("数据校验出现问题:{},异常类型:{}",e.getMessage(),e.getClass());
        BindingResult bindingResult = e.getBindingResult();
        List<FieldError> fieldErrors = bindingResult.getFieldErrors();
        Map<String,String> map = new HashMap<>();
        fieldErrors.forEach((fieldError)->{
            map.put(fieldError.getField(),fieldError.getDefaultMessage());
        });

        return R.error(400,"数据校验错误").put("data",map);
    }
	@ResponseBody
    @ExceptionHandler(value = Throwable.class)
    public R handleException(Throwable throwable){
        return R.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(),BizCodeEnume.UNKNOW_EXCEPTION.getMsg());
    }
}

3)在学习一遍
@ControllerAdvice 本质上是一个Component,因此也会被当成组件扫描,一视同仁,扫扫扫。
在这里插入图片描述

然后,我们来看一下此类的注释:
这个类是为那些声明了(@ExceptionHandler、@InitBinder 或 @ModelAttribute注解修饰的)方法的类而提供的专业化的@Component , 以供多个 Controller类所共享。
说白了,就是aop思想的一种实现,你告诉我需要拦截规则,我帮你把他们拦下来,具体你想做更细致的拦截筛选和拦截之后的处理,你自己通过@ExceptionHandler、@InitBinder 或 @ModelAttribute这三个注解以及被其注解的方法来自定义。

初定义规则:
ControllerAdvice 提供了多种指定Advice规则的定义方式,默认什么都不写,则是Advice所有Controller,当然你也可以通过下列方式指定规则:
比如对于 String[] value() default {} , 写成@ControllerAdvice(“org.my.pkg”) 或者 @ControllerAdvice(basePackages=“org.my.pkg”), 则匹配org.my.pkg包及其子包下的所有Controller,当然也可以用数组的形式指定,如:@ControllerAdvice(basePackages={“org.my.pkg”, “org.my.other.pkg”}), 也可以通过指定注解来匹配,比如我自定了一个 @CustomAnnotation 注解,我想匹配所有被这个注解修饰的 Controller, 可以这么写:@ControllerAdvice(annotations={CustomAnnotation.class})
还有很多用法,这里就不全部罗列了。

理解就是:@ControllerAdvice 是指定Advice规则的,需要拦截那些类,指明就好。

  • 处理全局异常

@ControllerAdvice 配合 @ExceptionHandler 实现全局异常处理
在这里插入图片描述
接收Throwable类作为参数,我们知道Throwable是所有异常的父类,所以说,可以自行指定所有异常
比如在方法上加:@ExceptionHandler(IllegalArgumentException.class),则表明此方法处理
IllegalArgumentException 类型的异常,如果参数为空,将默认为方法参数列表中列出的任何异常(方法抛出什么异常都接得住)。

/**
 * 统一异常处理类
 */
@ControllerAdvice
public class GlobalExceptionHandler {
	//全局异常
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result error(Exception e){
        e.printStackTrace();
        return Result.fail().message("执行了全局异常处理");
    }
    //处理特定异常
	@ExceptionHandler(ArithmeticException.class)
	@ResponseBody
	public Result error(ArithmeticException e){
		e.printStackTrace();
	return Result.fail().message("执行了特定异常处理");
	}
	//处理自定义异常方法
	@ExceptionHandler(GgktException.class)
	@ResponseBody
	public Result error(GgktException e){
		e.printStackTrace();
	return Result.fail().message(e.getMsg()).code(e.getCode());
	}
}
	//自定义异常需要常见自定义异常类,继承RuntimeException
	@Data
	@AllArgsConstructor
	@NoArgsConstructor
	public class GgktException extends RuntimeException {
   		 private Integer code;
   		 private String msg;
	}
  • 预设全局数据

@ControllerAdvice 配合 @ModelAttribute 预设全局数据
我们先来看看 ModelAttribute注解类的源码

/**
 * Annotation that binds a method parameter or method return value
 * to a named model attribute, exposed to a web view. Supported
 * for controller classes with {@link RequestMapping @RequestMapping}
 * methods.
 * 此注解用于绑定一个方法参数或者返回值到一个被命名的model属性中,暴露给web视图。支持在
 * 在Controller类中注有@RequestMapping的方法使用(这里有点拗口,不过结合下面的使用介绍
 * 你就会明白的)
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ModelAttribute {

	@AliasFor("name")
	String value() default "";

	@AliasFor("value")
	String name() default "";

	boolean binding() default true;

}

实际上这个注解的作用就是,允许你往 Model 中注入全局属性(可以供所有Controller中注有@Request Mapping的方法使用),value 和 name 用于指定 属性的 key ,binding 表示是否绑定,默认为 true。
具体使用方法如下:

  1. 全局参数绑定
    • 方式一:
@ControllerAdvice
public class MyGlobalHandler {
    @ModelAttribute
    public void presetParam(Model model){
        model.addAttribute("globalAttr","this is a global attribute");
    }
}

这种方式比较灵活,需要什么自己加就行了,加多少属性自己控制
方式二:

@ControllerAdvice
public class MyGlobalHandler {

    @ModelAttribute()
    public Map<String, String> presetParam(){
        Map<String, String> map = new HashMap<String, String>();
        map.put("key1", "value1");
        map.put("key2", "value2");
        map.put("key3", "value3");
        return map;
    }

}

这种方式对于加单个属性比较方便。默认会把返回值(如上面的map)作为属性的value,而对于key有两种指定方式:
1. 当 @ModelAttribute() 不传任何参数的时候,默认会把返回值的字符串值作为key,如上例的 key 则是 ”map"(值得注意的是,不支持字符串的返回值作为key)。
2. 当 @ModelAttribute(“myMap”) 传参数的时候,则以参数值作为key,这里 key 则是 ”myMap“。

  1. 全局参数使用
@RestController
public class AdviceController {

    @GetMapping("methodOne")
    public String methodOne(Model model){ 
        Map<String, Object> modelMap = model.asMap();
        return (String)modelMap.get("globalAttr");
    }

  
    @GetMapping("methodTwo")
    public String methodTwo(@ModelAttribute("globalAttr") String globalAttr){
        return globalAttr;
    }


    @GetMapping("methodThree")
    public String methodThree(ModelMap modelMap) {
        return (String) modelMap.get("globalAttr");
    }
    
}

这三种方式大同小异,其实都是都是从Model 中存储属性的 Map里取数据。

  1. 请求参数预处理

@ControllerAdvice 配合 @InitBinder 实现对请求参数的预处理
再次之前我们先来了解一下 @IniiBinder,先看一下源码,我会提取一些重要的注释进行浅析

具体参考CSDN@ControllerAdvice的介绍及三种用法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值