处理方法的数据绑定
视图和视图解析器
本地化
文件上传
WebSocket
静态资源处理
拦截器
异常处理
一、Spring MVC的概述
===================
MVC:Model + View + Controller(数据模型 + 视图 + 控制器)
三层架构
========
三层架构:Presentation tier + Application tier + Data tier(展示层 + 应用层 + 数据访问层)
MVC和三层架构的关系
===============
MVC和三层架构的关系, MVC只存在三层架构的展示层。
M实际是数据模型,是包含数据的对象。在Spring MVC里,有一个专门的类叫Model,用来和V之间的数据交互、传值。
V指的是视图界面,包含JSP、freeMarker、Velocity、Thymeleaf、Tile等。
C就是控制器(Spring MVC的注解@Controller的类)。
三层架构是整个应用的的架构,是由Spring框架负责管理的,一般项目结构中都由Service层、Dao层,这两个反馈在应用层和数据访问层。
Spring MVC框架围绕DispatcherServlet这个核心展开,它负责截获请求并将其分派给相应的处理器处理。Spring MVC框架包括注解驱动控制器、请求及响应的信息处理、视图解析、本地化解析、上传文件解析、异常处理以及表单标签绑定等内容。
体系结构
========
Spring MVC是基于Model 2实现的技术框架。Spring MVC通过一个DispatcherServlet接收所有请求,并将具体工作委托给其他组件进行处理。
Spring MVC体系结构
==================
客户端发出一个HTTP请求,Web应用服务器接收到这个请求,如果匹配DispatcherServlet的请求映射路径(在web.xml中指定),Web容器将该请求转交给DispatcherServlet处理。
DispatcherServlet接收到这个请求后,将根据请求的信息(包括URL、HTTP方法、请求报文头、请求参数、Cookie等)及HandlerMapping的配置找到处理请求的处理器(Handler)。可将HandlerMapping看成路由控制器,将Handler看成目标主机。值得注意的是:Spring MVC中并没有定义一个Handler接口,实际上任何一个Object都可以成为请求处理器。
当DispatcherServlet根据HandlerMapping得到对应当前请求的Handler后,通过HandlerAdapter对Handler进行封装,再以统一的适配器接口调用Handler。 HandlerAdapter是Spring MVC的框架级接口,顾名思义HandlerAdapter是一个适配器,它用统一的接口对各种Handler方法进行调用。
处理器完成业务逻辑的处理后将运回一个ModelAndView给DispatcherServlet,ModelAndView包含了视图逻辑名和模型数据信息。
ModelAndView中包含的是“逻辑视图名”而非真正的视图对象,DispatcherServlet借由ViewResolver完成逻辑视图名到真实视图对象的解析工作。
当得到真实的视图对象View后,DispatcherServlet就使用这个View对象对ModelAndView中的模型数据进行视图渲染。
最终客户端得到的响应消息,可能是一个普通的HTML页而,也可能是一个XML或JSON串, 甚至是一张图片或一个PDF文档等不同的媒体形式。
配置DispatcherServlet
=======================
可以在web.xml中配置一个Servlet,并通过指定其处理的URL。
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version=“3.0”> contextConfigLocation classpath:application-context.xml org.springframework.web.context.ContextLoaderListener web org.springframework.web.servlet.DispatcherServlet 1 web / 复制代码 在(1)处,通过contextConfigLocation参数指定业务层Spring容器的配置文件(多个配置文件用 , 分割)。 在(2)处,ContextLoaderListener是一个ServletLoaderListener,它通过contextConfigLocation指定的Spring配置文件启动业务层的Spring容器。 在(3)处,配置了名为web的DispatcherServlet,它默认加载/WEB-INF/web-servlet.xml(-servlet.xml)的Spring配置文件,启动Web层的Spring容器。Web层容器将作为业务层容器的子容器,Web层容器可以访问业务层容器的Bean,而业务层容器访问不了Web层容器的Bean。 在(4)处,通过指定DispatcherServlet处理 /* 全部的HTTP请求。一个web.xml可以配置多个DispatcherServlet,通过其对应的配置,让每个DispatcherServlet处理不同的请求。 DispatcherServlet 的配置参数 =========================== 可以通过的属性指定配置参数: namespace参数:DispatcherServlet对应的命名空间,默认是WEB-INF/-servlet.xml。在显式配置该参数后,新的配置文件对应的路径是WEB-INF/.xml,例如如果将namespace设置为sample,则对应的Spring配置文件为WEB-INFmple.xml。 contextConfigLocation:如果DispatcherServlet上下文对应的Spring配置文件有多个,则可以使用该属性按照Spring资源路径的方式指定,如classpath:sample1.xml,classpath:sample2.xml。 publishContext:默认为true。DispatcherServlet根据该属性决定是否将WebApplicationContext发布到ServletContext的属性列表中,方便调用者可借由ServletContext找到WebApplicationContext实例,对应的属性名为DispatcherServlet#getServletContextAttributeName()的返回值。 publishEvents:默认为true。当DispatcherServlet处理完一个请求后,是否需要向容器发布一个ServletRequestHandleEvent事件。 推荐观看:[传送门]( ) ======================================================= Spring容器配置 ============== xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xmlns:context=“http://www.springframework.org/schema/context” xmlns:mvc=“http://www.springframework.org/schema/mvc” xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> 复制代码 基于编程的配置 =========== Spring 4.0已经全面支持Servlet 3.0,可以使用编程的方式配置Servlet容器。在Servlet 3.0环境中,容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类,如果发现实现类,就会用它来配置Servlet容器。Spring提供了这个接口的实现,名为SpringServletContainerInitializer,这个类反过来又查找实现WebApplicationInitializer的类并将配置的任务交给它们来完成。Spring还提供了一个WebApplicationInitializer基础实现类AbstractAnnotationConfigDispatcherServletInitializer,使得它在注册DispatcherServlet时只需要简单地指定它的Servlet映射即可。 public class WebApplicationInitilalizer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { ServletRegistration.Dynamic registration = servletContext.addServlet(“web”, new DispatcherServlet()); registration.setLoadOnStartup(1); registration.addMapping("/"); } } 复制代码 DispatcherServlet的内部逻辑 ========================== protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); } 复制代码 DispatcherServlet#initStrategies()方法将在WebApplicationContext初始化后执行,此时Spring上下文中的Bean已经初始化完毕,该方法通过反射查找并装配Spring容器中用户自定义的Bean,如果找不到就装配默认的组件实例。 默认组件 ======== 在DispatcherServlet.properties配置文件里边,指定了DispatcherServlet所使用的默认组件。如果用户希望采用非默认的组件,只需在Spring配置文件中配置自定义的组件Bean即可。 org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager 复制代码 DispatcherServlet装配各型组件的逻辑 ============================== 二、注解驱动的控制器 ============== @RequestMapping映射请求 ======================= 在POJO类上标注@Controller,再通过 context:component-scan 扫描到该类,可以是POJO成为一个能处理HTTP请求的控制器。 在控制器的类定义和方法定义处都可以使用@RequestMapping映射对应的处理方法。 @RequestMapping不但支持标准的URL,还支持Ant风格和{XXX}占位符的URL。 @RequestMapping和value、method、params及headers分别表示请求路径、请求方法、请求参数及报文头的映射条件。 获取请求内容 ========== org.springframework.web.context.request 使用HttpMessageConverter ========================== HttpMessageConverter接口可以将请求信息转换为一个对象(类型为T),并将对象(类型为T)绑定到请求方法的参数中或输出为响应信息。DispatcherServlet默认已经安装了RequestMethodHandlerAdapter作为HandlerAdapter组件的实现类,HttpMessageConverter即由RequestMethodHandlerAdapter使用,将请求信息转换为对象,或将对象转换为响应信息。 HttpMessageConverter的实现类 ============================ Spring为HttpMessageConverter提供了众多的实现类: 实现类 ======= 实现类 ======= 默认的HttpMessageConverter =========================== RequestMappingHandlerAdapter已经默认装配了以下的HttpMessageConverter: StringHttpMessageConverter ByteArrayHttpMessageConverter SourceHttpMessageConverter AllEncompassingFormHttpMessageConverter 装配其他类型的HttpMessageConverter =============================== 如果需要装配其他类型的HttpMessageConverter,可以在Spring的Web容器上下文中自行定义一个RequestMappingHandlerAdapter,注册若干HttpMessageConverter。如果在Spring web容器中显式定义了一个RequestMappingHandlerAdapter,则Spring MVC将使用它 覆盖 默认的RequestMappingHandlerAdapter。 使用HttpMessageConverter ========================== 可以使用@RequestBody、@ResponseBody对处理方法进行标注 可以使用HttpEntity、ResponseEntity作为处理方法的入参或返回值 RestTemplate是Spring的模板类,可以使用该类调用Web服务端的服务,它支持Rest风格的URL。 结论 ====== 当控制器处理方法使用到@RequestBody、@ResponseBody 或 HttpEntity、ResponseEntity 时,Spring MVC才会使用注册的HttpMessageConvertor对请求、相应消息进行处理。 当控制器处理方法使用到@RequestBody、@ResponseBody 或 HttpEntity、ResponseEntity时,Spring 首先根据请求头或响应的Accept属性选择匹配的 HttpMessageConverter,进而根据参数类型或泛型类型的过滤得到匹配的 HttpMessageConverter,若找不到可用的 HttpMessageConverter 将报错。 @RequestBody、@ResponseBody不需要成对出现。 处理XML和JSON ============== Spring MVC提供了几个处理XML和JSON格式的请求、响应消息的HttpMessageConverter: MarshallingHttpMessageConverter:处理XML Jaxb2RootElementHttpMessageConverter:处理XML,底层使用JAXB MappingJackson2HttpMessageConverter:处理JSON格式 只要在Spring Web容器中为RequestMappingHandlerAdapter装配好相应的HttpMessageConverter,并在交互中通过请求的Accept指定MIME类型,Spring MVC就可以是服务器端的处理方法和客户端透明的通过XML或JSON格式进行通信。 复制代码 使用@RestController ===================== @RestController已经标注了@ResponseBody和@Controller,可以直接在控制器上标注该注解,就不用在每个@RequestMapping方法上添加@ResponseBody了。 AsyncRestTemplate ===================== Spring 4.0提供了AsyncRestTemplate用于以异步无阻塞的方式进行服务访问。 public class WebApplicationInitilalizer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { ServletRegistration.Dynamic registration = servletContext.addServlet(“web”, new DispatcherServlet()); registration.setLoadOnStartup(1); // 此处要设置为true registration.setAsyncSupported(true); registration.addMapping("/"); } } @RestController public class AsyncController { @RequestMapping(value = “/async”, method = RequestMethod.GET) public Callable async() { System.out.println(“hello!”); return new Callable() { @Override public String call() throws Exception { TimeUnit.SECONDS.sleep(5); return “ASYNC”; } }; } } public class Main { public static void main(String[] args) { AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate();
本地化解析器
主题解析器
处理器解析器
处理器适配器
异常处理器
视图名称处理器
视图解析器