spring-springmvc code-based

idea設置maven在下載依賴的同時把對應的源碼下載過來。圖0:
  • 1

這里寫圖片描述

主要實現零配置來完成springMVC環境搭建,當然現在有了springBoot也是零配置,但是很多同仁都是從spring3.x中的springMVC直接過渡到springBoot的,spring3.x的MVC大部分都是通過xml配置文件來完成(xml配置文件這種方式以下簡稱schema-based),其實在SpringBoot之前springMVC也是可以實現零配置文件(通過javaConfig和annotation實現0配置,以下簡稱code-based)。①并且在spring的官方文檔里面的QUICK START里面的例子也是基于code-based的。后面會給出文檔的附圖。本文的重點在于通過spring官方文檔來學習spring技術,而不去討論schema-based與code-based孰優孰劣。
spring的兩個重要的術語:

  1)、如果你的程序主要是通過配置文件(xml)來構建了,spring稱這種編碼風格為Schema-based。
  • 1

這個可以在官方文檔來解釋。②如spring對于AOP也提供兩種風格實現,即Schema-based和@AspectJ-based(也就是xm方法l和Aspectj注解的方法)

 2)、如果你的代碼是基于spring javaConfig來實現的spring稱這種代碼風格為code-based。
  • 1

搞清這個對閱讀本文以及閱讀spring文檔都很重要。spring官網

圖1:
這里寫圖片描述

spring官網首頁(截圖不全)。首頁介紹了spring公司的主要項目,其中有幾個我們耳熟能詳的,譬如springBoot,springData,springCloud等等。可以點開每個項目看看基本的介紹,比如我們點開上面的spring framework項目。可以看到 圖2:

這里寫圖片描述

這是spring Framework項目的主頁,上面有個Introduction,就是產品介紹。大概意思就是spring framework是一個綜合的程序,可以做企業級開發,是輕量級的等等。在Introduction上面有個QUICK START的按鈕,意思是快速開始spring Framework的技術開發,點擊后可以看到一個簡單的應用。圖3:

這里寫圖片描述

首先spring提供兩種方法來開發spring Framework項目

①第一種是maven
②第二種是Gradle
上圖紅線標記地方可以切換,看不同方法的代碼
  • 1
  • 2
  • 3

默認是maven,使用maven開發spring framework入門項目只需要通過maven去依賴spring-context(spring最核心的文件)。繼而就可以使用基本的spring Framework技術了。從官方的這個quick start例子(紅箭頭標記的地方)可以看出spring還是推薦我們使用code-based這種編碼風格的(解釋了文章開頭用①那段文字)。spring的code-based這種編碼風格是基于spring javaConfig(springJavaConfig 如果沒記錯應該spring2.5以后的技術,這里不做討論)。

這個QUICK START例子很簡單,我們只需要看看,看看spring怎么編碼的就夠了。再回到這個頁面的上面,可以看到我們所謂的spring framework到底包含了那些技術呢?就比如我們常常說J2EE,那么所謂的J2EE包含了那些技術呢?J2EE只是一個標準,包含了XML,JSP,SERVLET,JDBC等等等等技術,那么這里的spring framework只是一個項目,他也包含了很多技術。這些技術在文檔里面已經說得非常清楚了。(在我從業的生涯當中也面試過不少程序員,很多初入行業的一問及spring便說:spring核心就是IOC和AOP。甚至很多程序員認為spring就只是AOP和IOC,這種認知是大錯特錯的),通過一張圖來說明。
這里寫圖片描述

紅色箭頭地方說明了spring framework的核心構成:

1、Dependency Injection
  • 1

簡稱DI,依賴注入,很多人說這個就是IOC,嚴格來說是錯的,官方叫做DI,那么DI和IOC的是什么關系呢?ICO叫做控制反轉。是一種編程思想,也即是一種需要達到的目標(和spring無關,那么spring framework實現這種編程思想或者實現這種目標的技術手段叫做DI,也就是依賴注入。譬如小明說要發財,那么怎么實現發財呢?賣腎就能實現,這里的IOC相當于發財,賣腎相當于DI,小明相當于springframework)。

2、Aspect Oriented Programming.........
  • 1

(AOP技術,面向切面編程技術,AOP也是一種思想,spring framework實現AOP是基于AspectJ的技術。記得在spring早先他自己有一套AOP技術,但是貌似比較雞肋就放棄了,引入了AspectJ技術來實現,關于AOP的一些東西,后續的文章再討論)。

3、springMVC(本文要討論的重點,下面會詳細討論)。4、我們可以看到還有什么JDBC,JPA,JMS等等
  • 1
  • 2
  • 3

最后Much more表示還有更多。so,當以后有人問我們對spring的理解的時候千萬別再說就是AOP和IOC,spring這家公司開發了很多項目,包括了springBoot,spring Framewok,spring Cloud……..,而IOC和AOP只是spring framewrok里面的兩個核心技術。當然如果想學習更多的spring framework技術僅僅看這個quick start例子肯定不行,顧名思義,所謂quick start只是快速開始。如果需要查閱更多的spring framework文檔——顯然spring作為業界標桿,文檔毋庸置疑肯定提供的很全面。文檔——-圖5:
這里寫圖片描述

