Spring MVC高級框架

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):


image.png

Spring MVC 本質(zhì)可以認(rèn)為是對servlet的封裝卸亮,簡化了我們serlvet的開發(fā)


image.png

Spring MVC的工作流程:


image.png

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中去术陶。
為什么不管是用ModelModelMap 還是Map都能實現(xiàn),參數(shù)的綁定竭恬?
我們分別打印這三個對象,返現(xiàn)都是
class org.springframework.validation.support.BindingAwareModelMap 類的實例翁授。
查看這個類的類圖:

image.png

發(fā)現(xiàn)Model残拐、Map都是BindingAwareModeMap的接口,ModelMap是它的父類瑞侮。這里使用的其實都是BindingAwareModeMap的實例的圆,只是用了不同方式來引用它。

image.png

請求參數(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í)行流程

單個攔截器的執(zhí)行流程
源碼解析

1)程序先執(zhí)?preHandle()?法戏售,如果該?法的返回值為true侨核,則程序會繼續(xù)向下執(zhí)?處理器中的? 法,否則將不再向下執(zhí)?灌灾。

2)在業(yè)務(wù)處理器(即控制器Controller類)處理完請求后搓译,會執(zhí)?postHandle()?法,然后會通過
DispatcherServlet向客戶端返回響應(yīng)锋喜。

3)在DispatcherServlet處理完請求后些己,才會執(zhí)?afterCompletion()?法。

多個攔截器執(zhí)行流程

執(zhí)行流程
image.png

示例代碼:

實現(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框架核心流程:


image.png

代碼倉庫:https://gitee.com/xdf-lg/custom-springmvc/tree/master

Spring MVC源碼深度剖析

前端控制器DispatcherServlet繼承結(jié)構(gòu)

image.png

DispatcherServlet實現(xiàn)了Servlet接口(是一個Servlet)戈擒,關(guān)鍵方法調(diào)用結(jié)構(gòu):


image.png
  • doGet/doPost被FrameworkServlet類重寫眶明。
  • 在FrameworkServlet的doGet/doPost方法中調(diào)用processRequest方法處理請求
  • 在processRequest方法中調(diào)用DispatcherServel中的doService
  • doService方法中調(diào)用doDispatch方法做請求分發(fā)。

重要時機點分析

1)handler方法執(zhí)行時機
打斷點觀察:


image.png

調(diào)用棧:


image.png

image.png

2)頁面渲染時機


image.png

image.png

SpringMVC處理請求的流程圖
image.png

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í)?鏈


image.png

核心步驟getHandlerAdapter方法剖析

遍歷各個HandlerAdapter,看哪個Adapter?持處理當(dāng)前Handler


image.png

核心步驟ha.handle方法剖析

image.png
image.png

image.png

image.png

image.png

核心步驟processDispatchResult方法剖析

render?法完成渲染


image.png

視圖解析器解析出View視圖對象


image.png

在解析出View視圖對象的過程中會判斷是否重定向坛增、是否轉(zhuǎn)發(fā)等获雕,不同的情況封裝的是不同的View實現(xiàn)


image.png

解析出View視圖對象的過程中,要將邏輯視圖名解析為物理視圖名


image.png

封裝View視圖對象之后收捣,調(diào)?了view對象的render?法
image.png

渲染數(shù)據(jù)


image.png

把modelMap中的數(shù)據(jù)暴露到request域中届案,這也是為什么后臺model.add之后在jsp中可以從請求域取出來的根本原因


image.png

將數(shù)據(jù)設(shè)置到請求域中
image.png

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(),該?法中初始化了九?組件

image.png

initStrategies?法

image.png

觀察其中的?個組件initHandlerMappings(context)
image.png

如果按照類型和按照固定id從ioc容器中找不到對應(yīng)組件挎春,則會按照默認(rèn)策略進(jìn)?注冊初始化看疙,默認(rèn)策略在DispatcherServlet.properties?件中配置

image.png

DispatcherServlet.properties
image.png

注意:多部件解析器的初始化必須按照id注冊對象(multipartResolver)
image.png

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>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市吗垮,隨后出現(xiàn)的幾起案子垛吗,更是在濱河造成了極大的恐慌,老刑警劉巖烁登,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件职烧,死亡現(xiàn)場離奇詭異,居然都是意外死亡防泵,警方通過查閱死者的電腦和手機蚀之,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捷泞,“玉大人足删,你說我怎么就攤上這事∷遥” “怎么了失受?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長咏瑟。 經(jīng)常有香客問我拂到,道長,這世上最難降的妖魔是什么码泞? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任兄旬,我火速辦了婚禮,結(jié)果婚禮上余寥,老公的妹妹穿的比我還像新娘领铐。我一直安慰自己,他們只是感情好宋舷,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布绪撵。 她就那樣靜靜地躺著,像睡著了一般祝蝠。 火紅的嫁衣襯著肌膚如雪音诈。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天绎狭,我揣著相機與錄音细溅,去河邊找鬼。 笑死坟岔,一個胖子當(dāng)著我的面吹牛谒兄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播社付,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼承疲,長吁一口氣:“原來是場噩夢啊……” “哼邻耕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起燕鸽,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤兄世,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后啊研,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體御滩,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年党远,在試婚紗的時候發(fā)現(xiàn)自己被綠了削解。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡沟娱,死狀恐怖氛驮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情济似,我是刑警寧澤矫废,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站砰蠢,受9級特大地震影響蓖扑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜台舱,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一律杠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柿赊,春花似錦俩功、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽熬甫。三九已至胰挑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間椿肩,已是汗流浹背瞻颂。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留郑象,地道東北人贡这。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像厂榛,于是被迫代替她去往敵國和親盖矫。 傳聞我的和親對象是個殘疾皇子丽惭,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355