歡迎查看Java開發之上帝之眼系列教程,如果您正在為Java后端龐大的體系所困擾,如果您正在為各種繁出不窮的技術和各種框架所迷茫,那么本系列文章將帶您窺探Java龐大的體系。本系列教程希望您能站在上帝的角度去觀察(了解)Java體系。使Java的各種后端技術在你心中模塊化;讓你在工作中能將Java各個技術了然於心;能夠即插即用。本章我們來一起了解Java的MVC框架之SpringMVC。
Java語言現在應用比較多的MVC框架有SpringMVC,Struts2兩種。本章我們就來講解SpringMVC,對於本篇SpringMVC本篇不會介紹其詳細知識點及具體應用,Spring系列詳細使用和高級應用相關知識都在第四章:Spring專欄進行講解,本篇將會介紹SpringMVC的基礎相關概念,這些基礎概念是很重要的,它就如同蓋房子的基石。本章示例源碼下載
什么是MVC?
不可免俗地我還是想在本章開始與大家一起回顧一下什么是MVC?MVC其實就是一種軟件的設計模式。在開發中並沒有強制我們必須去遵循這種設計模式,但是遵循MVC模式會使我們系統層次更清晰;職責更明確;擴展性更強;耦合度降低。

什么是SpringMVC?
SpringMVC就是一個嚴格遵循MVC設計模式的框架。說其是一個框架,那么SpringMVC框架中就應該有與Model,View,Controller相對應的組件;分別是Model模型對象,視圖解析器,Controller控制器。
Spring MVC屬於SpringFrameWork的后續產品,SpringMVC對於構建WEB項目而言是可選的,如果你使用Spring框架,你可以選擇使用SpringMVC或者集成其他MVC框架。同時Spring MVC分離了控制器、模型對象、過濾器以及處理程序對象的角色,這種分離讓它們更容易進行定制。

- 學習門檻低,容易上手
- SpringMVC繼承了Spring框架的靈活性,容易擴展
- Spring將控制器,模型對象,過濾器等分離,使組件之間松耦合
- 支持多種視圖
- 輕松使用Spring生態下的其他組件
SpringMVC請求流程

