整个框架主要是围绕一个DispatcherServlet来进行设计的web
该Servlet会将请求分发给各个处理器,并支持可配置的处理器映射、视图渲染、本地化、时区与主题渲染等spring
其中,处理器是应用中注解了 @Controller 和 @RequestMapping的类和方法编程
DispatcherServletapp
DispatcherServlet其实就是一个Servlet(继承自HttpServlet基类)。同时,须要在web.xml文件中把须要处理的请求映射到URL上去,通常状况下,web.xml须要配置 DispatcherServlet 和路径映射的声明框架
例如:布局
<web-app>this
<servlet>url
<servlet-name>example</servlet-name>spa
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>设计
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>example</servlet-name>
<url-pattern>/example/*</url-pattern>
</servlet-mapping>
</web-app>
以上代码,全部路径以 /example 开头的请求都被会名字为 example 的 DispatcherServlet处理。
在Servlet3.0的环境下,还能使用编程的方式配置Servlet容器(暂不表)
DispatcherServlet的初始化过程,SpringMVC会在web应用的WEB-INF目录下查找一个名为 [servlet-name]-servlet.xml的配置文件,并建立其中所定义的bean
若是全局上下文中存在相同名字的bean,则它们会被新定义的同名bean覆盖
<web-app>
<servlet>
<servlet-name>golfing</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>golfing</servlet-name>
<url-pattern>/golfing/*</url-pattern>
</servlet-mapping>
</web-app>
有了以上的 Servlet的配置文件,还须要在应用的/WEB/INF路径下建立一个 golfing-servlet.xml文件,该文件定义了全部SpringMVC相关的组件(例如bean)
Spring当中的 ApplicationContext 实例都是有范围(scope)的。在SrpingMVC当中,每个 DispatcherServlet 都有一个本身的 WebApplicationContext 上下文对象,它继承了root的 WebApplicationContext对象中的全部bean,若是这个集成的bean在具体的 Servlet实例中被重载,在每一个Servlet实例中能够定义其scope下的新的bean。
若是应用当中只须要一个 DispatcherServlet 时,此时只须要配置一个根 context对象就好了。要配置一个惟一的context对象,直接在初始化参数中 配置一个空的 contextConfigLocation便可
web.xml
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/root-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
WebApplicationContext 继承自 ApplicationContext ,它提供了一些web应用常常须要用到的特性
定制 DispatcherServlet 的配置,具体作法是,在 web.xml 文件中,Servlet 的声明元素上添加一些 Servlet 的初始化参数(经过 init-param 元素)。可选参数列表以下:
contextClass
任意实现了 ApplicationContext 的类,这个类会初始化 Servlet 所须要的上下文对象。默认状况下,框架会使用 XmlWebApplicationContext对象
contextConfigLocation
用于指定上下文配置文件路径的字符串,这个值会被传入给 contextClass 指定的上下文对象。该字符串内能够包含多个字符串,字符串之间以逗号分割,以此支持多个上下文的配置。在多个上下文中重复定义的bean,以最后加在的bean定义为准
namespace
WebApplicationContext 的命名空间。默认是 [servlet-name]-servlet
bean的类型
HandlerMapping
处理器映射。根据规则将进入容器的请求映射到具体的处理器。最多见的一个实现是支持你在控制器上添加注解,配置请求路径。固然,也存在其余实现
HandlerAdapter
处理器适配器。党拿到所对应的处理器后,适配器将负责去调用该处理器,这使得DispathcerServlet无需关心具体的调用细节。例如,要调用的是一个机遇注解配置的控制器,那么调用前还须要从注解中解析相关配置信息。所以,HandlerAdapter具体的工做就是对 DispatcherServlet 屏蔽这些细节
HandlerExceptionResolver
处理器异常映射。主要负责将捕获的异常映射到不一样的视图上去
ViewResolver
视图解析器。负责将逻辑视图名(String)映射到一个具体实际的view上去
LocaleResolver & LocaleContextResolver
地区解析器 和 地区上下文解析器。它们负责解析客户端所在的地区信息甚至时区信息,为国际化的视图定制提供支持。
ThemeResolver
主题解析器。负责解析web当中可用的主题,好比一些个性化定制的布局
MulipartResolver
解析multi-part的传输请求,好比支持经过HTML表单进行的文件上传等。
FlashMapManager
请求通过DispatcherServlet时,DispatcherServlet会按照以下次序对请求进行处理:
a 首先,搜索本 DispatcherServlet 对应的应用上下文对象 WebApplicationContext,并将它做为一个属性绑定到该请求,以方便之后的控制器和其余组件可以使用它,属性的键名默认为
DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE
b 将时区(locale)解析器绑定到请求上,以便其余组件在处理请求(渲染视图、准备数据等)时能够获取到时区的相关信息,若不须要,可忽略此项
c 将主题(theme)解析器绑定到请求上,同理
d 若是你配置了multipart文件处理器,那么框架将查找该文件是否是multipart(分为多个部分连续上传)的。如果,则将该请求包装成一个 MultipartHttpServletRequest 对象,以便处理链中的其余组件对它作进一步的处理。
e 为请求寻找一个合适的处理器,若是处理器被找到,则整个执行莲(前处理器,后处理器,控制器等)都会被执行,以完成相应模型的准备或视图的渲染
f 若是返回获得了一个模型model,那么此时直接将该model渲染成相应的视图view,若没有任何返回模型。则不会渲染,并默认请求的处理已经由请求链处理完毕。
若是在处理的过程当中跑出了异常,,那么上下文 WebApplicationContext 对象中所定义的异常处理器将会负责捕获这些异常。经过配置你本身的异常处理器,你能够定制本身处理异常的方式。
控制器是应用程序逻辑的处理入口,Spring对控制器的定义相对宽松,实现控制器很自由
例如能够在控制器上添加
@RequestMapping @RequestParam @ModelAttribute
@Controller
public class HelloWorldController {
@RequestMapping("/helloWorld")
public String helloWorld(Model model) {
model.addAttribute("message", "Hello World!");
return "helloWorld";
}
}
使用@Controller关键字,代表了该类是一个做为控制器而存在的角色,Spring此时不要求你去集成任何控制器基类,也不须要去实现Servlet的那套API,固然若是须要也能够去实现
@Controller注解被认为是这个类的原型,代表这个类所承担的角色。分派器(DispatcherServlet)会扫描全部注解了@Controller的类,检测其中经过@RequestMapping注解配置的方法
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.springframework.samples.petclinic.web"/>
<!-- ... -->
</beans>
该关键字主要用来将请求 URL 映射到整个类上或者某个特定的方法上
一般,一个类的注解将某个连接映射到一个具体的控制器上,而其中的方法的映射则是更加细化了处理,便可以根据特定的HTTP请求方法(GET/POST等)、查看HTTP请求中是否携带特定参数等条件,将请求映射到匹配的方法上
@Controller
@RequestMapping("/appointments")
public class AppointmentsController {
private final AppointmentBook appointmentBook;
@Autowired
public AppointmentsController(AppointmentBook appointmentBook) {
this.appointmentBook = appointmentBook;
} @
RequestMapping(method = RequestMethod.GET)
public Map<String, Appointment> get() {
return appointmentBook.getAppointmentsForToday();
} @
RequestMapping(path = "/{day}", method = RequestMethod.GET)
public Map<String, Appointment> getForDay(@PathVariable @DateTimeFormat(iso=ISO.DA
TE) Date day, Model model) {
return appointmentBook.getAppointmentsForDay(day);
} @
RequestMapping(path = "/new", method = RequestMethod.GET)
public AppointmentForm getNewForm() {
return new AppointmentForm();
} @
RequestMapping(method = RequestMethod.POST)
public String add(@Valid AppointmentForm appointment, BindingResult result) {
if (result.hasErrors()) {
return "appointments/new";
} a
ppointmentBook.addAppointment(appointment);
return "redirect:/appointments";
}
}
类级别的@RequestMapping不是必须的,若不配置的前提下,则其中方法的映射都是绝对路径,而不是相对路径