前言
异常体系在任何计算机语言中都有着重要的分量,但是对于普通开发者来说总是存在着多多少少的疑问:什么时候使用异常?什么时候要对异常进行统一处理?该如何对异常进行统一处理?
这里,我将把我们后台系统的异常处理机制的演变过程进行阐释。
分散式处理
大家都知道,在spring-mvc中事务是要切在service层的,也就是当service层抛出异常时,进行数据库操作的回滚。其实也就是说,这一层我们不要去自己捕获异常,异常都由事务机制去拦截和处理,service层有异常只需要抛出即可。
那么捕获异常和处理异常的操作,很自然的就落到了controller层中,所以对于常见的,也就是分散式的处理方式,一般来说异常处理的代码是这个样子的:
//以下仅为示例代码
public class UserController{
@RequestMapping("/updateUserInfo")
public @ResponseBody String updateUserInfo(UserInfo ui){
try{
userService.updateUserInfo(ui)
}catch(Exception e){
return "更新失败";
}
return "更新成功";
}
}
这样实现的好处就是:很多人写的异常各自维护,不会相互影响,你改你的,我改我的。缺点也比较明显:就是很多的try…catch。
这时候,我们很自然的会想到统一处理,如果能够对异常进行统一处理,那么,在controller层就可以仅仅处理业务逻辑,不用写不必要的try…catch块了。
集中式处理
集中式处理异常有两种方式:一种是使用aop机制,给所有的controller层方面插入处理代码;另一种是使用spring提供的异常处理器机制。这里的第二种,更好一些,因为在实战中经常会遇到参数类型转换错误的异常,这是spring级别的异常,使用方法级别的aop机制不能捕获这些异常。以下说明spring的ExceptionResolver使用方法:
定义ExceptionResolver:
public class ExceptionResolver extends SimpleMappingExceptionResolver {
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
try {
Map<String,Object> result = new HashMap<String,Object>();
result.put("code", 1);
//有时候我们不希望直接把后台异常直接展示给用户
result.put("data", "请求处理错误");
JSONObject jo = JSONObject.fromObject(result);
//此行必加,否则返回的json在浏览器中看到是乱码,不易于识别
response.setHeader("Content-Type","text/html;charset=UTF-8");
response.getWriter().write(jo.toString());
response.getWriter().close();
} catch (Exception e) {
}
return null;
}
}
spring的配置文件中添加如下配置项:
<!-- 异常处理,返回json结果 -->
<bean id="exceptionResolver" class="你的ExceptionResolver类"></bean>
定义好以后,controller层中所有的try…catch就可以去掉了。是不是很好呢?
在实际中遇到复杂的业务逻辑时,也就是service层方法代码逻辑很复杂时,比如:下单、支付、领取优惠券等,根据不同的情况,需要给前端返回不同的错误信息,这个时候一种做法就是返回枚举值,在controller层去识别并返回具体错误信息,另外一种就是直接throw一个异常。
其实,我们只能用第二种方法,因为错误时,我们很可能需要让事务机制起效,想着让已经操作的一部分结果回滚,所以只能选择第二种方式来将错误信息放在异常的Message里面抛出。
这时候,我们就遇到了另外一个问题,spring级别的异常我们不想把message直接抛给前端,我们自己的异常又要把message抛给前端,这时候怎么办呢?
集中-分散式
遇到以上的情况,可以有一种方法处理。就是自定义异常,当controller层遇到自定义异常时,把异常信息返给前端。
也就是对于上述说到的复杂逻辑业务,在controller层仍然保留try…catch块,捕获自定义的异常。
那么,有没有,完全集中式的处理方案呢,其实,再前进一步就可以了。
改进型集中式处理
仍然需要自定义异常,当我们的逻辑要抛出逻辑层面的异常时,创建并抛出自定义的异常,然后在ExceptionResolver里对自定义异常进行差异化处理:
定义ExceptionResolver:
public class ExceptionResolver extends SimpleMappingExceptionResolver {
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
try {
Map<String,Object> result = new HashMap<String,Object>();
result.put("code", 1);
if(ex instanceof MyException){
result.put("data", "异常:"+ex.getMessage());
}else{
result.put("data", "请求处理错误");
}
JSONObject jo = JSONObject.fromObject(result);
//此行必加,否则返回的json在浏览器中看到是乱码,不易于识别
response.setHeader("Content-Type","text/html;charset=UTF-8");
response.getWriter().write(jo.toString());
response.getWriter().close();
} catch (Exception e) {
//e.printStackTrace();
}
return null;
}
}