整個框架主要是圍繞一個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不是必須的,若不配置的前提下,則其中方法的映射都是絕對路徑,而不是相對路徑