Spring 3.2 新增 @ControllerAdvice 和 @RestControllerAdvice 注解。
@RestControllerAdvice is just a syntactic sugar for @ControllerAdvice + @ResponseBody。
类注解了 @ControllerAdvice 会被 Spring 扫描到,自动加载。
Usage
查看 @ControllerAdvice 定义可以看到其使用方式,注解的属性是用来划定 Advice 可以管理的 Controller 的范围,可以通过包名,类名,以及注解等等方式来划分。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {
/**
* Alias for the {@link #basePackages} attribute.
* <p>Allows for more concise annotation declarations — for example,
* {@code @ControllerAdvice("org.my.pkg")} is equivalent to
* {@code @ControllerAdvice(basePackages = "org.my.pkg")}.
* @since 4.0
* @see #basePackages
*/
@AliasFor("basePackages")
String[] value() default {};
/**
* Array of base packages.
* <p>Controllers that belong to those base packages or sub-packages thereof
* will be included — for example,
* {@code @ControllerAdvice(basePackages = "org.my.pkg")} or
* {@code @ControllerAdvice(basePackages = {"org.my.pkg", "org.my.other.pkg"})}.
* <p>{@link #value} is an alias for this attribute, simply allowing for
* more concise use of the annotation.
* <p>Also consider using {@link #basePackageClasses} as a type-safe
* alternative to String-based package names.
* @since 4.0
*/
@AliasFor("value")
String[] basePackages() default {};
/**
* Type-safe alternative to {@link #basePackages} for specifying the packages
* in which to select controllers to be advised by the {@code @ControllerAdvice}
* annotated class.
* <p>Consider creating a special no-op marker class or interface in each package
* that serves no purpose other than being referenced by this attribute.
* @since 4.0
*/
Class<?>[] basePackageClasses() default {};
/**
* Array of classes.
* <p>Controllers that are assignable to at least one of the given types
* will be advised by the {@code @ControllerAdvice} annotated class.
* @since 4.0
*/
Class<?>[] assignableTypes() default {};
/**
* Array of annotation types.
* <p>Controllers that are annotated with at least one of the supplied annotation
* types will be advised by the {@code @ControllerAdvice} annotated class.
* <p>Consider creating a custom composed annotation or use a predefined one,
* like {@link RestController @RestController}.
* @since 4.0
*/
Class<? extends Annotation>[] annotations() default {};
}
basePackages 配置
//@ControllerAdvice("cn.myz.demo.controller")
//@ControllerAdvice(value = "cn.myz.demo.controller")
@ControllerAdvice(basePackages = {"cn.myz.demo.controller"})
public class GlobalExceptionHandler {}
basePackages 指定一个或多个包,这些包下的 Controller 都会被该 Advice 管理。
basePackageClasses
@ControllerAdvice(basePackageClasses = {MyController1.class})
public class GlobalExceptionHandler {}
是 basePackages 的一种变形,指定一个或多个 Controller 类,这些类所属的包及其子包下的所有 Controller 都被该 @ControllerAdvice 管理。
assignableTypes
@ControllerAdvice(assignableTypes = {MyController1.class})
public class GlobalExceptionHandler {}
assignableTypes:指定一个或多个 Controller 类,这些类被该 @ControllerAdvice 管理。
annotations
@ControllerAdvice(annotations = {RestController.class})
public class GlobalExceptionHandler {}
annotations:指定一个或多个注解,被这些注解所标记的 Controller 会被该 @ControllerAdvice 管理。
作用
@ControllerAdvice注解可以将对 Controller 的全局配置放到一个位置- 在
@ControllerAdvice注解的类的方法,可以使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法@ExceptionHandler:用于全局处理控制器里的异常,进行全局异常处理@InitBinder:用来设置WebDataBinder,用于自动绑定前台请求参数到Model中,全局数据预处理。@ModelAttribute:本来作用是绑定键值对到Model中,此处让全局的@RequestMapping都能获得在此处设置的键值对 ,全局数据绑定。
@ControllerAdvice注解将作用在所有注解了@RequestMapping的控制器的方法上。
全局异常处理
@Slf4j
@ControllerAdvice(annotations = {Controller.class, RestController.class})
public class WebControllerAdvice {
@ResponseBody
@ExceptionHandler
public Map errorHandler(Exception ex) {
Map errorMap = new HashMap();
errorMap.put("code", 400);
//判断异常的类型,返回不一样的返回值
if (ex instanceof MissingServletRequestParameterException) {
errorMap.put("msg", "缺少必需参数:" + ((MissingServletRequestParameterException) ex).getParameterName());
} else if (ex instanceof MyException) {
errorMap.put("msg", "这是自定义异常");
}
return errorMap;
}
全局数据预处理
@ControllerAdvice
public class MyGlobalDataHandler {
@ModelAttribute(name = "md")
public Map<String,Object> getGlobalData(){
HashMap<String, Object> map = new HashMap<>();
map.put("age", 99);
map.put("gender", "男");
return map;
}
绑定
@InitBind