spring mvc 统一异常处理

简介

框架的强大之处就在于把很多需要重复编写的代码剥离出来,形成核心的处理方式。

在异常的处理这块,你不需要再有过多的 try-catch 语句,只需要把异常抛给框架就行了,框架帮你处理!

在 spring mvc 中的统一异常处理有3种,本文拿最简单的一种来演示 。

自定义异常

为了更精确的定位异常,区分异常种类,我们会用到自定义异常。

考虑下如下场景:系统需要提供一个 API,供其它系统查看消息,服务器之间采用 json 交互,这时候我们需要自定一个异常,用来表示逻辑受理失败(比如对方未传必填参数)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ServiceException extends RuntimeException {

private String code;

public ServiceException(String msg) {
super(msg);
}

public ServiceException(String code, String msg) {
super(msg);
this.code = code;
}

public String getCode() {
return code;
}

public void setCode(String code) {
this.code = code;
}
}

上面定义了一个自定义异常类 ServiceException ,用来返回错误码及错误信息。

下面我们来看下 service 的代码:

1
2
3
4
5
6
public Message findById(Long id) {
if (id == null) {
throw new ServiceException("10001", "id不能为空!");
}
return messageManager.findOne(id);
}

接受一个 id 的参数,先判断是否为空,如果为空,抛出异常;如果不为空,查找该 id 对应的消息。

接下来,我们有两种选择:

  • 在 controller 中使用 try-catch 处理
  • 把异常抛给上层框架统一处理

使用 try-catch 处理异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RequestMapping("/getMessage")
@ResponseBody
public String getMessage(Long id) {
String result = StringUtils.EMPTY;
try {
Message message = messageService.findById(id);
result = JSON.toJSONString(message);
} catch (ServiceException e) {
JSONObject jb = new JSONObject();
jb.put("msg", e.getMessage());
jb.put("code", e.getCode());
result = JSON.toJSONString(jb);
}
return result;
}

这种方式是不可取的,我们需要对每个方法都加上 try-catch 进行处理。

如果有多种异常,或者说后期又增加了一种异常,维护起来会非常麻烦。

框架统一处理

spring 为我们提供了 ControllerAdvice 机制来统一处理异常,使用起来也比较方便。

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

@ExceptionHandler(value = ServiceException.class)
@ResponseBody
public String handleServiceException(ServiceException e) {
JSONObject jb = new JSONObject();
jb.put("msg", e.getMessage());
jb.put("code", e.getCode());
return JSON.toJSONString(jb);
}
}

这样,我们就能很轻松的统一地去处理异常了。

总结

我们只需要定义一个统一异常处理类,加上 @ControllerAdvice 注解,就能统一地处理异常。

在方法上使用 @ExceptionHandler 注解来处理指定的异常。

《java 编程思想》中说到:

异常设计的初衷是解决程序运行中的各种意外情况,且异常的处理效率比条件判断方式要低很多。

因此我们要尽量减少异常,更不要用异常进行业务逻辑处理。