Spring MVC應(yīng)用
Spring MVC介紹
MVC體系結(jié)構(gòu)
三層架構(gòu)
在B/S架構(gòu)中奕删,系統(tǒng)標(biāo)準(zhǔn)的三層架構(gòu)包括:表現(xiàn)層储笑、業(yè)務(wù)層孕暇、控制層。
- 表現(xiàn)層
表現(xiàn)層包括展現(xiàn)層和控制層:控制層負(fù)責(zé)接收請求只搁,展示層負(fù)責(zé)結(jié)果的展示音比。 - 業(yè)務(wù)層
業(yè)務(wù)層負(fù)責(zé)具體的業(yè)務(wù)邏輯處理。
表現(xiàn)層依賴業(yè)務(wù)層氢惋,業(yè)務(wù)層不依賴表現(xiàn)層洞翩。
業(yè)務(wù)層可能依賴持久層稽犁。 - 持久層
負(fù)責(zé)數(shù)據(jù)的持久化。
MVC設(shè)計模式(Model View Controller)
MVC分為三個部分:Model骚亿、View已亥、Controller,他們各司其職:
- Model(模型):分業(yè)務(wù)模型和數(shù)據(jù)模型来屠,業(yè)務(wù)模型處理業(yè)務(wù)陷猫,數(shù)據(jù)模型負(fù)責(zé)封裝數(shù)據(jù)。
- View(視圖):負(fù)責(zé)前端數(shù)據(jù)展示的妖,如Jsp绣檬、html。
- Controller(控制器):處理用戶交互嫂粟,處理程序邏輯娇未。
MVC提倡:每一層只編寫自己的東西,不編寫其他任何代碼星虹;分層是為了解耦零抬,解耦是為了維護(hù)方便和分工協(xié)作。
Spring MVC是什么
SpringMVC 全名叫 Spring Web MVC宽涌,是?種基于 Java 的實現(xiàn) MVC 設(shè)計模型的請求驅(qū)動類型的輕量級Web 框架平夜,屬于 SpringFrameWork 的后續(xù)產(chǎn)品。
Spring架構(gòu):
Spring MVC 本質(zhì)可以認(rèn)為是對servlet的封裝卸亮,簡化了我們serlvet的開發(fā)
Spring MVC的工作流程:
Spring Web MVC 工作流程
Spring MVC開發(fā)流程:
- 配置DispatchorServlet前端控制器
- 開發(fā)處理業(yè)務(wù)的@Controller,配置請求路徑@RequestMapping忽妒,返回ModelAndView
- xml配置?件配置controller掃描,配置springmvc三?件
- 處理器映射器
- 處理器適配器
- 視圖解析器
-
將xml?件路徑告訴springmvc(DispatcherServlet)
image.png
流程說明
第?步:?戶發(fā)送請求?前端控制器DispatcherServlet
第?步:DispatcherServlet收到請求調(diào)?HandlerMapping處理器映射器
第三步:處理器映射器根據(jù)請求Url找到具體的Handler(后端控制器)兼贸,?成處理器對象及處理器攔截
器(如果 有則?成)?并返回DispatcherServlet
第四步:DispatcherServlet調(diào)?HandlerAdapter處理器適配器去調(diào)?Handler
第五步:處理器適配器執(zhí)?Handler
第六步:Handler執(zhí)?完成給處理器適配器返回ModelAndView
第七步:處理器適配器向前端控制器返回 ModelAndView段直,ModelAndView 是SpringMVC 框架的?個底層對 象,包括 Model 和 View
第?步:前端控制器請求視圖解析器去進(jìn)?視圖解析溶诞,根據(jù)邏輯視圖名來解析真正的視圖鸯檬。
第九步:視圖解析器向前端控制器返回View
第?步:前端控制器進(jìn)?視圖渲染,就是將模型數(shù)據(jù)(在 ModelAndView 對象中)填充到 request 域
第??步:前端控制器向?戶響應(yīng)結(jié)果
Spring MVC九大組件
- HandlerMapping(處理器映射器)
管理請求到handler和Intercepor的映射關(guān)系
- HandlerAdapter(處理器適配器)
因為 Spring MVC 中 Handler 可以是任意形式的螺垢,只要能處理請求即可喧务。但是把請求交給 Servlet 的時候,由于 Servlet 的?法結(jié)構(gòu)都是 doService(HttpServletRequest req,HttpServletResponse resp)形式的枉圃,要讓固定的 Servlet 處理?法調(diào)? Handler 來進(jìn)?處理功茴,便是 HandlerAdapter 的職責(zé)。
- HandlerExceptionResolver(處理器異常解析器)
根據(jù)異常設(shè)置ModelAndView讯蒲,之后交給渲染?法進(jìn)?渲染痊土,渲染?法會將 ModelAndView 渲染成??肄扎。
- ViewResoulver(視圖解析器)
ViewResolver即視圖解析器墨林,?于將String類型的視圖名和Locale解析為View類型的視圖赁酝,只有? 個resolveViewName()?法。從?法的定義可以看出旭等,Controller層返回的String類型視圖名 viewName 最終會在這?被解析成為View酌呆。View是?來渲染??的,也就是說搔耕,它會將程序返回 的參數(shù)和數(shù)據(jù)填?模板中隙袁,?成html?件。ViewResolver 在這個過程主要完成兩件事情: ViewResolver 找到渲染所?的模板(第?件?事)和所?的技術(shù)(第?件?事弃榨,其實也就是找到 視圖的類型菩收,如JSP)并填?參數(shù)。默認(rèn)情況下鲸睛,Spring MVC會?動為我們配置?個 InternalResourceViewResolver,是針對 JSP 類型視圖的娜饵。
- RequestToViewNameTranslator(請求視圖名轉(zhuǎn)換器)
是從請求中獲取 ViewName.
RequestToViewNameTranslator 組件的作?是從請求中獲取 ViewName.因為 ViewResolver 根據(jù)
ViewName 查找 View,但有的 Handler 處理完成之后,沒有設(shè)置 View官辈,也沒有設(shè)置 ViewName箱舞,
便要通過這個組件從請求中查找 ViewName。
- LocaleResovler(國際化解析器)
做國際化支持
ViewResolver 組件的 resolveViewName ?法需要兩個參數(shù)拳亿,?個是視圖名晴股,?個是 Locale。
LocaleResolver ?于從請求中解析出 Locale肺魁,?如中國 Locale 是 zh-CN电湘,?來表示?個區(qū)域。這
個組件也是 i18n 的基礎(chǔ)鹅经。
- ThemeResovler(主題解析器)
多套樣式主題配置管理胡桨。
ThemeResolver 組件是?來解析主題的。主題是樣式瞬雹、圖?及它們所形成的顯示效果的集合昧谊。
Spring MVC 中?套主題對應(yīng)?個 properties?件,??存放著與當(dāng)前主題相關(guān)的所有資源酗捌,如圖
?呢诬、CSS樣式等。創(chuàng)建主題?常簡單胖缤,只需準(zhǔn)備好資源尚镰,然后新建?個“主題名.properties”并將資
源設(shè)置進(jìn)去,放在classpath下哪廓,之后便可以在??中使?了狗唉。SpringMVC中與主題相關(guān)的類有
ThemeResolver、ThemeSource和Theme涡真。ThemeResolver負(fù)責(zé)從請求中解析出主題名分俯,
ThemeSource根據(jù)主題名找到具體的主題肾筐,其抽象也就是Theme,可以通過Theme來獲取主題和
具體的資源缸剪。
- MutipartResovler(多元素解析器)
文件上傳
MultipartResolver ?于上傳請求吗铐,通過將普通的請求包裝成 MultipartHttpServletRequest 來實
現(xiàn)。MultipartHttpServletRequest 可以通過 getFile() ?法 直接獲得?件杏节。如果上傳多個?件唬渗,還
可以調(diào)? getFileMap()?法得到Map<FileName,F(xiàn)ile>這樣的結(jié)構(gòu)奋渔,MultipartResolver 的作?就
是封裝普通的請求镊逝,使其擁有?件上傳的功能。
- FlashMapManager
重定向參數(shù)傳遞
FlashMap ?于重定向時的參數(shù)傳遞嫉鲸,?如在處理?戶訂單時候蹋半,為了避免重復(fù)提交,可以處理完
post請求之后重定向到?個get請求充坑,這個get請求可以?來顯示訂單詳情之類的信息减江。這樣做雖然
可以規(guī)避?戶重新提交訂單的問題,但是在這個??上要顯示訂單的信息捻爷,這些數(shù)據(jù)從哪?來獲得
呢辈灼?因為重定向時么有傳遞參數(shù)這?功能的,如果不想把參數(shù)寫進(jìn)URL(不推薦)也榄,那么就可以通
過FlashMap來傳遞巡莹。只需要在重定向之前將要傳遞的數(shù)據(jù)寫?請求(可以通過ServletRequestAttributes.getRequest()?法獲得)的屬性O(shè)UTPUT_FLASH_MAP_ATTRIBUTE
中,這樣在重定向之后的Handler中Spring就會?動將其設(shè)置到Model中甜紫,在顯示訂單信息的??
上就可以直接從Model中獲取數(shù)據(jù)降宅。FlashMapManager 就是?來管理 FalshMap 的。
url-pattern配置:
- /*.subfix囚霸,后綴方式
- / 攔截除.jsp外的請求腰根,包括靜態(tài)資源。
- /* 攔截所有拓型,包括.jsp
為什么/不攔截jsp额嘿?
因為在web.xml的父配置文件中配置了一個jsp的Servlet用于處理jsp請求。
怎么解決/攔截靜態(tài)資源劣挫?
- 1册养、在springmvc.xml中配置<mvc:default-servlet-handler/>。
DefaultServletHandler會解析請求压固,如果發(fā)現(xiàn)是靜態(tài)資源就還給web容器處理球拦,如果不是今天資源就由springmvc繼續(xù)處理。
但是這個配置只對webapp更目錄下的靜態(tài)資源有效。
- 2坎炼、在springmvc.xml中配置<mvc:resources mapping="/resource/**" location="classpath:/" />
由Spring mvc自己管理靜態(tài)資源愧膀。
請求參數(shù)綁定
參數(shù)綁定的幾種方式(見代碼):
/**
* @author xdf
* @version 1.0
* @date Create in 17:12 2021/6/17
* @description springmvc 示例的Controller
* @modifiedBy
*/
@Controller
@RequestMapping("/demo")
public class DemoController {
/**
* 1、ModelAndView方式
*/
@RequestMapping("/handle01")
public ModelAndView handle01() {
Date date = new Date();
// 返回服務(wù)器時間
// 封裝了數(shù)據(jù)和頁面信息的ModelAndView
ModelAndView modelAndView = new ModelAndView();
// 向請求域中設(shè)置 request.setAttribute("date",date)
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
/**
* 2点弯、ModelMap 方式
*
* /
@RequestMapping("/handle02")
public String handle02(ModelMap map) {
System.out.println(map.getClass());
Date date = new Date();
// 返回服務(wù)器時間
// 封裝了數(shù)據(jù)和頁面信息的ModelAndView
// 向請求域中設(shè)置 request.setAttribute("date",date)
map.addAttribute("date",date);
return "success";
}
/**
* 3扇调、Map模式
*/
@RequestMapping("/handle03")
public String handle03(Map<String,Object> map) {
System.out.println(map.getClass());
Date date = new Date();
// 返回服務(wù)器時間
// 封裝了數(shù)據(jù)和頁面信息的ModelAndView
// 向請求域中設(shè)置 request.setAttribute("date",date)
map.put("date",date);
return "success";
}
/**
* 4矿咕、Model模式
*/
@RequestMapping("/handle04")
public String handle04(Model map) {
System.out.println(map.getClass());
Date date = new Date();
// 返回服務(wù)器時間
// 封裝了數(shù)據(jù)和頁面信息的ModelAndView
// 向請求域中設(shè)置 request.setAttribute("date",date)
map.addAttribute("date",date);
return "success";
}
}
這四種方式都能將數(shù)據(jù)綁定到請求參數(shù)岸啡,然后傳遞到j(luò)sp中去术陶。
為什么不管是用Model
、ModelMap
還是Map
都能實現(xiàn),參數(shù)的綁定竭恬?
我們分別打印這三個對象,返現(xiàn)都是
class org.springframework.validation.support.BindingAwareModelMap
類的實例翁授。
查看這個類的類圖:
發(fā)現(xiàn)Model残拐、Map都是BindingAwareModeMap的接口,ModelMap是它的父類瑞侮。這里使用的其實都是BindingAwareModeMap的實例的圆,只是用了不同方式來引用它。
請求參數(shù)綁定:說?了SpringMVC如何接收請求參數(shù)
http協(xié)議(超?本傳輸協(xié)議)
原?servlet接收?個整型參數(shù):
(1)String ageStr = request.getParameter("age");
(2) Integer age = Integer.parseInt(ageStr);
SpringMVC框架對Servlet的封裝半火,簡化了servlet的很多操作
SpringMVC在接收整型參數(shù)的時候越妈,直接在Handler?法中聲明形參即可
@RequestMapping("xxx")
public String handle(Integer age) {
System.out.println(age);
}
參數(shù)綁定:取出參數(shù)值綁定到handler?法的形參上
- 默認(rèn)?持 Servlet API 作為?法參數(shù)
當(dāng)需要使?HttpServletRequest、HttpServletResponse钮糖、HttpSession等原?servlet對象時梅掠,直接在handler?法中形參聲明使?即可。
/**
*
* SpringMVC 對原?servlet api的?持 url:/demo/handle02?id=1
*
* 如果要在SpringMVC中使?servlet原?對象店归,?如
HttpServletRequest\HttpServletResponse\HttpSession阎抒,直接在Handler?法形參中聲
明使?即可
*
*/
@RequestMapping("/handle02")
public ModelAndView handle02(HttpServletRequest request,
HttpServletResponse response,HttpSession session) {
String id = request.getParameter("id");
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
- 綁定簡單類型參數(shù)
簡單數(shù)據(jù)類型:?種基本數(shù)據(jù)類型及其包裝類型
參數(shù)類型推薦使?包裝數(shù)據(jù)類型,因為基礎(chǔ)數(shù)據(jù)類型不可以為null
整型:Integer消痛、int
字符串:String
單精度:Float且叁、flfloat
雙精度:Double、double
布爾型:Boolean秩伞、boolean
說明:對于布爾類型的參數(shù)谴古,**請求的參數(shù)值為true或false〕砬福或者1或0 **
注意:綁定簡單數(shù)據(jù)類型參數(shù)掰担,只需要直接聲明形參即可(形參參數(shù)名和傳遞的參數(shù)名要保持?
致,建議 使?包裝類型怒炸,當(dāng)形參參數(shù)名和傳遞參數(shù)名不?致時可以使?@RequestParam注解進(jìn)?
?動映射)
/*
* SpringMVC 接收簡單數(shù)據(jù)類型參數(shù) url:/demo/handle03?id=1
*
* 注意:接收簡單數(shù)據(jù)類型參數(shù)带饱,直接在handler?法的形參中聲明即可,框架會取出參數(shù)值
然后綁定到對應(yīng)參數(shù)上
* 要求:傳遞的參數(shù)名和聲明的形參名稱保持?致
*/
@RequestMapping("/handle03")
public ModelAndView handle03(@RequestParam("ids") Integer id,Boolean
flag) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
- 綁定Pojo類型參數(shù)
/*
* SpringMVC接收pojo類型參數(shù) url:/demo/handle04?id=1&username=zhangsan
*
* 接收pojo類型參數(shù),直接形參聲明即可勺疼,類型就是Pojo的類型教寂,形參名?所謂
* 但是要求傳遞的參數(shù)名必須和Pojo的屬性名保持?致
*/
@RequestMapping("/handle04")
public ModelAndView handle04(User user) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
- 綁定Pojo包裝對象參數(shù)
包裝類型 QueryVo
package com.lagou.edu.pojo;
public class QueryVo {
private String mail;
private String phone;
// 嵌套了另外的Pojo對象
private User user;
public String getMail() {
return mail;
}
public void setMail(String mail) {
this.mail = mail;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
Handler?法
/*
* SpringMVC接收pojo包裝類型參數(shù) url:/demo/handle05?
user.id=1&user.username=zhangsan
* 不管包裝Pojo與否,它?先是?個pojo执庐,那么就可以按照上述pojo的要求來
* 1酪耕、綁定時候直接形參聲明即可
* 2、傳參參數(shù)名和pojo屬性保持?致轨淌,如果不能夠定位數(shù)據(jù)項迂烁,那么通過屬性名 + "." 的
?式進(jìn)?步鎖定數(shù)據(jù)
*
*/
@RequestMapping("/handle05")
public ModelAndView handle05(QueryVo queryVo) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
- 綁定?期類型參數(shù)(需要配置?定義類型轉(zhuǎn)換器)
- 前端jsp
<fieldset>
<p>測試?例:SpringMVC接收?期類型參數(shù)</p>
<a href="/demo/handle06?birthday=2019-10-08">點擊測試</a>
</fieldset>
- 后臺Handler?法
/**
* 綁定?期類型參數(shù)
* 定義?個SpringMVC的類型轉(zhuǎn)換器 接?,擴展實現(xiàn)接?接?递鹉,注冊你的實現(xiàn)
* @param birthday
* @return
*/
@RequestMapping("/handle06")
public ModelAndView handle06(Date birthday) {
Date date = new Date();ModelAndView modelAndView = new
ModelAndView();
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
- ?定義類型轉(zhuǎn)換器
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author 應(yīng)癲
* ?定義類型轉(zhuǎn)換器
* S:source盟步,源類型
* T:target:?標(biāo)類型
*/
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
// 完成字符串向?期的轉(zhuǎn)換
SimpleDateFormat simpleDateFormat = new
SimpleDateFormat("yyyy-MM-dd");
try {
Date parse = simpleDateFormat.parse(source);
return parse;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
- 注冊?定義類型轉(zhuǎn)換器
<!--
?動注冊最合適的處理器映射器,處理器適配器(調(diào)?handler?法)
-->
<mvc:annotation-driven conversion?
service="conversionServiceBean"/>
<!--注冊?定義類型轉(zhuǎn)換器-->
<bean id="conversionServiceBean"
class="org.springframework.format.support.FormattingConversionServiceF
actoryBean">
<property name="converters">
<set>
<bean class="com.lagou.edu.converter.DateConverter">
</bean>
</set>
</property>
</bean>
Restful風(fēng)格請求支持
什么是Restful
REST(Representational State Transfer),資源表現(xiàn)層狀態(tài)轉(zhuǎn)移躏结。他是一種網(wǎng)絡(luò)接口風(fēng)格却盘。
Restful優(yōu)點
- 結(jié)構(gòu)清晰
- 符合標(biāo)準(zhǔn)
- 易于理解
- 擴展方便
Restful特性
資源:網(wǎng)絡(luò)上的一個實體。
表現(xiàn)層:把資源呈現(xiàn)出來的形式媳拴。(txt黄橘、html、xml屈溉、json...)
狀態(tài)轉(zhuǎn)換:就是 HTTP 協(xié)議??塞关,四個表示操作?式的動詞:
GET 、POST 语婴、PUT 描孟、DELETE 。它們分別對應(yīng)四種基本操作:GET ?來獲取資源砰左,POST ?來新建資源匿醒,PUT ?來更新資源,DELETE ?來刪除資源缠导。
RESTful風(fēng)格的URL:互聯(lián)網(wǎng)上的所有事物都是資源廉羔,URL中只有表示資源的名稱,沒有操作的動詞僻造。
RESTful風(fēng)格資源操作:使用HTTP請求中的method方法get憋他、post、update髓削、delete來操作資源竹挡。put 和 delete?乎不使?。
RESTful風(fēng)格資源表述:可以有多種返回數(shù)據(jù)類型:json立膛、xml等揪罕。
Spring MVC對Restful的支持
Restful代碼示例:
- 前端代碼
<h2>SpringMVC對Restful?格url的?持</h2>
<fieldset>
<p>測試?例:SpringMVC對Restful?格url的?持</p>
<a href="/demo/handle/15">rest_get測試</a>
<form method="post" action="/demo/handle">
<input type="text" name="username"/>
<input type="submit" value="提交rest_post請求"/>
</form>
<form method="post" action="/demo/handle/15/lisi">
<input type="hidden" name="_method" value="put"/>
<input type="submit" value="提交rest_put請求"/>
</form>
<form method="post" action="/demo/handle/15">
<input type="hidden" name="_method" value="delete"/>
<input type="submit" value="提交rest_delete請求"/>
</form>
</fieldset>
- 后臺handler
@RequestMapping(value = "/handle/{id}", method = RequestMethod.GET)
public ModelAndView handleGet(@PathVariable("id") String id) {
System.out.println(id);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("data", id);
modelAndView.setViewName("success");
return modelAndView;
}
@RequestMapping(value = "/handle/{id}/{name}", method = RequestMethod.POST)
public ModelAndView handlePost(@PathVariable("id") String id, @PathVariable("name") String name) {
System.out.println(id);
String data = "id:" + id + ",name:" + name;
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("data", data);
modelAndView.setViewName("success");
return modelAndView;
}
@RequestMapping(value = "/handle/{id}/{name}", method = RequestMethod.PUT)
public ModelAndView handlePut(@PathVariable("id") String id, @PathVariable("name") String name) {
System.out.println(id);
String data = "id:" + id + ",name:" + name;
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("data", data);
modelAndView.setViewName("success");
return modelAndView;
}
@RequestMapping(value = "/handle/{id}", method = RequestMethod.DELETE)
public ModelAndView handleDelete(@PathVariable("id") String id) {
System.out.println(id);
String data = "id:" + id;
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("data", data);
modelAndView.setViewName("success");
return modelAndView;
}
- web配置文件
<!--配置springmvc請求?式轉(zhuǎn)換過濾器梯码,會檢查請求參數(shù)中是否有_method參數(shù),如果有就
按照指定的請求?式進(jìn)?轉(zhuǎn)換-->
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Ajax JSON交互
什么是JSON
略
@ResponseBody注解
將Controller的返回值轉(zhuǎn)換為指定的格式寫入到Response的body區(qū)好啰,一般是Json 格式轩娶。
分析Spring MVC使用Json交互
- 引入json支持
<!--json數(shù)據(jù)交互所需jar,start-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<!--json數(shù)據(jù)交互所需jar框往,end-->
- handler方法返回值用@ResponseBody標(biāo)注
@RequestMapping("/handle07")
// 添加@ResponseBody之后鳄抒,不再?視圖解析器那個流程,?是等同于response直接輸出數(shù)據(jù)
public @ResponseBody User handle07(@RequestBody User user) {
// 業(yè)務(wù)邏輯處理椰弊,修改name為張三豐
user.setName("張三豐");
return user;
}
Spring MVC高級技術(shù)
攔截器(Interceptor)使用
監(jiān)聽器许溅、過濾器和攔截器對比
- Servlet:處理Request請求和Response響應(yīng)
- 過濾器(Filter):對Request請求起到過濾作用,作用在Servlet之前男应。實現(xiàn)Filter接口闹司,配置在web.xml文件中娱仔,有web容器調(diào)用沐飘,不歸springmvc管。
- 監(jiān)聽器(Listener):實現(xiàn)了javax.servlet.ServletContextListener 接?的服務(wù)器端組件牲迫,它隨 Web應(yīng)?的啟動?啟動耐朴,只初始化?次,然后會?直運?監(jiān)視盹憎,隨Web應(yīng)?的停??銷毀筛峭。
- 作用一:做一些初始化工作,web應(yīng)用中spring容器啟動ContextLoaderListener陪每。
- 作用二:監(jiān)聽web中的特定事件影晓,比如HttpSession,ServletRequest的創(chuàng)建和銷毀;變量的創(chuàng)建檩禾、銷毀和修改等挂签。
- 攔截器(Interceptor):是SpringMVC、Struts等表現(xiàn)層框架自己的盼产,只會攔截控制器饵婆。
- 在Handler執(zhí)行業(yè)務(wù)之前攔截一次
- 在Handler邏輯執(zhí)行完畢但為跳轉(zhuǎn)到頁面之前攔截一次
- 在跳轉(zhuǎn)頁面之后調(diào)用一次
過濾器解決亂碼:
- post亂碼,配置web.xml
<!-- 解決post亂碼問題 -->
<filter>
<filter-name>encoding</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<!-- 設(shè)置編碼參是UTF8 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- Get請求亂碼,修改server.xml
<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080"
protocol="HTTP/1.1" redirectPort="8443"/>
攔截器的執(zhí)行流程
1)程序先執(zhí)?preHandle()?法戏售,如果該?法的返回值為true侨核,則程序會繼續(xù)向下執(zhí)?處理器中的? 法,否則將不再向下執(zhí)?灌灾。
2)在業(yè)務(wù)處理器(即控制器Controller類)處理完請求后搓译,會執(zhí)?postHandle()?法,然后會通過
DispatcherServlet向客戶端返回響應(yīng)锋喜。
3)在DispatcherServlet處理完請求后些己,才會執(zhí)?afterCompletion()?法。
多個攔截器執(zhí)行流程
示例代碼:
實現(xiàn)三個攔截器:
- GlobalInterceptor:全局?jǐn)r截器
package com.xdf.mvcdemo.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author xdf
* @version 1.0
* @date Create in 14:18 2021/6/21
* @description 自定義攔截器1
* @modifiedBy
*/
public class GlobalInterceptor implements HandlerInterceptor {
/**
* 前置攔截
* @param request 請求
* @param response 響應(yīng)
* @param handler 控制器
* @return true 繼續(xù)執(zhí)行,false攔截請求
* @throws Exception 異常信息
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("GlobalInterceptor preHandle");
return true;
}
/**
* 后置攔截
* @param request 請求
* @param response 響應(yīng)
* @param handler 控制器
* @param modelAndView 數(shù)據(jù)和視圖
* @throws Exception 異常
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("GlobalInterceptor postHandle");
}
/**
* 視圖渲染完攔截器
* @param request 請求
* @param response 響應(yīng)
* @param handler 控制器
* @param ex 異常轴总,可以在這個方法中處理異常
* @throws Exception 異常
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("GlobalInterceptor afterCompletion");
}
}
- MyInterceptor1:普通攔截器
package com.xdf.mvcdemo.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author xdf
* @version 1.0
* @date Create in 14:18 2021/6/21
* @description 自定義攔截器1
* @modifiedBy
*/
public class MyInterceptor1 implements HandlerInterceptor {
/**
* 前置攔截
* @param request 請求
* @param response 響應(yīng)
* @param handler 控制器
* @return true 繼續(xù)執(zhí)行直颅,false攔截請求
* @throws Exception 異常信息
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("interceptor1 preHandle");
return true;
}
/**
* 后置攔截
* @param request 請求
* @param response 響應(yīng)
* @param handler 控制器
* @param modelAndView 數(shù)據(jù)和視圖
* @throws Exception 異常
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("interceptor1 postHandle");
}
/**
* 視圖渲染完攔截器
* @param request 請求
* @param response 響應(yīng)
* @param handler 控制器
* @param ex 異常,可以在這個方法中處理異常
* @throws Exception 異常
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("interceptor1 afterCompletion");
}
}
- MyInterceptor2:普通攔截器
package com.xdf.mvcdemo.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author xdf
* @version 1.0
* @date Create in 14:18 2021/6/21
* @description 自定義攔截器1
* @modifiedBy
*/
public class MyInterceptor2 implements HandlerInterceptor {
/**
* 前置攔截
* @param request 請求
* @param response 響應(yīng)
* @param handler 控制器
* @return true 繼續(xù)執(zhí)行怀樟,false攔截請求
* @throws Exception 異常信息
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("interceptor2 preHandle");
return true;
}
/**
* 后置攔截
* @param request 請求
* @param response 響應(yīng)
* @param handler 控制器
* @param modelAndView 數(shù)據(jù)和視圖
* @throws Exception 異常
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("interceptor2 postHandle");
}
/**
* 視圖渲染完攔截器
* @param request 請求
* @param response 響應(yīng)
* @param handler 控制器
* @param ex 異常功偿,可以在這個方法中處理異常
* @throws Exception 異常
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("interceptor2 afterCompletion");
}
}
在springmvc.xml配置攔截器
<mvc:interceptors>
<bean class="com.xdf.mvcdemo.interceptor.GlobalInterceptor"/>
<mvc:interceptor>
<!-- 攔截所有請求 -->
<mvc:mapping path="/**"/>
<bean class="com.xdf.mvcdemo.interceptor.MyInterceptor1"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.xdf.mvcdemo.interceptor.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
隨便請求一個接口,輸出
GlobalInterceptor preHandle
interceptor1 preHandle
interceptor2 preHandle
15
interceptor2 postHandle
interceptor1 postHandle
GlobalInterceptor postHandle
interceptor2 afterCompletion
interceptor1 afterCompletion
GlobalInterceptor afterCompletion
因此:請求到控制器之間的攔截器執(zhí)行順序是配置順序往堡,控制器到響應(yīng)返回攔截器執(zhí)行順序是配置順序的反序械荷。
處理multipart形式的數(shù)據(jù)
文件上傳
原?servlet處理上傳的?件數(shù)據(jù)的,springmvc?是對serlvet的封裝
需要的依賴:
<!--?件上傳所需jar坐標(biāo)-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
配置?件上傳解析器
<!--配置?件上傳解析器虑灰,id是固定的multipartResolver-->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--設(shè)置上傳??吨瞎,單位字節(jié)-->
<property name="maxUploadSize" value="1000000000"/>
</bean>
前端:
<%--
1 method="post"
2 enctype="multipart/form-data"
3 type="file"
--%>
<form method="post" enctype="multipart/form-data" action="/demo/upload">
<input type="file" name="uploadFile"/>
<input type="submit" value="上傳"/>
</form>
后臺接收Handler
@RequestMapping("upload")
public String upload(MultipartFile uploadFile, HttpServletRequest request)
throws IOException {
// ?件原名,如xxx.jpg
String originalFilename = uploadFile.getOriginalFilename();
// 獲取?件的擴展名,如jpg
String extendName =
originalFilename.substring(originalFilename.lastIndexOf(".") + 1,
originalFilename.length());
String uuid = UUID.randomUUID().toString();
// 新的?件名字
String newName = uuid + "." + extendName;
String realPath =
request.getSession().getServletContext().getRealPath("/uploads");
// 解決?件夾存放?件數(shù)量限制穆咐,按?期存放
String datePath = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
File floder = new File(realPath + "/" + datePath);
if(!floder.exists()) {
floder.mkdirs();
}
uploadFile.transferTo(new File(floder,newName));
return "success";
}
在控制器處理異常
// 可以讓我們優(yōu)雅的捕獲所有Controller對象handler?法拋出的異常
@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");
return modelAndView;
}
}
基于Flash屬性的跨重定向請求數(shù)據(jù)傳遞
重定向時請求參數(shù)會丟失颤诀,我們往往需要重新攜帶請求參數(shù),我們可以進(jìn)??動參數(shù)拼接如下:
return "redirect:handle01?name=" + name;
但是上述拼接參數(shù)的?法屬于get請求对湃,攜帶參數(shù)?度有限制崖叫,參數(shù)安全性也不?,此時拍柒,我們可以使
?SpringMVC提供的flash屬性機制心傀,向上下?中添加flash屬性,框架會在session中記錄該屬性值拆讯,當(dāng)跳轉(zhuǎn)到??之后框架會?動刪除flflash屬性脂男,不需要我們?動刪除,通過這種?式進(jìn)?重定向參數(shù)傳遞种呐,參數(shù)長度和安全性都得到了保障宰翅,如下:
/**
* SpringMVC 重定向時參數(shù)傳遞的問題
* 轉(zhuǎn)發(fā):A 找 B 借錢400,B沒有錢但是悄悄的找到C借了400塊錢給A
* url不會變,參數(shù)也不會丟失,?個請求
* 重定向:A 找 B 借錢400陕贮,B 說我沒有錢堕油,你找別?借去,那么A ?帶著400塊的借錢需求找到
C
* url會變,參數(shù)會丟失需要重新攜帶參數(shù),兩個請求
*/
@RequestMapping("/handleRedirect")
public String handleRedirect(String name,RedirectAttributes
redirectAttributes) {
//return "redirect:handle01?name=" + name; // 拼接參數(shù)安全性肮之、參數(shù)?度都有 局限
// addFlashAttribute?法設(shè)置了?個flash類型屬性掉缺,該屬性會被暫存到session中,在 跳轉(zhuǎn)到??之后該屬性銷毀
redirectAttributes.addFlashAttribute("name",name);
return "redirect:handle01";
}
手寫MVC框架
自定義MVC框架核心流程:
代碼倉庫:https://gitee.com/xdf-lg/custom-springmvc/tree/master
Spring MVC源碼深度剖析
前端控制器DispatcherServlet繼承結(jié)構(gòu)
DispatcherServlet實現(xiàn)了Servlet接口(是一個Servlet)戈擒,關(guān)鍵方法調(diào)用結(jié)構(gòu):
- doGet/doPost被FrameworkServlet類重寫眶明。
- 在FrameworkServlet的doGet/doPost方法中調(diào)用processRequest方法處理請求
- 在processRequest方法中調(diào)用DispatcherServel中的doService
- doService方法中調(diào)用doDispatch方法做請求分發(fā)。
重要時機點分析
1)handler方法執(zhí)行時機
打斷點觀察:
調(diào)用棧:
2)頁面渲染時機
SpringMVC處理請求的流程圖
SpringMVC處理請求的流程(doDispatch流程):
- 調(diào)用getHandler方法獲取能處理請求的執(zhí)行連HandlerExecutionChain
- 調(diào)用getHandlerAdapter獲取執(zhí)行器適配器筐高。
- 適配器調(diào)用Handler執(zhí)行ha.handle方法返回一個ModelAndView
- 調(diào)用processDispatchResult方法完成視圖渲染跳轉(zhuǎn)搜囱。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
// 1 檢查是否是?件上傳的請求
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
/*
2 取得處理當(dāng)前請求的Controller丑瞧,這?也稱為Handler,即處理器
這?并不是直接返回 Controller蜀肘,?是返回 HandlerExecutionChain 請求處
理鏈對象
該對象封裝了Handler和Inteceptor
*/
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
// 如果 handler 為空绊汹,則返回404
this.noHandlerFound(processedRequest, response);
return;
}
// 3 獲取處理請求的處理器適配器 HandlerAdapter
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
// 處理 last-modified 請求頭
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
// 4 實際處理器處理請求,返回結(jié)果視圖對象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 結(jié)果視圖對象的處理
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
// 5 跳轉(zhuǎn)??扮宠,渲染視圖
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
//最終會調(diào)?HandlerInterceptor的afterCompletion ?法
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
核心步驟getHandler方法剖析
遍歷兩個HandlerMapping西乖,試圖獲取能夠處理當(dāng)前請求的執(zhí)?鏈
核心步驟getHandlerAdapter方法剖析
遍歷各個HandlerAdapter,看哪個Adapter?持處理當(dāng)前Handler
核心步驟ha.handle方法剖析
核心步驟processDispatchResult方法剖析
render?法完成渲染
視圖解析器解析出View視圖對象
在解析出View視圖對象的過程中會判斷是否重定向坛增、是否轉(zhuǎn)發(fā)等获雕,不同的情況封裝的是不同的View實現(xiàn)
解析出View視圖對象的過程中,要將邏輯視圖名解析為物理視圖名
封裝View視圖對象之后收捣,調(diào)?了view對象的render?法
渲染數(shù)據(jù)
把modelMap中的數(shù)據(jù)暴露到request域中届案,這也是為什么后臺model.add之后在jsp中可以從請求域取出來的根本原因
將數(shù)據(jù)設(shè)置到請求域中
Spring MVC九大組件初始化
九大組件初始化時機:DispatcherServlet中有一個內(nèi)部類ContextRefreshListener實現(xiàn)了ApplicationListener,監(jiān)聽了IOC容器的onRefresh方法罢艾。當(dāng)IOC容器執(zhí)行onRefresh方法時楣颠,執(zhí)行九大組件初始化。如圖:
無法復(fù)制加載中的內(nèi)容
在DispatcherServlet中定義了九個屬性昆婿,每?個屬性都對應(yīng)?種組件
/** MultipartResolver used by this servlet. */
// 多部件解析器
@Nullable
private MultipartResolver multipartResolver;
/** LocaleResolver used by this servlet. */
// 區(qū)域化 國際化解析器
@Nullable
private LocaleResolver localeResolver;
/** ThemeResolver used by this servlet. */
// 主題解析器
@Nullable
private ThemeResolver themeResolver;
/** List of HandlerMappings used by this servlet. */
// 處理器映射器組件
@Nullable
private List<HandlerMapping> handlerMappings;
/** List of HandlerAdapters used by this servlet. */
// 處理器適配器組件
@Nullable
private List<HandlerAdapter> handlerAdapters;
/** List of HandlerExceptionResolvers used by this servlet. */
// 異常解析器組件
@Nullable
private List<HandlerExceptionResolver> handlerExceptionResolvers;
/** RequestToViewNameTranslator used by this servlet. */
// 默認(rèn)視圖名轉(zhuǎn)換器組件
@Nullable
private RequestToViewNameTranslator viewNameTranslator;
/** FlashMapManager used by this servlet. */
// flash屬性管理組件
@Nullable
private FlashMapManager flashMapManager;
/** List of ViewResolvers used by this servlet. */
// 視圖解析器
@Nullable
private List<ViewResolver> viewResolvers;
九?組件都是定義了接?球碉,接?其實就是定義了該組件的規(guī)范蜓斧,?如ViewResolver仓蛆、HandlerAdapter等都是接?
九?組件的初始化時機
DispatcherServlet中的onRefresh(),該?法中初始化了九?組件
initStrategies?法
觀察其中的?個組件initHandlerMappings(context)
如果按照類型和按照固定id從ioc容器中找不到對應(yīng)組件挎春,則會按照默認(rèn)策略進(jìn)?注冊初始化看疙,默認(rèn)策略在DispatcherServlet.properties?件中配置
DispatcherServlet.properties
注意:多部件解析器的初始化必須按照id注冊對象(multipartResolver)
SSM整合
整合策略
SSM = Spring + SpringMVC + Mybatis = (Spring + Mybatis)+ SpringMVC
先整合 Spring + Mybatis
然后再整合 SpringMVC
基于的需求:查詢 Account 表的全部數(shù)據(jù)顯示到??
MyBatis整合Spring
- 整合?標(biāo)
- 數(shù)據(jù)庫連接池以及事務(wù)管理都交給Spring容器來完成
- SqlSessionFactory對象應(yīng)該放到Spring容器中作為單例對象管理
- Mapper動態(tài)代理對象交給Spring管理,我們從Spring容器中直接獲得Mapper的代理對象
- 整合所需 Jar 分析
- Junit測試jar(4.12版本)
- Mybatis的jar(3.4.5)
- Spring相關(guān)jar(spring-context直奋、spring-test能庆、spring-jdbc、spring-tx脚线、spring-aop搁胆、 aspectjweaver)
- Mybatis/Spring整合包jar(mybatis-spring-xx.jar)
- Mysql數(shù)據(jù)庫驅(qū)動jar
- Druid數(shù)據(jù)庫連接池的jar
- 整合后的 Pom 坐標(biāo)
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!--spring相關(guān)-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!--mybatis與spring的整合包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.3</version>
</dependency>
<!--數(shù)據(jù)庫驅(qū)動jar-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!--druid連接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
- jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/bank
jdbc.username=root
jdbc.password=123456
- Spring 配置?件
- applicationContext-dao.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!--包掃描-->
<context:component-scan base-package="com.lagou.edu.mapper"/>
<!--數(shù)據(jù)庫連接池以及事務(wù)管理都交給Spring容器來完成-->
<!--引?外部資源?件-->
<context:property-placeholder
location="classpath:jdbc.properties"/>
<!--第三?jar中的bean定義在xml中-->
<bean id="dataSource"
class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--SqlSessionFactory對象應(yīng)該放到Spring容器中作為單例對象管理
原來mybaits中sqlSessionFactory的構(gòu)建是需要素材的:SqlMapConfig.xml中的內(nèi)
容
-->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<!--別名映射掃描-->
<property name="typeAliasesPackage" value="com.lagou.edu.pojo"/>
<!--數(shù)據(jù)源dataSource-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--Mapper動態(tài)代理對象交給Spring管理晶默,我們從Spring容器中直接獲得Mapper的代理對
象-->
<!--掃描mapper接?她按,?成代理對象,?成的代理對象會存儲在ioc容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--mapper接?包路徑配置-->
<property name="basePackage" value="com.lagou.edu.mapper"/>
<property name="sqlSessionFactoryBeanName"
value="sqlSessionFactory"/>
</bean>
</beans>
- applicationContext-service.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:lgContext="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!--包掃描-->
<lgContext:component-scan base-package="com.lagou.edu.service"/>
<!--事務(wù)管理-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--事務(wù)管理注解驅(qū)動-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
- AccountMapper接?
package com.lagou.edu.mapper;
import com.lagou.edu.pojo.Account;
import java.util.List;
public interface AccountMapper {
// 定義dao層接??法--> 查詢account表所有數(shù)據(jù)
List<Account> queryAccountList() throws Exception;
}
- AccountMapper.xml
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lagou.edu.mapper.AccountMapper">
<select id="queryAccountList" resultType="com.lagou.edu.pojo.Account">
select * from account
</select>
</mapper>
- 測試程序
import com.lagou.edu.pojo.Account;
import com.lagou.edu.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:application*.xml"})
public class MybatisSpringTest {
// 希望測試ioc容器中的哪個對象你注?即可镰禾。
@Autowired
private AccountService accountService;
@Test
public void testMybatisSpring() throws Exception {
List<Account> accounts = accountService.queryAccountList();
for (int i = 0; i < accounts.size(); i++) {
Account account = accounts.get(i);
System.out.println(account);
}
}
}
整合Spring MVC
- 整合思路
把SpringMVC的??案例整合進(jìn)來即可(在已有?程基礎(chǔ)之上開發(fā)?個SpringMVC??案例) - 引?pom坐標(biāo)
<!--SpringMVC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
<!--jsp-api&servlet-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--??使?jstl表達(dá)式-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<!--json數(shù)據(jù)交互所需jar船逮,start-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<!--json數(shù)據(jù)交互所需jar顾腊,end-->
- 添加SpringMVC ??案例
- springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<!--掃描controller-->
<context:component-scan base-package="com.lagou.edu.controller"/>
<mvc:annotation-driven/>
</beans>
- Controller類
package com.lagou.edu.controller;
import com.lagou.edu.pojo.Account;
import com.lagou.edu.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequestMapping("/account")
public class AccountController {
/**
* Spring容器和SpringMVC容器是有層次的(??容器)
* Spring容器:service對象+dao對象
* SpringMVC容器:controller對象,挖胃,杂靶,梆惯,可以引?到Spring容器中的對象
*/
@Autowired
private AccountService accountService;
@RequestMapping("/queryAll")
@ResponseBody
public List<Account> queryAll() throws Exception {
return accountService.queryAccountList();
}
}
- web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext*.xml</param-value>
</context-param>
<!--spring框架啟動-->
<listener>
<listener?
class>org.springframework.web.context.ContextLoaderListener</listener?
class>
</listener>
<!--springmvc啟動-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet?
class>org.springframework.web.servlet.DispatcherServlet</servlet?
class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>