spring統一異常處理的3種方法(含可運行的完整代碼)

代碼中一堆try-catch塊非常冗餘和囉嗦,對閱讀也造成了一定的干擾,使注意力很難集中到核心業務上來。

因此我們使用統一異常處理,將這些重複的try-catch塊抽取出來,這樣使我們可以更專注於業務邏輯的處理,同時能夠使得異常的處理有一個統一的控制。

1.HandlerExceptionResolver全局異常處理

使用全局異常處理器只需要兩步:
1.實現HandlerExceptionResolver接口。
2.將實現類作爲Spring Bean,這樣Spring就能掃描到它並作爲全局異常處理器加載。

/**
 * 全局異常處理
 * 
 * @Order(-1000) 爲了使優先級最高
 * 寫@Order(0)也行,-1000保險點
 * 
 * @Component 把普通pojo實例化到spring容器中,
 * 相當於配置文件中的 <bean id="" class=""/>
 */
@Order(-1000)
@Component
public class ExceptionResolver implements HandlerExceptionResolver {

    private static Logger logger = LoggerFactory.getLogger(ExceptionResolver.class);

    @Override
    public ModelAndView resolveException(HttpServletRequest request,
                                         HttpServletResponse response, Object handler, Exception ex) {
        ResultVO result = new ResultVO();
        StringBuilder sb = new StringBuilder();

        //處理異常
        if(ex instanceof BussinessException) {
            resolverBussinessException(ex, sb, result);
        } else if (ex instanceof BindException) {
            resolverBindException(ex, sb, result);
        } else {
            resolverOtherException(ex, sb, result);
        }

        result.setCode(0);
        result.setResult(sb);
        result.setTime(new Date());

        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Cache-Control", "no-cache, must-revalidate");
        try {
            response.getWriter().write(JSON.toJSONString(result));
        } catch (IOException e) {
            logger.error("與客戶端通訊異常:" + e.getMessage(), e);
            e.printStackTrace();
        }

        logger.debug("異常:" + ex.getMessage(), ex);
        ex.printStackTrace();

        return new ModelAndView();
    }

    /*
     * 處理業務層異常
     */
    private void resolverBussinessException(Exception ex, StringBuilder sb, ResultVO result) {
        BussinessException businessException = (BussinessException) ex;
        sb.append(businessException.getMsg());
        addResult(result, "業務異常");
    }

    /*
     * 處理參數綁定異常
     */
    private void resolverBindException(Exception ex, StringBuilder sb, ResultVO result) {
        BindException be = (BindException) ex;
        List<FieldError> errorList = be.getBindingResult().getFieldErrors();
        for (FieldError error : errorList) {
            sb.append(error.getObjectName());
            sb.append("對象的");
            sb.append(error.getField());
            sb.append("字段");
            sb.append(error.getDefaultMessage());
        }
        addResult(result, "參數傳遞異常");
    }

    /*
     * 處理其他異常
     */
    private void resolverOtherException(Exception ex, StringBuilder sb, ResultVO result) {
        sb.append(ex.getMessage());
        addResult(result, "其他異常");
    }

    /*
     * 封裝code和msg
     */
    private void addResult(ResultVO result, String msg) {
        result.setMsg(msg);
    }

}

2. Controller局部異常處理

這種異常處理只局部於某個Controller內,如:


@RestController
public class TestControllerException {

    @RequestMapping("/conError")
    public String conError() {
        int a = 1 / 0;
        return "this is conError" + a;
    }

    /**
     * 單個controller進行異常處理
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public String exceptionHandler(Exception e) {
        System.out.println(e);
        return "這是controller內的異常處理方法 。。。 ";
    }
}

3.@ControllerAdvice

如果單使用2中的@ExceptionHandler,只能在當前Controller中處理異常。但當配合@ControllerAdvice一起使用的時候,則可以全局捕獲。

@ControllerAdvice,是Spring3.2提供的新註解,它是一個Controller增強器,可對controller中被@RequestMapping註解的方法加一些邏輯處理,最常用的就是異常處理。

需要配合@ExceptionHandler使用。
當將異常拋到controller時,可以對異常進行統一處理,規定返回的json格式或是跳轉到一個錯誤頁面。

@ControllerAdvice
public class ControllerExceptionHandler {

    private Logger logger = LoggerFactory.getLogger(ControllerExceptionHandler.class);

    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody // 如果使用了@RestControllerAdvice,這裏就不需要@ResponseBody了
    public Map handler(Exception ex) {
        logger.error("統一異常處理", ex);
        Map<String, Object> map = new HashMap<>();
        map.put("code", 400);
        //判斷異常的類型,返回不一樣的返回值
        if(ex instanceof MissingServletRequestParameterException){
            map.put("msg","缺少必需參數:"+((MissingServletRequestParameterException) ex).getParameterName());
        }
        else if(ex instanceof BussinessException){
            map.put("msg","這是自定義異常");
        }
        return map;
    }
}
@RestController
public class TestAdvice {

    @RequestMapping("testException")
    public String testException() throws Exception{
        throw new MissingServletRequestParameterException("name","String");
    }

    @RequestMapping("testBussinessException")
    public String testMyException() throws BussinessException {
        throw new BussinessException("i am a BussinessException");
    }
}

4.完整項目代碼

可以運行調試的代碼:https://github.com/Aiwz1314/StudyDemo/tree/master/StudySpring

運行效果如下圖:
原生異常
自定義異常

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章