一伊佃、簡介
?Spring MVC屬于SpringFrameWork的后續(xù)產(chǎn)品辅斟,已經(jīng)融合在Spring Web Flow里面。Spring 框架提供了構(gòu)建 Web 應(yīng)用程序的全功能 MVC 模塊噩斟。SpringMVC是一種web層的mvc框架阳欲,用于替代servlet(處理響應(yīng)請求巴元,獲取表單參數(shù)毡咏,表單驗證等)
二、工作流程
- 用戶發(fā)送請求至前端控制器DispatcherServlet逮刨。
- DispatcherServlet收到請求調(diào)用HandlerMapping處理器映射器呕缭。
- 處理器映射器找到具體的處理器(可以根據(jù)xml配置、注解進行查找)禀忆,生成處理器對象及處理器攔截器(如果有則生成)一并返回給DispatcherServlet臊旭。
- DispatcherServlet調(diào)用HandlerAdapter處理器適配器。
- HandlerAdapter經(jīng)過適配調(diào)用具體的處理器(Controller箩退,也叫后端控制器)离熏。
- Controller執(zhí)行完成返回ModelAndView。
- HandlerAdapter將controller執(zhí)行結(jié)果ModelAndView返回給DispatcherServlet戴涝。
- DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器滋戳。
- ViewReslover解析后返回具體View
- DispatcherServlet根據(jù)View進行渲染視圖(即將模型數(shù)據(jù)填充至視圖中)。
- DispatcherServlet響應(yīng)用戶啥刻。
三奸鸯、理解
1、為什么要使用springMVC可帽?
?SpringMVC是一種基于Java娄涩,實現(xiàn)了Web MVC設(shè)計模式,請求驅(qū)動類型的輕量級Web框架,即使用了MVC架構(gòu)模式的思想蓄拣,將Web層進行職責(zé)解耦扬虚。基于請求驅(qū)動指的就是使用請求-響應(yīng)模型球恤,框架的目的就是幫助我們簡化開發(fā)辜昵,SpringMVC也是要簡化日常Web開發(fā)。(處理業(yè)務(wù)數(shù)據(jù)的對象和顯示業(yè)務(wù)數(shù)據(jù)的視圖之間存在緊密耦合)
2咽斧、什么是MVC設(shè)計模式堪置?
?MVC即Model-View-Controller,將應(yīng)用按照Model(模型)张惹、View(視圖)舀锨、Controller(控制)這樣的方式分離。
?視圖(View):代表用戶交互界面诵叁,對于Web應(yīng)用來說雁竞,可以是HTML钦椭,也可能是jsp拧额、XML和Applet等。一個應(yīng)用可能有很多不同的視圖彪腔,MVC設(shè)計模式對于視圖的處理僅限于視圖上數(shù)據(jù)的采集和處理侥锦,以及用戶的請求,而不包括在視圖上的業(yè)務(wù)流程的處理德挣。業(yè)務(wù)流程的處理交予模型(Model)處理恭垦。
? 模型(Model):是業(yè)務(wù)的處理以及業(yè)務(wù)規(guī)則的制定。模型接受視圖請求的數(shù)據(jù)格嗅,并返回最終的處理結(jié)果番挺。業(yè)務(wù)模型的設(shè)計是MVC最主要的核心。MVC設(shè)計模式告訴我們屯掖,把應(yīng)用的模型按一定的規(guī)則抽取出來玄柏,抽取的層次很重要,抽象與具體不能隔得太遠贴铜,也不能太近粪摘。MVC并沒有提供模型的設(shè)計方法,而只是組織管理這些模型绍坝,以便于模型的重構(gòu)和提高重用性徘意。
? 控制(Controller):可以理解為從用戶接收請求, 將模型與視圖匹配在一起,共同完成用戶的請求轩褐。劃分控制層的作用也很明顯椎咧,它清楚地告訴你,它就是一個分發(fā)器把介,選擇什么樣的模型勤讽,選擇什么樣的視圖竹宋,可以完成什么樣的用戶請求〉丶迹控制層并不做任何的數(shù)據(jù)處理蜈七。
3、SpringMVC的特點
- 清晰的角色劃分:控制器(controller)莫矗、驗證器(validator)飒硅、 命令對象(command object)、表單對象(formobject)作谚、模型對象(model object)三娩、 Servlet分發(fā)器(DispatcherServlet)、處理器映射(handler mapping)妹懒、視圖解析器(view resolver)等雀监。每一個角色都可以由一個專門的對象來實現(xiàn)。
- 強大而直接的配置方式:將框架類和應(yīng)用程序類都能作為JavaBean配置眨唬,支持跨多個context的引用会前,例如,在web控制器中對業(yè)務(wù)對象和驗證器(validator)的引用匾竿。
- 可適配瓦宜、非侵入:可以根據(jù)不同的應(yīng)用場景,選擇合適的控制器子類 (simple型岭妖、command型临庇、form型、wizard型昵慌、multi-action型或者自定義)假夺,而不是從單一控制器 (比如Action/ActionForm)繼承。
- 可重用的業(yè)務(wù)代碼:可以使用現(xiàn)有的業(yè)務(wù)對象作為命令或表單對象斋攀,而不需要去擴展某個特定框架的基類已卷。
- 可定制的綁定(binding) 和驗證(validation):比如將類型不匹配作為應(yīng)用級的驗證錯誤, 這可以保存錯誤的值蜻韭。再比如本地化的日期和數(shù)字綁定等等悼尾。在其他某些框架中,你只能使用字符串表單對象肖方,需要手動解析它并轉(zhuǎn)換到業(yè)務(wù)對象闺魏。
- 可定制的handlermapping和view resolution:Spring提供從最簡單的URL映射, 到復(fù)雜的俯画、專用的定制策略析桥。與某些webMVC框架強制開發(fā)人員使用單一特定技術(shù)相比,Spring顯得更加靈活。
- 靈活的model轉(zhuǎn)換:在Springweb框架中泡仗,使用基于Map的 鍵/值對來達到輕易地與各種視圖技術(shù)的集成埋虹。
可定制的本地化和主題(theme)解析:支持在JSP中可選擇地使用Spring標簽庫、支持JSTL娩怎、支持Velocity(不需要額外的中間層)等等搔课。 - 簡單而強大的JSP標簽庫(SpringTag Library):支持包括諸如數(shù)據(jù)綁定和主題(theme) 之類的許多功能。
- JSP表單標簽庫:在Spring2.0中引入的表單標簽庫截亦,使得在JSP中編寫 表單更加容易爬泥。
- Spring Bean的生命周期可以被限制在當(dāng)前的HTTP Request或者HTTP Session。
4崩瓤、SpringMVC的優(yōu)點
- 讓我們能非常簡單的設(shè)計出干凈的Web層和薄薄的Web層
- 進行更簡潔的Web層的開發(fā)
- 天生與Spring框架集成(如IoC容器袍啡、AOP等)
- 提供強大的約定大于配置的契約式編程支持
- 非常靈活的數(shù)據(jù)驗證、格式化和數(shù)據(jù)綁定機制
- 支持Restful風(fēng)格
5却桶、SpringMVC的入門程序
web.xml
<web-app>
<servlet>
<!-- 加載前端控制器 -->
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--
加載配置文件
默認加載規(guī)范:
* 文件命名:xxx-servlet.xml(xxx=定義的servlet-name 即<servlet-name>springmvc</servlet-name>)====springmvc-servlet.xml
* 路徑規(guī)范:必須在WEB-INF目錄下面
修改加載路徑:
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
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:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 1.處理器映射器 -->
<!-- 方式一 配置映射處理器:根據(jù)bean(自定義Controller)的name屬性的url去尋找handler境输;springmvc默認的映射處理器是BeanNameUrlHandlerMapping-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- 方式二 -->
<!-- <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/hello.do">myController</prop>
</props>
</property>
</bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="urlMap">
<map>
<entry key="/login1.action" value="userController"></entry>
<entry key="/login2.action" value="userController2"></entry>
</map>
</property>
</bean> -->
<!-- 2.處理器適配器 -->
<!-- 方式一 配置處理器適配器來執(zhí)行Controller ,springmvc默認的是SimpleControllerHandlerAdapter
-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!-- 方式二 貼近原生態(tài) -->
<!-- <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean>-->
<!-- 3.處理器:配置自定義Controller -->
<bean id="myController" name="/hello.do" class="com.howick.controller.MyController"></bean>
<bean id="userController2" name="/login2.action" class="com.neuedu.controller.UserController2"></bean>
<!-- 4.配置sprigmvc視圖解析器:解析邏輯視圖;
后臺返回邏輯視圖:index
視圖解析器解析出真正物理視圖:前綴+邏輯視圖+后綴====/WEB-INF/jsps/index.jsp
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsps/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
自定義處理器(適配器方式一)實現(xiàn)Controller接口
public class MyController implements Controller{
public ModelAndView handleRequest(HttpServletRequest arg0,
HttpServletResponse arg1) throws Exception {
ModelAndView mv = new ModelAndView();
//設(shè)置頁面回顯數(shù)據(jù)
mv.addObject("hello", "歡迎學(xué)習(xí)springmvc颖系!");
//返回物理視圖
//mv.setViewName("/WEB-INF/jsps/index.jsp");
//返回邏輯視圖
mv.setViewName("index");
return mv;
}
}
自定義處理器(適配器方式二)實現(xiàn)HttpRequestHandler 接口
public class UserController2 implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//保存消息
HttpSession session = request.getSession();
session.setAttribute("message", "恭喜你成功訪問第一個springMVC環(huán)境成功了嗅剖!--實現(xiàn)方式為:HttpRequestHandlerAdapter");
//頁面跳轉(zhuǎn)(使用重定向,保存消息那里集晚,我們要用 窗悯? request session application pageContext )
response.sendRedirect(request.getContextPath()+"/main.jsp");
}
}
SpringMVC注解方式處理器適配器区匣、映射器
注解映射器
在spring3.1版本之前偷拔,系統(tǒng)默認加載DispatcherServlet.properoties文件中的org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping注解映射器,3.1版本之后要使用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping這個注解映射器亏钩。在springmvc.xml中進行RequestMappingHandlerMapping的配置:
<!--注解處理器映射器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
使用RequestMappingHandlerMapping需要在Handler 中使用@controller標識此類是一個控制器莲绰,使用@requestMapping指定Handler方法所對應(yīng)的url。
注解適配器
Spring3.1之前默認加載DispatcherServlet.properoties中的注解適配器是
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter姑丑,3.1版本之后要使用:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter這個注解適配器蛤签。在springmvc.xml中進行如下配置:
<!--注解的適配器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
RequestMappingHandlerAdapter,不要求Handler實現(xiàn)任何接口栅哀,它需要和RequestMappingHandlerMapping注解映射器配對使用震肮,主要解析Handler方法中的形參。
也可以使用使用 <mvc:annotation-driven/> 標簽來配置留拾,它是一種簡寫模式戳晌,它會自動注冊處理器適配器,配置方式如下:
<!-- 處理器映射器 處理器適配器 他們兩個可以通過注解進行配置痴柔,而且一個注解即可搞定兩步配置 -->
<mvc:annotation-driven></mvc:annotation-driven>
自定義控制器
//使用Controller來標識它是一個控制器
@Controller
public class TestControllerTest{
@RequestMapping("/testurl")
public ModelAndView testurl() throws Exception{
//邏輯代碼
}
}
然后在springmvc.xml中對該Handler進行配置:
<!--注解的Handler不用id沦偎,url在@RequestMapping注解中已經(jīng)聲明-->
<bean class="com.howick.controller.TestControllerTest"/>
上面我們通過對單個注解Handler的配置,也可以使用組件掃描<context:component-scan base-package="包名"/>對整個包下的Handler進行配置。
<context:component-scan base-package="com.howick.controller"/>
6豪嚎、SpringMVC常用注解及其作用
@Controller:標識這個類是一個控制器
@RequestMapping:給控制器方法綁定一個uri
@ResponseBody:將java對象轉(zhuǎn)成json搔驼,并且發(fā)送給客戶端
@RequestBody:將客戶端請求過來的json轉(zhuǎn)成java對象
@RequestParam:當(dāng)表單參數(shù)和方法形參名字不一致時,做一個名字映射
@PathVarible:用于獲取uri中的參數(shù),比如user/1中1的值
Rest風(fēng)格的新api
@RestController相當(dāng)于@Controller+ @ResponseBody
@GetMapping@DeleteMapping@PostMapping@PutMapping
其他注解
@SessionAttribute:聲明將什么模型數(shù)據(jù)存入session
@CookieValue:獲取cookie值
@ModelAttribute:將方法返回值存入model中
@HeaderValue:獲取請求頭中的值
7侈询、SpringMVC和Struts2的對比
框架機制:SpringMVC的入口是servlet舌涨,而Struts2是filter。
Filter在容器啟動后就初始化扔字,服務(wù)停止后銷毀泼菌,晚于Servlet;Servlet是在調(diào)用之后初始化并且先于Filter調(diào)用啦租,服務(wù)停止后銷毀哗伯。
調(diào)用順序:filter的調(diào)用順序:
- 按照web.xml中的映射配置順序按照配置條件從后向前調(diào)用
- 層次調(diào)用doFilter()方法中FilterChain.doFilter()之前的內(nèi)容(filter-mapping的name先調(diào)用doFilter方法,但是每個dofilter方法的內(nèi)部存在chain.dofilter會調(diào)用下一個filter-mapping,一直到不存在下一個filter后在返回篷角,執(zhí)行chain.dofilter()后面的代碼)(相當(dāng)于遞歸調(diào)用)
- 調(diào)用Servlet中的service()方法
- service方法執(zhí)行完畢后焊刹,層次調(diào)用doFilter()中FilterChain.doFilter()之后的方法,順序與之前的相反
例如:
- filter和servlet同時存在恳蹲,且容器初始化都要加載虐块,則先加載filter再加載servlet的init方法。
- 如果請求的url既匹配filter又匹配servlet嘉蕾,并且servlet的init方法沒有在容器初始化加載贺奠,則先加載匹配的servlet的最后一個servlet的init方法,再按順序執(zhí)行filter方法错忱,最后再執(zhí)行匹配的最后一個servlet方法
攔截機制:
- Struts2:
- Struts2框架是類級別的攔截儡率,每次請求就會創(chuàng)建一個Action,和Spring整合時Struts2的ActionBean注入作用域是原型模式prototype(否則會出現(xiàn)線程并發(fā)問題)以清,然后通過setter儿普,getter吧request數(shù)據(jù)注入到屬性;
- 一個Action對應(yīng)一個request掷倔,response上下文眉孩,在接收參數(shù)時,可以通過屬性接收勒葱,說明屬性參數(shù)是讓多個方法共享的浪汪;
- Action的一個方法可以對應(yīng)一個url,而其類屬性卻被所有方法共享凛虽,這也就無法用注解或其他方式標識其所屬方法了死遭。
- SpringMVC:
- SpringMVC是方法級別的攔截,一個方法對應(yīng)一個Request上下文涩维,所以方法直接基本上是獨立的殃姓,獨享request袁波,response數(shù)據(jù)。而每個方法同時又何一個url對應(yīng)蜗侈,參數(shù)的傳遞是直接注入到方法中的篷牌,是方法所獨有的。處理結(jié)果通過ModeMap返回給框架踏幻;
- 在Spring整合時枷颊,SpringMVC的Controller Bean默認單例模式Singleton,所以默認對所有的請求该面,只會創(chuàng)建一個Controller夭苗,有應(yīng)為沒有共享的屬性,所以是線程安全的隔缀,如果要改變默認的作用域题造,需要添加@Scope注解修改;
Struts2有自己的攔截Interceptor機制猾瘸,SpringMVC這是用的是獨立的Aop方式界赔,這樣導(dǎo)致Struts2的配置文件量還是比SpringMVC大。
性能方面:SpringMVC實現(xiàn)了零配置牵触,由于SpringMVC基于方法的攔截淮悼,有加載一次單例模式bean注入。而Struts2是類級別的攔截揽思,每次請求對應(yīng)實例一個新的Action袜腥,需要加載所有的屬性值注入,所以钉汗,SpringMVC開發(fā)效率和性能高于Struts2羹令。
配置方面:spring MVC和Spring是無縫的。從這個項目的管理和安全上也比Struts2高(當(dāng)然Struts2也可以通過不同的目錄結(jié)構(gòu)和相關(guān)配置做到SpringMVC一樣的效果儡湾,但是需要xml配置的地方不少)特恬;
SpringMVC可以認為已經(jīng)100%零配置。
設(shè)計思想:Struts2更加符合OOP的編程思想徐钠, SpringMVC就比較謹慎,在servlet上擴展役首。
集成方面:SpringMVC集成了Ajax尝丐。
注意:springmvc是單例模式的框架,但它是線程安全的,因為springmvc沒有成員變量,所有參數(shù)的封裝都是基于方法的,屬于當(dāng)前線程的私有變量. 因此是線程安全的框架。所以效率高衡奥。
struts action是多例的爹袁。所以可以使用成員變量獲取參數(shù)。所以效率低矮固。