1. 程式人生 > >SpringMVC 知識整理

SpringMVC 知識整理

bre 更強 post ble 註解 get factory type() gmv

SpringMVC架構設計

MVC是一種架構模式,它把業務的實現和展示相分離。

技術分享圖片

SpringMVC與struts2的區別

  1. Struts2是類級別的攔截, 一個類對應一個request上下文,SpringMVC是方法級別的攔截,一個方法對應一個request上下文,而方法同時又跟一個url對應,所以說從架構本身上SpringMVC就容易實現restful url,而struts2的架構實現起來要費勁,因為Struts2中Action的一個方法可以對應一個url,而其類屬性卻被所有方法共享,這也就無法用註解或其他方式標識其所屬方法了。
  2. springmvc可以進行單例開發,並且建議使用單例開發,struts2通過類的成員變量接收參數,無法使用單例,只能使用多例。
  3. 由於Struts2需要針對每個request進行封裝,把request,session等servlet生命周期的變量封裝成一個一個Map,供給每個Action使用,並保證線程安全,所以在原則上,是比較耗費內存的。
  4. 攔截器實現機制上,Struts2有以自己的interceptor機制,SpringMVC用的是獨立的AOP方式,這樣導致Struts2的配置文件量還是比SpringMVC大。
  5. servlet和filter的區別了。
  6. SpringMVC集成了Ajax,使用非常方便,只需一個註解@ResponseBody就可以實現,然後直接返回響應文本即可,而Struts2攔截器集成了Ajax,在Action中處理時一般必須安裝插件或者自己寫代碼集成進去,使用起來也相對不方便。
  7. SpringMVC驗證支持JSR303,處理起來相對更加靈活方便,而Struts2驗證比較繁瑣,感覺太煩亂。
  8. spring MVC和Spring是無縫的。從這個項目的管理和安全上也比Struts2高(當然Struts2也可以通過不同的目錄結構和相關配置做到SpringMVC一樣的效果,但是需要xml配置的地方不少)。
  9. 設計思想上,Struts2更加符合OOP的編程思想, SpringMVC就比較謹慎,在servlet上擴展。
  10. SpringMVC開發效率和性能高於Struts2。
  11. SpringMVC可以認為已經100%零配置。

SpringAOP整合SpringMVC

spring容器不註冊controller層組件,controller組件由springMVC容器單獨註冊。

// applicationContext.xml
<context:component-scan base-package="com.shuyun.channel">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.RestController" />
    <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" />
</context:component-scan>

// springmvc-servlet.xml
<context:component-scan base-package="com.shuyun.channel" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.RestController" />
    <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" />
</context:component-scan>

註意

關於<context:annotation-config /><context:component-scan />:

component-scan會自動加上annotation-config功能,有了component-scan不用再寫annotation-config了。參見spring官方reference

配置層次化Spring容器

參考 配置層次化Spring容器

我們知道,在開發基於spring的Web應用時,通常使用兩個IoC容器,一個是由DispatchServlet初始化的WebApplicationContext,一個是由ContextLoaderListener初始化的ApplicationContext。對於Spring容器,Spring的官方參考手冊詳細地講解了依賴註入的配置方式,對於容器本身的配置和多個容器之間的關系卻不曾提及。於是,很多人以為在一個應用中只有一個全局的Spring容器,或者不了解MVC使用的WebApplicationContext和根ApplicationContext的關系。

通過查看Spring的源碼和API,發現Spring可以配置為多個容器,容器之間可以配置為層級關系,一個根容器可以配置許多子容器,子容器還可以配置子容器,從而形成一個單根的層次化結構。對於該容器結構中的每個容器,在其中查找特定的bean時,會首先在本容器內查找,如果找到對應的bean,就返回該bean;如果沒有找到,就會從直接父容器中去查找,依此類推,直到根容器為止。

從上面的示例中可以看到,從子容器中可以取得父容器中配置的bean,而父容器中不能夠取得子容器中的bean。

在Spring MVC中WebApplicationContext配置為根ApplicationContext的子容器,所以,MVC使用的容器中能夠取得根ApplicationContext中的bean。在一個web程序中可以配置多個DispatchSerlvet,每個Servlet對應一個容器,所有這些容器都作為根容器的子容器,這樣,我們就可以把通用的bean放在根容器中,而針對特定DispatchServlet的bean,可以放在各自的子容器中。

文件上傳

  • Controller的方法中需要接受一個Spring MVC提供的MultipartFile接口作為方法的參數,該參數接收前臺表單type為file提交的對象,使用@RequestParam註解指明參數,那麽Spring就會自動將表單傳遞過來的對象的類型轉換為MultipartFile類型。

  • MultipartFile中提供了getName()、getSize()、getByte()
    getContentType()、isEmpty()、getInputStream()、getOriginalFilename()方法來訪問文件。getOriginalFilename()方法是獲取最初文件名,即本地文件名。
  • 在Controller方法中使用FileUtils下的copyInputStreamToFile(InputStream in,File file)方法來完成文件的拷貝.第一個參數是文件拷貝源的輸入流,直接使用MultipartFile下的getInputStream()方法.第二個參數是文件將要保存的位置.

