spring注解@ControllerAdvice的原理分析和使用

@ControllerAdvice注解是Spring3.2中新增的注解,学名是Controller增强器,作用是给Controller控制器添加统一的操作或处理。

对于@ControllerAdvice,我们比较熟知的用法是结合@ExceptionHandler用于全局异常的处理,但其作用不止于此。ControllerAdvice拆开来就是Controller Advice,关于Advice,在Spring的AOP中,是用来封装一个切面所有属性的,包括切入点和需要织入的切面逻辑。这里ControllerAdvice也可以这么理解,其抽象级别应该是用于对Controller进行切面环绕的,而具体的业务织入方式则是通过结合其他的注解来实现的。@ControllerAdvice是在类上声明的注解,其用法主要有三点:

1.全局异常处理:结合方法型注解@ExceptionHandler,用于捕获Controller中抛出的指定类型的异常,从而达到不同类型的异常区别处理的目的。

2.全局数据预处理:结合方法型注解@InitBinder,用于request中自定义参数解析方式进行注册,从而达到自定义指定格式参数的目的。

3.全局数据绑定:结合方法型注解@ModelAttribute,表示其注解的方法将会在目标Controller方法执行之前执行。

从上面的讲解可以看出,@ControllerAdvice的用法基本是将其声明在某个bean上,然后在该bean的方法上使用其他的注解来指定不同的织入逻辑。不过这里@ControllerAdvice并不是使用AOP的方式来织入业务逻辑的,而是Spring内置对其各个逻辑的织入方式进行了内置支持。

测试代码:


/**
 * @ControllerAdvice 使用场景
 */
@ControllerAdvice(annotations = RestController.class)
public class GlobalControllerHandler {
    private static final Logger logger = LoggerFactory.getLogger(GlobalControllerHandler.class);


    /**
     * 把值绑定到Model中,使全局@RequestMapping可以获取到该值
     * @param model
     */
    @ModelAttribute
    public void addAttributes(Model model) {
        model.addAttribute("nandao", "hello world");
    }

    @ModelAttribute(value = "msg")
    public String globalModelAttribute() {
        System.out.println("hello word。");
        return "msg";
    }

    @ModelAttribute(name = "person")
    public Map<String,Object> mydata() {
        HashMap<String, Object> map = new HashMap<>();
        map.put("age", 99);
        map.put("gender", "人");
        return map;
    }

    /**
     * 应用到所有被@RequestMapping注解的方法,在其执行之前初始化数据绑定器
     */
    @InitBinder
    public void globalInitBinder(WebDataBinder binder) {
        binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
    }

    @InitBinder("nan")
    public void b(WebDataBinder binder) {
        binder.setFieldDefaultPrefix("nan.");
    }

    @InitBinder("nv")
    public void a(WebDataBinder binder) {
        binder.setFieldDefaultPrefix("nv.");
    }

    /**
     * 此注解主要是自定义异常功能
     * @param e
     * @return
     * @throws UnsupportedEncodingException
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Object logicExceptionHandler( Exception e) throws UnsupportedEncodingException {
        //系统级异常,错误码固定为-1,提示语固定为系统繁忙,请稍后再试
        RestResult result = new RestResult("5000", null, ErrorMessage.SYSTEM_EXCEPTION);

        //如果是业务逻辑异常,返回具体的错误码与提示信息,即可以自定义多种异常类型
        if (e instanceof BadRequestException) {
            BadRequestException badRequestException = (BadRequestException) e;
            setData(result,badRequestException.getCode(),badRequestException.getErrorMsg(),badRequestException.getInnerCode(),e);
        }else if (e instanceof TestException) {
            TestException testException = (TestException) e;
            setData(result,testException.getCode(),testException.getErrorMsg(),testException.getInnerCode(),e);
        }else {
            String msg = e.getMessage();
            if (!ContMsgExpUtil.isContMsg(msg)){
               msg = ErrorMessage.SYSTEM_EXCEPTION +msg;
            }
            result.setMessage(msg);
            logger.error("errorMsg={},innerCode={},exception={}" ,e.getMessage(),5000, e);
        }
        return JSONObject.toJSON(result);//正式返回给前端信息
    }
     void setData(RestResult result, int code, String errorMsg, String innerCode, Exception e) throws UnsupportedEncodingException {
        result.setMessage(errorMsg);
        result.setCode(innerCode);
        logger.error("errorMsg={},innerCode={},exception={}" ,errorMsg,innerCode,e);
        logger.info("已经爆出异常了啊!!!!!!");
     }
}

自定义异常:

/**
 * Created by nandao on 2021/12/22.
 * 业务逻辑异常类
 */
public class TestException extends RuntimeException {
    /**
     * 异常信息
     */
    private String errorMsg;
    /**
     * 错误码
     */
    private String innerCode;

    private int code;

    public String getInnerCode() {
        return innerCode;
    }

    public int getCode() {
        return code;
    }

    public String getErrorMsg() {
        return errorMsg;
    }


    public TestException(String errorMsg) {
        super(errorMsg);
        this.code = 500;
        this.innerCode = "5000";
        this.errorMsg = errorMsg; 
        this.errorMsg = "Internal Server Error: "+errorMsg;
         
    }

    public TestException(Integer innerCode, String errorMsg) {
        super(errorMsg);
        this.code = 500;
        this.innerCode = "500"+innerCode.toString();
        this.errorMsg = errorMsg;
        this.errorMsg = "Test Internal Server Error: "+errorMsg;
        
    }

