在使用基于注解的spring mvc时,使用情况如下:
@Controller @RequestMapping("/test") public class TestController { @RequestMapping(value="/index/{userId}", params="username") public ModelAndView index(@PathVariable("userId") String userId, @RequestParam("password") String password, @RequestParam("id") int id, Map<String, Object> map) throws Exception { System.out.println(userId); System.out.println(password); System.out.println(id); JSONObject obj = new JSONObject(); obj.put("data", ""); obj.put("status", ""); return new ModelAndView("index"); } }
出现异常会有一下几种情况:
1 参数不匹配, spring mvc有自己的异常处理,会调到一个也没,HttpStatus 400
2 用户在调用的service中,自己抛出异常或者代码异常,这个最好统一捕捉,不要在每个Controller方法里进行捕捉
看spring mvc的源码,可以知道spring mvc处理步骤如下:
1 spring mvc的入口为:
<servlet> <servlet-name>spring-mvc-servlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:/spring-mvc-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring-mvc-servlet</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
2 DispatcherServlet 是一个Servlet,DispatcherServlet首先处理请求时会调用doService方法:
@Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isDebugEnabled()) { String requestUri = urlPathHelper.getRequestUri(request); String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : ""; logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed + " processing " + request.getMethod() + " request for [" + requestUri + "]"); } // Keep a snapshot of the request attributes in case of an include, // to be able to restore the original attributes after the include. Map<String, Object> attributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { logger.debug("Taking snapshot of request attributes before include"); attributesSnapshot = new HashMap<String, Object>(); Enumeration<?> attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) { attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } } // Make framework objects available to handlers and view objects. request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); try { //上面做了一系列的操作是想获取必要的资源,在这里分发了请求 doDispatch(request, response); } finally { if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { return; } // Restore the original attribute snapshot, in case of an include. if (attributesSnapshot != null) { restoreAttributesAfterInclude(request, attributesSnapshot); } } }
doDispatch方法代码如下:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = processedRequest != request; // Determine handler for the current request. mappedHandler = getHandler(processedRequest, false); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { String requestUri = urlPathHelper.getRequestUri(request); logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } try { // Actually invoke the handler.在此处真实的调用了我们的Controller mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); } finally { if (asyncManager.isConcurrentHandlingStarted()) { return; } } applyDefaultViewName(request, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) {//当出现错误的时候,捕捉到请求在下面的processDispatchResult处理异常信息 dispatchException = ex; } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);//处理异常信息 } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); return; } // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } }
processDispatchResult方法的代码为:
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception { boolean errorView = false; if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else {//此处处理真正的异常 Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handler, exception); errorView = (mv != null); } } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isDebugEnabled()) { logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() + "': assuming HandlerAdapter completed request handling"); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } if (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, null); } }
processHandlerException方法如下,这里会选取HandlerExceptionResolver来处理对应的异常
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // Check registered HandlerExceptionResolvers... ModelAndView exMv = null; //遍历HandlerExceptionResolver,获取合适来处理异常 for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) { exMv = handlerExceptionResolver.resolveException(request, response, handler, ex); if (exMv != null) { break; } } if (exMv != null) { if (exMv.isEmpty()) { return null; } // We might still need view name translation for a plain error model... if (!exMv.hasView()) { exMv.setViewName(getDefaultViewName(request)); } if (logger.isDebugEnabled()) { logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex); } WebUtils.exposeErrorRequestAttributes(request, ex, getServletName()); return exMv; } throw ex; }
spring mvc 在Dispatcher里容器onRefresh()方法的时候加载了HandlerExceptionResolver:
@Override protected void onRefresh(ApplicationContext context) { initStrategies(context); } protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); //初始化HandlerExceptionResolvers initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); } private void initHandlerExceptionResolvers(ApplicationContext context) { this.handlerExceptionResolvers = null; if (this.detectAllHandlerExceptionResolvers) { // Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts. //从spring mvc的容器中获取类型为HandlerExceptionResolver的bean Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils .beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerExceptionResolvers = new ArrayList<HandlerExceptionResolver>(matchingBeans.values()); // We keep HandlerExceptionResolvers in sorted order. OrderComparator.sort(this.handlerExceptionResolvers); } } else { try { HandlerExceptionResolver her = context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class); this.handlerExceptionResolvers = Collections.singletonList(her); } catch (NoSuchBeanDefinitionException ex) { // Ignore, no HandlerExceptionResolver is fine too. } } // Ensure we have at least some HandlerExceptionResolvers, by registering // default HandlerExceptionResolvers if no other resolvers are found. if (this.handlerExceptionResolvers == null) { this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class); if (logger.isDebugEnabled()) { logger.debug("No HandlerExceptionResolvers found in servlet '" + getServletName() + "': using default"); } } }
由上面可知:spring mvc 从容器中获取了处理异常的HandlerExceptionResolver,spring mvc提供三种异常处理器:
DefaultHandlerExceptionResolver, ResponseStatusExceptionResolver, ExceptionHandlerExceptionResolver,用户可以在spring mvc的配置文件中配置自己的异常处理类:
<bean id="diyExceptionHandler" class="com.malone.handler.MyExceptionHandler"/> <bean id="myDefaultHandlerExceptionResolver" class="com.malone.handler.MyDefaultHandlerExceptionResolver"/>
为了统一异常处理,我们可以自定义一个HandlerExceptionResolver,所有的异常均由自定义的异常处理, 由此我们可以重写DispatcherServlet类的
processHandlerException()方法:
public class MyDispatcherServlet extends DispatcherServlet { private Map<String, HandlerExceptionResolver> matchingBeans = new HashMap<String, HandlerExceptionResolver>(); private Map<String, HandlerExceptionResolver> getMatchingBeans () { if (matchingBeans.isEmpty()) { System.out.println(SpringUtils.getContext()); synchronized (this) { matchingBeans = BeanFactoryUtils .beansOfTypeIncludingAncestors(SpringUtils.getContext(), HandlerExceptionResolver.class, true, false); } } return matchingBeans; } @Override protected void onRefresh(ApplicationContext context) { initStrategies(context); //把spring mvc容器缓存起来 SpringUtils.setContext(context); } @Override protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { //获取HandlerExceptionResolver Map<String, HandlerExceptionResolver> matchingBeans = this.getMatchingBeans(); if (matchingBeans == null || matchingBeans.size() == 0) {//没有配置处理异常的Controller return new ModelAndView(); } Map<String, HandlerExceptionResolver> newMatchingBeans = new HashMap<String, HandlerExceptionResolver>(); for (Iterator<String> iterator = matchingBeans.keySet().iterator(); iterator.hasNext();) {//使用指定handlerResolver String key = iterator.next(); if (Objects.equals(key, "diyExceptionHandler") || Objects.equals(key, "myDefaultHandlerExceptionResolver")) { newMatchingBeans.put(key, matchingBeans.get(key)); } } // Check registered HandlerExceptionResolvers... ModelAndView exMv = null; for (HandlerExceptionResolver handlerExceptionResolver : new ArrayList<HandlerExceptionResolver>(newMatchingBeans.values())) { exMv = handlerExceptionResolver.resolveException(request, response, handler, ex); if (exMv != null) { break; } } if (exMv != null) { if (exMv.isEmpty()) { return null; } // We might still need view name translation for a plain error model... if (!exMv.hasView()) { exMv.setViewName(getDefaultViewName(request)); } if (logger.isDebugEnabled()) { logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex); } WebUtils.exposeErrorRequestAttributes(request, ex, getServletName()); return exMv; } throw ex; } }
自定义了MyDispatcherServlet类,此类继承了DispatcherServlet,重写了一下方法:
onRefresh():重写此方法的目的是在原来的代码基础上增加缓存spring mvc容器的方法
processHandlerException ():重写此方法是为了修改获取HandlerExceptionResolver的逻辑,由上面代码可知,我们使用onRefresh()方法中缓存的spring mvc容器,
获取到自己注册的HandlerExceptionResolver,然后使用自己的注册HandlerExceptionResolver来处理所有异常
附完整的测试代码:
相关推荐
Spring MVC提供异常处理注解,如@ControllerAdvice和@ExceptionHandler,以及数据校验注解,如@NotNull、@Size等。 总结,基于注解的Spring MVC简化了Web应用的开发,通过注解可以快速地定义路由、数据绑定、事务...
Spring MVC 是一个基于Java的轻量级Web应用框架,它为构建RESTful应用程序提供了强大的支持。在本教程中,我们将深入探讨Spring MVC的核心概念,特别是关于注解的使用以及简单的控制器实现。 首先,Spring MVC的...
`ModelAndView` 是Spring MVC中用于封装视图和模型数据的对象,而在现代Spring MVC应用中,更常使用`Model`接口来添加模型数据,然后返回视图名称来决定展示哪个视图。 9. **视图解析器(View Resolver)** 视图...
4. **ModelAndView对象**: 这是Spring MVC中用于封装模型数据和视图名的对象。在Controller方法中,可以返回一个ModelAndView对象,指定返回的视图和传递给视图的数据。 5. **视图解析**: Spring MVC支持多种视图...
Spring MVC 是一款基于Java的轻量级Web应用框架,它是Spring框架的重要组成部分,主要用于构建Web应用程序的后端控制器。在本实例中,我们有一个名为"spring-MVC.zip"的压缩包,里面包含了一个关于Spring MVC的开发...
这个"spring mvc 整合包"可能包含了Spring MVC的jar文件、配置示例、启动脚本或者示例代码,帮助开发者快速启动基于Spring MVC的Web项目。使用时,开发者需要根据自己的项目需求,进行相应的配置调整,比如数据库...
Spring MVC 是一个基于Java的轻量级Web应用框架,它是Spring框架的重要组成部分,主要用于构建Web应用程序的后端控制器。这个"Spring MVC 基础实例源码01"的资源很可能是为了帮助初学者理解Spring MVC的核心概念和...
- 在Spring MVC的Controller中通过@Autowired注解注入Service,然后调用Service中的方法执行数据库操作。 4. **封装**:封装主要体现在以下几个方面: - **Service层**:创建Service接口,包含业务逻辑方法,这些...
Spring mvc 返回数据格式采用统一的对象(JSONReturn)进行封装 09. 通过自定义处理器 ExceptionIntercept 实现 Spring mvc的全局异常捕获 10. 系统中包含了企业中采用的开发工具类的集合 11. AbstractDao 父类...
8. **异常处理**: Spring MVC 提供了 `@ExceptionHandler` 注解,允许在 Controller 中直接处理异常,提高异常处理的灵活性。 9. **JSON 支持**: 通过集成 Jackson 或者 Gson,Spring MVC 可以方便地进行 JSON 数据...
Spring MVC 是一款强大的Java Web开发框架,由Spring Software Foundation维护,它简化了构建基于模型-视图-控制器(MVC)架构的Web应用程序的过程。在本示例中,我们将深入探讨如何利用注解来增强Spring MVC的功能...
Spring MVC 是一个基于 Java 的轻量级 Web 开发框架,它是 Spring 框架的重要组成部分。Spring 框架以其依赖注入(Dependency Injection, DI)和面向切面编程(Aspect-Oriented Programming, AOP)为核心,而 Spring...
Spring MVC 是一款基于 Java 的轻量级 Web 开发框架,它是 Spring 框架的重要组成部分。这个经典入门案例将引导你逐步了解并掌握 Spring MVC 的基本概念、配置以及实际应用。 1. **Spring MVC 概述** Spring MVC ...
Spring MVC 是 Spring 框架的一个重要模块,它为构建基于Java的Web应用程序提供了一个强大的模型-视图-控制器(MVC)架构。Spring MVC 的设计允许开发者将业务逻辑、数据处理和用户界面分离,从而实现更好的可维护性...
在本文中,我们将深入探讨一个基于Spring MVC实现的后台登录系统验证的源代码。Spring MVC是Java Web开发中的一个强大框架,它提供了模型-视图-控制器(MVC)架构模式,帮助开发者构建可维护、可扩展的Web应用。我们...
SSM框架是Java Web开发中常用的一种组合,由Spring MVC、Spring和Mybatis三个组件构成,用于构建高效、灵活的Web应用。这个基于SSM的客户关系管理系统(CRM)毕业设计,利用了Maven进行项目构建,确保了依赖管理的便捷...
Spring MVC 是一个基于Java的轻量级Web应用框架,它是Spring框架的重要组成部分,主要用于构建Web应用程序的后端控制器。在本实例中,我们将探讨如何利用Spring MVC的注解来简化前后台交互,以及如何实现简单视图...
这些模块的实现将展示如何将业务逻辑封装在Service层,然后通过Spring MVC的Controller暴露为HTTP端点。同时,你还将学习到如何利用Hibernate进行数据持久化,包括增删改查操作。 为了更好地理解和学习这个案例,你...