天天看點

SpringMVC 知識整理

SpringMVC架構設計

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

SpringMVC 知識整理

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,可以調用業務邏輯。

攔截器方法的作用順序

SpringMVC 知識整理

攔截器的其它實作方式:

  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層最佳實踐