    /**
     * 抛出逻辑异常的两个静态类,对应上面两种构造方法
     * @param errorMsg
     * @return
     */
    public static TestException le(String errorMsg) {
        return new TestException(errorMsg);
    }
    public static TestException le(Integer innerCode, String errorMsg) {
        return new TestException(innerCode,errorMsg);
    }

}

此时控制的的代码就会进行功能增强和全局异常处理,业务代码:


/**
 * @author wanghuainan
 * @date 2021/1/15 14:30
 */
@Slf4j
@RequestMapping("/nandao")
@RestController
public class TestControllerAdviceController {


    @RequestMapping(value = "/users", method = RequestMethod.GET)
    public void users(Date date) {
        System.out.println(date); // Tue May 02 00:00:00 CST 2019
    }

    @RequestMapping("/indexMap")
    public int indexMap(ModelMap modelMap) {
        System.out.println(modelMap.get("nandao"));
        Object nandao = modelMap.get("nandao");
        Object md = modelMap.get("md");
  //      JSONObject jsonObject = (JSONObject) JSON.toJSON(modelMap);
      //  JSONObject jsonObject = (JSONObject) JSON.toJSON(nandao);
        Map map =(HashMap)md;
        String age = ((HashMap) md).get("gender").toString();
        log.info(age);

        String s = String.valueOf(nandao);

        return 1;
    }

    // 也可以通过@ModelAttribute获取
    @RequestMapping("/indexAttribute")
    public Object indexAttribute(@ModelAttribute("words") String words) {
        System.out.println(words);
        return words;
    }

    //通过get方法获取数据
    @GetMapping("/hello")
    public String hello(Model model) {
        throw TestException.le(333,"参数为空");
      /*  Map<String, Object> map = model.asMap();
        System.out.println(map);
        int i = 1 / 0;*/
      //  return "hello controller advice";
    }

    @PostMapping("/book")
    public void book(@ModelAttribute("b") Book book) {
        System.out.println(book);
        throw TestException.le("参数为空");
      //  System.out.println(author);
    }

}

多测试几次,总结心得,就会在实战中使用的游刃有余,此篇文章和上一篇文章是一定关系大家可以参考一下相辅相成参考

### 回答1: @ControllerAdvice 注解是一种特殊的@Component,它可以用来全局处理控制器中的异常。它可以在控制器中定义一个通用的异常处理方法,以处理所有控制器中抛出的异常,而无需在每个控制器中定义异常处理方法。 ### 回答2: @ControllerAdvice注解Spring框架中的一个注解,用于定义全局异常处理器。它可以捕获在Controller层中抛出的异常,并对其进行统一的处理和转换。 @ControllerAdvice注解可以应用于类上,表示该类是一个全局异常处理类。它可以通过设置basePackages属性来指定需要处理异常的Controller所在的包路径。同时,它还可以通过设置annotations属性来指定需要处理的Controller类的注解使用@ControllerAdvice注解的类中的方法可以添加其他异常处理注解,比如@ExceptionHandler、@InitBinder和@ModelAttribute。这些注解可以用于定义特定的异常处理方法,达到根据不同的异常类型进行不同的异常处理的效果。 @ControllerAdvice注解的异常处理方法可以接受一个或多个异常类型参数,表示要处理的异常类型。在方法体中,可以对异常进行处理,比如打印日志、转换异常信息、返回错误页面等。 对于异常处理方法,可以设置返回值类型,返回值可以是ModelAndView、ResponseEntity或者@ResponseBody注解修饰的对象。通过返回值,可以指定异常处理后的跳转页面、返回错误信息等。 需要注意的是,当出现多个全局异常处理类时,Spring框架会按照顺序依次调用这些异常处理类的方法进行异常处理,直到找到一个匹配的处理方法为止。因此,在编写多个全局异常处理类时,应确保处理方法的顺序是正确的。 总的来说,@ControllerAdvice注解是一个非常强大的异常处理功能,它能够将所有Controller层抛出的异常进行统一的处理,提高代码的可维护性和可重用性。 ### 回答3: @ControllerAdvice注解Spring MVC框架中的一个注解,用于定义一个全局的异常处理类。它可以被用于定义一组可被所有@Controller注解的类所共享的通用异常处理逻辑。当控制器方法或请求处理过程中发生异常时,@ControllerAdvice注解会捕获这些异常,并根据定义的处理逻辑进行处理。 @ControllerAdvice注解使用步骤如下: 1. 创建一个类,并使用@ControllerAdvice注解进行注解。这个类通常放在与其他控制器类相同的包或子包下。 2. 在被@ControllerAdvice注解的类中,可以定义多个带有@ExceptionHandler注解的方法。这些方法用于处理特定类型的异常。例如,可以定义一个方法用于处理NullPointerException,另一个方法用于处理IOException等。 3. 在被@ControllerAdvice注解的类中,还可以定义带有@ModelAttribute注解的方法。这些方法可以添加全局的模型属性,这些属性可以在所有的@RequestMapping注解的方法中使用。 4. 在Spring MVC配置中,需要配置扫描被@ControllerAdvice注解的类。 @ControllerAdvice注解的优势在于它能够提供可重用的全局异常处理逻辑。它可以将异常处理逻辑与控制器类完全解耦,从而提高代码的可读性和可维护性。此外,@ControllerAdvice注解还可以用于添加全局的模型属性,进一步简化了开发过程。 总结来说,@ControllerAdvice注解Spring MVC框架中用于定义全局异常处理的注解。通过它,我们可以定义一组可以被所有@Controller注解的类所共享的通用异常处理逻辑,提高代码的可读性和可维护性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寅灯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值