异常的统一处理:在用 springboot 搭建项目,返回 json 数据时,例如某个接口需要查询用户 id 为 10 的个人信息。假如查询 id 为 20 的用户,而这个用户不存在,那么需要返回友好的处理信息。这时可以编写一个自定义异常,在未查询到结果的时候,抛出这个异常,并在异常中添加产生的原因等信息。
创建一个项目,目录结构如下:
先看看 controller 层中的代码,只有一个方法,根据 id 返回用户的基本信息。
@Controller public class UserController { @Autowired private UserService userService; @GetMapping("/user") public ResponseEntity getUser(@Param("id")Integer id) throws Exception { String result = userService.getUser(id); return ResponseEntity.ok(new ResultData<String>(result)); } }
里面调用了 service 层的方法。查看 service 层的代码。
@Service public class UserService { public String getUser(Integer id) { String user = null; // 模拟数据库查询 if (id == 10) { user = "name: tom; age: 12"; } // 判断是否查询到结果 未查询到则抛出异常 if (user == null) { throw new MyException("505", "can not find record"); } // 返回结果 return user; } }
service 调用 dao 层从数据库查数据,这里简化了一下逻辑,并没有从数据库查数据。
这里抛出了一个自定义异常,查看自定义异常 MyException 的内容:
public class MyException extends RuntimeException{ private String code; private String msg; public MyException(String code, String msg) { this.code = code; this.msg = msg; } }
继承了 RuntimeException 并且加了两个属性值。
运行项目,然后查看 id 为 20 的用户信息,显然是没有,此时项目返回的数据如下:
{ "timestamp": "2019-11-02T09:13:56.919+0000", "status": 500, "error": "Internal Server Error", "message": "No message available", "path": "/user" }
这样的返回数据肯定有问题,出现这样的问题是因为我们的自定义异常 MyException 没有被 springmvc 的内置拦截器处理,需要自定义一下 MyException 的处理逻辑。
增加一个 MyControllerAdvice 类,并加上 @ControllerAdvice 注解,其内容核心如下:
@ResponseBody @ControllerAdvice public class MyControllerAdvice { @ExceptionHandler(Exception.class) public Map<String, Object> errorHandle(Exception e){ Map<String, Object> map = new HashMap<String, Object>(); map.put("code", -1); map.put("msg", e.getMessage()); return map; } @ExceptionHandler(value = MyException.class) public Map<String,Object> errorHandle(MyException e){ Map<String,Object> map = new HashMap<String,Object>(); map.put("code",e.getCode()); map.put("msg",e.getMsg()); return map; } }
这个类中有两个方法,第一个方法是处理通常的异常 Exception 的, 这个方法不加也可以。第二个方法就是处理我们自定义的异常的。获取异常中的信息存入 map 然后返回。