Spring-Web项目中的异常处理

前言

异常体系在任何计算机语言中都有着重要的分量,但是对于普通开发者来说总是存在着多多少少的疑问:什么时候使用异常?什么时候要对异常进行统一处理?该如何对异常进行统一处理?

这里,我将把我们后台系统的异常处理机制的演变过程进行阐释。

分散式处理

大家都知道,在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;
    }   
}
    原文作者:不去天涯
    原文地址: https://blog.csdn.net/BuquTianya/article/details/51115887
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