实现方式和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);
}
}