@ControllerAdvice实现全局异常处理,以及其他两个应用场景详解

@ControllerAdvice实现全局异常处理,以及其他两个应用场景详解

一、@ControllerAdvice是什么?

@ControllerAdvice,是Spring3.2提供的新注解,它是一个Controller增强器,可对controller中被 @RequestMapping注解的方法加一些逻辑处理。我们可以使用@ControllerAdvice来声明一些全局性的东西,最常见的是结合@ExceptionHandler注解用于全局异常的处理。以及搭配@ModelAttribute和@InitBinder使用。

二、三种使用场景

1. 搭配@ExceptionHandler,实现全局异常处理

  1. 创建一个全局异常类;
  2. 在该全局异常类上添加注解:@ControllerAdvice;
  3. 在该全局异常类中定义"方法1",并添加注解:@ExceptionHandler(AccessDeniedException.class);
  4. 其中定义的 AccessDeniedException.class 表明该"方法1"用来处理 AccessDeniedException类型的异常。
  5. 在该全局异常类中定义"方法2",并添加注解:@ExceptionHandler(Exception.class);
  6. 表明该"方法2"用来处理所有类型的异常。
  7. 在该全局异常类中定义的方法的参数,可以是异常类的实例、HttpServletResponse、HttpServletRequest或者Model 等;
  8. 在该全局异常类中定义的方法的返回值可以是一段 JSON、一个 ModelAndView、一个逻辑视图名等等;
  9. @ControllerAdvice可以指定扫描路径:@ControllerAdvice(basePackages={“cn.hadoopx.system”, “cn.hadoopx.common”})
示例代码如下:
/**
 * 全局异常处理
 */
@ControllerAdvice // 可指定包前缀,比如:(basePackages = "com.pj.admin")
public class GlobalException {

    @ResponseBody
    @ExceptionHandler
    public ServerResponse<String> handlerException(Exception e, HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        // 不同异常返回不同状态码
        ServerResponse<String> serverResponse = new ServerResponse<>();
        if (e instanceof NotLoginException) {
            // 如果是未登录异常
            NotLoginException ee = (NotLoginException) e;
            serverResponse.setMessage("用户未登录!");
            serverResponse.setCode(StateCode.NOT_LOGIN);
            serverResponse.setData(ee.getMessage());
        } else if(e instanceof NotRoleException) {
            // 如果是角色异常
            NotRoleException ee = (NotRoleException) e;
            serverResponse.setCode(StateCode.NOT_JUR);
            serverResponse.setMessage("角色异常!");
            serverResponse.setData(ee.getMessage());
        } else if(e instanceof NotPermissionException) {
            // 如果是权限异常
            NotPermissionException ee = (NotPermissionException) e;
            serverResponse.setMessage("权限异常!");
            serverResponse.setCode(StateCode.NOT_JUR);
            serverResponse.setData(ee.getMessage());
        } else if(e instanceof DisableLoginException) {
            // 如果是被封禁异常
            DisableLoginException ee = (DisableLoginException) e;
            serverResponse.setMessage("封禁异常!");
            serverResponse.setData(ee.getMessage());
        } else if(e instanceof HttpRequestMethodNotSupportedException) {
            serverResponse.setMessage("请求异常!");
            serverResponse.setCode(StateCode.ILLEAGL_ARG);
            serverResponse.setData(e.getMessage());
        } else {
            // 普通异常, 输出:500 + 异常信息
            e.printStackTrace();
            serverResponse.setMessage("服务器内部错误!");
            serverResponse.setData(e.getMessage());
            serverResponse.setCode(StateCode.ERROR);
        }
        return serverResponse;
    }
}
优缺点:

优点:将Controller层的异常和数据校验的异常进行统一处理,减少模板try-catch的代码,减少编码量,提升扩展性和可维护性。
缺点:只能处理Controller层未捕获的异常,无法捕获拦截器层和SPRING框架层的异常。

2. 搭配@ModelAttribute注解组合使用,完成全局数据绑定

用法:

全局数据绑定可以用来做一些初始化数据的操作,可以将一些公共的数据定义在添加了@ControllerAdvice注解的类中,这样的话每个Controller接口都能访问这些数据。
A. 使用@Model Attribute 注解标记的方法,返回数据是一个全局数据;
B. @ModelAttribute(value = “looker”), 其中 value 属性表示这条返回数据的KEY,而方法的返回值是返回数据的VALUE。