點擊紅色箭頭可以查閱詳細的spring framework文檔(5.x和4.x有一點點區別),5.x點進去之后會有一個小分類,小分類里面提供各種技術的文檔鏈接。4.x點進去之后就是所有技術的文檔,博主更習慣4.x的文檔。以下是5.x的文檔—圖6:

這里寫圖片描述

5.x點進來之后會有一個小分類,比如上面的CORE一欄就包含了IOC,validation和AOP的文檔,假設你想查閱spring MVC的文檔可以點擊Web Servlet那個鏈接
這里先點擊Core,驗證文章開頭②處粗斜體所述。圖7:

這里寫圖片描述

可以從左邊的導航中找到AOP相關的文檔(紅色箭頭),如果想系統的學習AOP可以查閱這個文檔,非常詳細。

spring為AOP提供了兩種代碼風格來實現,Schema-based---也就是XML方式,以及@AsepectJ----也就是基于ApsectJ的注解來實現
  • 1

當然本文主要討論SpringMVC,所以需要查閱springMVC的文檔,點擊圖6當中的Web Servlet鏈接,進入到spring Web文檔頁面。圖8

這里寫圖片描述

進入SpringMVC的文檔首頁,紅色箭頭的Introduction(介紹)簡單說明了springMVC技術基本信息。大概意思:

springMVC 依賴servlet API(說白了就是開發springMVC必須下載servlet-api.jar)
并且springMVC一開始就包含在spring framework體系里面。
springMVC的全稱叫做Spring Web MVC。這個名字是來自其中一個叫做spring-webmvc
的模塊(pom里面經常配置的一個依賴),但是常見的名字叫做spring MVC。。。。。。。
  • 1
  • 2
  • 3
  • 4

繼而便開始介紹springMVC里面非常重要的一個類DispatcherServlet。圖9:

這里寫圖片描述

上圖首先簡單介紹了一下這個類,繼而給出了這個類在springMVC項目當中的配置,一共有兩種方法,也就是文章開頭說的基于code-based(javaConfig零配置,上圖紅色標記的)和schema-based(xml配置,黑色標記)。在springMVC的文檔里面幾乎給大部分的配置都列出了這兩種風格的代碼(有一些只有一種),但是所有的都是先介紹code-based。不知道可不可以理解為spring推薦我們使用code-based的coding風格,姑且這么認為吧。上圖那種基于schema-based風格的配置是現在大部分的springMVC的都在用的。

再次說明一下,這兩種風格無高下之分,更無優劣之別,就算有也不是本文討論的。本文主要來討論基于code-based的風格來實現springMVC。
  • 1

這樣能夠更好的去理解、學習springBoot(直接從schema-based跳到springBoot有點不好,但是現在網上對于springMVC code-based的資料比較少)。

重點是讓初學者學會看spring文檔,可以快速學習一些spring的技術。根據上圖我們可以建立一個項目來做實驗(本文使用idea來coding),pom文件里面添加相應的依賴。圖10:
這里寫圖片描述

建立項目復制官網的代碼:寫一個類來實現WebApplicationInitializer 。圖11:

這里寫圖片描述

附圖12(繼上圖,代碼過長一次截圖不完):

這里寫圖片描述

MyWebApplicationInitializer這個類(以下簡稱Initializer)的主要作用就是來代替schema-based風格中的web.xml,熟悉spring web開發的人肯定知道web.xml主要做兩個事情。

①配置一個listener來load spring的配置文件(就是通常取名叫做applicationContext.xml)
根據配置文件里面的信息來初始化spring的上下文環境。②、配置一個servlet(DispatcherServlet)來load springMVC的配置文件。并且根據springMVC的配置文件信息來完成對springWEB的環境初始化。
  • 1
  • 2
  • 3
  • 4

觀察Initializer這個類的代碼—-它其實是通過spring javaConfig的技術同樣來完成了上述的兩件事情。具體代碼可以下載文末提供的demo自行查看。

其實對于這個類,spring官網提供兩種寫法,第一種便是圖11(也即是下圖粉紅色圈圈標記),另外一種寫法(圖中黑色箭頭)附圖:N

這里寫圖片描述

圖N里面粉紅色標記的代碼也就是本例使用的,跟著下面這段文字spring解釋了還有另一種寫法,除了這種基于ServletContext API的寫法之外還有一種便是去繼承

(紅色箭頭標記)AbstractAnnotationConfigDispatcherServletInitializer 這個抽象類。點擊黑色箭頭標記的連接,spring給出了第二種寫法的相應代碼,

并且做了一段很長的說明,還把類之間的關系圖給出來了。可以自行翻譯(關于這種方法的寫法本文沒有實現,有興趣的可以和我討論哈)。N1(圖有點長兩次截):

這里寫圖片描述

續上圖N2

這里寫圖片描述

