SpringMVC 统一异常处理

阅读更多
先说说 网上流传的几种处理方式:
方式1:使用SimpleMappingExceptionResolver实现异常处理  (试验过, 对于表单请求异常 和ajax 请求异常处理不方便) 实验的结果就是判断 如果出现404 500错误,判断不出来源是ajax 还是 普通页面请求  所以放弃了
package cn.mwee.wpos.report.cache;

import cn.mwee.utils.error.ThrowableUtil;
import cn.mwee.wpos.report.consts.ResultCode;
import cn.mwee.wpos.service.conts.ErrorCode;
import cn.mwee.wpos.service.conts.ErrorDesc;
import cn.mwee.wpos.service.dto.common.ErrorResult;
import com.alibaba.fastjson.JSON;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;


/**
 * Created by luob on 2017/6/27.
 */
public class GlobalExceptionResolver extends SimpleMappingExceptionResolver {
   @Override
   protected ModelAndView doResolveException(HttpServletRequest request,
                          HttpServletResponse response, Object handler, Exception ex){
             String viewName = determineViewName(ex,request);
             response.setCharacterEncoding("UTF-8");

             String requestType = request.getHeader("X-Requested-With");
             if (viewName != null) {// JSP格式返回
                 if (!(request.getHeader("accept").indexOf("application/json") > -1 || (request
                         .getHeader("X-Requested-With") != null && request
                         .getHeader("X-Requested-With").indexOf("XMLHttpRequest") > -1))) {
                        // 如果不是异步请求
                             // Apply HTTP status code for error views, if specified.
                             // Only apply it if we're processing a top-level request.
                             Integer statusCode = determineStatusCode(request, viewName);
                             if (statusCode != null){
                                 applyStatusCodeIfPossible(request, response, statusCode);
                             }
                             return getModelAndView(viewName, ex, request);
                         } else {// JSON格式返回
                             try {
                                     PrintWriter writer = response.getWriter();
                                     Map  result=new HashMap<>();
                                     ErrorResult error=new ErrorResult(ErrorCode.FAIL, ErrorDesc.FAIL, ThrowableUtil.getStackTrace(ex));
                                     result.put(ResultCode.ERROR,error);
                                     writer.write(JSON.toJSONString(result));
                                     writer.flush();
                                     writer.close();
                                 } catch (IOException e) {
                                     e.printStackTrace();
                                 }
                             return null;
                         }
             } else{
                 return null;
             }
         }
    
}


方法二:@ExceptionHandler + @ControllerAdvice
问题是:可以正确获取 所有的异常 ,但是request 和response 获取不到 异常后 应该返回的 status 比如 404  500 415
package cn.mwee.wpos.report.controller;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;

@ControllerAdvice
@Slf4j
public class ErrorHandlerController {

    @ExceptionHandler(value = Exception.class)
    public String exception(HttpServletRequest request, Exception ex) {
        log.info("ErrorHandlerController.exception");
        request.setAttribute("httpStatus", Integer.toString(getHttpStatus(ex).value()));
        request.setAttribute("httpMessage", getHttpStatus(ex).getReasonPhrase());
        request.setAttribute("errorType", ex.getClass().getName());
        request.setAttribute("errorMessage", ex.getMessage());
        request.setAttribute("errorStackTrace", ExceptionUtils.getStackTrace(ex));
       //必须是 forward 否则 /error 区分不了 ajax 和普通的请求
        return "forward:/error";
    }

    public HttpStatus getHttpStatus(Exception ex) {
        if (ex instanceof org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException) {
            return HttpStatus.NOT_FOUND;
        } else if (ex instanceof HttpRequestMethodNotSupportedException) {
            return HttpStatus.METHOD_NOT_ALLOWED;
        } else if (ex instanceof HttpMediaTypeNotSupportedException) {
            return HttpStatus.UNSUPPORTED_MEDIA_TYPE;
        } else if (ex instanceof HttpMediaTypeNotAcceptableException) {
            return HttpStatus.NOT_ACCEPTABLE;
        } else if (ex instanceof MissingPathVariableException) {
            return HttpStatus.INTERNAL_SERVER_ERROR;
        } else if (ex instanceof MissingServletRequestParameterException) {
            return HttpStatus.BAD_REQUEST;
        } else if (ex instanceof ServletRequestBindingException) {
            return HttpStatus.BAD_REQUEST;
        } else if (ex instanceof ConversionNotSupportedException) {
            return HttpStatus.INTERNAL_SERVER_ERROR;
        } else if (ex instanceof TypeMismatchException) {
            return HttpStatus.BAD_REQUEST;
        } else if (ex instanceof HttpMessageNotReadableException) {
            return HttpStatus.BAD_REQUEST;
        } else if (ex instanceof HttpMessageNotWritableException) {
            return HttpStatus.INTERNAL_SERVER_ERROR;
        } else if (ex instanceof MethodArgumentNotValidException) {
            return HttpStatus.BAD_REQUEST;
        } else if (ex instanceof MissingServletRequestPartException) {
            return HttpStatus.BAD_REQUEST;
        } else if (ex instanceof BindException) {
            return HttpStatus.BAD_REQUEST;
        } else if (ex instanceof NoHandlerFoundException) {
            return HttpStatus.NOT_FOUND;
        } else if (ex instanceof AsyncRequestTimeoutException) {
            return HttpStatus.SERVICE_UNAVAILABLE;
        } else {
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }
    }
}


方法3: web.xml + controller 来实现
web.xml 中配置
    
    
        /error
    

package cn.mwee.wpos.report.controller.error;

import cn.mwee.utils.error.ThrowableUtil;
import cn.mwee.utils.log4j2.LogData;
import cn.mwee.utils.uuid.UUIDUtil;
import cn.mwee.wpos.common.utils.AlfredCommonUtils;
import cn.mwee.wpos.report.consts.ResultCode;
import cn.mwee.wpos.service.conts.ErrorCode;
import cn.mwee.wpos.service.conts.ErrorDesc;
import cn.mwee.wpos.service.dto.common.ErrorResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import org.springframework.web.util.WebUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

@Controller
public class ErrorController {
    /**
     * 异常页面
     * @param ex
     * @param response
     * @return
     */
    @RequestMapping(path = "/error")
    public ModelAndView errorHtml(HttpServletRequest request,Exception ex,HttpServletResponse response) {
        int status=response.getStatus();
        ModelAndView modelAndView;
        if(status == 403 || status == 404 || status == 500) {
            modelAndView = new ModelAndView("error/" +status);
        }else{
            modelAndView = new ModelAndView("error/error");
        }
        modelAndView.addObject("status",status);
        return modelAndView;
    }

    /**
     * 异常json
     * @param ex
     * @param response
     * @return
     */
    @RequestMapping(path = "/error",consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ResponseBody
    public Map errorJson(HttpServletRequest request,Exception ex,HttpServletResponse response) {
        Map result=new HashMap<>();
        Object obj=request.getAttribute(DispatcherServlet.EXCEPTION_ATTRIBUTE);
        if(obj == null){
            obj=request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE);
        }
        if(obj !=null && obj instanceof Exception){
            ex=(Exception)obj;
        }
        ErrorResult error=new ErrorResult(ErrorCode.FAIL, ErrorDesc.FAIL, ThrowableUtil.getStackTrace(ex));
        result.put(ResultCode.ERROR,error);
        return result;
    }

}



你可能感兴趣的:(SpringMVC 统一异常处理)