示例代码如下:
@ControllerAdvice
public class TheLooker{
	// 方式1
    @ModelAttribute(value  = "looker")
    public Map<String, String> globalData() {
        HashMap<String, String> map = new HashMap<>();
        map.put("name", "ROCKY");
        map.put("age", "30");
        map.put("info", "rich");
        return map;
    }
    // 方式2, @ModelAttribute也可以不写value参数,直接在方法中对全局Model设置key和value
	@ModelAttribute
    public void addAttributes(Model model) {
        HashMap<String, String> map = new HashMap<>();
        map.put("name", "ROCKY");
        map.put("age", "30");
        map.put("info", "rich");
        model.addAttribute("looker", map);
    }
}

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello(Model model) {
        Map<String, Object> map = model.asMap();
        // 获取全局数据
        Map<String, String> info = (Map<String, String>)map.get("looker");
        String result = "info:" + info;
        return result;
    }
}

3. 与@InitBinder注解组合使用,完成全局数据预处理(请求参数预处理)

用法:
  1. 在Controller中定义一个方法public void initBinder(WebDataBinder binder) {};
  2. 在initBinder方法上添加注解:@InitBinder;
  3. 一般会定义一个Controller的基类,在该基类中定义initBinder方法。
示例代码如下:
/**
 * WEB层通用数据处理
 * @author ROCKY
 */
public class BaseController {

    /**
     * 将前台传递过来的日期格式的字符串转化为Date类型,否则无法将数据绑定到实体中。
     * 自定义类型转换器有两种方式:A. implements Converter<String, Date> 或者 B. extends PropertyEditorSupport;
     * 在WebDataBinder对象中,可以设置前缀,可以设置允许、禁止的字段、必填字段以及验证器,可以自定义类型转换器。
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        // Date 类型转换
        binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
            @Override
            public void setAsText(String text) {
                setValue(DateUtils.parseDate(text));
            }
        });
    }
}
好的,您想了解关于使用 @ExceptionHandler + @ControllerAdvice +枚举实现全局异常统一处理的内容,这是一个常用的方案,可以实现全局异常的捕获和处理,让程序更加健壮和稳定。 @ExceptionHandler注解用于标记一个方法,该方法用于处理指定的异常类型。@ControllerAdvice注解用于标记一个类,该类用于处理全局异常。枚举则可以用于定义异常类型,方便异常处理时的统一管理。 在实现全局异常处理时,我们可以通过 @ExceptionHandler 注解来捕获指定的异常类型,并在方法中进行相应的处理。@ControllerAdvice注解可以让我们在一个类中定义多个 @ExceptionHandler方法,用于处理不同类型的异常。同时,我们也可以使用枚举来定义不同的异常类型,方便管理和调用。 下面是一个简单的示例,演示如何使用 @ExceptionHandler + @ControllerAdvice +枚举实现全局异常统一处理: ```java @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(value = BusinessException.class) @ResponseBody public ResultVO handleBusinessException(BusinessException e) { return ResultVO.error(e.getCode(), e.getMessage()); } } public enum ExceptionEnum { PARAMETER_ERROR(1001, "参数错误"), DATA_NOT_FOUND(1002, "数据不存在"), SYSTEM_ERROR(5000, "系统错误"); private final int code; private final String message; ExceptionEnum(int code, String message) { this.code = code; this.message = message; } public int getCode() { return code; } public String getMessage() { return message; } } public class BusinessException extends RuntimeException { private final int code; public BusinessException(int code, String message) { super(message); this.code = code; } public BusinessException(ExceptionEnum exceptionEnum) { super(exceptionEnum.getMessage()); this.code = exceptionEnum.getCode(); } public int getCode() { return code; } } ``` 在上面的示例中,GlobalExceptionHandler类标记了@ControllerAdvice注解,用于全局异常处理。其中,handleBusinessException方法用于处理BusinessException异常,返回一个ResultVO对象,其中含错误码和错误信息。 BusinessException则是一个自定义的异常类,它含一个code属性和一个message属性,用于表示异常的错误码和错误信息。同时,它还提供了一个构造方法,可以根据ExceptionEnum来构造一个BusinessException对象。 ExceptionEnum则是一个枚举类,含了不同的异常类型,每个异常类型都有一个对应的错误码和错误信息。 在实际开发中,我们可以根据实际需求来定义不同的异常类型和错误码,以便更好地管理和调用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值