再次說明這種方式本文不做討論.回到圖12的內容。其中的AppConfig.class相當于schame-based里面的spring和SpringMVC的配置文件。

簡單說就是以前用xml來配置spring mvc的一些信息,現在用這個類AppConfig來替代那兩個文件,這種技術就是開頭我們說的spring javaConfig技術。他的主要代碼。圖13:

這里寫圖片描述

上文提到這個類Appconfig就相當于schema-based里面的springMVC的配置文件和spring核心的配置文件,因為他完全代替了這兩個配置文件,故而這個類的代碼才是本文討論的重點。

如果熟悉`spring javaConfig`技術的話就會知道這個類可以任意命名。
而且他可以是沒有任何依賴的(官網和本文中這個類是實現了一個`WebMvcConfigurer`接口)。
  • 1
  • 2

為什么這里我們會去實現一個接口呢?這是spring為了方便程序員開發,其實如果熟悉spring javaConfig技術完全可以不必要實現這個接口。

我看過很關于springBoot的文章就是沒有實現這個接口,自行寫的代碼。這里附圖一張我在百度找的一篇文章(討論springBoot實現SpringMVC視圖技術的文章,

他的`Appconfig`類就沒有去實現任何接口) 圖:14
  • 1

這里寫圖片描述

圖14中就是通過code-based的方法配置了一個視圖解析器,相當于schema-based中的下圖代碼。圖15:
這里寫圖片描述

這是只是為了說明那個接口其實不必要去實現,可以完全自行寫spring javaConfig,但是spring已經提供一個方便的接口那么最好還是實現一下。
implements這個接口后有18個方法需要去實現,這個18個方法可以完成絕大部分的環境配置。

標記①:如果有一些特殊的環境是這18個接口無法實現的,
那么你可以就在`Appcinfig`類當中自行通過`spring JavaConfig`的技術去實現
本文中就有一個對象是自行實現的,一個關于上傳的配置,后面會有提及。
  • 1
  • 2
  • 3

那么這18個方法的作用和意義本文不會全部來討論,只會討論到一些在項目中會涉及到的和一些重要的方法,下一篇博客打算再來討論。誠如上文所說現在這個Appconfig類就是為了替代spring的配置文件,那么怎么來替代呢?我們可以依次來分析。對于spring環境而言

?掃描類,然后通過DI來完成注IOC。
  • 1

在schema-based中我們一般會在xml中寫一個配置來完成<context:component-scan base-package="org.example.web"/>。那么在code-based的實現spring 官網已經給出非常詳細的代碼 圖16:

這里寫圖片描述

在spring mvc的文檔1.4節里面———-黑色箭頭,spring提到:開啟一個自動檢測、搜索所有Controller bean,你需要在你的java config添加一個搜索組件。

繼而給出了兩種方案,分別是code-based(紅色箭頭)和schema-based(藍色箭頭)。本文的實驗代碼便是參考官網的這段code-based。

如此便完成了?------自動掃描spring bean
  • 1

?、開啟對springMVC的支持,在springMVC的文檔的1.11中有關于springMVC的所有配置說明 圖17:

這里寫圖片描述

同樣是兩種方案,首先是code-based(藍色箭頭)

spring官網重要的說明:in javaconfig use the @EnableWebMvc annotaion
  • 1

繼而是schame-based(黑色箭頭)

spring官網重要的說明:in xml use the<mvc:annotaion-driven> element 
  • 1

對于熟悉schame-based的程序員來說黑色箭頭處的代碼應該已經非常親切了。

如此便完成了第?步,開啟springMVC的支持這里稍微做點說明所謂開啟springMVC的支持意思讓程序員能夠使用springMVC技術
比如springMVC中的視圖轉換、視圖檢測等等,最直觀的:博主自己測試過,比如不加@EnableWebMvc這個annotation
程序可以正常啟動并且能夠訪問,但是當controller中的方法返回一個XXX的字符串時候,程序員是無法跳轉到XXX.jsp.
即使程序員配置了視圖解析器也不行,但是加上@EnableWebMvc之后便可以。
  • 1
  • 2
  • 3
  • 4

?、配置springmvc的視圖解析器。一般javaweb項目里面使用都是jsp,所以我們首先配置一個jsp的視圖解析器。查閱springmvc的文檔的第1.12節—View Technologies

圖N3

這里寫圖片描述

查閱1.12節—View Technologies(箭頭1),展開后其實springmvc提供了很多視圖技術,比如圖中的Freemarkertilesjsp等等。

目前只需要配置對jsp的視圖解析。
so 點擊箭頭2,繼而點擊View Resolvers(視圖解析),看到spring給出了schema-based風格的jsp解析器配置代碼。但是spring沒有給出code-based的代碼,其實spring的文檔里面也有提到,只是在這里沒有。仔細看這段xml配置,無非就是聲明、注冊了一個bean而已,如果換成code-based無非就是利用spring javaConfig的方法去聲明、注冊一個bean。這對熟悉spring javaconfig的人來說很簡單。文章中圖14里面的代碼(網上我找的)就是通過spring javaconfig的方法,在Appconfig這個類中聲明、注冊了一個InternalResourceViewResolver的對象

