SSM框架開發web項目系列(七) SpringMVC請求接收


  前言

  在上篇Spring MVC入門篇中,我們初步了解了Spring MVC開發的基本搭建過程,本文將針對實際開發過程的着重點Controller部分,將常用的知識點羅列出來,並配以示例。在這之前,我們有必要回顧一下,Spring MVC在我們的WEB開發中,定位或者作用是什么?Spring MVC在項目中,主要作用是接收客戶端請求、解析路徑並分發請求到相應的控制器即Controller中執行相應方法,在方法中,我們常見的操作有,調用業務邏輯層(后面會介紹到)方法,訪問數據庫,獲取數據或者更新數據,如果是獲取數據一般是要返回給前端,常用方式有兩種:1.傳統的Jsp開發中,我們可以將數據封裝到Model屬性中,然后在頁面中通過el表達式之類的方式得到;2.隨着Ajax技術/RESTful風格的興起,同樣可以在前后端分離的情況下傳遞數據(RESTful基礎學習階段可以不作重點,但Ajax一定要掌握)。另外基於Spring MVC的開發模式下,參數的獲取、匹配,以及頁面的跳轉都十分方便,下面我們就來實踐操作一下。

   0.頁面文件路徑以及頁面跳轉問題

  如果學習階段習慣將Jsp文件直接放在web文件根目錄webapp下,建議現在開始轉變,將其分類放置WEB-INF下,這樣一來,我們希望訪問一個頁面,將不再是直接通過路徑去訪問,而是通過Spring MVC中的請求,匹配到相應控制器中方法內部,再跳轉至相應頁面。區別在於WEB-INF下文件針對服務器端,而客戶端例如瀏覽器是無法直接訪問的,這樣可以減少直接訪問的風險,另外即使拋開安全性隱蔽性不談,需要填充Model傳遞數據的Jsp頁面如果在直接訪問的情況下,可能會出現各種奇奇怪怪的問題,空白、無數據、樣式錯亂等等。頁面跳轉SpringMVC默認是請求轉發,本文主要針對請求部分,均作默認請求轉發處理。

  1.本文注解預介紹

  @Controller

  該注解用於Spring識別並實例化控制器bean到上下文中,即加上這個注解的類Spring才能識別知道它是要作為控制器。

  @RequestMapping

  該注解既可用於類上也可以用在方法上,實際開發往往兩者都會用到,用於匹配url路徑,接收請求,只有匹配的請求才會進入該控制器執行相關方法。

  @RequestParam

  在控制器方法中,用於將注入的參數與前台請求參數綁定

  @PathVariable

  用於綁定url路徑中占位的參數

  2.自動匹配客戶端傳來的參數

  登錄應該是大家再熟悉不過的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&param2=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即匹配該參數值,我們便可以獲取到該數據了。輸入地址后回車,即可看到控制台,輸出如下:

   3.改進登錄模塊

  前面提到的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";
    }

   這樣我們同樣可以實現前面的效果。

  4.獲取請求參數后我們要干嘛?

  在沒有應用maven時,之前經常使用下面的方式新建web項目。

  我們首先要理清的是,我們的web項目都是動態的( dynamic),這個動態最上層,是客戶端的各種動態操作,深入到底層,大多會反映到數據庫,那么兩者有什么關聯,或者是怎樣關聯起來的?其中上面講到的請求參數往往就是一個中間人。以上面的登錄為例,客戶端通過表單提交了用戶名和密碼兩個參數,那么我們到底是要到數據庫中查詢有沒有賬號和密碼都同時匹配的用戶記錄,有的話代表輸入正確,沒有的話則代表輸入信息有誤。客戶端得到的登錄成功或者失敗這種不確定的結果,基於他的輸入,也基於數據庫中數據,無數個類似這樣的關聯關系個構建起了我們的web項目業務邏輯結構。

  所以后面我們就要理清什么是業務邏輯了。在登錄過程中,我們驗證用戶名和密碼是否正確,會調用到用戶的持久層對象,去查詢數據庫用戶表記錄;但是同時我們需要記錄登錄信息,即在日志表中插入一條登錄信息。但是持久層有查詢用戶表的方法,也有插入日志信息的方法,但是兩種方法一起調用的並沒有,所以這里需要我們在控制層和持久層之間添加一層業務邏輯層,整合這些持久操作,封裝好業務邏輯方法供控制層調用。

  當然這里舉例日志可能有點不太恰當,因為基於Spring AOP,例如事務管理、日志信息記錄等通用組件能很方便的實現,能讓我們專注於實現項目中的業務邏輯,但是總的來說,這里可以先簡單的理解為,業務邏輯Service層,作用於持久層(dao)和控制層(controller)之間,它往往用於組裝比持久層更復雜的操作過程,並且也不局限於數據庫操作,然后供控制層調用,控制層則是專注於接收請求,分發到相應業務邏輯方法進行處理,然后作出響應。

  小結

  以上講到了Spring MVC通用請求相關的處理參數過程及方法,當然還有例如文件上傳也是一種特殊的請求,並且常用到,后面會理出來。我們在實際開發中往往下功夫最多的是如何實現那些復雜的業務邏輯,相反控制層不應該作用到這些業務處理。所以下面會專門理清一下業務邏輯層的部分,通過注入前面我們學習的MyBatis封裝的持久對象,然后將業務邏輯層對象注入到控制層,實現Spring MVC與MyBatis的整合。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM