SpringBoot全局异常处理与自定义异常处理
下层基础决定上层建筑,所以我今天研究了一波异常处理机制。
为什么要研究“下层基础”呢?
首先,当只有把基础设施给建设完全我们才能快速进行开发,因为SpringBoot相对于Spring而言,已经提高了我们的开发效率,我们只需要在此基础上再完善,最终才能帮助我们快速开发。
话不多说,接下来讲讲我研究的一种思路。
全局异常处理
我们首先在SpringBoot工程下创建一个名为exception的包,然后在包下面新建一个类叫GlobalException
,我们利用@ControllerAdvice注解来捕获异常。
public class GlobalException {
@ResponseBody
@ExceptionHandler(value = Exception.class)
public Map getSysError(Exception e) {
Map<String,Object> map = new HashMap<>();
map.put("code", -1);
map.put("msg", e.getMessage());
map.put("request",RequestHelper.getRequestUrl());
return map;
}
}
getSysError
方法就是捕获系统出现的异常的一个方法,然后RequestHelper是我封装的一个获取请求方法和请求URL的类。具体实现如下:
public class RequestHelper {
public static HttpServletRequest getRequest() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
return request;
}
public static String getRequestUrl() {
String methods = getRequest().getMethod();
return methods+" "+getRequest().getServletPath();
}
}
然后,根据全局异常处理看看捕获到的异常结果是怎么样的,我们利用
1/0这个大家都很熟悉的一个异常作为例子。
@RestController
public class HelloController {
@GetMapping("/hello")
public int hello() {
return 1 / 0;
}
}
返回结果如下:
{
"msg": "/ by zero",
"request": "GET /hello",
"code": -1
}
但是需要注意的一点是,在部署上线项目的时候,我们不能直接去返回具体的系统错误信息,因此,在生产环境中,我们需要修改为“msg”:"服务器开小差了",类似于这种模糊的错误信息。
自定义异常处理
新建一个HttpException的自定义异常基础类,
@Data
public class HttpException extends RuntimeException {
private String msg;
private int code;
private String url = RequestHelper.getRequestUrl();
}
之后所有的自定义异常类都去继承HttpException,然后还有很重要的一点是为什么HttpException不去继承Exception这个类,而去继承RuntimeException这个类呢?原因请看
Java自定义异常,应该继承Exception还是Runtime
Exception,为什么?
然后在此示例中,我创建了一个NotFound类。
@Data
public class NotFound extends HttpException {
private String msg = "资源不存在";
private int code = 999;
public NotFound(String msg) {
this.msg = msg;
}
public NotFound() {
}
}
然后在GlobalExceptin 中添加以下代码:
@ControllerAdvice
public class GlobalException {
// 系统异常捕获
@ResponseBody
@ExceptionHandler(value = Exception.class)
public Map getSysError(Exception e) {
Map<String,Object> map = new HashMap<>();
map.put("code", -1);
map.put("msg", e.getMessage());
map.put("request",RequestHelper.getRequestUrl());
return map;
}
// 自定义异常捕获
@ResponseBody
@ExceptionHandler(value = HttpException.class)
public Map errorHandler(HttpException ex) {
Map<String,Object> map = new HashMap<>();
map.put("code", ex.getCode());
map.put("msg", ex.getMsg());
map.put("request",ex.getRequest());
return map;
}
}
我们在@ExceptionHandler(value = HttpException.class)中还是捕获了
HttpException这个类,这就是为什么之前
我们所有的自定义异常类全部继承HttpException这个基类的原因之一了。
然后我们再来测试下NotFound这个异常。
@RestController
public class HelloController {
@GetMapping("/hello")
public int hello() {
throw new NotFound();
}
}
结果如下:
{
"msg": "资源不存在",
"request": "GET /hello",
"code": 999
}
至此,异常处理就已经完成了。