注意,圖14的代碼是沒有實現接口的
  • 1

圖14的代碼的效果相當于此處圖N3紅色箭頭xml代碼的效果。可是現在的程序中AppConfig類實現了一個接口。其實spring提供的這個接口當中有一個方法就是專門來注冊視圖解析器的。查閱這個類的源碼注釋有一個方法 configureViewResolvers
這個方法就是使用spring javaconfig 技術專門來實現對視圖解析器的聲明、注冊用的。

關于這個方法的解釋和說明(很重要)本文提供的代碼有詳細注釋說明。可以下載代碼查閱demo會在文章末尾提供的地址
  • 1

圖18:

這里寫圖片描述

上圖代碼其實和圖14的效果是一樣的,

再次說明,圖14沒有實現接口
  • 1

上圖的代碼是實現了WebMvcConfigurer這個接口,通過接口中的一個方法來完成對象的聲明、注冊。查閱registry.jsp方法的源碼,可以看到spring的代碼其實和圖14的幾乎一樣。

如此我們便完成了第?步,對spring視圖解析器的注冊
  • 1

圖19(spring的源碼,可以對比一下圖14百度上找的代碼):

這里寫圖片描述

對于一個springmvc的項目而言,完成以上三步就完成了基本的配置,程序員可以定義controller,并且返回字符串,會跳轉到對應的頁面。于是便把項目發布tomcat跑起來看看結果。

本文的demo是通過maven的tomcat 插件來配置的,博主也推薦使用這種maven plugs的方法來開發web項目
  • 1

至此項目的結構圖如下。圖20

這里寫圖片描述

程序中定義了一個IndexController 其中有一個index方法,最后返回字符串”index”,并且web.xml是沒有任何代碼的。講道理發布、啟動tomcat后,訪問index.xhtml程序會跳轉到index.jsp。圖21:

這里寫圖片描述

此處的index.xhtml是一個request請求,而非一個文件。博主之前開發程序便習慣把請求后綴取名.xhtml
  • 1

至此便完成了一個基于code-based的springmvc程序,就是所謂的零配置。其實和springBoot很相像了。通過這種查閱官方文檔的方式去學習spring我覺得非常好,這樣就會加深對spring體系的認知。當然我們僅僅是完成了對jsp視圖的解析,通常項目當中還會對json處理。

當方法加了@ResponseBody后消息會自動轉換成JSON格式響應給客戶端。譬如在controller中定義了一個返回Map的方法。
如果給方法加上@ResponseBody,繼而請求該方法,最后服務器會響應一個段JSON,就是由spring 轉換的,不需要程序員寫代碼去轉。
  • 1
  • 2

springmvc的官網給出了利用jackson技術來處理JSONXML。圖22,分兩次截圖

這里寫圖片描述

繼上圖

這里寫圖片描述

如果使用jackson只需要加上上圖中的配置,繼而依賴好jackson的幾個jar包便能處理JSON了。可是在國內一般都是用馬云爸爸開發的fastJson居多,所以本文就來討論在springmvc code-based中如何使用fastJson來處理JSON

1、首先在pom當中添加fastjson的依賴
2、查閱官方文檔,消息轉換(Message Converters,姑且這么翻譯吧)這一節。圖23:
  • 1
  • 2

這里寫圖片描述

上圖紅色標記區的信息已經說的非常詳細了———如果我們需要使用自定義的轉換器,那么必須去覆蓋Appconfig當中的configureMessageConverters方法,并且以jackson為例,給出了重寫configureMessageConverters方法的代碼,從上圖可以看出,spring官網代碼的Appconfig類也是實現了WebMvcConfigurer接口的,和本文的例子一樣。我們只需要在Appcnfig這個類中找到這個方法,繼而重寫然后定義、注冊fastJson的轉換器就可以了。上圖的jackson的轉換器叫做MappingJackson2XmlHttpMessageConverter那么如果我們重寫這個方法,fastJson的轉換器叫什么名字呢?其實比較簡單。

文檔有一段非常重要的話Customization of HttpMessageConverter can be achieved in Java config by overriding
  • 1

這段描述中可以猜spring要求自定義的轉換器必去實現HttpMessageConverter這個接口。且事實就是如此。可以找到這個接口,在org.springframework.http.converter包下面就定義了這個接口,程序員也可以通過MappingJackson2XmlHttpMessageConverter這個類去找。
按住ctrl點擊一路找過去就能找到HttpMessageConverter
找到這個接口后在idea下面打開這個類,繼而選中接口名字。

idea中按ctrl+alt+b,可以查看該接口的所有實現類圖24:
  • 1

這里寫圖片描述

