作用

@ControllerAdvice,是 Spring3.2 提供的新注解

  • @ControllerAdvice 是一个 @Component,用于定义@ExceptionHandler,@InitBinder 和@ModelAttribute 方法,适用于所有使用 @RequestMapping 方法。
  • Spring4 之前,@ControllerAdvice 在同一调度的 Servlet 中协助所有控制器。Spring4 已经改变:@ControllerAdvice 支持配置控制器的子集,而默认的行为仍然可以利用。
  • 在 Spring4 中, @ControllerAdvice 通过 annotations(), basePackageClasses(), basePackages()方法定制用于选择控制器子集。

简单来说就是给所有的 Controller 加上统一的 @ExceptionHandler 或 @InitBinder 或 @ModelAttribute 处理。

统一异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

/**
* 处理所有不可知的异常
*/
@ExceptionHandler(Exception.class)
public ResponseEntity handleException(Exception e){
log.error("服务器异常:{}", e);
return new ResponseEntity<>("服务器异常,请稍后重试", HttpStatus.BAD_REQUEST);
}

/**
* 处理数组越界异常
*/
@ExceptionHandler(ArrayIndexOutOfBoundsException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR,reason = "数组越界")
public void handleAccessDeniedException(ArrayIndexOutOfBoundsException e){
log.error("数组越界:{}", e.getMessage());
}

/**
* 业务代码错误
*/
@ExceptionHandler(value = ServiceException.class)
public ResponseEntity serviceException(ServiceException e) {
log.error("业务代码错误:{}", e.getMessage());
return new ResponseEntity<>("业务代码错误:", HttpStatus.BAD_REQUEST);
}
}

@RestControllerAdvice 是 @ControllerAdvice 的增强,类似于 @RestController

上面的代码中可以看到通过 @RestControllerAdvice 注解,将上面的三种异常处理加到了所有的 controller 上,这样就能捕获所有能到达 controller 层的异常。

以上只是 demo 展示,最佳实战请见另一篇博客 spring 统一异常处理

统一日期映射处理

1
2
3
4
5
6
7
8
9
10
11
@ControllerAdvice
public class ControllerHandler {

@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}

}

相当于给所有的 controller 加了 initBinder,这样就可以自定义映射时间到 bean 中。还有一种通过 Converter 的写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// ControllerHandler.java
@ControllerAdvice
public class ControllerHandler {

@InitBinder
public void initBinder(WebDataBinder binder) {
GenericConversionService genericConversionService = (GenericConversionService) binder.getConversionService();
if (genericConversionService != null) {
genericConversionService.addConverter(new DateConverter());
}
}

}

// DateConverter.java
public class DateConverter implements Converter<String, Date> {
private static final String dateFormat = "yyyy-MM-dd HH:mm:ss";
private static final String shortDateFormat = "yyyy-MM-dd";
private static final String timeStampFormat = "^\\d+$";

@Override
public Date convert(String value) {
if(StringUtils.isEmpty(value)) {
return null;
}
value = value.trim();
try {
if (value.contains("-")) {
SimpleDateFormat formatter;
if (value.contains(":")) {
formatter = new SimpleDateFormat(dateFormat);
} else {
formatter = new SimpleDateFormat(shortDateFormat);
}
return formatter.parse(value);
} else if (value.matches(timeStampFormat)) {
Long lDate = new Long(value);
return new Date(lDate);
}
} catch (Exception e) {
throw new RuntimeException(String.format("格式化时间 %s 失败", value));
}
throw new RuntimeException(String.format("格式化时间 %s 失败", value));
}

}