在上篇Spring MVC入門篇中,咱們初步瞭解了Spring MVC開發的基本搭建過程,本文將針對實際開發過程的着重點Controller部分,將經常使用的知識點羅列出來,並配以示例。在這以前,咱們有必要回顧一下,Spring MVC在咱們的WEB開發中,定位或者做用是什麼?Spring MVC在項目中,主要做用是接收客戶端請求、解析路徑並分發請求到相應的控制器即Controller中執行相應方法,在方法中,咱們常見的操做有,調用業務邏輯層(後面會介紹到)方法,訪問數據庫,獲取數據或者更新數據,若是是獲取數據通常是要返回給前端,經常使用方式有兩種:1.傳統的Jsp開發中,咱們能夠將數據封裝到Model屬性中,而後在頁面中經過el表達式之類的方式獲得;2.隨着Ajax技術/RESTful風格的興起,一樣能夠在先後端分離的狀況下傳遞數據(RESTful基礎學習階段能夠不做重點,但Ajax必定要掌握)。另外基於Spring MVC的開發模式下,參數的獲取、匹配,以及頁面的跳轉都十分方便,下面咱們就來實踐操做一下。html
若是學習階段習慣將Jsp文件直接放在web文件根目錄webapp下,建議如今開始轉變,將其分類放置WEB-INF下,這樣一來,咱們但願訪問一個頁面,將再也不是直接經過路徑去訪問,而是經過Spring MVC中的請求,匹配到相應控制器中方法內部,再跳轉至相應頁面。區別在於WEB-INF下文件針對服務器端,而客戶端例如瀏覽器是沒法直接訪問的,這樣能夠減小直接訪問的風險,另外即便拋開安全性隱蔽性不談,須要填充Model傳遞數據的Jsp頁面若是在直接訪問的狀況下,可能會出現各類奇奇怪怪的問題,空白、無數據、樣式錯亂等等。頁面跳轉SpringMVC默認是請求轉發,本文主要針對請求部分,均做默認請求轉發處理。前端
@Controllerweb
該註解用於Spring識別並實例化控制器bean到上下文中,即加上這個註解的類Spring才能識別知道它是要做爲控制器。spring
@RequestMapping數據庫
該註解既可用於類上也能夠用在方法上,實際開發每每二者都會用到,用於匹配url路徑,接收請求,只有匹配的請求才會進入該控制器執行相關方法。後端
@RequestParam瀏覽器
在控制器方法中,用於將注入的參數與前臺請求參數綁定spring-mvc
@PathVariable安全
用於綁定url路徑中佔位的參數服務器
登陸應該是你們再熟悉不過的web程序操做,這裏以用戶名、密碼爲例,分別對應實體類User中屬性username和password,那麼咱們的頁面表單部分以下所示:
login.jsp中
<form action="${pageContext.request.contextPath }/user/login" method="post"> 用戶名<input type="text" name="username" /><br/> 密碼<input type="password" name="password" /><br/> <button type="submit">登陸</button> </form>
Controller代碼
package com.mmm.web; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("user") public class DemoController { @RequestMapping(value="/toLogin") public String toLogin() { return "login"; } @RequestMapping(value="/login") public String login(String username,String password) { System.out.println("用戶名---" + username); System.out.println("密碼---" + password); return "index"; } }
有了前面的文件路徑問題,這裏咱們先定義一個toLogin方法用於訪問登陸頁面login.jsp,而後在頁面表單點擊提交後會請求到這裏的login方法,重點:form表單中輸入框<input>的name屬性值,對應Controller中方法的參數名,即這裏login方法的兩個參數名,username和password,經過這兩處的值,Spring MVC便可自動匹配使咱們輕鬆獲取參數。
啓動Tomcat,在地址欄輸入http://localhost/spring-mvc/user/toLogin,便可訪問到登陸頁面,以下所示
任意輸入用戶名和密碼內容後,點擊登陸,便可看到eclipse控制檯輸出相似以下信息
並跳轉至index.jsp頁面,這裏即成功獲取到了前臺傳遞來的參數,這種方式十分方便,但並非惟一,因此下面分別介紹其它的方法。
***基於以前學過的Servlet系列的請求對象HttpServletRequest,它有一個getParameter(String parameterName)方法,這個parameterName即前臺參數名,這裏即一樣對應輸入框<input>的name屬性值。
***應用Spring MVC的機制,經過實體類裝配屬性,一樣能夠匹配到參數,這裏的用戶名和密碼,每每是對應實體類這裏以User爲例,類中有username和password這2兩個字符串屬性。這樣一來,經過User對象咱們也能夠匹配到前臺的這兩個參數。
下面咱們彙總上面的內容,修改login方法爲以下所示
@RequestMapping(value="/login") public String login(String username,String password, HttpServletRequest req,User user) { System.out.println("直接參數名匹配獲取:用戶名---" + username); System.out.println("直接參數名匹配獲取:密碼---" + password); System.out.println("HttpServletRequest獲取:用戶名---" + req.getParameter("username")); System.out.println("HttpServletRequest獲取:密碼---" + req.getParameter("password")); System.out.println("User獲取:用戶名---" + user.getUsername()); System.out.println("User獲取:密碼---" + user.getPassword()); return "index"; }
再次訪問登陸頁面,輸入內容並點擊登陸後,便可看到eclipse控制檯輸出相似以下信息
代表以上方式都可用於獲取前臺傳遞參數值。
PS:上面第一種方式(也是經常使用方式中)若是前端表單中name值和我這裏方法中的參數名確實不同,有沒有別的辦法能解決這個問題?目前Spring MVC各方面的註解漸漸在完善,這裏Spring MVC就爲咱們提供了這樣一種註解,@RequestParam,用於指定前臺參數名,即這裏若是咱們將上面登陸頁面中的密碼輸入框的name屬性值改成pwd,以下所示
密碼<input type="password" name="pwd" /><br/>
按照前面咱們的參數名匹配,Controller的login方法中是password,前臺是pwd,這樣是匹配不上,隨之也沒法獲取數據的。可是引入上面提到的註解,方法能夠中參數能夠將String password修改成:@RequestParam("pwd") String password,這樣一來,便可成功獲取數據了。
上面結合表單示例介紹了幾種方式獲取請求參數,以前學習Servlet部分,應該都熟悉doPost和doGet方法,這裏的表單每每就是用的post請求方式提交。
使用post提交時,數據將以數據塊的形式提交到服務器,URL地址欄中不會出現數據,因此用這種方式提交的表單數據是相對安全的。因此表單提交包含相似於密碼等數據時,建議使用post方法。
使用get提交時地址欄上會在你當前項目路徑後加上相似?pram1=value1¶m2=value2」的形式,將表單數據附加到URL的後面,提交到服務器處理,這種方式效率更高,因此在沒有私密數據時,請求推薦這種。
除了上面提到的方式,還有一種獲取路徑傳參的方式,這裏也介紹一下,比較實用,經過@PathVariable註解,經過url路徑實現動態傳參並獲取參數值,代碼以下示例:
@RequestMapping(value="/show/{id}") public String show(@PathVariable(value="id") String str) { System.out.println("url獲取:id參數值---" + str); return "index"; }
而後,咱們在地址欄中輸入localhost/spring-mvc/user/show/abcdefg,路徑末尾的abcdefg即對應上面Controller代碼@RequestMapping(value="/show/{id}")中的id,咱們經過{id}這個大括號加參數名的方式去動態接收它,不論你的值是多少,這裏就是用id變量來對應,因而下面@PathVariable(value="id")中的id即與之相應,隨後綁定到String str上,這個str即匹配該參數值,咱們即可以獲取到該數據了。輸入地址後回車,便可看到控制檯,輸出以下:
前面提到的get、post主要是講前臺請求方式,name咱們後臺是否能夠選擇接受指定方式的請求呢?固然是能夠的。@RequestMapping的屬性中有個method,英文是方法的意思,在這裏用於指定要接收的請求方式,以下所示
爲了方便,Spring MVC還爲咱們提供了RequestMethod枚舉,以下所示
* @author Juergen Hoeller * @since 2.5 * @see RequestMapping * @see org.springframework.web.servlet.DispatcherServlet#setDispatchOptionsRequest * @see org.springframework.web.servlet.DispatcherServlet#setDispatchTraceRequest */ public enum RequestMethod { GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE }
其中指定了各類請求方式,咱們能夠直接經過例如RequestMetho.GET來指定。
例如上面的登陸部分,咱們首先要前往登陸頁面,請求並無參數傳遞,因此咱們直接經過get方式請求,而後在登陸頁面中輸入信息後點擊登陸,提交表單登陸時,咱們每每用post。上面咱們的@RequestMapping(value="")這個value值一個是toLogin,一個是login,兩個不一樣的值,就是爲了區別這兩個請求,可是實際上是能夠寫成同樣的,這裏咱們稍做修改成以下:
@RequestMapping(value="/login",method=RequestMethod.GET) public String toLogin() { return "login"; } @RequestMapping(value="/login",method=RequestMethod.POST) public String login(String username, String password) { System.out.println("直接參數名匹配獲取:用戶名---" + username); System.out.println("直接參數名匹配獲取:密碼---" + password); return "index"; }
這樣咱們一樣能夠實現前面的效果。
在沒有應用maven時,以前常用下面的方式新建web項目。
咱們首先要理清的是,咱們的web項目都是動態的( dynamic),這個動態最上層,是客戶端的各類動態操做,深刻到底層,大多會反映到數據庫,那麼二者有什麼關聯,或者是怎樣關聯起來的?其中上面講到的請求參數每每就是一箇中間人。以上面的登陸爲例,客戶端經過表單提交了用戶名和密碼兩個參數,那麼咱們究竟是要到數據庫中查詢有沒有帳號和密碼都同時匹配的用戶記錄,有的話表明輸入正確,沒有的話則表明輸入信息有誤。客戶端獲得的登陸成功或者失敗這種不肯定的結果,基於他的輸入,也基於數據庫中數據,無數個相似這樣的關聯關係個構建起了咱們的web項目業務邏輯結構。
因此後面咱們就要理清什麼是業務邏輯了。在登陸過程當中,咱們驗證用戶名和密碼是否正確,會調用到用戶的持久層對象,去查詢數據庫用戶表記錄;可是同時咱們須要記錄登陸信息,即在日誌表中插入一條登陸信息。可是持久層有查詢用戶表的方法,也有插入日誌信息的方法,可是兩種方法一塊兒調用的並無,因此這裏須要咱們在控制層和持久層之間添加一層業務邏輯層,整合這些持久操做,封裝好業務邏輯方法供控制層調用。
固然這裏舉例日誌可能有點不太恰當,由於基於Spring AOP,例如事務管理、日誌信息記錄等通用組件能很方便的實現,能讓咱們專一於實現項目中的業務邏輯,可是總的來講,這裏能夠先簡單的理解爲,業務邏輯Service層,做用於持久層(dao)和控制層(controller)之間,它每每用於組裝比持久層更復雜的操做過程,而且也不侷限於數據庫操做,而後供控制層調用,控制層則是專一於接收請求,分發到相應業務邏輯方法進行處理,而後做出響應。
以上講到了Spring MVC通用請求相關的處理參數過程及方法,固然還有例如文件上傳也是一種特殊的請求,而且經常使用到,後面會理出來。咱們在實際開發中每每下功夫最多的是如何實現那些複雜的業務邏輯,相反控制層不該該做用到這些業務處理。因此下面會專門理清一下業務邏輯層的部分,經過注入前面咱們學習的MyBatis封裝的持久對象,而後將業務邏輯層對象注入到控制層,實現Spring MVC與MyBatis的整合。