只要fastJson的依賴,講道fastjson如果想springmvc中處理方法放JSON那么fastJson肯定提供了一個符合spring`標準的消息轉換類

上文提到spring的要去實現HttpMessageConvter接口
  • 1

這就是標準的魅力,一流公司賣標準,二流公司賣服務,三流公司賣產),像spring這種準一流公司,開發標準可謂輕車熟路,馬云爸爸在電商界呼風喚雨,可是在code方面只能去實現spring的標準了,這樣也好,程序員倒是很歡喜,試想如果沒有這個標準,那么程序員在spring項目中用不同公司提供的技術去實json支持那么API完全就不會不同。。。。。。。。言歸正常。

圖24用藍色標記的2箭頭可以看到有一個叫FastJsonHttpMessageConverter的類,顯然就是馬云爸爸開發的,于是程序就變得簡單了,我們只需要把圖23中jackson的轉換器改成fastJson的轉換器便可。

注意的是圖23中jackson處理的不僅僅是JSON。
  • 1

還對xmlbihernate做了處理,故而代碼有點復雜(這個文檔上有說明的,我想不到為什么還要對hibernate做處理,講道理hibernate現在已經不怎么用了),本例中只需對JSON進行處理,代碼相對就簡單的多。圖25

這里寫圖片描述

誠然fastJson也有也有很多配置,比如對于key是否加雙引號啊等等配置,不在本文討論的,可以查閱fastJson的文檔。上圖的代碼注釋里面就有一些fastJson的基本配置,其實這個轉換器的默認配置已經可以滿足基本開發需求了,比如字符集的處理,查閱源碼可以看到他有默認的字符集設置UTF-8。圖26

這里寫圖片描述

有小插曲,博主在查閱fastJson的源碼過程當中發覺一個特別有趣的事,附圖:N4
  • 1

這里寫圖片描述

天地良心,這是阿里巴巴的程注釋
  • 1

至此code-basedsspringmvc項目對 fastjson支持已經配置好,可以啟動tomcat檢查一下是否能夠正常處理json圖27:

這里寫圖片描述

index.jsp頁面用jQuery去發了一個ajax請求,可以看到在IndexControllerjson.xhtml是一個加了@ResponseBody的方法,并且返回了一個map

注意map當中是有中文的
  • 1

最后在客戶端的JavaScriptsuccess方法中打印了服務器響應的消息。講道理會正常返回JSON數據給瀏覽器。圖28:

這里寫圖片描述

可以看到中文也是可以正常顯示的,至此我們通過code-based的方式完成了對jspjson的處理。當然一般項目里面還會涉及到上傳,由于篇幅原因,本文接下來只會對上傳進行介紹,還有他的比如類型轉換,驗證等等下一篇博客再來介紹。關于springmvc的上傳,文檔中已經說得非常非常清楚了。查閱spring的文檔,其中有一節就是專門講文件處理。圖29:

這里寫圖片描述

這段文字的大概意思是spring內置Mulitipart Request技術就包含了文件上傳的處理,其中有一個可插拔的對象叫MultipartResolver可以支持文件上傳請求。但是這個類只是一個接口,說白了就是一個標準,實現這個標準有兩種方法,第一種(箭頭標記‘第一種’)commons-fileupload這也是現在普遍用的方法。第二種(箭頭標記‘第二種’)便是基于servlet3.0

    對于servlet3.0,如果我沒記錯tomcat7以上就是servlet3.0了。  
  • 1

對于這兩種方法spring文檔中都給了非常詳細的說明。圖30:

這里寫圖片描述

Ⅰ、commns-fileuplod實現,需要把相應的依賴寫到pom中,然后在聲明、注冊一個做叫CommonsMultipartResolver(1藍色箭頭)的對象。

并且名字一定叫做multipartResolver(2藍色箭頭)
  • 1

這樣就完成了對commons-fileupload的配置,意思是一個上傳文件的請求就會由commons-fileupload的技術來處理。

這里說去注冊一個CommonsMultipartResolver 對像,上文說過一個對象的聲明、注冊spring有兩種方法`schema-based`和`code-based`
  • 1

本文討論的是code-based,文章下面有通過code-based來注冊、聲明CommonsMultipartResolver的詳細說明

Ⅱ、servlet3.0的方式就比較復雜,文檔的大概意思?需要我們在web.xml中的DisptcherServlet的節點中配置一個Multipart-config的節點。?或者去配置一個叫做MultipartConfigElement類的對象,并且把這個對象給Servlet Registration

這里?有點繞,下面會詳細說明
  • 1

?再或者你自己定義一個servlet在定義的servlet類上面加上@MultipartConfig

也就是有三個或者。。。spring真的牛逼呀,三個呀!!
  • 1

但是ⅠCommons-fleUpload和Ⅱservlet3.0最大的不同

注冊處理文轉件上傳的轉換器不同
Ⅰ、需要注冊CommonsMultipartRver
Ⅱ、需要StandardServletMultipartResolveresolver          
但是名字都需要一樣叫做multipartRelover(2藍色箭頭)為什么需要叫這個名字,下次再討論
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

首先討論Ⅰcommons-fileupload上文所述,首先需要去注冊、聲明一個CommonsMultipartResolver 對象,如果是用schema-based的方式就很簡單,直接在springmvc的配置文件中聲明一個bean。

<bean id="xxx" class="xxx">對于`code-based`方式,spring的文檔中并未說明,其實去查閱`Appconfig`類中的那18個方法發現也沒有一個方法提供了對該類`CommonsMultipartResolver` 的注冊。回到上文說的。如果接口中提供的方法不能滿足程序開發需求了,則需要程序員自行通過spring javaConfig的技術去實現。
  • 1
  • 2
  • 3
  • 4
  • 5

對于這個類CommonsMultipartResolver 的注冊,使用sping javaconfig技術來實現注冊還是比較簡單,查閱源碼:

該類有一個不帶參數的構造方法,即可以直接new圖CommonsMultipartResolver 源碼。圖31:
  • 1

這里寫圖片描述

既然該類提供了無參的構造方法那么程序員只需要在Appconfig類當中通過spring javaConfig技術簡單注冊一下便可,代碼比較簡單。圖(本文demo中的代碼)32:

這里寫圖片描述

如此便完成了CommonsMultipartResolver的注冊,關于上傳文件的其他設置,比如文件大小的限制的等等如何設置呢?schema-based的方式是通過xml配置的。那么code-based的設置也比較簡單的,查閱CommonsMultipartResolver的源碼可以看到他提供各種API來設置這些信息,其中就有關于文件大小限制的設置。附圖33:

這里寫圖片描述

查閱CommonsMultipartResolver源碼,該類繼承了一個CommonsFileUplaodSupport的父類,查看這個父類。圖34:

這里寫圖片描述

這個父類里面提供了很多上傳文件的設置,setMaxUploadSIze。。。。顧名思義、設置文件最大上限。所以我們可以在實例化CommonsMultipartResolver之后調用這些方法去做相應的設置。圖35:

這里寫圖片描述

可以根據具體的應用去設置具體的值,本文不再做討論了。
  • 1

至此,關于springmvc第Ⅰ種方案處理文件上傳請求的對象CommonsMultipartResolver的注冊已經完成了。那么剩下我們的controller中的代碼如何寫呢?查閱springmvc文檔1.4.3節中可以看到對應代碼。圖36:

這里寫圖片描述

上述代碼表示,我們HTML頁面需要提供一個上傳的表單,繼而controller中提供一個方法。文檔上面有一段話非常的精髓。

The next step is to create a controller that handles the file upload. This controller is very similar to a normal annotated @Controller, except that we use MultipartHttpServletRequest or MultipartFile in the method parameters:
  • 1

大概的意思就是-創建一個處理文件上傳的controller。這個controller和一個正常加了@Controllercontroller沒很大區別,無非就是這個處理文件上傳的controller需要使用MultipartHttpServletRequestMultipartFile作為方法參數而已。

是把文件當成一個普通參數,繼而加上指定的注解便可以了。同時也體現了spring性感到骨子里的特點:

無侵入性,不破壞封裝,輕量級,低耦合等等....
  • 1

我記得struts2的文件上傳需要程序員定義幾個全局變量,并且對于這些全局變量要有規定的方法與之對應,這樣程序員的代碼便有了依賴了。比起spring的這種處理,spring還是做得好多了)。。。。言歸正傳,寫完這些之后啟動tomcat測試一下文件上傳。圖37:

這里寫圖片描述

至此已經徹底完成了springmvc處理jsp,處理JSON,處理文件,處理正常參數。當然文件上傳是基于ⅠCommons-fileUpload的這種方式。記得上文提到還有第Ⅱ種方式來。

基于servlet3.0
  • 1

Ⅱ、基于Servlet3.0來處理文件上傳,首先給出一個schema-based的代碼

在web.xml中配置對應擋標簽  圖38:
  • 1

這里寫圖片描述

這種配置其實和spring沒有關系,意思就是就算開發一個servlet+jsp項目也可以用這個配置。然而這種方法需要去配置xml與spring的code-based不符,故而本文不再做討論。

     直接用code-base方式實現springmvc基于servlet3.0的文件上傳的程序
  • 1

上文說到實現spring上傳的方法有3個或者,第?個或者就是如上圖配置(不是零配置),第?和?種其實都差不多。本文重點在第?個。但是第?個或者spring只是簡單的說明了一下,并沒有詳細的代碼,需要我們自己去查閱spring的源碼。
1、MultipartConfigElement查閱這代碼的源碼發現他有三個構造方法

這里寫圖片描述
仔細查閱源碼,其實三個構造方法無非就是對上傳信息的設置,比如第一個構造方法要求我們提供文件保存的位置,第二個構造方法的四個參數spring源碼的注釋寫的非常清楚了,這里稍微解釋一下。圖:

這里寫圖片描述

具體用哪種方法程序員自己考慮,本文例子代碼使用的第一個構造方法,僅僅傳入了一個文件保存路徑。

 如果這個類被實例化出來了,跟著要怎么辦呢?直觀的看spring文檔對于這個類的說明比較模糊如圖40:
  • 1

這里寫圖片描述

就簡單的一句話便描述完了,意思是把這個對像給一個Servlet Registration。很迷茫?到底意思呢?大膽的猜一下,在程序初始化的時候MyWebApplicationInitializer中的onStartup方法程序不是通過ServletRegistration.Dynamic去add了一個servlet

查閱源碼發現ServletRegistration.Dynamic是一個接口。
  • 1

他的真實對象是通過servletContext對象的一個方法servletContext.addServlet返回來的。這個對象的定義是沒有的,因為ServletContext也是一個接口,程序中的servletContxt對象是由tomcat在啟動創建的。

這個如果要討論就要討論tomat的實現原理了,這個放到以后討論
  • 1

也就是這個servlet-api.jar把接口寫好了供程序員調用,真實的實現都是基于tomcat的。這么理解吧:

假設servlet-api.jar里面有一個UserDao的接口,里面有各種查詢方法,add方法啊;但是他只是接口。
真正實現這個UserDao的類是不在jar中,是由容器啟動時把這個接口的對象給程序,所以程序有userDao的對象。
  • 1
  • 2

再于是猜想所謂的Servlet Registration 就是這個ServletRegistration.Dynamic接口的對象。 查閱源碼,還真發現他有一個方法setMultipartConfig的方法,并且參數類型就是MultipartConfigElemen圖41:

這里寫圖片描述

為了驗證這個猜想就在初始化那個方法MyWebApplicationInitializer.onStartup里面里面把這個MultipartConfigElement set一下。圖42:

這里寫圖片描述

最后根據文檔的說明,serlvet3.0需要注冊的文件轉換器叫做StandardServletMulti
partResolver
于是把Appconfig類里面MultipartResolver改成返回StandardServletMultipartResolver。圖42:

這里寫圖片描述

啟動tomcat 運行程序 圖last:
  • 1

這里寫圖片描述
至此兩種上傳文件的方法都完成了,第一種依賴commons-fileUpaload,第二種可以不需要這個jar了。介于篇幅原因本文就到此殺青了。

文的目的不是為了搭建springMVC code-based框架,僅僅是博主感嘆一下spring公司編寫的性感的開發文檔。一下兩個都是代碼地址
代碼:http://download.csdn.net/download/java_lyvee/10162574
代碼:http://dl.iteye.com/topics/download/a6e61837-4236-364d-8c22-5eeb848fea2e   
  • 1
  • 2
  • 3

末了打個廣告http://lubanedu.ke.qq.com/魯班學院,每晚八點都有免費的java試聽課,都是面向高級開發的課堂內容,非常不錯

轉載于:https://www.cnblogs.com/xuxinstyle/p/9784040.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/279194.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/279194.shtml
英文地址,請注明出處:http://en.pswp.cn/news/279194.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

powershell 入門_使用PowerShell入門的5個Cmdlet

powershell 入門PowerShell is quickly becoming the preferred scripting language and CLI of Power Users as well as IT Pros. It’s well worth learning a few commands to get you started, so we’ve got 5 useful cmdlets for you to learn today. PowerShellSwift成為…

Part 3: Services

介紹 在第3部分中&#xff0c;我們將擴展應用程序并啟用負載平衡。為此&#xff0c;我們必須在分布式應用程序的層次結構中提升一個級別:服務。 StackServices (你在這里)Container (涵蓋在第2部分中)關于服務 在分布式應用程序中&#xff0c;應用程序的不同部分被稱為“服務”…

mysql ldf文件太大_Linux_數據庫清除日志文件(LDF文件過大),清除日志: 復制代碼 代碼如 - phpStudy...

數據庫清除日志文件(LDF文件過大)清除日志&#xff1a;復制代碼 代碼如下:DECLARE LogicalFileName sysname,MaxMinutes INT,NewSize INTUSE szwzcheck -- 要操作的數據庫名SELECT LogicalFileName szwzcheck_Log, -- 日志文件名MaxMinutes 10, -- Limit on time allowed to …

emwin之錯誤使用控件函數導致死機現象

2018-10-15 導致死機的代碼示例如下 1 /**2 * brief widget ID define3 * {4 */5 6 #define ID_WINDOW_0 (GUI_ID_USER 0x00)7 #define ID_TEXT_0 (GUI_ID_USER 0x01)8 #define ID_TEXT_1 (GUI_ID_USER …

diy感應usb攝像頭拍照_DIY無線感應充電器

diy感應usb攝像頭拍照Courtesy of Instructables user Inducktion shares a very detailed tutorial on how to build a wireless power charger. He explains the impetus behind the project: 由Instructables用戶提供Inducktion分享了有關如何構建無線電源充電器的非常詳細…

ubuntu7.10安裝到3D開啟

累了好幾天&#xff0c;重裝了十幾遍終于把ubuntu7.10搞定到了我自認為完美的狀態了。現在總結一下安裝過程&#xff08;按操作順序記錄&#xff09;&#xff1a;1.在xp下不管用pqmajac還是其他硬盤分區工具分出10G的空余分區來&#xff08;實驗階段10G嘗試下&#xff09;&…

初學者對python的認識_Python初學者列表,python,初識

1.認識列表列表可以放入所有我們目前學習過的數據類型&#xff0c;甚至包括列表2.有關列表的方法、內置函數(設列表的名稱為list)向列表中添加元素&#xff1a;append()&#xff1a;list.append(要添加的元素)&#xff0c;注意每次只能添加一個元素&#xff0c;被添加的元素自動…

常用模塊之 time,datetime,random,os,sys

time與datetime模塊 先認識幾個python中關于時間的名詞&#xff1a; 時間戳(timestamp)&#xff1a;通常來說&#xff0c;時間戳表示的是從1970年1月1日00:00:00開始按秒計算的偏移量。我們運行“type(time.time())”&#xff0c;返回的是float類型。1970年之前的日期無法以此表…

使用aSpotCat控制您的Android應用權限

Viewing the permissions of each installed Android app requires digging through the Manage Applications screen and examining each app one by one — or does it? aSpotCat takes an inventory of the apps on your system and the permissions they require. 要查看每…

xtrabackup備份mysql“ib_logfile0 is of different”錯誤分析

今天用xtrabackup工具完整備份mysql數據庫的時候出現“./ib_logfile0 is of different”錯誤&#xff0c;具體的日志信息如下: 我第一時間查詢了百度和谷歌都沒有找見相對應的答案。決定從錯誤日志入手&#xff0c;上面的日志提示說&#xff1a;mysql數據庫inondb的日志文件的大…

java socket 報文解析_java socket解析和發送二進制報文工具(附java和C++轉化問題)

解析:首先是讀取字節:/*** 讀取輸入流中指定字節的長度* * 輸入流**paramlength 指定長度*return指定長度的字節數組*/public static byte[] readBytesFromTo(byte[] buffer, int from, intlength) {byte[] sub new byte[length];int cur 0;for (int i from; i < length …

Ubuntu防火墻:ufw

原始linux的防火墻是iptables&#xff0c;以為過于繁瑣&#xff0c;各個發行版幾乎都有自己的方案; ubuntu下的防火墻是ufw[ubuntu fireward的縮寫]&#xff0c;centos的防火墻是fireward ubuntu下&#xff1a; 啟用或者關閉防火墻 sudo ufw enable|disable sudo ufw default d…

如何使自己的不和諧機器人

Discord has an excellent API for writing custom bots, and a very active bot community. Today we’ll take a look at how to get started making your own. Discord具有出色的用于編寫自定義機器人的API&#xff0c;以及非常活躍的機器人社區。 今天&#xff0c;我們將探…

?css3屬性選擇器總結

css3屬性選擇器總結 &#xff08;1&#xff09;E[attr]只使用屬性名&#xff0c;但沒有確定任何屬性值 <p miaov"a1">111111</p> <p miaov"a2">111111</p> p[miaov]{background: red;} /*所有屬性為miaov的元素都會被背景變紅&a…

java復合賦值運算符_Java 之復合賦值運算符

1.引入問題切入正題&#xff0c;看下面代碼&#xff0c;結果應該是怎么樣的public class App{public static void main( String[] args ){byte a1 ;int b 10;a ab;System.out.println(a);ab;System.out.println(a);}}這段代碼的執行結果是什么&#xff1f;&#xff1f;2. 執行…

程序代碼初學者_初學者:如何使用熱鍵在Windows中啟動任何程序

程序代碼初學者Assigning shortcut keys to launch programs in Windows is probably one of the oldest geek tricks in the book, but in true geek fashion we are going to show you how to do it in Windows 8. 分配快捷鍵以在Windows中啟動程序可能是本書中最古老的怪胎技…

stevedore——啟用方式

2019獨角獸企業重金招聘Python工程師標準>>> setuptools維護的入口點注冊表列出了可用的插件&#xff0c;但是并沒有為最終用戶提供使用或啟用的方法。 下面將描述用于管理要使用的擴展集的公共模式。 通過安裝方式啟用 對于許多應用程序&#xff0c;僅僅安裝一個擴…

java 重置定時器_可重置Java定時器

我想有一個java.utils.Timer與一個可重置時間在java.I需要設置一次off事件發生在X秒。如果在創建定時器的時間和X秒之間沒有發生任何事情&#xff0c;則事件會正常發生。然而&#xff0c;如果在X秒之前&#xff0c;我決定該事件應該發生在Y秒后&#xff0c;然后我想要能夠告訴定…

C# -- 文件的壓縮與解壓(GZipStream)

文件的壓縮與解壓 需引入 System.IO.Compression; 1.C#代碼&#xff08;入門案例&#xff09; 1 Console.WriteLine("壓縮文件...............");2 using (FileStream fr File.OpenRead("d:\\test.txt"))3 {4 …

win7屏保文件.scr_如何將屏保添加到Ubuntu 12.04

win7屏保文件.scrUbuntu 12.04 doesn’t ship with any screen savers, just a black screen that appears when your system is idle. If you’d rather have screensavers, you can swap gnome-screensaver for XScreenSaver. Ubuntu 12.04沒有附帶任何屏幕保護程序&#xff…