# 7.4　为控制器添加通知

如果控制器类的特定切面能够运用到整个应用程序的所有控制器中，那么这将会便利很多。举例来说，如果要在多个控制器中处理异常，那 @ExceptionHandler 注解所标注的方法是很有用的。不过，如果多个控制器类中都会抛出某个特定的异常，那么你可能会发现要在所有的控制器方法中重复相同的 @Exception-Handler 方法。或者，为了避免重复，我们会创建一个基础的控制器类，所有控制器类要扩展这个类，从而继承通用的 @ExceptionHandler 方法。

Spring 3.2 为这类问题引入了一个新的解决方案：控制器通知。控制器通知（controller advice）是任意带有 @ControllerAdvice 注解的类，这个类会包含一个或多个如下类型的方法：

* @ExceptionHandler 注解标注的方法；
* @InitBinder 注解标注的方法；
* @ModelAttribute 注解标注的方法。

在带有 @ControllerAdvice 注解的类中，以上所述的这些方法会运用到整个应用程序所有控制器中带有 @RequestMapping 注解的方法上。

@ControllerAdvice 注解本身已经使用了 @Component，因此@Controller-Advice 注解所标注的类将会自动被组件扫描获取到，就像带有 @Component 注解的类一样。

@ControllerAdvice 最为实用的一个场景就是将所有的 @ExceptionHandler 方法收集到一个类中，这样所有控制器的异常就能在一个地方进行一致的处理。例如，我们想将 DuplicateSpittleException 的处理方法用到整个应用程序的所有控制器上。如下的程序清单展现的 AppWideExceptionHandler 就能完成这一任务，这是一个带有 @ControllerAdvice 注解的类。

{% code title="程序清单 7.10　使用 @ControllerAdvice，为所有的控制器处理异常" %}

```java
package spittr.web;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class AppWideExceptionHandler {

  @ExceptionHandler(DuplicateSpittleException.class)
  public String handleNotFound() {
    return "error/duplicate";
  }

}
```

{% endcode %}

现在，如果任意的控制器方法抛出了 DuplicateSpittleException，不管这个方法位于哪个控制器中，都会调用这个 duplicateSpittleHandler() 方法来处理异 常。我们可以像编写 @RequestMapping 注解的方法那样来编写 @Exception-Handler 注解的方法。如程序清单 7.10 所示，它返回 `error/duplicate` 作为逻辑视图名，因此将会为用户展现一个友好的出错页面。
