文章越往後越是精華
一、SpringMvc介紹
1.什麼是springmvc
Spring Web MVC是一種基於Java的實現了Web MVC設計模式的請求驅動型別的輕量級Web框架,即使用了MVC架構模式的思想,將web層進行職責解耦,基於請求驅動指的就是使用請求-響應模型,框架的目的就是幫助我們簡化開發,Spring Web MVC也是要簡化我們日常Web開發的。
2.springmvc優勢
清晰的角色劃分:
前端控制器(DispatcherServlet)
請求到處理器對映(HandlerMapping)
處理器介面卡(HandlerAdapter)
檢視解析器(ViewResolver)
處理器或頁面控制器(Controller)
驗證器( Validator)
命令物件(Command 請求引數繫結到的物件就叫命令物件)
表單物件(Form Object 提供給表單展示和提交到的物件就叫表單物件)
分工明確
而且擴充套件點相當靈活,可以很容易擴充套件,雖然幾乎不需要;
無需繼承API直接命令操作
由於命令物件就是一個POJO,無需繼承框架特定API,可以使用命令物件直接作為業務物件;
與spring無縫銜接
和Spring 其他框架無縫整合,是其它Web框架所不具備的;
適配任意類作為處理器
可適配,通過HandlerAdapter可以支援任意的類作為處理器;
支援簡單定製
可定製性,HandlerMapping、ViewResolver等能夠非常簡單的定製;
功能強大
功能強大的資料驗證、格式化、繫結機制;
靈活的單元測試
利用Spring提供的Mock物件能夠非常簡單的進行Web層單元測試;
更容易的主題與國際化
本地化、主題的解析的支援,使我們更容易進行國際化和主題的切換。
強大的jsp標籤庫
強大的JSP標籤庫,使JSP編寫更容易。
還有比如RESTful風格的支援、簡單的檔案上傳、約定大於配置的契約式程式設計支援、基於註解的零配置支援等等。
二、springmvc執行原理
核心架構的具體流程步驟如下:
1.首先使用者傳送請求——>DispatcherServlet,前端控制器收到請求後自己不進行處理,而是委託給其他的解析器進行處理,作為統一訪問點,進行全域性的流程控制;
2.DispatcherServlet——>HandlerMapping,HandlerMapping將會把請求對映為HandlerExecutionChain物件(包含一個Handler處理器(頁面控制器)物件、多個HandlerInterceptor攔截器)物件,通過這種策略模式,很容易新增新的對映策略;
3.DispatcherServlet——>HandlerAdapter,HandlerAdapter將會把處理器包裝為介面卡,從而支援多種型別的處理器,即介面卡設計模式的應用,從而很容易支援很多型別的處理器;
4.HandlerAdapter——>處理器功能處理方法的呼叫,HandlerAdapter將會根據適配的結果呼叫真正的處理器的功能處理方法,完成功能處理;並返回一個ModelAndView物件(包含模型資料、邏輯檢視名);
5.ModelAndView的邏輯檢視名——> ViewResolver, ViewResolver將把邏輯檢視名解析為具體的View,通過這種策略模式,很容易更換其他檢視技術;
6.View——>渲染,View會根據傳進來的Model模型資料進行渲染,此處的Model實際是一個Map資料結構,因此很容易支援其他檢視技術;
7.返回控制權給DispatcherServlet,由DispatcherServlet返回響應給使用者,到此一個流程結束。
更簡流程記憶:
使用者發起請求到前端控制器(Controller)
前端控制器沒有處理業務邏輯的能力,需要找到具體的模型物件處理(Handler),到處理器對映器(HandlerMapping)中查詢Handler物件(Model)。
HandlerMapping返回執行鏈,包含了2部分內容: ① Handler物件、② 攔截器陣列
前端處理器通過處理器介面卡包裝後執行Handler物件。
處理業務邏輯。
Handler處理完業務邏輯,返回ModelAndView物件,其中view是檢視名稱,不是真正的檢視物件。
將ModelAndView返回給前端控制器。
檢視解析器(ViewResolver)返回真正的檢視物件(View)。
(此時前端控制器中既有檢視又有Model物件資料)前端控制器根據模型資料和檢視物件,進行檢視渲染。
返回渲染後的檢視(html/json/xml)返回。
給使用者產生響應。
三、框架元件
DispatcherServlet:前端控制器
使用者請求到達前端控制器,它就相當於mvc模式中的c,dispatcherServlet是整個流程控制的中心,由它呼叫其它元件處理使用者的請求,dispatcherServlet的存在降低了元件之間的耦合性。
HandlerMapping:處理器對映器
HandlerMapping負責根據使用者請求找到Handler即處理器,springmvc提供了不同的對映器實現不同的對映方式,例如:配置檔案方式,實現介面方式,註解方式等。
Handler:處理器
Handler 是繼DispatcherServlet前端控制器的後端控制器,在DispatcherServlet的控制下Handler對具體的使用者請求進行處理。
由於Handler涉及到具體的使用者業務請求,所以一般情況需要程式設計師根據業務需求開發Handler。
HandlAdapter:處理器介面卡
通過HandlerAdapter對處理器進行執行,這是介面卡模式的應用,通過擴充套件介面卡可以對更多型別的處理器進行執行。
View Resolver:檢視解析器
View Resolver負責將處理結果生成View檢視,View Resolver首先根據邏輯檢視名解析成物理檢視名即具體的頁面地址,再生成View檢視物件,最後對View進行渲染將處理結果通過頁面展示給使用者。
View:檢視
springmvc框架提供了很多的View檢視型別的支援,包括:jstlView、freemarkerView、pdfView等。我們最常用的檢視就是jsp。
一般情況下需要通過頁面標籤或頁面模版技術將模型資料通過頁面展示給使用者,需要由程式設計師根據業務需求開發具體的頁面。
說明:在springmvc的各個元件中,處理器對映器、處理器介面卡、檢視解析器稱為springmvc的三大元件。
需要使用者開放的元件有handler、view
四、springmvc與struts2不同
springmvc的入口是一個servlet即前端控制器,而struts2入口是一個filter過慮器。
springmvc是基於方法開發(一個url對應一個方法),請求引數傳遞到方法的形參,可以設計為單例或多例(建議單例),struts2是基於類開發,傳遞引數是通過類的屬性,只能設計為多例。
Struts採用值棧儲存請求和響應的資料,通過OGNL存取資料, springmvc通過引數解析器是將request請求內容解析,並給方法形參賦值,將資料和檢視封裝成ModelAndView物件,最後又將ModelAndView中的模型資料通過reques域傳輸到頁面。Jsp檢視解析器預設使用jstl。
五、springmvc與struts2有什麼區別?
1. 底層實現機制 match
struts2:filter
springmvc:servlet
2. 執行效率
struts2:底層是Servlet,引數基於屬性封裝,如果配置單例,會出現執行緒安全問題,所以配置多例
springmvc:底層是Servlet,單例
3. 引數封裝
struts2:基於屬性封裝
springmvc:基於方法進行封裝
六、入門案例
建立工程
導jar包
寫好頁面
建立Controller
建立springmvc.xml
在web.xml中配置前端控制器
註解驅動的作用:
1. 自動建立處理器對映器
2. 自動建立處理器介面卡
3. 支援所有註解
4. 支援json格式資料
七、引數繫結
springmvc接收引數方式:直接把接收引數變數放在方法中自動接收引數
1.解決引數亂碼
get請求亂碼:
1).再次編碼
String(request.getParamter(“userName”).getBytes(“ISO8859-1”),”utf-8”)
2). server.xml設定 URIEncoding=”UTF-8”
post請求亂碼:
1). 使用spring編碼過濾器(web.xml),必須配置在前端控制器之前.
2.接收自定義引數
1).註解:@InitBinder:轉換引數
2).自定義轉換工具
在springmvc.xml中配置
3.預設支援的引數型別
1).HttpServletRequest:通過request物件獲取請求資訊
2).HttpServletResponse:通過response處理響應資訊
3).HttpSession:通過session物件得到session中存放的物件
4).Model/ModelMap:ModelMap是Model介面的實現類,通過Model或ModelMap向頁面傳遞資料.
model.addAttribute("item", item);
頁面通過${item.XXXX}獲取item物件的屬性值。
如果使用Model則可以不使用ModelAndView物件,Model物件可以向頁面傳遞資料,View物件則可以使用String返回值替代。不管是Model還是ModelAndView,其本質都是使用Request物件向jsp傳遞資料。
5).繫結簡單型別:當請求的引數名稱和處理器形參名稱一致時會將請求引數與形參進行繫結。從Request取引數的方法可以進一步簡化。
4.支援的資料型別
引數型別推薦使用包裝資料型別,因為基礎資料型別不可以為null
整形:Integer、int
字串:String
單精度:Float、float
雙精度:Double、double
布林型:Boolean、boolean
5.接收POJO
如果提交的引數很多,或者提交的表單中的內容很多的時候可以使用pojo接收資料。要求pojo物件中的屬性名和表單中input的name屬性一致。
如果是包裝型別的POJO,包裝物件.
頁面定義:
Controller方法定義如下:
6.接收陣列
7.接收list
標籤中varStatus屬性常用引數總結下:
八、springmvc註解
常用註解:
1. Controller
2. RequestMapping
3. RequestParam
4. Redirect
5. Forward
6. RequestBody/ResponseBody
1.Controller
@Controller:用於標識是處理器類.表示把我的控制器物件交給spring來建立。
Controller起作用:只需要掃描即可。
2.RequestMapping
@RequestMapping :請求對映註解
用法舉例:
1. @RequestMapping(“list.do”)
2. @RequestMapping(“/list.do”)
3. @RequestMapping(“list”)
4. @RequestMapping(value=”list”)
5. @RequestMapping(value=”list”,method.RequestMethod.POST)
get請求:
1. 所有從瀏覽器直接傳送的請求,都是get請求
2. href傳送的請求都是get請求
post:
1. 表單提交是post請求
2. ajax是post請求
3.URL路徑對映
@RequestMapping:請求到處理器功能方法的對映規則;
URL路徑對映:@RequestMapping(value=”/user”)或@RequestMapping(“/user”)
RequestMethod請求方法限定
4.URL模板對映
@RequestMapping(value="/useredit/{userId}”):{×××}
佔位符請求的URL可以是
“/useredit/001”或“/useredit/abc”,通過在方法中使用@PathVariable獲取{×××}中的×××變數
實現restFul,所有的url都是一個資源的連結,有利於搜尋引擎對網址收錄。
多個佔位符
如果有多個pojo、並且裡面具有相同的屬性,解決方案:
我們使用包裝類來包裝pojo、經過包裝的pojo相當於加了一層包結構。所以後面即使具有相同的屬性也無所謂。
5.RequestParam
value:引數名字,即入參的請求引數名字,如value=“studentid”表示請求的引數區中的名字為studentid的引數的值將傳入;
required:是否必須,預設是true,表示請求中一定要有相應的引數,否則將報400錯誤碼;
defaultValue:預設值,表示如果請求中沒有同名引數時的預設值
@RequestParam(defaultValue=”1”,value=”myid”)
功能1:設定預設值
功能2:給引數定義別名,別名和頁面傳遞引數匹配即可
6.Redirect
Contrller方法返回結果重定向到一個url地址.
- 同一個類內跳轉
redirect:add.do 與 redirect:/user/add.do” 在同一個類裡面進行跳轉。上面2個都可以實現跳轉。但是有區別:第一個是同一個根路徑下面跳轉。第二個是在專案路徑下進行跳轉。
- 不同的類進行跳轉
不同的類進行跳轉只能使用:redirect:/user/add.do進行跳轉。即是從專案路徑下來查詢。
redirect方式相當於“response.sendRedirect()”,轉發後瀏覽器的位址列變為轉發後的地址,因為轉發即執行了一個新的request和response。
由於新發起一個request原來的引數在轉發時就不能傳遞到下一個url,如果要傳引數可以/user/userlist.do後邊加引數,如下:
/user/userlist.action?groupid=2&…..
7.Forward
controller方法執行後繼續執行另一個controller方法。
return “forward:/user/userlist.action”;
forward方式相當於
“request.getRequestDispatcher().forward(request,response)”,轉發後瀏覽器位址列還是原來的地址。轉發並沒有執行新的request和response,而是和轉發前的請求共用一個request和response。所以轉發前請求的引數在轉發後仍然可以讀取到。
8.json資料互動
@RequestBody註解用於讀取http請求的內容(字串),通過springmvc提供的HttpMessageConverter介面將讀到的內容轉換為json、xml等格式的資料並繫結到controller方法的引數上。
@RequestBody註解實現接收http請求的json資料,將json資料轉換為java物件
@RequestBody/@ResponseBody要依賴Jackson
支援註解,註解對映器和註解介面卡可以使用代替。
預設註冊了註解對映器和註解介面卡等bean。
九、異常處理
springmvc在處理請求過程中出現異常資訊交由異常處理器進行處理,自定義異常處理器可以實現一個系統的異常處理邏輯。
1.自定義異常
全域性異常解析介面 HandlerExceptionResolver
2.自定義異常處理器
3.新建錯誤提示頁面
略
4.異常處理器配置
在springmvc.xml中配置:
十、上傳檔案
採用跨伺服器非同步上傳方式.
1.jar包
依賴:commons-io,commons-fileupload,jersey框架下的jar包
2.配置解析器
配置springmvc.xml
3.配置圖片伺服器許可權
readonly
false
4.Controller編寫
5.頁面編寫
十一、RESTful支援
Restful就是一個資源定位及資源操作的風格。不是標準也不是協議,只是一種風格,是對http協議的詮釋。
資源定位:網際網路所有的事物都是資源,要求url中沒有動詞,只有名詞。沒有引數
Url格式:
http://blog.dn.net/beat_the_world/article/details/45621673
資源操作:使用put、delete、post、get,使用不同方法對資源進行操作。分別對應新增、刪除、修改、查詢。
1.前端控制器設定
2.靜態資源訪問
springmvc支援restFull風格軟體架構模式:
1. 沒有副檔名
2. 沒有?方式傳遞引數,引數都在url連結中
3. springmvc提供url預設對映,對映:
@RequestMapping(“/item/deitItem/{id}”)
4. 通過@Pathvariable 對映引數傳遞
十二、攔截器
Spring Web MVC 的處理器攔截器類似於Servlet 開發中的過濾器Filter,用於對處理器進行預處理和後處理。
1.自定義攔截器
2.攔截器配置
在springmvc中配置
3.攔截器執行順序
preHandle按攔截器定義順序呼叫
postHandler按攔截器定義逆序呼叫
afterCompletion按攔截器定義逆序呼叫
postHandler在攔截器鏈內所有攔截器返成功呼叫
afterCompletion只有preHandle返回true才呼叫
4.攔截器與過濾器的區別
過濾器Filter依賴於Servlet容器,基於回撥函式,過濾範圍大
攔截器Inerceptor依賴於框架容器,基於反射機制,只過濾請求
十三、ssm整合
控制層採用springmvc、持久層使用mybatis實現.
1.需求
實現商品查詢列表,從mysql資料庫查詢商品資訊。
2.導jar包
包括:spring(包括springmvc)、mybatis、mybatis-spring整合包、資料庫驅動、第三方連線池、日誌等。
3.spring與mybatis整合
1).db.properties
2).log4j.properties
3).配置sqlMapConfig.xml
在classpath下建立mybatis/sqlMapConfig.xml
4).配置applicationContext.xml
5).配置ItemsMapper.xml
6).ItemsMapper.java
4.spring管理service
1).Service由spring管理。
2).spring對Service進行事務控制。
service層程式碼:
5.spring與springmvc整合
1).配置springmvc.xml
2).web.xml
3).Controller編寫
SpringMVC專案總結:
一、通過指定的url獲取頁面的html
1.為了避免中文亂碼,需要實現指定jsp頁面的編碼為utf-8,但是如果遇到html頁面的特殊標籤可能會產生一些部分中文亂碼
更好的解決方案可以用jsonp
maven座標如下:
2.
二、SpringMVC框架裡jsp客戶端向服務端傳遞List型別的引數
客戶端
服務端
接收list資料
三.SpringMVC中的檔案下載
四、基於iText和flying saucer結合freemark把html生成pdf (支援css樣式)
專案地址:
http://git.oschina.net/lemonzone2010/doc-render
嘗試了幾個開源專案感覺這個效果最好,而且文旦詳盡,需要注意的是
1、不支援css3特殊樣式,html裡如果有中文需要現在css樣式裡申明所用字型
2、專案裡讀取html時使用了freemark技術也但是我自己操作的時候利用總結一里的jsonp讀取更加方便
五、把檔案打包生成zip
六、圖片上傳到非工程資料夾下,希望通過該工程的url訪問該圖片
檔案上傳到tomcat下的工程下,專案重新啟動圖片就沒了
解決的思路:
在配置檔案下配置路徑
BASE_FILEUPLOAD_URL=/upload/username/type/year/month/
BASE_FILEUPLOAD_PATH=../../upload/username/type/year/month/
上傳檔案時讀取該路徑並進行拼接:
//檔案上傳目錄路徑
String savePath = pageContext.getServletContext().getRealPath(“/”) + BASE_FILEUPLOAD_PATH;
這樣配置以後圖片就上傳到tomcat的一級目錄下了
定義訪問的時候url為localhost:8080//btkjsite_designcloud/before/getFile/upload/username/type/year/month/20160911.jpg
先根據訪問的url找到圖片的實際物理路徑,再通過輸入流讀取檔案,寫入輸出流在網頁上把圖片顯示出來
企業工作實踐SpringMVC總結
一:配置SpringMVC開發環境
任何mvc的框架,都是需要在web.xml中進行核心的配置的,struts2是一個過濾器,而SpringMVC則是一個servlet,但是配置方法大同小異,都是在web.xml中進行配置,配置方法如下:
再然後就是配置springMVC-servlet.xml,這個檔名之前說過,可以自定義路徑與名稱,如果不自定義,則一定要放在WEB-INFO下,注意引入正確的名稱空間,然後加入核心分解解析器,就是解析url的請求,類似於stuts的配置檔案,配置如下:
然後就是正式使用SpringMVC了,我們通常是用註解的方式,因為註解真的太好用了,省事好多,但是這裡也簡單介紹一下使用xml配置檔案的方式來寫一個簡單的helloworld
1.1.配置檔案的helloworld
首先新建一個類,這個類要實現Controller介面,然後實現它的一個ModelAndView方法,程式碼如下:
然後在springMVC-servlet.xml中配置一個bean:配置方法如下:
這種配置和struts2其實是一樣的,name屬性就是瀏覽器請求的url,而class就是它處理的類,而執行的方法,就是上面所繼承的介面,然後在瀏覽器輸入http://localhost:8080/springMVC/test,就可以跳轉到welcome.jsp下,這是根據之前配置的檢視分解解析器的前字尾前該方法返回的字串拼接而成的。
1.2.基於註解的helloworld
使用註解就要簡單得多了,首先是在springMVC-servlet.xml中配置掃描的包,這樣spring就會自動根據註解來描述一些特定的註解,然後把這些bean裝載進入spring容器中,配置如下:
然後,在指定的包,或者其子包下新建一個類,程式碼如下:
這樣就不用再寫配置檔案,只要加上相應的註解就行,比如說這裡的helloworld方法,只要在瀏覽器輸入http://localhost:8080/project/hellowrold,就可以進入spring.jsp頁面
二:@RequestMapping詳解
2.1.類的@RequestMapping註解
剛才看到了@RequestMapping這個註解是用於給一個方法加上url的請求地址,不過,這個註解不僅僅可以加在方法上面,也可以加在類上面,程式碼如下圖所示:
如上程式碼如示,如果同時在類與方法上面同時加上@RequestMapping註解的話,那麼URL肯定不會是之前的那種寫法了,現在要寫成類的註解加上方法的註解,就是有點類似struts2中,的nameplace屬性,那如如上程式碼,URL應該為http://localhost:8080/project/springMVC/testReuqestMapping
2.2.請求方式的設定
像我們平常提交一個表單,肯定會有get,與post這兩個常用的請求,那麼在springMVC中要如何設定呢?很簡單,也是在@RequestMapping中使用,不過需要在方法的註解上面使用,程式碼如下:
這下在from表單中,或者非同步請求中,就需要以post做為請求,不然會報錯的,因為這裡已經設定為了post,如果客戶端再請求get,將會報錯。
2.3.引數的規定與請求頭的規定設定
我們都知道http請求會有著請求引數與請求頭訊息,那麼在springMVC裡面,是可以規範這些資訊的,首先給一段程式碼示例:
無論是params,還是headers,都可以包含多個引數,以逗號相隔就行,如果不滿足寫了的條件,則就會報錯,不允許請求資源。其次這兩個屬性還支援一些簡單的表示式:
2.4.@RequestMapping對映中的萬用字元
在@RequestMapping的value屬性中,還支援Ant格式的能配符:
/user/*/createUser 匹配/user/abcd/createUser
/user/**/createUser 匹配/user/aa/bb/cc/createUser
/user/?/createUser 匹配/user/a/createUser
這裡就不作程式碼演示了,相信大家一看就懂,因為這種萬用字元真的太常見了
2.5.@RequestMapping與@PathVariable註解的一起使用
springMVC很靈活,它可以獲取URL地址中的值,然後當作變數來輸出,這裡要使用@PathVariable註解,故名思意,就是路徑變數的意思,通常的話,@PathVariable要使用,是一定要與@RequestMapping一起使用的,下面給出程式碼示例:
先在括號中加上註解,其中value就是@RequestMapping中佔位符的宣告,然後加上資料型別和定義的變數,這樣就可以對其進行使用了
2.6.Rest風格的URL
通常的話,表單有著post,與get提交方式,而rest風格的URL,則有著get,post,put,delete這四種請求方式,但是瀏覽器卻是隻支援get與post,所以我們可以使用springMVC,把它進行轉換,我們要利用org.springframework.web.filter.HiddenHttpMethodFilter這個類,這是一個過濾器,我們首先要在web.xml中配置它,請配置在第一個位置,不然的話,可能會先進入其它的過濾器,配置程式碼如下:
如上的配置,這個過濾器則會攔截所有的請求,我們可以看一下org.springframework.web.filter.HiddenHttpMethodFilter的部分原始碼:
當這個過濾器攔截到一個請求時,就會先拿到這個請求的引數,它要滿足兩個條件,第一,瀏覽器發出的請求為post請示,第二,它還要有一個引數,引數名為_method,而它的值,則可以為get,post,delete,put,此時過濾器就會把post請求轉換成相應的請求,不然的話就不進行轉換,直接請求。至於新增_method引數的話,則可以使用hidden隱藏域,或者使用?拼接引數都可以。
下面就該是控制器的方法了,在本處第2小點中,有講到@RequestMapping的請求方式的設定,只要把這個請求方式設定成對應的請求就行,比如說轉換成了DELETE請求,則@RequestMapping也要寫成對應的DELETE請求,不然會出錯,示例程式碼如下:
此時,就可以正確轉換請求方式了。
三:獲取http請求中的資訊
3.1.獲取請求中的引數,@RequestParam
在獲取類似這種:http://localhost:8080/project/test?user=a&password=2這種請求引數時,就需要用@RequestParam這個註解來獲取,程式碼如下:
如上面註釋所寫,它常用這三個屬性,value是引數名,但是如果只寫了引數名的話,請求時,就必須帶此引數,不然就會報錯。如果把required屬性設定為false,就可以使得該引數不傳,還有defaultValue屬性,此屬性可以當瀏覽器沒有傳此引數時,給這個引數一個預設值
3.2.獲取請求頭的資訊,@RequestHeader
之前也有提到過http的請求頭的資訊,那麼這裡就可以使用@RequestHeader註解來獲取請求頭的資訊,它的使用方法與上面的@RequestParam是完全一樣的,同樣擁有value,requied,defaultValue這三個屬性,而有代表的作用也是一樣的,下面給出程式碼示例:
因為它的用法與本章第一點的獲取請求引數的用法一樣,所以這裡就不作過多的說明,詳細可以檢視@RequestParam的用法
3.3.獲取Cookie的資訊,@CookieValue
在開發中,有很多情況都會用到Cookie,這裡可以使用@CookieValue註解來獲取,其使用方法與@RequestParam與@RequestHeader一樣,這裡就不過多敘述,給出示例程式碼:
它也有著三個屬性,value,required,defaultValue,分別對應Cookie名,是否非空,預設值。
3.4.使用Pojo來獲取請求中的大量引數
如果http請求中只有一兩個引數,那麼使用@RequestParam還可以,但是如果一個請求中帶有著大量的引數,那麼這樣就有點麻煩了,那麼springMVC就可以使用Pojo物件來獲取這次請求中的所有引數,並且全部封裝到這個物件裡面,這種方式類似struts2的ModelDriver,相信使用過struts2的同學都清楚,這種方式極其簡便,下面一邊給程式碼,一邊解釋,首先給出請求的處理方法:
這裡無需使用其它的註解,只需要在這個處理方法中加上一個類就行,那麼springMVC就會自動把請求引數封裝到你寫好的類中,而且這種封裝還支援級聯操作,什麼是級聯操作呢?就是User類中的屬性還有著另外的一個類,下面給出User類的程式碼:
由上面可見,其中不僅有普通的屬性,還有著一個Address的類,我們再來看一下Address類的程式碼:
可以很清楚的看清User類與Address類的關係,那麼像這種關係的物件,在瀏覽器form表單中的name屬性該如何寫呢?Address類中的欄位,要加上address,比如address.province,或者address.city,其它的屬性,就直接寫User類中的屬性就可以了。而這裡為什麼Address變成了小寫的呢?其實這並不是什麼命名規則,而是我在User類中就是這麼定義的
這下沒有什麼問題了吧,我們再來看一下瀏覽器表單是怎麼寫的:
如上表單元素就可以看到表單的name屬性是如何與User類對應的,其Address類中的屬性,就以address.city。
下面來說一下這種請求方式的特點:
1.簡便,不需要大量的@RequestParam註解。
2.與struts2的ModelDriver的用法差不多,只不過ModelDriver是介面,整個類裡面所有的方法都可以使用。而springMVC中這個Pojo物件的作用僅僅是當前的處理方法中。
3.這種Pojo的使用中,瀏覽器的引數可以為空,就是可以不傳引數,也不會報錯,不像@RequestParam,如果不指定requried=false的話,還會報錯。
四:Servlet原生API
4.1.使用Servlet原生API
在我們平常使用springMVC中,雖然說springMVC已經幫我們做了很多工作了,但是我們實際中還是會要用到Servlet的原生API,那這個時候要如何得到Servlet的原生物件呢?這裡與struts2不同,springMVC是在方法中宣告對應的引數來使用這些物件,而struts2則是呼叫相應的方法來得到這些物件。當然,對於沒有學過struts2的同學,可以忽略,下面給出程式碼示例:
如上程式碼所示,直接在對應的處理方法裡面宣告這些需要使用的物件就可以了,那如果同時要使用Pojo來獲得請求引數怎麼辦呢?這個不用擔心,照常使用就行了,如上程式碼所示,同樣宣告瞭一個User類來接收引數,並不會有任何的影響。
4.2.使用Servlet原生API的原理(部分springMVC的原始碼)
如果你想問,springMVC中的處理方法,裡面可以支援哪些Servlet的原生API物件呢?或者你又想問,為什麼可以照常的使用Pojo來獲取請求引數呢?那麼這裡,我們先來看一下springMVC的原始碼,然後再作解釋:
從這裡就可以說明了一個問題了,springMVC首先會通過反射技術得到這個方法裡面的引數(原始碼沒有貼上,有興趣的可以自行檢視springMVC的原始碼),然後比較這些引數的型別,是否與上面的九個型別想匹配,如果匹配成功,則返回這個物件,請注意,是與物件型別相匹配,而不是與形參名作匹配,所以這樣,就不會使得Pojo無法工作了
4.3.springMVC支援哪些原生API
其實從4.2中的原始碼中也是可以看到了,這裡支援九種個物件,對應關係分別是:
五:頁面中的傳值
5.1.簡單的使用ModelAndView來向頁面傳遞引數
實際開發中,總要大量的向頁面中傳遞後臺的資料,那麼存放資料的方法也有多種多樣,比如說存到request中,大家都知道是使用request.setAtrribute()來向request域中傳遞值,但是實際上springMVC給我們封裝了更好的方法,那就是使用ModelAndView。
首先,方法的返回值,該由String變成ModelAndView,然後在處理方法中new一個ModelAndView物件,然後返回這個物件就可以了,物件中可以增加返回頁面的字元,也可以向這個物件裡面傳遞引數,現在給出一個簡單的示例程式碼:
如上程式碼如示,我們可以使用構造方法給它傳一個值,那就是它最終要返回的頁面的值,或者使用setViewName方法來給它一個返回頁面的名字。使用addObject方法來給這個模型新增資料,這是一個鍵值對的資料,然後返回這個ModelAndView物件。
5.2.使用引數Map來向頁面傳值
可以在執行方法中定義一個Map引數,然後在方法中,向map新增內容,然後在頁面中根據map的鍵來取對應的值,也是存在request域中,下面給出程式碼示例:
這裡面就是在方法中有著一個Map型別的引數,其實不僅僅可以是Map型別,還可以是Model與ModelMap型別的,因為最終傳入的根本就不是Map,而是
org.springframework.validation.support.BindingAwareModelMap
5.3.使用@SessionAttributes註解,把值放到session域中
其實5.1和5.2所訴的內容,雖然是把後臺資料傳遞到前臺,但是全部都是放置到request域中,這裡講訴一下使用@SessionAtrributes註解,把後臺資料同時放到session中。
首先介紹一下這個註解,這個註解只能放在類上面,而不能放在方法上面。它有兩個屬性,一個是value屬性,一個是types屬性,這兩個資料都是陣列,所以可以宣告多個,其實不論是value屬性,還是types屬性,都可以把資料同時放到session域中,只不過value屬性對應的是執行方法中的map集合的鍵,只要是對應的鍵,那麼其值,也會同時被傳遞到session域中(這裡之所以加上“同時”這個詞,是因為它會同時存到request與session中),而types屬性,則是放置類的集合,只要map集合中存的是該類的資料,則也會同時被放到request中,下面給示例程式碼:
如上程式碼所示,先是在類上面使用了@SessionScope註解,然後同時使用了value與types屬性,第一個value屬性的值”user”,則是testSessionAtrributes方法中map集合中的”user”的鍵,所以這一個鍵值對會被同時放入session域中,而第二個types的屬性中的String.class,則是代表著這個類了,意思就是說,只要是map集合中放的String型別的資料,都會被放到session中。
注意:使用了value屬性後,這個屬性也就必須存在,意思就是說,必須有一個map,然後有一個user的鍵,不然會報錯,當然,這個是可以解決的,後面會詳細講到。
5.4.@SessionAtrribute引發的異常
上一講說到使用@SessionAtrribute來修飾一個類,就可以把一些值存放到session域中,但是如果找不到對應的值,就會報異常,這裡可以用@ModelAtrribute來進行修飾,對它改名就可以了,程式碼如下:
或者加上一個有著@ModelAtrribute所修飾的方法,至於@ModelAtrribute註解,將會在第六章講到。
六:@ModelAtrribute註解詳解
6.1.簡單介紹@ModelAtrribute及其執行流程
在我們開發中,會有這樣一種情況,比如說我要修改一個人的資訊,但是使用者名稱是不讓修改的,那麼我在瀏覽器頁面中肯定會有一個表單,裡面有一個隱藏域的id,可以改密碼,可以改郵箱,但是使用者名稱不讓修改,所以我們不能給使用者名稱的輸入框,然後使用者修改完資料後,點選提交儲存,然後發現這個時候使用者名稱不見了!當然大家都會想到就是重新取出使用者名稱,然後給這個物件賦值,或者先從資料庫裡面找到這個使用者的物件,然後再來修改這個物件,而不是自己來建立物件,@ModelAtrribute註解就是基於這種情況的。
那麼這種情況在springMVC中要如何實現呢?
首先給出執行的目標方法的程式碼:
這個程式碼很簡單,只是使用Pojo來獲取表單的引數,但是User類是不可能從表單得到使用者名稱的,所以這個類就缺少了一個屬性,如果這樣存到資料庫裡面,是肯定要出問題的,那麼按照之前所說,我們可以先得到這個User物件,然後給這個物件賦值,但是我們有著簡化的方法,下面給出@ModelAtrribute註解的用法:
可以發現,上面的類是沒有返回值的,但是經有一個map集合,我們把這個從資料庫查出來的user物件放到了Map集合中,然後就不需要做什麼了,然後上面的
testModelAtrribute方法執行的時候,就會自動把使用者名稱給填充進去。
下面講一個@ModelAtrribute註解的執行流程
1.執行@ModelAtrribute註解修飾的方法:從資料庫中取出物件,並把物件放到了Map中,鍵為user
2.springMVC從Map集合中取出User物件,並把表單的請求引數賦值給user物件相應的屬性
3.springMVC把上述物件傳入目標方法的引數
4.這個user物件是存在request中,如果jsp表單中有對應的欄位,還會自動填充表單
注意:在@ModelAtrribute修飾的方法中,放入Map時的鍵要和目標方法的引數名一致
6.2.@ModelAtrribute原始碼分析
可以一邊除錯一邊檢視原始碼,這裡的原始碼有點多,我就不貼出來了,有興趣的同學可以自己看,我這裡講訴一下原理:
1.呼叫@ModelAtrribute註解修飾的方法,實際上是把@ModelAtrribute中的Map放到了implicitModel中。
2.解析請求處理器的標引數,實際上目標引數來自於WebDataBinder物件的target屬性
(1).建立WebDataBinder物件
確定objectName屬性,若傳入的attrName屬性為”“,則objectName為類名第一個字母小寫
注意:atrributeName,若目標方法的Pojo屬性使用了@ModelAtrribute註解來修飾,則atrributeName值即為@ModelAtrribute的value屬性值
(2).確定target屬性
>在implicitModel中查詢atrrName對應的屬性值,若存在ok,若不存在,則驗證Hander,是否使用了@SessionAtrributes進行修飾,若使用了,則嘗試從session中獲取attrName所對應的屬性值,若session中沒有對應的值,則丟擲異常
>若Hander沒有使用@SessionAtrributes進行修飾,或@SessionAtrributes中沒有使用value值指定的鍵和attrName相互匹配,則通過反射建立了Pojo物件,這個時候target就建立好了。
3.springMVC把表單的請求引數賦給了WebDataBinder的target屬性
4.springMVC會把WebDataBinder的attrName和target給到implicitModel
5.把WebDataBinder的target作為引數傳遞給目標方法的入參
6.3.解決@ModelAtrribute註解中,map集合的鍵與執行目標方法的引數名不一致的情況
其實我們可以在目標方法裡面的引數中,定義一個@ModelAtrribute註解,並把其值指定為@ModelAtrribute註解修飾的方法中的map的鍵,下面給出程式碼示例:
可以看到,目標方法的引數中,有著@ModelAtrribute修飾,其value屬性為”abc”,再來看一下@ModelAtrribute所修飾的方法:
在這裡就可是很顯示的看到map是存放了一個”abc”的鍵。
七:轉發與重定向
7.1標籤
在springMVC的配置檔案中使用標籤可以使得url不需要進入handler處理方法,就可以直接跳轉頁面,配置方法如下
根據如上的配置,就可以直接在瀏覽器中輸入http://localhost:8080/project/good,就可以跳轉至success.jsp頁面,而無需進入handler處理方法,更不需要進行@RequestMapping對映。
但是如果僅僅是這樣的配置,會有一個很大的問題,就是之前所寫的handler處理方法全部都不能使用了,全部會進行報錯,那麼要怎麼解決呢?可以在springMVC的配置檔案中,寫一個下面的標籤,就不會有這樣的問題了:
只要寫上這樣的一個標籤,那麼就可以解決上面的問題,而且也不要寫任何引數。不過這個標籤具體有什麼用呢?後面會作介紹。
7.2.自定義檢視
下面來講一下自定義檢視,使用它可以很好的和jfreechar或excel整合,下面來具體說明。
首先新建一個檢視,新建一個類,繼承view介面,然後覆蓋裡面的方法,程式碼如下:
如上所示,寫一個類,繼承View介面,然後覆蓋裡面的方法,就可以自己自定義檢視了,但是目前這個檢視還沒有用,需要在springMVC的配置檔案中進行配置,才能使用這個檢視,配置方法如下:
只要在springMVC的配置檔案中寫如上的配置,那麼這個檢視就可以使用了,然後我們寫一個handler處理方法,程式碼如下:
然後的話,我們輸入如下url,http://localhost:8080/project/testView,就不會進行helloView.jsp,因為配置的解析檢視的order值為最高,也就代表著它的優先順序是最低的,所以會先執行我們自定義的檢視,那麼就會在瀏覽器中顯示之前檢視中向瀏覽器寫的資料。
7.4.檢視的重定向操作
上面所說的全部都是檢視的轉發,而不是重定向,這次我來講一下重定向是怎麼操作的。
只要字串中以forward或者redirect開頭,那麼springMVC就會把它解析成關鍵字,然後進行相應的轉發,或者重定向操作,下面給出示例程式碼:
上面就分別是重定向與轉發操作,其實不止java程式碼,標籤中的返回檢視,也可以加上redirect或者forward字串,也會進行相應的操作。
八:資料的格式化
8.1 日期格式化
form表單向後臺處理方法提交一個引數的時候,如果提交一個日期的資料,而後臺接收的資料型別則是Date型別,那麼springMVC肯定無法將其轉換成,因為springMVC不知道你傳的資料的格式是怎麼樣的,所以需要為接收的欄位指定日期的格式,使用@DateTimeFormat註解,使用方法如下:
使用前提:需要在springMVC-servlet.xml的配置檔案中配置,這個在開發中肯定會配置的,因為它有好多作用,如果不配置,則下面程式碼無效:
下面是目標方法的程式碼:
上面就是在接收的引數前面加了一個@DateTimeFormat註解,註解中寫明pattern屬性,寫上日期的格式,然後在瀏覽器輸入:http://localhost:8080/project/dateFormat?date=19951029,這樣springMVC就可以把這個字串轉成Date日期了。
如果是使用Pojo,使用一個物件來接收引數,那麼也是一樣的,同樣是在欄位的上方,加上一個@DateTimeFormat註解,如下:
8.2.數字的格式化
除了日期的格式化,我們可能還會遇到數字的格式化,比如會計人員作賬時,數字喜歡這樣寫 1,234,567.8 因為這樣簡單明瞭,但是如果由java直接來解析的話,肯定是不行的,因為這根本就不是一個Float型別的資料,肯定是要報錯的,那麼要如何呢?我們可以使用@NumberFormat()註解,這個註解的使用方式,和使用前提和8.1章節,日期的格式化是一樣的,請先檢視8.1章節,再看本章。
和之前一樣,是肯定要配置的,不過這裡就不詳細說明了,下面給出執行方法的程式碼:
其使用方法,其實是和@DateTimeFormat是一樣的,但是這裡的引數有必要說明一樣,”#“是代表數字,那麼這個時候,就可以對其進行解析了。如果你傳入的是一個正確的Float型別的資料,那麼它會被正確的接收這個數字,如果不是一個Float型別的資料,那麼springMVC會嘗試使用@NumberFoamat註解的引數來嘗試解析。
如輸入的是http://locathost:8080/project?num=123,那麼springMVC會解析成123.0,如果是http://locathost:8080/project?num=123.1,則會正常顯示成123.1,那如果是http://locathost:8080/project?num=1,234,567.8這種特殊的寫法,則也會正確的解析成1234567.8
8.3.資料的校驗
資料的檢驗是使用Hibernate-validator的擴充套件註解,它是javaee6.0提出的JSR303的實現,使用它,可以用註解對資料進行校驗,下面來說一下使用方法。
1.首先要匯入jar包,這不是spring的jar包,需要下載Hibernate-validator的jar包,然後新增到專案工程中
2.其次是要在springMVC的配置檔案中,即springMVC-servlet.xml中配置,不需要寫其它的屬性:
3.然後在欄位面前加上對應的校驗註解,下面以一個bean作一個簡單的例子:
這樣就會對使用了註解的欄位進行校驗,然後這樣還不行,還需要指定目標執行方法,所以需要在執行方法上面也加上一個註解@Valid,這樣加了這個註解的執行方法就會校驗資料,下面給出目標方法的註解:
只要在這個方法上面加上@Valid註解,然後這個執行方法就會校驗資料,校驗的結果可以使用BindingResult物件顯示,這個物件會不僅僅會儲存資料校驗的結果,還會儲存資料型別轉換的結果,所以都可以使用這個物件得到相應的資訊,顯示的方法如下面的程式碼如示。
注意:需要校驗的bean物件與其繫結結果物件或錯誤物件是成對出現的,他們中間不允許宣告其它的引數
8.4.JSR303的驗證型別
通過上面的例子我們知道可以使用註解來驗證資料型別,但是具體可以使用哪些註解呢,下面給出說明:
8.5.傳遞json型別的資料
而在springMVC中,使用json非常的簡單,但是首先需要引進其它的一些jar包,那就是jackson,這是一個解析json的jar包,然後就可以直接使用了,下面給出程式碼示例:
如上如示,只要在執行方法的上面加上@ResponseBody註解,然後定義目標方法的返回值,其返回值可以是任意集合,也可以是任意物件,然後springMVC會自動將其轉換成json
8.6.檔案上傳
springMVC也封裝了檔案上傳,變的極其簡單,但是需要引入common-io.jar與common.upload.jar包,然後需要在spinrgMVC-serlvet.xml中作如下的配置:
注意:id必須如上寫法,不然會報錯
然後給出處理方法的程式碼:
如果是多個檔案上傳,則改為陣列,如果是單個,方式也是一樣,與struts2的檔案的上傳極其的類似。
九:攔截器
9.1.第一個攔截器
編寫攔截器極其簡單,只要編寫一個類,實現HandlerInterceptor的方法,然後在springMVC的配置檔案中配置這個類,就可以使用這個攔截器了。
首先給出配置檔案的寫法:
然後再來寫FirstInterceptor這個攔截器,程式碼如下:
然後在每個執行方法呼叫之前,都會先進攔截器,這就是一個簡單的攔截器的寫法了。
9.2.攔截器的指定範圍
在使用攔截器時候,並不一定要對所有的目標方法都進行攔截,所以我們可以只對指定的方法進行攔截,這就需要更改配置檔案了,下面給出配置檔案的寫法:
只需要在中配置一個,然後指定其路徑,就可以了,這個路徑可以指定一個URL,也可以使用萬用字元。
9.3.攔截器的使用順序
當同時定義了多個攔截器的時候,那麼它的使用順序是怎麼樣的呢?
preHandle是按配置檔案中的順序執行的
postHandle是按配置檔案中的倒序執行的
afterCompletion是按配置檔案中的倒序執行的
作者:Java幫幫
連結:https://www.jianshu.com/p/25a78698d7fa
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。