欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring mvc捕获异常时,如何判断应该返回json还是跳转错误页面

程序员文章站 2022-07-13 23:11:26
...

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有哪些信息呢?


spring mvc捕获异常时,如何判断应该返回json还是跳转错误页面
            
    
    博客分类: Java Webspring MVC 捕获异常时判断jsonExceptionHandler 
 

所以我们可以通过反射获取控制器方法,然后判断是否有注解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判断

  • spring mvc捕获异常时,如何判断应该返回json还是跳转错误页面
            
    
    博客分类: Java Webspring MVC 捕获异常时判断jsonExceptionHandler 
  • 大小: 102.8 KB