SpringMVC異常統一処理データまたはビュービュービューを返す


実装方法はSpringMVCブロッキングHandlerInterceptorブロッキング後に返されるデータまたはビューViewと一致しています.ここでは、コードリファレンスを貼ります.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
import org.springframework.web.servlet.mvc.method.annotation.ViewNameMethodReturnValueHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;

/**
 * @author obiteaaron
 * @since 2019/12/27
 */
@Component
public class SpringMvcExceptionHandlerResolver extends AbstractHandlerExceptionResolver implements ApplicationContextAware {

    private static final Logger LOGGER = LoggerFactory.getLogger(SpringMvcExceptionHandlerResolver.class);

    private ApplicationContext applicationContext;

    @Autowired
    SpringMvcExceptionHandlerResolver.ExceptionHandler exceptionHandler = new SpringMvcExceptionHandlerResolver.ExceptionHandler() {
        private String EXCEPTION_VIEW = "error";

        @Override
        public String getViewName(Exception ex) {
            //     
            return EXCEPTION_VIEW;
        }

        @Override
        public Object getResponseBody(Exception ex) {
            //     
            if (ex instanceof IllegalArgumentException) {
                throw new UnsupportedOperationException();
            } else if (ex instanceof UnsupportedOperationException) {
                throw new UnsupportedOperationException();
            } else {
                throw new UnsupportedOperationException();
            }
        }
    };

    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        try {
            //      ,    
            if (((HandlerMethod) handler).getMethodAnnotation(ResponseBody.class) != null) {
                //   json
                HandlerMethod handlerMethod = new HandlerMethod(((HandlerMethod) handler).getBean(), ((HandlerMethod) handler).getMethod());
                Object returnValue = exceptionHandler.getResponseBody(ex);
                MethodParameter returnValueType = handlerMethod.getReturnValueType(returnValue);
                applicationContext.getBean(RequestMappingHandlerAdapter.class).getReturnValueHandlers();
                RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor = findRequestResponseBodyMethodProcessor();
                requestResponseBodyMethodProcessor.handleReturnValue(returnValue, returnValueType, new ModelAndViewContainer(), new ServletWebRequest(request, response));
                return new ModelAndView();
                // end
            } else {
                //     
                HandlerMethod handlerMethod = new HandlerMethod(((HandlerMethod) handler).getBean(), ((HandlerMethod) handler).getMethod());
                String viewName = exceptionHandler.getViewName(ex);
                MethodParameter returnValueType = handlerMethod.getReturnValueType(viewName);
                ViewNameMethodReturnValueHandler viewNameMethodReturnValueHandler = findViewNameMethodReturnValueHandler();
                ModelAndViewContainer modelAndViewContainer = new ModelAndViewContainer();
                // viewNameMethodReturnValueHandler         ,         ,  new ModelAndViewContainer()   。
                viewNameMethodReturnValueHandler.handleReturnValue(viewName, returnValueType, modelAndViewContainer, new ServletWebRequest(request, response));

                //   ModelAndView Spring  
                ModelMap model = modelAndViewContainer.getModel();
                ModelAndView modelAndView = new ModelAndView(modelAndViewContainer.getViewName(), model, modelAndViewContainer.getStatus());
                exceptionHandler.fillModelAndView(ex, modelAndView);
                return modelAndView;
                // end
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private RequestResponseBodyMethodProcessor findRequestResponseBodyMethodProcessor() {
        RequestMappingHandlerAdapter requestMappingHandlerAdapter = applicationContext.getBean(RequestMappingHandlerAdapter.class);
        for (HandlerMethodReturnValueHandler value : Objects.requireNonNull(requestMappingHandlerAdapter.getReturnValueHandlers())) {
            if (value instanceof RequestResponseBodyMethodProcessor) {
                return (RequestResponseBodyMethodProcessor) value;
            }
        }
        // SpringMVC            
        throw new UnsupportedOperationException("cannot find RequestResponseBodyMethodProcessor from RequestMappingHandlerAdapter by Spring Context.");
    }

    private ViewNameMethodReturnValueHandler findViewNameMethodReturnValueHandler() {
        RequestMappingHandlerAdapter requestMappingHandlerAdapter = applicationContext.getBean(RequestMappingHandlerAdapter.class);
        for (HandlerMethodReturnValueHandler value : Objects.requireNonNull(requestMappingHandlerAdapter.getReturnValueHandlers())) {
            if (value instanceof ViewNameMethodReturnValueHandler) {
                return (ViewNameMethodReturnValueHandler) value;
            }
        }
        // SpringMVC            
        throw new UnsupportedOperationException("cannot find ViewNameMethodReturnValueHandler from RequestMappingHandlerAdapter by Spring Context.");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public interface ExceptionHandler {
        /**
         *           
         *
         * @param ex
         * @see ModelAndView
         * @see ViewNameMethodReturnValueHandler
         */
        String getViewName(Exception ex);

        /**
         *              
         *
         * @param ex
         * @see ModelAndView
         * @see ViewNameMethodReturnValueHandler
         */
        default void fillModelAndView(Exception ex, ModelAndView modelAndView) {
        }

        /**
         *         
         *
         * @param ex
         * @see ResponseBody
         * @see RequestResponseBodyMethodProcessor
         */
        Object getResponseBody(Exception ex);
    }
}