- 用戶發起請求到DispatchServlet
- Handler Mapping匹配請求信息的Handler(匹配條件:請求路徑,方法,header信息)
- HandlerMapping向DispatchServlet返回handler,返回過程執行攔截器鏈(一系列攔截器Interceptor)
- 請求HandlerAdapter執行Handler
- HandlerAdapter根據Handler類型執行不同的Handler(處理器)
- Handler執行完畢返回給HandlerAdapter(處理器適配器)ModelAndView對象
- HandlerAdapter將ModelAndView返回給DispatchServlet
- DispatchServlet請求ViewResolver解析ModelAndView
- ViewResolver向DispatchServlet返回View
- DispatchServlet將View和模型數據進行視圖渲染
- DispatchServlet向用戶響應結果
SpringMVC常用組件
前端控制器DispatcherServlet
|
接受請求,響應結果,相當於轉發器,中央處理器,減少了與其他組件之間的耦合度
|
處理器映射器HandlerMapping
|
根據規則查找需要執行的Handler
|
處理器適配器HandlerAdapter
|
根據Handler類型,尋找相應處理器執行Handler
|
處理器 Handler
|
可以實際處理請求的方法,如被@RequestMapping標注的方法
|
視圖解析器 ViewResolver
|
進行視圖解析,根據邏輯視圖名解析成真正的視圖(view)
|
視圖View
|
View是一個接口,實現類支持不同的view類型(jsp,framemark,pdf…)
|
文件上傳解析器MultipartResolver
|
用於處理上傳請求
|
配置SpringMVC
典型的XML配置方式
<?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:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd 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"> <!--加載數據字典--> <context:property-placeholder location="classpath:resource.properties"/> <!--配置默認的Servlet作為靜態資源的Handler--> <mvc:default-servlet-handler/> <!-- 注解驅動:作用:替我們自動配置最新版的注解的處理器映射器和處理器適配器--> <mvc:annotation-driven/> <!-- 配置@Controller注解掃描 --> <context:component-scan base-package="com.jimisun.controller"></context:component-scan> <!--配置InternalResourceViewResolver視圖解析器解析返回數據--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="cache" value="false"/> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> <property name="contentType" value="text/html;charset=UTF-8"/> </bean> <!--配置自定義exceptionResolver異常解析器處理異常--> <bean id="exceptionResolver" class="com.jimisun.exception.MyExceptionResolver"/> <!--配置文件上傳--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="104857600"/> <property name="maxInMemorySize" value="4096"/> <property name="defaultEncoding" value="UTF-8"></property> </bean> <!--配置攔截器--> <mvc:interceptors> <mvc:interceptor> <!--攔截路徑規則--> <mvc:mapping path="/user/**"/> <!--排除路徑--> <mvc:exclude-mapping path="/user/login.html"></mvc:exclude-mapping> <mvc:exclude-mapping path="/user/register.html"></mvc:exclude-mapping> <bean id="viewLoginInterceptor" class="com.jimisun.interceptor.ViewLoginInterceptor"></bean> </mvc:interceptor> </mvc:interceptors> </beans>
從Servlet3.0開始,可以完全脫離XML對SpringWeb項目進行配置
/** * @Author:jimisun * @Description: * @Date:Created in 19:42 2018-09-28 * @Modified By: */ public class MyWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[]{RootConfig.class}; } @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{WebConfig.class}; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } }
SpringMVC單元測試 單元測試示例源碼下載
/** * @Author:jimisun * @Description: * @Date:Created in 07:58 2018-09-25 * @Modified By: */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:SpringMvc.xml", }) public class TestControllerTest { @Autowired private TestService testService; @Test public void sayhello() { String test = testService.sayHelloService("test"); System.out.println(test); } }
驗證Web請求參數
對於Controller接收到的參數,幾乎在所有情況下我們都需要驗證,SpringMVC開發中常用的驗證方法有兩種,Spring框架定義Validator校驗和JSP-303 Bean Validation校驗。
Spring Validator參數校驗
Spring Validator參數示例源碼下載
@RequestMapping("sayhello") public void sayhello(@Validated User user, BindingResult bindingResult) { if (bindingResult.hasErrors()) { System.out.println(bindingResult.getFieldError().getDefaultMessage()); } else { String s = testService.sayHelloService(user.getUsername()); System.out.println(s); }
JSP-303 Bean Validation校驗 Bean Validation校驗源碼下載
Spring在3.1的時候增加了對JSP-303 Bean Validation規范的支持,不僅可以對SpringMVC進行校驗,還可以對Hibernate的對象存儲進行校驗,是一個通用的校驗框架,在開發中我們都是用JSP-303 Bean Validation進行校驗,也是個人推薦使用的。
hibernate-validator依賴
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.4.Final</version> </dependency>
相關配置
<mvc:annotation-driven validator="validator"/> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/> <property name="validationMessageSource" ref="messageSource"/> </bean> <!-- 校驗錯誤信息配置文件 --> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <!-- 資源文件名 --> <property name="basename" value="classpath:validationMessages"/> <!-- 對資源文件內容緩存時間,單位秒 --> <property name="fileEncodings" value="GBK"/> <property name="defaultEncoding" value="GBK"/> <property name="cacheSeconds" value="120"/> </bean>
在接收參數時使用
@Valid進行校驗
@RequestMapping("sayhello")
public void sayhello(@Valid User user, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
System.out.println(bindingResult.getFieldError().getDefaultMessage());
} else {
String s = testService.sayHelloService(user.getUsername());
System.out.println(s);
}
}
使用下面注解對參數進行約束
public void sayhello(@Valid User user, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
System.out.println(bindingResult.getFieldError().getDefaultMessage());
} else {
String s = testService.sayHelloService(user.getUsername());
System.out.println(s);
}
}
Bean Validation 中內置的 constraint
Hibernate Validator 附加的 constraint
Java開發之上帝之眼系列教程其他文章
---------------------------------------------------------------------------------------------------------------------------------------------------------------------