Spring MVC是Spring給我們提供的一個(gè)用于簡化Web開發(fā)的框架
簡介
MVC體系
常用的開發(fā)框架一般基于兩種形式,一種C/S架構(gòu)掸茅,一種B/S架構(gòu)椅邓。在JavaEE開發(fā)中,幾乎都是基于B/S架構(gòu)的昧狮。在B/S架構(gòu)中景馁,系統(tǒng)標(biāo)準(zhǔn)的三層包括:表現(xiàn)層、業(yè)務(wù)層逗鸣、持久層合住。
-
表現(xiàn)層
也就是我們常說的Web層绰精。它負(fù)責(zé)接收客戶端請(qǐng)求,向客戶端響應(yīng)結(jié)果透葛,通潮渴梗客戶端使用http協(xié)議請(qǐng)求web層,完成http響應(yīng)僚害。表現(xiàn)層包括展示層和控制層:控制層負(fù)責(zé)接收請(qǐng)求硫椰,展示層負(fù)責(zé)結(jié)果的展示。表現(xiàn)層依賴業(yè)務(wù)層贡珊,接收到客戶端請(qǐng)求一般回調(diào)用業(yè)務(wù)層進(jìn)行業(yè)務(wù)處理最爬,并將處理結(jié)果響應(yīng)給客戶端涉馁。表現(xiàn)層的設(shè)計(jì)一般都使用MVC模型门岔。 -
業(yè)務(wù)層
也就是我們常說的Service層。它負(fù)責(zé)業(yè)務(wù)邏輯處理烤送,和我們開發(fā)項(xiàng)目的需求息息相關(guān)寒随。web層依賴業(yè)務(wù)層,但業(yè)務(wù)層不依賴web層帮坚。 -
持久層
也就是我們常說的dao層妻往。負(fù)責(zé)數(shù)據(jù)持久化,包括數(shù)據(jù)層即數(shù)據(jù)庫和數(shù)據(jù)訪問層试和,數(shù)據(jù)庫是對(duì)數(shù)據(jù)進(jìn)行持久化的載體讯泣,數(shù)據(jù)訪問層是業(yè)務(wù)層和持久層交互的接口,業(yè)務(wù)層需要通過數(shù)據(jù)訪問層將數(shù)據(jù)持久化到數(shù)據(jù)庫中阅悍。
MVC設(shè)計(jì)
MVC全名Model View Controller好渠,是模型(model)-視圖(view)-控制器(controller)的縮寫,是一種用于設(shè)計(jì)創(chuàng)建Web應(yīng)用程序表現(xiàn)層的模式节视。
-
Model(模型)
模型包含業(yè)務(wù)模型和數(shù)據(jù)模型拳锚,數(shù)據(jù)模型用于封裝數(shù)據(jù),業(yè)務(wù)模型用于處理業(yè)務(wù) -
View(視圖)
通常指我們的JSP或者HTML頁面寻行,作用一般就是展示數(shù)據(jù)霍掺。視圖是依據(jù)模型數(shù)據(jù)創(chuàng)建 -
Controller(控制器)
應(yīng)用程序中處理用戶交互的部分。作用一般是處理程序邏輯的拌蜘。
TIPS:MVC提倡每一層只編寫自己的東西杆烁,不編寫任何其他的代碼;分層是為了解耦简卧,為了維護(hù)方便和分工協(xié)作
Spring MVC
SpringMVC全名Spring Web MVC连躏,是一種基于Java實(shí)現(xiàn)的MVC設(shè)計(jì)模型的請(qǐng)求驅(qū)動(dòng)類型的輕量級(jí)Web框架,屬于spring-framework后續(xù)產(chǎn)品贞滨。SpringMVC本質(zhì)可以認(rèn)為是對(duì)Servlet的封裝入热,簡化了我們Servlet的開發(fā)
工作流程
1拍棕、配置DispatchServlet前端控制器
2、開發(fā)處理具體業(yè)務(wù)邏輯的Handler(@Controller勺良、@RequestMapping)
3绰播、xml配置文件配置Controller掃描,配置springmvc三個(gè)件
4尚困、將xml文件路徑告訴springmvc(DispatchServlet)
請(qǐng)求處理流程
-
step1:用戶發(fā)送請(qǐng)求至前端控制器DispatchServlet
step2:DispatchServlet收到請(qǐng)求調(diào)用HandlerMapping處理器映射器
step3:處理器映射器根據(jù)請(qǐng)求URL找到具體的Handler蠢箩,生產(chǎn)處理器對(duì)象及處理器攔截器,返回DispatchServlet
step4:DispatchServlet調(diào)用HandlerAdapter處理器適配器去調(diào)用Handler
step5:處理器適配器執(zhí)行handler
step6:Handler執(zhí)行完成給處理器適配器返回ModelAndView
step7:處理器適配器向前端控制返回ModelAndView事甜,ModelAndView是SpringMVC框架的一個(gè)底層對(duì)象谬泌,包括model和view
step8:前端控制器請(qǐng)求視圖解析器去進(jìn)行視圖解析,根據(jù)邏輯視圖名來解析真正的視圖
step9:視圖解析器向前端控制器返回view
step10:前端控制器進(jìn)行視圖渲染逻谦,就是將模型數(shù)據(jù)填充到request域
step11:前端控制器向用戶響應(yīng)結(jié)果
九大組件
-
HandlerMapping(處理器映射器)
HandlerMapping是用來查找Handler的掌实,也就是處理器,具體的表現(xiàn)形式可以是類邦马,也可以是方法贱鼻。比如標(biāo)注了@RequestMapping的每個(gè)方法都可以看成一個(gè)Handler。Handler負(fù)責(zé)具體實(shí)際的請(qǐng)求處理滋将,在請(qǐng)求到達(dá)后邻悬,HandlerMapping的作用就是找到請(qǐng)求相應(yīng)的處理器Handler和Interceptor -
HandlerAdapter(處理器適配器)
HandlerAdapter是一個(gè)適配器。因?yàn)镾pringMVC中Handler可以是任意形式的随闽,只要能處理請(qǐng)求即可父丰。但是把請(qǐng)求交給Servlet的時(shí)候,由于Servlet的方法結(jié)構(gòu)都是doService(HttpServletRequest,HttpServletResponse)形式的掘宪,要讓固定的Servlet處理方法調(diào)用Handler來進(jìn)行處理蛾扇,便是HandlerAdapter的職責(zé) -
HandlerExceptionResolver
HandlerExceptionResolver用于處理Handler產(chǎn)生的異常情況。它的作用是根據(jù)異常設(shè)置ModelAndView添诉,之后交給渲染方法進(jìn)行渲染屁桑,渲染方法會(huì)將ModelAndView渲染成頁面 -
ViewResolver
ViewResolver即視圖解析器,用于將String類型的視圖名和Locale解析為View類型的視圖栏赴,只有一個(gè)resolveViewName方法蘑斧。Controller層返回的String類型視圖名viewName最終會(huì)在這里被解析成View。View是用來渲染頁面的须眷,也就是說它會(huì)將程序返回的參數(shù)和數(shù)據(jù)填入模板中竖瘾,生產(chǎn)HTML文件。ViewResolver主要完成兩件事:1)找到渲染所用的模板花颗,2)找到所用的技術(shù)(找到視圖的類型捕传,如JSP)并填入?yún)?shù)。默認(rèn)情況下扩劝,SpringMVC會(huì)自動(dòng)配置一個(gè)InternalResourceViewResolver是針對(duì)JSP類型視圖的庸论。 -
RequestToViewNameTranslator
RequestToViewNameTranslator組件的作用是從請(qǐng)求中獲取ViewName职辅。因?yàn)閂iewResolver根據(jù)ViewName查找View,但有的Handler處理完成之后沒有設(shè)置View也沒有設(shè)置ViewName聂示,便要通過這個(gè)組件從請(qǐng)求中查找ViewName -
LocaleResolver
ViewResolver組件的resolveViewName方法需要兩個(gè)參數(shù)域携,一個(gè)是視圖名,一個(gè)是Locale鱼喉。LocaleResolver用于從請(qǐng)求中解析出Locale秀鞭,比如中國Locale是zh-CN,用來表示一個(gè)區(qū)域扛禽。這個(gè)組件也是i18n的基礎(chǔ) -
ThemeResolver
ThemeResolver組件是用來解析主題的锋边。主題是樣式、圖片及它們所形成的的顯示效果的集合编曼。SpringMVC中一套主題對(duì)應(yīng)一個(gè)properties文件豆巨。里面存放著與當(dāng)前主題相關(guān)的所有資源,如圖片灵巧、CSS樣式等搀矫。創(chuàng)建主題只需要準(zhǔn)備好資源抹沪,然后新建一個(gè)“主題名.properties”并將資源設(shè)置進(jìn)去刻肄,放在classpath下,之后便可以在頁面中使用了融欧。SpringMVC中與主題相關(guān)的類有ThemeResolver敏弃、ThemeSource和Theme。ThemeResolver負(fù)責(zé)從請(qǐng)求中解析出主題名噪馏,ThemeSource根據(jù)主題名找到具體的主題麦到,其抽象就是Theme,可以通過Theme來獲取主題和具體的資源欠肾。 -
MultipartResolver
MultipartResolver用于上傳請(qǐng)求瓶颠,通過將普通的請(qǐng)求包裝成MultipartHttpServletRequest來實(shí)現(xiàn)。MultipartHttpServletRequest可以通過getFile方法直接獲得文件刺桃。如果上傳多個(gè)文件粹淋,還可以調(diào)用getFileMap方法得到Map<FileName, File>這樣的結(jié)構(gòu),MultipartResolver的作用就是封裝普通的請(qǐng)求瑟慈,使其擁有文件上傳的功能桃移。 -
FlashMapManager
FlashMap用于重定向時(shí)的參數(shù)傳遞。因?yàn)橹囟ㄏ驎r(shí)沒有傳遞參數(shù)這一功能葛碧,如果不想把參數(shù)寫進(jìn)URL(不推薦)借杰,那么就可以通過FlashMap來傳遞。只需要在重定向之前將要傳遞的數(shù)據(jù)寫入請(qǐng)求的屬性O(shè)UTPUT_FLASH_MAP_ATTRIBUTE中进泼,這樣在重定向之后的handler中Spring就會(huì)自動(dòng)將其設(shè)置到Model中蔗衡。FlashMapManager就是用來管理FlashMap的纤虽。
參數(shù)綁定
-
默認(rèn)支持Servlet API作為方法參數(shù)
當(dāng)需要使用HttpServletRequest、HttpServletResponse绞惦、HttpSession等原生Servlet對(duì)象時(shí)廓推,直接在handler方法中形參聲明使用即可
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, HttpSession session) {}
-
綁定簡單類型參數(shù)
綁定簡單數(shù)據(jù)類型參數(shù),只需要直接聲明形參即可翩隧,形參參數(shù)名和傳遞的參數(shù)名要保持一致樊展。當(dāng)形參參數(shù)名和傳遞參數(shù)名不一致時(shí)可以使用@RequestParam注解進(jìn)行手動(dòng)映射。建議使用包裝類型堆生,因?yàn)榛A(chǔ)數(shù)據(jù)類型不可以為null
public ModelAndView handle(@RequestParam("ids") Integer id, Boolean flag) {}
-
綁定POJO類型參數(shù)
接受POJO類型參數(shù)专缠,直接形參聲明即可,類型就是POJO類型淑仆,形參名無所謂涝婉,但是要求傳遞的參數(shù)名必須和POJO的屬性名保持一致
public ModelAndView handle(User user) {}
-
綁定POJO包裝對(duì)象參數(shù)
不管包裝POJO與否,首先它是一個(gè)POJO蔗怠,那么就可以按照POJO的要求來墩弯。綁定是直接形參聲明即可;傳參參數(shù)名和POJO屬性保持一致寞射,如果不能定位數(shù)據(jù)項(xiàng)渔工,那么通過屬性名+“.”的方式進(jìn)一步鎖定數(shù)據(jù)
public class QueryVO {
private User user;
}
// url: /demo/handle?user.id=1&user.username=zhangsan
public ModelAndView handle(QueryVO query) {}
- 自定義類型轉(zhuǎn)換器
// 定義類型轉(zhuǎn)換器
public class DateConverter implements Converter<String, Date> {
public Date convert(String source) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
try {
Date parse = simpleDateFormat.parse(source);
return parse;
} catch (ParseException e) {}
}
return null;
}
// 注冊(cè)自定義類型轉(zhuǎn)換器
<!-- 自動(dòng)注冊(cè)最合適的處理器映射器,處理器適配器 -->
<mvc:annotation-driven conversion-service="conversionServiceBean"/>
<!--注冊(cè)自定義轉(zhuǎn)化器-->
<bean id="conversionServiceBean" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.xxx.converter.DateConverter"/>
</set>
</property>
</bean>
@RequestMapping("/handle")
public ModelAndView handle(Date birthday) {
}
RESTful風(fēng)格支持
RESTful風(fēng)格URL:互聯(lián)網(wǎng)所有的事物都是資源桥温,要求URL中只有表示資源的名詞引矩,沒有動(dòng)詞
RESTful風(fēng)格資源操作:使用HTTP請(qǐng)求中的method方法put、delete侵浸、post旺韭、get來操作資源,分別對(duì)應(yīng)添加掏觉、刪除区端、修改、查詢澳腹。不過一般使用時(shí)還是POST和GET织盼。PUT和DELETE幾乎不用
RESTful風(fēng)格資源表述:可以根據(jù)需求對(duì)URL定位的資源返回不同的表述(也就是返回?cái)?shù)據(jù)類型,比如XML遵湖、JSON等數(shù)據(jù)格式)
SpringMVC支持RESTful風(fēng)格請(qǐng)求悔政,具體講就是使用@PathVariable注解獲取RESTful風(fēng)格的請(qǐng)求URL中的路徑變量
<form method="post" action="/demo/handle">
<input type="text" name="username"/>
<input type="submit" value="修改"/>
</form>
<form method="post" action="/demo/handle/15/lisi">
<input type="hidden" name="_method" value="put"/>
<input type="submit" value="新增"/>
</form>
<form method="post" action="/demo/handle">
<input type="hidden" name="_method" value="delete"/>
<input type="submit" value="刪除"/>
</form>
@RequestMapping(value = "/demo/handle/{id}", method={RequestMethod.GET}
public ModelAndView get(@PathVariable("id") Integer id) {
}
@RequestMapping(value = "/demo/handle/{id}/{name}", method={RequestMethod.PUT}
public ModelAndView add(@PathVariable("id") Integer id, @PathVariable("username") String username) {
}
@RequestMapping(value = "/demo/handle/{id}", method={RequestMethod.POST}
public ModelAndView update(@PathVariable("id") Integer id, String username) {
}
@RequestMapping(value = "/demo/handle/{id}", method={RequestMethod.DELETE}
public ModelAndView add(@PathVariable("id") Integer id) String username) {
}
<!-- 配置springmvc請(qǐng)求方式轉(zhuǎn)換過濾器,會(huì)檢查請(qǐng)求參數(shù)中是否有_method參數(shù)延旧,如果有就按照指定的請(qǐng)求方式進(jìn)行轉(zhuǎn)換-->
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*<url-pattern>
</filter-mapping>
Ajax Json交互
@ResponseBody注解
@ResponseBody注解的作用是將Controller的方法返回的對(duì)象通過適當(dāng)?shù)霓D(zhuǎn)化器轉(zhuǎn)化為指定的格式之后谋国,寫入到response對(duì)象的body區(qū),通常用來返回JSON數(shù)據(jù)或者XML數(shù)據(jù)迁沫。
TIPS:在使用此注解之后不會(huì)再走視圖處理器芦瘾,而是直接將數(shù)據(jù)寫入輸入流中捌蚊,它的效果等同于通過response對(duì)象輸入指定格式的數(shù)據(jù)
@RequestMapping("/handle")
public @ResponseBody User handle(@RequestBody User user) {
}
SpringMVC高級(jí)技術(shù)
攔截器(Interceptor)
監(jiān)聽器、過濾器和攔截器對(duì)比
- Servlet:處理Request請(qǐng)求和Response相應(yīng)
- 過濾器(Filter):堆Request請(qǐng)求起到過濾的作用近弟,作用在Servlet之前缅糟,如果配置為/*可以對(duì)所有的資源訪問進(jìn)行過濾處理
-
監(jiān)聽器(Listener):實(shí)現(xiàn)了javax.servlet.ServletContextListener接口的服務(wù)端組件,它隨Web應(yīng)用的啟動(dòng)而啟動(dòng)祷愉,只初始化一次窗宦,然后會(huì)一直運(yùn)行監(jiān)視,隨web應(yīng)用的停止而銷毀
作用一:做一些初始化工作二鳄,web應(yīng)用中spring容器啟動(dòng)ContextLoaderListener
作用二:監(jiān)聽web中的特定事件赴涵,比如HttpSession,ServletRequest的創(chuàng)建和銷毀订讼;變量的創(chuàng)建髓窜、銷毀和修改等∑鄣睿可以在某些動(dòng)作前后增加處理寄纵,實(shí)現(xiàn)監(jiān)控,比如統(tǒng)計(jì)在線人數(shù)脖苏,利用HttpSessionListener -
攔截器(Interceptor):是SpringMVC程拭、Struts等表現(xiàn)層框架自己的,不會(huì)攔截jsp/html/css/images的訪問等帆阳,只會(huì)攔截訪問的控制器方法(Handler)
從配置的角度也能夠發(fā)現(xiàn):servlet哺壶、filter屋吨、listener是配置在web.xml中的蜒谤,而Interceptor是配置在表現(xiàn)層框架自己的配置文件中的。
攔截器執(zhí)行流程
1)程序先執(zhí)行preHandle方法至扰,如果該方法的返回值為true鳍徽,則程序會(huì)繼續(xù)向下執(zhí)行處理器中的方法,否則將不再向下執(zhí)行
2)在業(yè)務(wù)處理器(即控制器Controller類)處理完請(qǐng)求后敢课,會(huì)執(zhí)行postHandle方法阶祭,然后會(huì)通過DispatchServlet向客戶端返回響應(yīng)
3)在DispatchServlet處理完請(qǐng)求后,才會(huì)執(zhí)行afterCompletion方法
多攔截器的執(zhí)行流程
當(dāng)有多個(gè)攔截器同時(shí)工作時(shí)直秆,它們的preHandle方法會(huì)按照配置文件中攔截器的配置順序執(zhí)行濒募,而它們的postHandle和afterCompletion則會(huì)按照配置順序的反序執(zhí)行
控制器中處理異常
@ControllerAdvice
public class GlobalExceptionResolver {
@ExceptionHandler(ArithmeticException.class)
public ModelAndView handleException(ArithmeticException exception, HttpServletResponse response) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", exception.getMessage());
modelAndView.setViewName("error");
}
}
基于Flash屬性的跨重定向請(qǐng)求數(shù)據(jù)傳遞
重定向時(shí)請(qǐng)求參數(shù)會(huì)丟失,我們往往需要重新攜帶請(qǐng)求參數(shù)圾结,我們可以進(jìn)行手動(dòng)參數(shù)拼接瑰剃。
return "redirect:handle?name=" + name;
但上述拼接參數(shù)的方法屬于get請(qǐng)求,攜帶參數(shù)長度有限筝野,參數(shù)安全性也不高晌姚,此時(shí)粤剧,我們可以使用SpringMVC提供的flash屬性機(jī)制,向上下文中添加flash屬性挥唠,框架會(huì)在session中記錄該屬性抵恋,當(dāng)跳轉(zhuǎn)到頁面之后框架會(huì)自動(dòng)刪除flash屬性,不需要我們手動(dòng)刪除宝磨,通過這種方式進(jìn)行重定向參數(shù)傳遞弧关,參數(shù)長度和安全性都得到了保障。
@RequestMapping("/handle")
public String handle(String name, RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("name", name);
return "redirect:handle01";
}