@RequestMapping("/doUpload")
public Result doUpload(@RequestParam("file") MultipartFile file) throws IOException {
    if (!file.isEmpty()) {
        FileUtils.copyInputStreamToFile(file.getInputStream(), new File("E://", file.getOriginalFilename()));
    }
    return ResultUtil.SUCCESS_RESULT;
}

Jackson

  • How to enable pretty print JSON output (Jackson)
  • Jackson 2 – Convert Java Object to / from JSON
  • SpringMVC關於json、xml自動轉換的原理研究(附帶源碼分析)

SpringMVC攔截器

攔截器好比你要去取經,那麽,你就必須經過九九八十一關,主要用來解決請求的共性問題,如:亂碼問題、權限驗證問題等

實現SpringMVC攔截器的三個步驟

  1. 創建一個實現HandlerInterceptor接口,並實現接口的方法的類
  2. 將創建的攔截器註冊到SpringMVC的配置文件中實現註冊

    <mvc:interceptors>
    <bean class="路徑下的類">
    </mvc:interceptors>
  3. 配置攔截器的攔截規則:

    <mvc:interceptors>
       <mvc:interceptor>
              <mvc:mapping path="攔截的action">
              <bean class="路徑下的類">
       </mvc:interceptor>
    </mvc:interceptors>

攔截器中三個方法的介紹:

  1. preHandle()方法是否將當前請求攔截下來。(返回true請求繼續運行,返回false請求終止(包括action層也會終止),Object arg代表被攔截的目標對象。)
  2. postHandle()方法的ModelAndView對象可以改變發往的視圖或修改發往視圖的信息。
  3. afterCompletion()方法表示視圖顯示之後在執行該方法。(一般用於資源的銷毀)

攔截器和過濾器

共同:他們都是用來檢查程序的共同場景,只不過攔截器是面向Action的,過濾器是面向整個web應用的。

  1. 解決權限驗證問題
  2. 解決亂碼問題

攔截器和過濾器的區別:

  1. 攔截器是基於java的反射機制的,而過濾器是基於函數回調。
  2. 攔截器不依賴與servlet容器,過濾器依賴與servlet容器。
  3. 攔截器只能對action請求起作用,而過濾器則可以對幾乎所有的請求起作用。
  4. 攔截器可以訪問action上下文、值棧 裏的對象,而過濾器不能訪問。
  5. 在action的生命周期中,攔截器可以多次被調用,而過濾器只能在容器初始化時被調用一次。
  6. 攔截器可以獲取IOC容器中的各個bean,而過濾器就不行,這點很重要,在攔截器裏註入一個service,可以調用業務邏輯

攔截器方法的作用順序

技術分享圖片

攔截器的其它實現方式:

  1. 攔截器的類還可以通過實現WebRequestInterceptor(HandlerInterceptor)接口來編寫。
  2. 向SpringMVC框架註冊的寫法不變。
  3. 弊端:preHandler方法沒有返回值,不能終止請求。

Ps:建議使用功能更強大的實現方式,實現HandlerInterceptor接口。

Spring4增加功能

Spring4主要在Web服務方面有下面兩個方面提升:

  1. 控制器使用@ResponseBody@RestController
  2. 異步調用。

Spring整合Struts2

Spring默認是單例,Struts2默認是多實例的。

如果是spring配置文件中的 bean的名字的話就是spring創建,那麽單實例還是多實例就由spring的action Bean中的業務邏輯控制器類是否配置為scope=”prototype”,有就是多實例的,沒有就是單實例的,順序是先從spring中找,找不到再從struts配置文件中找。

  1. 對於無Spring插件(Struts2-spring-plugin-XXX.jar)的整合方式,需要在spring的action Bean中加業務邏輯控制器類配scope="prototype"。

    <bean id="user" class="modle.User" scope="prototype"/>
  2. 對於有Spring插件(Struts2-spring-plugin-XXX.jar)的整合方式:反編譯StrutsSpringObjectFactory以及相關的代碼才發現,如果在struts action的配置文件 <action name=".." class=".."/> 中class寫的如果是完整的包名和類名的話就是struts創建action對象,也就是多實例的;

參考文檔

  1. 史上最全最強SpringMVC詳細示例實戰教程
  2. Spring MVC快速入門
  3. Web MVC framework - Part VI. The Web
  4. Spring 註解學習手劄(七) 補遺——@ResponseBody,@RequestBody,@PathVariable
  5. SpringMVC4.1之Controller層最佳實踐

SpringMVC 知識整理