spring mvc捕獲異常時,如何判斷應該返回json還是跳轉錯誤頁面

spring mvc捕獲異常時,如何判斷應該返回json還是跳轉錯誤頁面

 在異常捕獲handler  BusinessExceptionHandlerAdvice

 判斷控制器的方法是否有ResponseBody註解,如果有,則返回json,

關鍵問題是:

如何判斷控制器的方法是否有ResponseBody註解

我們先看看@ExceptionHandler方法中注入的參數有哪些?

1. ServletResponse.class
2. OutputStream.class
3. Writer.class
4. WebRequest.class
5. ServletRequest.class
6. MultipartRequest.class
7. HttpSession.class
8. Principal.class
9. Locale.class
10. InputStream.class
11. Reader.class

直接獲取控制器方法(java.lang.reflect.Method)的計劃破滅了,

那麼還有沒有其他方法呢?

有!通過異常的堆棧 StackTraceElement

那麼StackTraceElement有哪些信息呢?



 

所以我們可以通過反射獲取控制器方法,然後判斷是否有註解ResponseBody.class

具體實現(直接上代碼):

package oa.web.controller.handler;

import com.common.bean.BaseResponseDto;
import com.common.bean.exception.LogicBusinessException;
import com.common.util.ReflectHWUtils;
import com.common.util.SystemHWUtil;
import com.common.util.WebServletUtil;
import com.string.widget.util.ValueWidget;
import org.apache.log4j.Logger;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URLEncoder;

/**
 * Created by whuanghkl on 3/30/16.
 * 注意使用註解@ControllerAdvice作用域是全局Controller範圍
 * 可應用到所有@RequestMapping類或方法上的@ExceptionHandler、@InitBinder、@ModelAttribute,在這裏是@ExceptionHandler<br />
 * 用於檢測第三方接口,比如bsvc或cia的504,502等異常<br />
 * 這些異常均屬於非業務異常,與業務毫無關係,所以單獨處理<br />
 * 注意:StoreBusinessException 不要捕獲,否則無法被BusinessExceptionHandlerAdvice 截獲<br />
 * 注意:傳遞url中的參數如果可能包含中文一定要URL編碼,
 */
@ControllerAdvice
public class BusinessExceptionHandlerAdvice {
    public static Logger logger = Logger.getLogger(BusinessExceptionHandlerAdvice.class);

    /***
     * 判斷接口的註解是否是ResponseBody,是,那麼返回json,而不是跳轉錯誤頁面
     * @param stackTraceElement
     * @return
     */
    public static boolean isControllerAction(StackTraceElement stackTraceElement) {
        String className = stackTraceElement.getClassName();
        if (className.endsWith("Controller")) {
            try {
                Class controllerClass = Class.forName(className);
                Method actionMethod = ReflectHWUtils.getMethod(controllerClass, stackTraceElement.getMethodName(), ResponseBody.class);
                if (null == actionMethod) {
                    return false;
                }
                return true;
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    /***
     * 判斷接口的註解是否是ResponseBody,是,那麼返回json,而不是跳轉錯誤頁面<br />
     * 限制最多循環4次,否則影響性能
     * @param stackTraceElements
     * @return
     */
    public static boolean isControllerAction(StackTraceElement[] stackTraceElements) {
        int length = stackTraceElements.length;
        if (length > 4) {
            length = 4;
        }
        for (int i = 0; i < length; i++) {
            StackTraceElement stackTraceElement = stackTraceElements[i];
            if (isControllerAction(stackTraceElement)) {
                return true;
            }
        }
        return false;
    }
    @ExceptionHandler(LogicBusinessException.class)
//    @RESPONSE_CONTENTTYPE_JSON_UTFStatus(HttpStatus.BAD_REQUEST)
//    @ResponseBody
    public String handleBusinessException(LogicBusinessException ex, HttpSession session, HttpServletRequest request, HttpServletResponse response) {
//        return ClassUtils.getShortName(ex.getClass()) + ex.getMessage();
        logger.error(ex);//{errorCode='1021', errorMessage='用戶不在組織的企業客戶身份中'}


        logger.error("old url:" + request.getRequestURL());
        logger.error("query string:" + request.getQueryString());
        StackTraceElement[] stackTraceElements = ex.getStackTrace();
       
        if (!ex.isWap()) {
            boolean isControllerAction = isControllerAction(stackTraceElements);
            System.out.println("isControllerAction :" + isControllerAction);
            if (isControllerAction) {
                ex.setWap(true);//表示返回json
            }
        }

        if (ex.isWap() || WebServletUtil.getMobileOsInfo(request).isMobile()) {//如果是手機端
            PrintWriter out = null;
            try {
                out = response.getWriter();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (ValueWidget.isNullOrEmpty(ex.getResponseBody())) {
                out.print(new BaseResponseDto(ex.getErrorCode(), ex.getErrorMessage()).toJson());
            } else {
                out.print(ex.getResponseBody());
            }
            out.flush();
        } else {
            String redirectUrl = null;
            if (ValueWidget.isNullOrEmpty(ex.getRedirectUrl())) {
                String message = null;
                message = getMessage(ex);
                redirectUrl = "/error.html?error=" + ex.getErrorCode() + "&errorMessage=" + message;
            } else {
                redirectUrl = ex.getRedirectUrl();
            }
            logger.error("redirect url:" + redirectUrl);
            try {
                response.sendRedirect(redirectUrl);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    /***
     *
     * @param ex
     * @param message :中文已經經過url 編碼
     * @return
     */
    private static String getMessage(LogicBusinessException ex) {
        String message = null;
        if (ValueWidget.isNullOrEmpty(ex.getErrorMessage())) {
            message = SystemHWUtil.EMPTY;
        } else {
            try {
                message = URLEncoder.encode(ex.getErrorMessage(), "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return message;
    }
}

 

簡單說明下:

先判斷isWap是否爲true,如果爲true,說明已經手動指定返回json了,那麼就不用判斷了.

否則才需要通過StackTraceElement判斷

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