SpringMVC unified global exception handling

SpringMVC unified global exception handling and processing order
problem recently when using a unified global exception handling SpringMVC do encountered, they want ajax request and ordinary web requests return json error message or jump to the wrong page separately.

When actually doing the standard way to customize a HandlerExceptionResolver, named SpringHandlerExceptionResolver, implementing the HandlerExceptionResolver interface resolveException rewriting method, embodied as follows:

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonJsonView;
import com.butioy.common.bean.JsonResult;
import com.butioy.common.exception.BaseSystemException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
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.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException;

/**
 * <p>
 * spring MVC 统一异常处理
 * </p>
 *
 * @author butioy
 */
public class SpringHandlerExceptionResolver implements HandlerExceptionResolver {

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

    private FastJsonConfig fastJsonConfig;

    @Autowired
    public SpringHandlerExceptionResolver(FastJsonConfig fastJsonConfig) {
        this.fastJsonConfig = fastJsonConfig;
    }

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ModelAndView mv = specialExceptionResolve(ex, request);
        if (null == mv) { 
            String the Message = " system abnormalities, please contact the administrator " ;
             // BaseSystemException is my custom exception base class inherits from RuntimeException 
            IF (EX instanceof BaseSystemException) { 
                the Message = ex.getMessage (); 
            } 
            Music Videos = errorResult (Message, " / error " , Request); 
        } 
        return Music Videos; 
    } 

    / * * 
     * this method is copied {@link org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver # doResolveException}, 
     * Add custom processing, 400, 404, 405, 406, 415, 500 (parameters cause problems), a process 503 
     * 
     * @param abnormality information EX 
     * @param request the current request object (for judging whether the current request is ajax request) 
     * @return view model object 
     * / 
    Private ModelAndView specialExceptionResolve (Exception EX, the HttpServletRequest request) {
         the try {
             IF (EX NoSuchRequestHandlingMethodException the instanceof 
                 || EX NoHandlerFoundException the instanceof) {
                 return Result (HttpExceptionEnum.NOT_FOUND_EXCEPTION, request); 
            } 
            the else  IF ( the instanceof HttpRequestMethodNotSupportedException EX) {
                 return result(HttpExceptionEnum.NOT_SUPPORTED_METHOD_EXCEPTION, request);
            }
            else if (ex instanceof HttpMediaTypeNotSupportedException) {
                return result(HttpExceptionEnum.NOT_SUPPORTED_MEDIA_TYPE_EXCEPTION, request);
            }
            else if (ex instanceof HttpMediaTypeNotAcceptableException) {
                return result(HttpExceptionEnum.NOT_ACCEPTABLE_MEDIA_TYPE_EXCEPTION, request);
            }
            else if (ex instanceof MissingPathVariableException) {
                return result(HttpExceptionEnum.NOT_SUPPORTED_METHOD_EXCEPTION, request);
            }
            else if (ex instanceof MissingServletRequestParameterException) {
                return result(HttpExceptionEnum.MISSING_REQUEST_PARAMETER_EXCEPTION, request);
            }
            else if (ex instanceof ServletRequestBindingException) {
                return result(HttpExceptionEnum.REQUEST_BINDING_EXCEPTION, request);
            }
            else if (ex instanceof ConversionNotSupportedException) {
                return result(HttpExceptionEnum.NOT_SUPPORTED_CONVERSION_EXCEPTION, request);
            }
            else if (ex instanceof TypeMismatchException) {
                return result(HttpExceptionEnum.TYPE_MISMATCH_EXCEPTION, request);
            }
            else if (ex instanceof HttpMessageNotReadableException) {
                return result(HttpExceptionEnum.MESSAGE_NOT_READABLE_EXCEPTION, request);
            }
            else if (ex instanceof HttpMessageNotWritableException) {
                return result(HttpExceptionEnum.MESSAGE_NOT_WRITABLE_EXCEPTION, request);
            }
            else if (ex instanceof MethodArgumentNotValidException) {
                return result(HttpExceptionEnum.NOT_VALID_METHOD_ARGUMENT_EXCEPTION, request);
            }
            else if (ex instanceof MissingServletRequestPartException) {
                return result(HttpExceptionEnum.MISSING_REQUEST_PART_EXCEPTION, request);
            }
            else if (ex instanceof BindException) {
                return result(HttpExceptionEnum.BIND_EXCEPTION, request);
            }
            else if (ex instanceof AsyncRequestTimeoutException) {
                return result(HttpExceptionEnum.ASYNC_REQUEST_TIMEOUT_EXCEPTION, request);
            }
        } catch (Exception handlerException) {
            logger.warn("Handling of [". Ex.getClass + () getName () + " ] resulted in Exception " , handlerException); 
        } 
        return  null ; 
    } 

    / * * 
     * determined whether ajax request
     *
     * @param request 请求对象
     * @Return true: ajax request false: non ajax request 
      
     * @param url error page url* / 
    Private Boolean isajax (the HttpServletRequest Request) {
         return  " the XMLHttpRequest " .equalsIgnoreCase (request.getHeader ( " X--Requested-With " )); 
    } 

    / * * 
     * Returns Error information 
     * 
     * @param error message 
     * @param request the requested object 
     * @return model view objects 
     * / 
    Private ModelAndView errorResult (message String, String URL, the HttpServletRequest request) { 
        logger.warn ( " request processing fails, the request url = [{ }], failure reason: {} " , Request.getRequestURI (), Message);
        IF (isajax (Request)) {
             return JsonResult ( 500 , Message); 
        } the else {
             return normalResult (Message, URL); 
        } 
    } 

    / * * 
     * return exception information 
     * 
     * @param HttpException abnormality information 
     * @param request request object
     * @Return model view objects 
     * / 
    Private ModelAndView Result (HttpExceptionEnum HttpException, the HttpServletRequest Request) { 
        logger.warn ( " request processing fails, the request url = [{}], failure reason: {} " , Request.getRequestURI (), HttpException .getMessage ());
         IF (isajax (Request)) {
             
     *return JsonResult (httpException.getCode (), httpException.getMessage ()); 
        } the else {
             return normalResult (httpException.getMessage (), " / error " ); 
        } 
    } 

    / * * 
     * page returned error 
     * @param message error 
     * @param url error page URL 
     * @return model view objects 
     * / 
    Private ModelAndView normalResult (Message String, String URL) { 
        the Map <String, String> model = new new the HashMap <String, String> (); 
        model.put ( " errorMessage " , message);
         return  new new ModelAndView (URL, model); 
    } 

    / * * 
     * returns error data 
     * 
     * @param error message 
     * @return model view objects 
     * / 
    Private ModelAndView JsonResult ( int code, String message) { 
        ModelAndView Music Videos = new new ModelAndView (); 
        FastJsonJsonView View = new new FastJsonJsonView (); 
        view.setFastJsonConfig (fastJsonConfig); 
        view.setAttributesMap ((the JSONObject) JSON.toJSON (JsonResult.fail (code, Message))); 
        mv.setView (View); 
        return Music Videos; 
    } 
}

