1. 接收請(qǐng)求參數(shù)
1.1. 【不推薦】通過HttpServletRequest
在處理請(qǐng)求的方法中太防,添加HttpServletRequest對(duì)象作為參數(shù),在方法體中魔策,直接調(diào)用參數(shù)對(duì)象的getParameter()或類似功能的方法匈子,即可獲取請(qǐng)求參數(shù):
@RequestMapping("handle_reg.do")
public String handleReg(
? ? ? ? HttpServletRequest request) {
? ? System.out.println("UserController.handleReg()");
? ? String username
? ? ? ? = request.getParameter("username");
? ? String password
? ? ? ? = request.getParameter("password");
? ? Integer age
? ? ? ? = Integer.valueOf(request.getParameter("age"));
? ? String phone
? ? ? ? = request.getParameter("phone");
? ? String email
? ? ? ? = request.getParameter("email");
? ? System.out.println("username=" + username);
? ? System.out.println("password=" + password);
? ? System.out.println("age=" + age);
? ? System.out.println("phone=" + phone);
? ? System.out.println("email=" + email);
? ? return null;
}
1.2. 【推薦】在處理請(qǐng)求的方法中聲明同名參數(shù)
假設(shè)用戶提交的參數(shù)是username=root,則參數(shù)名是username闯袒,當(dāng)需要獲取這個(gè)參數(shù)的值時(shí)虎敦,直接在處理請(qǐng)求的方法中聲明String username即可游岳,框架會(huì)把root值直接用于調(diào)用處理請(qǐng)求的方法,即String username的值就已經(jīng)是root了:
@RequestMapping("handle_reg.do")
public String handleReg(
? ? ? ? String username, String password,
? ? ? ? Integer age, String phone, String email) {
? ? System.out.println("[2] username=" + username);
? ? System.out.println("[2] password=" + password);
? ? System.out.println("[2] age=" + (age + 1));
? ? System.out.println("[2] phone=" + phone);
? ? System.out.println("[2] email=" + email);?
? ? return null;
}
使用這種做法時(shí)其徙,可以無(wú)視數(shù)據(jù)類型胚迫,例如希望age是Integer類型的,則直接聲明為Integer類型即可唾那,無(wú)須自行轉(zhuǎn)換访锻!
使用這種做法時(shí),必須保證提交的請(qǐng)求參數(shù)的名稱通贞,與處理請(qǐng)求的方法中的參數(shù)名稱是一致的朗若!如果不一致,則處理請(qǐng)求的方法中昌罩,對(duì)應(yīng)的參數(shù)值會(huì)是null值!
如果參數(shù)名稱無(wú)法統(tǒng)一灾馒,后續(xù)有解決方案茎用。
這種做法最大的缺陷是:不適用于數(shù)據(jù)項(xiàng)目太多的表單!否則睬罗,會(huì)導(dǎo)致處理請(qǐng)求的方法中需要添加大量的參數(shù)轨功!
1.3. 【推薦】使用自定義類型獲取多項(xiàng)數(shù)據(jù)
假設(shè)請(qǐng)求參數(shù)中包含多項(xiàng)數(shù)據(jù),例如:username=admin&password=123456&age=22&phone=13900139001&email=admin%40tedu.cn容达,而這些數(shù)據(jù)都可以封裝在同一個(gè)類型中古涧,則直接使用該類型作為處理請(qǐng)求的參數(shù)即可:
@RequestMapping("handle_reg.do")
public String handleReg(User user) {
? ? System.out.println("[3] username=" + user.getUsername());
? ? System.out.println("[3] password=" + user.getPassword());
? ? System.out.println("[3] age=" + (1 + user.getAge()));
? ? System.out.println("[3] phone=" + user.getPhone());
? ? System.out.println("[3] email=" + user.getEmail());
? ? return null;
}
這種做法,適用于請(qǐng)求參數(shù)較多的場(chǎng)合花盐!
注意:如果請(qǐng)求參數(shù)的參數(shù)名稱羡滑,與類中的屬性名稱不一致,則類對(duì)象中對(duì)應(yīng)的屬性值為null算芯!
注意:這種做法可以與前序介紹的第2種做法組合來使用柒昏!
1.4. 小結(jié)
關(guān)于獲取請(qǐng)求參數(shù),首先熙揍,并不推薦使用HttpServletRequest职祷,主要原因是相對(duì)比較原始,編碼比較繁瑣届囚!而聲明同名參數(shù)有梆,或聲明對(duì)象,都是推薦的做法意系,至于使用哪一種泥耀,可以根據(jù)參數(shù)的數(shù)量及數(shù)據(jù)是否適合被封裝到同一個(gè)類中,綜合評(píng)定昔字,并且爆袍,這2種做法可以組合使用首繁!
2. 控制器的響應(yīng)
2.1. 常見的響應(yīng)方式
【轉(zhuǎn)發(fā)】在轉(zhuǎn)發(fā)過程中,客戶端只發(fā)出過1次請(qǐng)求陨囊!在瀏覽器的地址欄中弦疮,也只會(huì)顯示第1次請(qǐng)求的路徑!轉(zhuǎn)發(fā)是在服務(wù)器內(nèi)部完成的蜘醋,可以傳遞數(shù)據(jù)胁塞!
【重定向】當(dāng)服務(wù)器響應(yīng)重定向時(shí),客戶端會(huì)發(fā)出第2次請(qǐng)求压语!最終啸罢,在瀏覽器的地址欄中,會(huì)顯示第2次請(qǐng)求的路徑胎食!由于是2次不同的請(qǐng)求扰才,基于Http協(xié)議是無(wú)狀態(tài)協(xié)議,沒有經(jīng)過特殊處理(Session/Cookie/數(shù)據(jù)庫(kù)存取……)的數(shù)據(jù)是無(wú)法在2次請(qǐng)求之間傳遞的厕怜!
2.2. 常見的響應(yīng)碼
被服務(wù)器接收到的每個(gè)請(qǐng)求衩匣,在最終響應(yīng)時(shí),服務(wù)器端都會(huì)給出一個(gè)響應(yīng)碼粥航,例如200琅捏、404等。通常:
2xx:正確的響應(yīng)递雀,例如200柄延、206等……
3xx:重定向,例如302缀程、301等……
4xx:請(qǐng)求錯(cuò)誤搜吧,例如請(qǐng)求的資源不存在,或者請(qǐng)求類型錯(cuò)誤杠输、或者請(qǐng)求參數(shù)錯(cuò)誤等等赎败,例如400、404蠢甲、405僵刮、406等……
5xx:服務(wù)器內(nèi)部錯(cuò)誤,通仇信#可能是出現(xiàn)某種異常搞糕,例如500等……
3. 轉(zhuǎn)發(fā)數(shù)據(jù)
3.1. 【不推薦】將轉(zhuǎn)發(fā)的數(shù)據(jù)封裝在HttpServletRequest對(duì)象中
可以為處理請(qǐng)求的方法添加HttpServletRequest request參數(shù),當(dāng)需要轉(zhuǎn)發(fā)數(shù)據(jù)時(shí)曼追,將數(shù)據(jù)封裝在request中即可窍仰,后續(xù)也不需要顯式的執(zhí)行轉(zhuǎn)發(fā),在SpringMVC的控制器中礼殊,默認(rèn)的響應(yīng)方式就是轉(zhuǎn)發(fā)驹吮。
@RequestMapping("handle_reg.do")
public String handleReg(User user,
? ? ? ? HttpServletRequest request) {
? ? // 假定輸入的用戶名已經(jīng)被占用
? ? // 提示:您輸入的用戶名XXX已經(jīng)被占用
? ? request.setAttribute("msg",
? ? ? ? "您輸入的用戶名" + user.getUsername() + "已經(jīng)被占用针史!");
? ? // 返回視圖名,也可以理解為文件的文件名
? ? return "error"; // 頁(yè)面:/WEB-INF/error.jsp
}
3.2. 【不推薦】使用ModelAndView
可以將處理請(qǐng)求的方法的返回值設(shè)置為ModelAndView類型碟狞,該類型的常用構(gòu)造方法有:
ModelAndView()
ModelAndView(String viewName)
ModelAndView(String viewName, Map<String, ?> model)
當(dāng)需要轉(zhuǎn)發(fā)數(shù)據(jù)時(shí)啄枕,可以使用以上3種中的最后一種:
@RequestMapping("handle_reg.do")
public ModelAndView handleReg(String username) {
? ? String viewName = "error";
? ? Map<String, Object> model
? ? ? ? = new HashMap<String, Object>();
? ? model.put("msg",
? ? ? ? ? ? "[2] 您輸入的用戶名" + username + "已經(jīng)被占用!");
? ? ModelAndView mav
? ? ? ? = new ModelAndView(viewName, model);
? ? return mav;
}
由于這種方式使用相對(duì)比較復(fù)雜族沃,所以频祝,一般不推薦使用這種做法!
3.3. 【推薦】使用ModelMap封裝需要轉(zhuǎn)發(fā)的數(shù)據(jù)
使用ModelMap的流程與使用HttpServletRequest完全相同脆淹,即:方法的返回值依然使用String類型常空,在方法中聲明該參數(shù),然后在方法體中直接封裝數(shù)據(jù)盖溺,最后漓糙,返回視圖名:
@RequestMapping("handle_reg.do")
public String handleReg(String username,
? ? ? ? ModelMap modelMap) {
? ? modelMap.addAttribute("msg",
? ? ? ? "[3] 您輸入的用戶名" + username + "已經(jīng)被占用!");
? ? return "error";
}
3.4. 小結(jié)
在SpringMVC中咐柜,轉(zhuǎn)發(fā)數(shù)據(jù)共有3種做法兼蜈,第1種使用HttpServletRequest的做法簡(jiǎn)單直接,但是拙友,并不推薦這樣處理,主要是因?yàn)榭蚣芤呀?jīng)幫我們處理了request需要執(zhí)行的任務(wù)歼郭,而我們?cè)诰帉懘a時(shí)應(yīng)該盡量不干預(yù)框架的處理過程遗契,第2種使用ModelAndView,是框架的核心處理方式病曾,但是牍蜂,因?yàn)槭褂梅绞竭^于麻煩,所以泰涂,也不推薦這樣使用鲫竞,第3種使用ModelMap,使用簡(jiǎn)潔逼蒙,推薦使用从绘。
3.5. 附:重定向
在SpringMVC中,當(dāng)需要重定向時(shí)是牢,首先僵井,應(yīng)該保證處理請(qǐng)求的方法的返回值是String類型(與轉(zhuǎn)發(fā)一樣),然后驳棱,返回值使用redirect:作為前綴即可批什,例如:
@RequestMapping("handle_reg.do")
public String handleReg() {
? ? // 假設(shè)注冊(cè)成功,需要登錄
? ? return "redirect:login.do";
}
需要注意的是:在redirect:右側(cè)的不是視圖名社搅,而是重定向的目標(biāo)的路徑驻债,可以是絕對(duì)路徑乳规,也可以是相對(duì)路徑。
當(dāng)處理的請(qǐng)求的返回值類型是String時(shí)合呐,如果返回值使用redirect:作為前綴暮的,是重定向,否則合砂,是轉(zhuǎn)發(fā)青扔!
4. 關(guān)于@RequestMapping注解
通過配置@RequestMapping,可以綁定請(qǐng)求路徑與處理請(qǐng)求的方法翩伪,例如:
@RequestMapping("login.do")
public String showLogin() { ...
即:通過以上配置微猖,當(dāng)接收到login.do請(qǐng)求時(shí),SpringMVC會(huì)自動(dòng)調(diào)用showLogin()方法缘屹。
除了在方法之前添加該注解以外凛剥,該注解還可以添加在控制器類的聲明之前,例如:
@RequestMapping("user")
@Controller
public class UserControler { ...
當(dāng)方法之前添加了該注解之后轻姿,方法內(nèi)配置的所有請(qǐng)求路徑犁珠,在最終訪問時(shí)都必須添加user路徑,例如:http://localhost:8080/SPRINGMVC-02-USER/user/reg.do互亮。
通常犁享,推薦在類之前也添加該注解,方便管理路徑豹休,例如在某個(gè)新聞管理的應(yīng)用中炊昆,可能存在news_list.do、news_info.do的請(qǐng)求威根,而在這個(gè)應(yīng)用中凤巨,也會(huì)有用戶數(shù)據(jù),就存在user_list.do洛搀、user_info.do敢茁,可以發(fā)現(xiàn),為了保證請(qǐng)求路徑是唯一的留美,都需要在路徑之前添加xxx_作為前綴彰檬,這樣的管理方式是非常不方便的,在類之前添加@RequestMapping注解就可以很好的解決這個(gè)問題独榴,每個(gè)路徑之前根本就不需要配置前綴字符僧叉,也不會(huì)發(fā)生沖突!
在@RequestMapping的使用過程中棺榔,路徑可以使用/作為第1個(gè)字符瓶堕,也可以不需要這個(gè)字符,例如:
/user? ? ? /login.do
user? ? ? ? login.do
/user? ? ? login.do
user? ? ? ? /login.do
以上4種配置都是正確的症歇!通常郎笆,推薦使用/作為第1個(gè)字符谭梗,即以上第1種方式!
除了配置請(qǐng)求路徑以外宛蚓,使用@RequestMapping還可以限制請(qǐng)求方式激捏,即某個(gè)路徑可以設(shè)置為只允許POST請(qǐng)求,而不接收GET請(qǐng)求凄吏!
【GET】會(huì)將請(qǐng)求的參數(shù)與值體現(xiàn)在URL中远舅;請(qǐng)求的參數(shù)與值會(huì)受到URL長(zhǎng)度限制,不適用于傳遞大量的數(shù)據(jù)痕钢;
【POST】請(qǐng)求的參數(shù)與值不會(huì)體現(xiàn)在URL中图柏;可以傳遞大量的數(shù)據(jù);
【選取】請(qǐng)求的參數(shù)與值涉及隱私(例如密碼)則必須使用POST任连;數(shù)據(jù)量可能較大時(shí)必須使用POST蚤吹;需要共享URL且其中包含參數(shù)時(shí)必須使用GET;支持頁(yè)面刷新必須使用GET随抠。
【復(fù)雜度】如果要發(fā)出POST請(qǐng)求裁着,只能通過<form>中的<input type="submit" />或<button />,或者通過JS技術(shù)拱她,否則二驰,在Web領(lǐng)域無(wú)法發(fā)出POST請(qǐng)求,而這2種方式也都可以用于發(fā)出GET請(qǐng)求秉沼,除此以外诸蚕,直接在瀏覽器中輸入某個(gè)URL發(fā)出的也是GET請(qǐng)求,總的來說氧猬,發(fā)GET請(qǐng)求要簡(jiǎn)單得多。
【小結(jié)】參考以上“選取”原則坏瘩,選擇請(qǐng)求方式盅抚,如果兩者均可,則使用GET即可倔矾。
在@RequestMapping中配置method屬性可以限制請(qǐng)求類型:
@RequestMapping(value="handle_reg.do",
? ? ? ? method=RequestMethod.POST)
public String handleReg() {
例如以上代碼限制了handle_reg.do必須通過POST方式來請(qǐng)求妄均,如果使用GET方式,則會(huì)返回405錯(cuò)誤哪自!
只有需要限定請(qǐng)求方式時(shí)丰包,才需要顯式的配置value="handlereg.do",否則壤巷,直接將"handlereg.do"配置在注解中即可邑彪!
小結(jié):關(guān)于@RequestMapping注解,主要作用是配置請(qǐng)求路徑胧华,推薦在控制器類和處理請(qǐng)求的方法之前都添加該注解寄症,類之前的注解是用于配置請(qǐng)求路徑中的層次宙彪,方法之前的注解是用于配置請(qǐng)求的資源,關(guān)于路徑的配置是該屬性的value屬性有巧,如果只配置請(qǐng)求路徑释漆,可以不用顯式的聲明這是配置value屬性,而是直接把值寫出來即可篮迎,例如不需要寫成@RequestMapping(values="login.do")男图,而可以直接寫成@RequestMapping("login.do"),在配置路徑時(shí)甜橱,推薦使用/作為第1個(gè)字符逊笆,例如@RequestMapping("/login.do"),如果還需要限制請(qǐng)求方式渗鬼,則必須顯式的聲明路徑為value屬性的值览露,并且添加配置method屬性,例如:@RequestMapping(value="handle_reg.do", method=RequestMethod.POST)譬胎。
5. 關(guān)于@RequestParam注解
使用@RequestParam注解差牛,可以解決請(qǐng)求參數(shù)名稱與處理請(qǐng)求的方法的參數(shù)名稱不一致的問題,例如:
public String handleLogin(
? ? @RequestParam("name") String username,
? ? ? ? String password) { ...
則請(qǐng)求參數(shù)的名稱是name堰乔,而處理請(qǐng)求的方法中的參數(shù)名稱卻是username偏化,這是可以正常運(yùn)行的!
一旦使用了@RequestParam注解镐侯,默認(rèn)情況下侦讨,參數(shù)就是必須的!例如配置了@RequestParam("passwd") String password后苟翻,如果請(qǐng)求中并不存在名為passwd的參數(shù)韵卤,則會(huì)出現(xiàn)400錯(cuò)誤:
HTTP Status 400 - Required String parameter 'passwd' is not present
沒有提交名為passwd的參數(shù),與提交了空值崇猫,是兩碼事沈条!即:如果提交了passwd參數(shù)卻沒有值(例如輸入框中沒有輸入值),在服務(wù)器將得到空字符串("")诅炉,程序并不會(huì)出現(xiàn)錯(cuò)誤蜡歹!如果根本就沒有提交名為passwd的參數(shù),則會(huì)導(dǎo)致400錯(cuò)誤涕烧!
如果使用了@RequestParam注解月而,卻又不想設(shè)置為必須提交該參數(shù),可以:
@RequestParam(value="name", required=false)
則將根據(jù)name去接收參數(shù)议纯,如果有值父款,會(huì)正確接收,如果沒有(沒有提交該名稱的參數(shù)),則會(huì)是null值铛漓!
當(dāng)required=false時(shí)溯香,意味著可以不必提交該參數(shù),還可以多配置一項(xiàng)defaultValue屬性(The default value to use as a fallback when the request parameter value is not provided or empty. Supplying a default value implicitly sets required() to false.)浓恶,表示如果請(qǐng)求中沒有提交該參數(shù)玫坛,則默認(rèn)值是多少!例如:
@RequestParam(value="passwd", required=false, defaultValue="888999") String password
以上代碼表示:希望請(qǐng)求中包含名為passwd的參數(shù)包晰,如果有湿镀,則值用于方法的String password的參數(shù),如果沒有伐憾,也不是必須要提供(required=false)勉痴,并且使用"888999"作為默認(rèn)值(defaultValue="888999"),即:在這種情況下树肃,String password的值是"888999"蒸矛。
小結(jié):@RequestParam注解是用于處理請(qǐng)求的方法中的參數(shù)之前,可以配置3項(xiàng)屬性胸嘴,分別是value表示請(qǐng)求參數(shù)名稱雏掠,required表示請(qǐng)求中是否必須包含該參數(shù),defaultValue表示參數(shù)的默認(rèn)值劣像,當(dāng)有以上任何一種需求時(shí)乡话,都需要配置該注解,即:請(qǐng)求參數(shù)名稱與處理請(qǐng)求的方法的參數(shù)名稱不一致耳奕;強(qiáng)制必須提交某個(gè)參數(shù)绑青;為某個(gè)參數(shù)配置默認(rèn)值。