Written after configure the look in springContext.xml profile

<bean class = "com.butioy.common.handler.SpringHandlerExceptionResolver" / >
and then start tomcat, everything is normal there is no error message, but did not return a custom error page as I guess at the time of the request, but tomcat default error pages

 

So I debugger to track the implementation of the code. I finally found to have a handlerExceptionResolvers collection processHandlerException method DispatcherServlet class of Spring, which is stored inside the exception handler bean declaration.

 

Then find and there are three exception handler bean is we have not declared, checked the information I realized that these three bean is SpringMVC default initialization, the spring-webmvc the jar package, with the same package under DispatcherServlet.java the DispatcherServlet.properties configuration file, the configuration file reads as follows:

 

Although there are three default bean, but why priority is higher than I customize it? So I point to open these classes look. These are found in the indirect implements the Spring Ordered interface. This interface is only one way getOrder (), this method returns an int value that indicates the priority of execution of this bean. Unified exception handling implementation comments above class are also mentioned, it is a copy of the DefaultHandlerExceptionResolver # doResolveException method, here wondering what the error message has been handling this class. When the above debugger tracking, we know the order of execution DefaultHandlerExceptionResolver instance of the bean is a bean precedence over SpringHandlerExceptionResolver our custom, so those 404,415 would be consistent with an error message such as the default exception handling SpringMVC bean processing. Which is inconsistent with our original intention. So I SpringHandlerExceptionResolver transform a bit, but also to achieve the Ordered interface:

 

Here I give it a default highest priority, so you can make custom class priority executed. Sure enough, the results just like I expected.

Here is returning an error page:


Here it is json return data (I have used here is the way jsonp request):


At this point, the entire SpringMVC global exception handler is complete. I'm just here to request json ajax requests as data, so we did. The actual case may be.

NOTE: When using this method do not remember to be disposed in a spring-mvc.xml <mvc: default-servlet-handler />, which should be arranged such that no effect on SpringHandlerExceptionResolver 404 error. In doDispatch method DispatcherServlet class, we will find a line of code

// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
  noHandlerFound(processedRequest, response);
  return;
}

Here getHandler () retrieves a handler, if there is no handler corresponding to the acquired will url
<mvc: default-servlet-handler /> a declaration
org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler.
This method does not perform noHandlerFound, will not throw an exception of the 404.
Another point to note is that in the web.xml configuration file, in the allocation of DispatcherServlet to add

<the init-param> 
    <-! path if no mapping is found, an exception is thrown, rather than to the 404 error page web.xml configuration -> 
    <param-name> throwExceptionIfNoHandlerFound </ param-name> 
    <param -value> to true </ param-value> 
</ the init-param>

Because if you do not add this configuration, in the event of 404, it will not throw an exception, but returns a 404 response status of the 
following is the source of part of DispatcherServlet.java:

protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
  if (pageNotFoundLogger.isWarnEnabled()) {
      pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" + getRequestUri(request) +
              "] in DispatcherServlet with name '" + getServletName() + "'");
  }
  if (this.throwExceptionIfNoHandlerFound) {
      throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request),
                new ServletServerHttpRequest(request).getHeaders());
  }
  else {
      response.sendError(HttpServletResponse.SC_NOT_FOUND);
  }
}

Here you can see, if throwExceptionIfNoHandlerFound is false, no exception is thrown, but give the browser a 404 response status. The default value of this property in DispatcherServlet.java is false.

Original link: https: //blog.csdn.net/butioy_org/article/details/78718405

Guess you like

Origin www.cnblogs.com/muxi0407/p/11607708.html