學(xué)習(xí)視頻:孫哥說(shuō)SpringMVC:結(jié)合Thymeleaf,重塑你的MVC世界?。八从械腤eb開(kāi)發(fā)探索之旅
第三章、SpringMVC控制器開(kāi)發(fā)詳解
3.1 核心要點(diǎn)
?? 1. 接受客戶(hù)端(client)請(qǐng)求參數(shù)[講解] 2. 調(diào)用業(yè)務(wù)對(duì)象 3. 頁(yè)面跳轉(zhuǎn)3.2 控制器接受客戶(hù)端(client)請(qǐng)求參數(shù)詳解
3.2.1 回顧:Web開(kāi)發(fā)中如何接受Client請(qǐng)求參數(shù)
3.2.2 基于Servlet API接受Client請(qǐng)求參數(shù)
@Controller
@RequestMapping("/param")
public class ParamController {
@RequestMapping("param1")
public String param(HttpServletRequest request) {
String name = request.getParameter("name");
String password = request.getParameter("password");
System.out.println("name = " + name);
System.out.println("password = " + password);
return "param1";
}
}
**注意:這種方式雖然最為直觀,簡(jiǎn)單,但是代碼冗余且與ServletAPI存在耦合,所以在SpringMVC開(kāi)發(fā)中并不建議使用**
3.2.3 基于簡(jiǎn)單變量接受Client請(qǐng)求參數(shù)
- 所謂簡(jiǎn)單變量:指的就是8種基本類(lèi)型+String這些類(lèi)型的變量。把這些類(lèi)型的變量,作為控制器方法的形參,用于接受client提交的數(shù)據(jù)。
- 思路分析
-
代碼
@Controller @RequestMapping("/param") public class ParamController { @RequestMapping("param2") public String param2(String name,String password) { System.out.println("name = " + name); System.out.println("password = " + password); return "param1"; } }
-
細(xì)節(jié)分析
-
常見(jiàn)類(lèi)型自動(dòng)轉(zhuǎn)換
@RequestMapping("param3") public String param3(String name,int age) { System.out.println("name = " + name); System.out.println("age = " + age); return "param1"; } SpringMVC底層針對(duì)age接受數(shù)據(jù)時(shí)會(huì)自動(dòng)調(diào)用 int age = Integer.parseInt("10")
- 常見(jiàn)類(lèi)型泛指:8種基本類(lèi)型及其包裝器,String等常見(jiàn)類(lèi)型。
- Date日期等特殊類(lèi)型,默認(rèn)不支持,需要程序員自定義類(lèi)型轉(zhuǎn)換器【后續(xù)講解】
-
基本類(lèi)型盡量使用包裝器
客戶(hù)端請(qǐng)求:http://localhost:8989/param/param/param3?name=jack @Controller @RequestMapping("/param") public class ParamController { @RequestMapping("param3") public String param3(String name,int age) { System.out.println("name = " + name); System.out.println("age = " + age); return "param1"; } } 程序報(bào)錯(cuò):原因在于age沒(méi)有提交內(nèi)容,等同于null,而int是基本類(lèi)型無(wú)法存儲(chǔ)null值,所以報(bào)錯(cuò) 改正方式:1.age參數(shù)使用包裝器類(lèi)型,可以存儲(chǔ)null值 2.為age參數(shù)設(shè)置默認(rèn)值,需要@RequestParam注解配合使用。
-
3.2.4 基于POJO類(lèi)型接受Client請(qǐng)求參數(shù)
- 什么是POJO
- POJO全稱(chēng)叫做 Plain Ordinary Java Object(簡(jiǎn)單的Java對(duì)象)
- POJO類(lèi)型對(duì)象的特點(diǎn)是:
- 類(lèi)型中如果存在成員變量,必須提供set get
- 提供默認(rèn)無(wú)參構(gòu)造
- 可以實(shí)現(xiàn)Serializable,也可以不實(shí)現(xiàn)
- 不實(shí)現(xiàn)容器或者框架所規(guī)定的接口
- 用戶(hù)根據(jù)業(yè)務(wù)封裝的實(shí)體,DTO這些類(lèi)型就是POJO
- 使用場(chǎng)景
準(zhǔn)備一個(gè)實(shí)體,成員變量名字要和表單的name對(duì)應(yīng),其次在控制器方法中,將POJO類(lèi)作為形參類(lèi)型定義在控制器方法參數(shù)中。
-
代碼
// POJO public class User implements Serializable { private String name; private String password; private int age; // Controller @RequestMapping("param4") public String param4(User user) { System.out.println("user = " + user); return "param1"; } // 表單請(qǐng)求 <form method="post" action="${pageContext.request.contextPath}/param/param4"> UserName <input type="text" name="name"><br> Password <input type="text" name="password"><br> Age <input type="text" name="age"><br> <input type="submit" value="reg"> </form> **POJO的成員變量的名字要和請(qǐng)求參數(shù)的key或者表單name屬性的值嚴(yán)格對(duì)應(yīng)**
-
注意1.提交的表單中的name和控制器方法的name同名,那么誰(shuí)會(huì)獲取到內(nèi)容?
http://localhost:8989/param/param/param4?name=小明&age=12&password=12 @RequestMapping("param4") public String param4(**String name**,User user) { System.out.println("user = " + user); return "param1"; } **name形參與user對(duì)象的name屬性都會(huì)獲取對(duì)應(yīng)的內(nèi)容,這個(gè)特定在后續(xù)前后端分離中會(huì)使用。**
-
注意2.
- 如果SpringMVC發(fā)現(xiàn)控制器形參類(lèi)型,是8種基本類(lèi)型+String的話,他會(huì)通過(guò)形參名與請(qǐng)求參數(shù)的key對(duì)象,接受數(shù)據(jù)
- 如果SpringMVC發(fā)現(xiàn)控制器形參類(lèi)型,不是8種基本類(lèi)型+String的話,他會(huì)通過(guò)形參類(lèi)型的屬性名與請(qǐng)求參數(shù)的key對(duì)象,接受數(shù)據(jù)
- 如果存在自定義類(lèi)型轉(zhuǎn)換器不適用于上述規(guī)律
3.2.5 接受一組簡(jiǎn)單變量的請(qǐng)求參數(shù)
- 使用場(chǎng)景
-
代碼
@RequestMapping("param5") public String param5(Integer[] ids) { for (Integer id : ids) { System.out.println("id = " + id); } return "param1"; } // checkbox表單 <form method="post" action="${pageContext.request.contextPath}/param/param5"> <input type="checkbox" name="ids" value="1"><br> <input type="checkbox" name="ids" value="2"><br> <input type="checkbox" name="ids" value="3"><br> <input type="checkbox" name="ids" value="4"><br> <input type="checkbox" name="ids" value="5"><br> <input type="submit" value="reg"> </form>
-
細(xì)節(jié)分析 以List類(lèi)舉例
@RequestMapping("param6") public String param6(ArrayList<Integer> ids) { for (Integer id : ids) { System.out.println("id = " + id); } return "param1"; } 沒(méi)有異常,但接收不到數(shù)據(jù):SpringMVC會(huì)按照POJO的匹配方式,進(jìn)行成員變量查找 @RequestMapping("param6") public String param6(List<Integer> ids) { for (Integer id : ids) { System.out.println("id = " + id); } return "param1"; } 拋出異常:SpringMVC無(wú)法提供具體的實(shí)現(xiàn)類(lèi)、實(shí)例化形參
3.2.6 接收一組POJO類(lèi)型對(duì)象的請(qǐng)求參數(shù)
- 使用場(chǎng)景
按照POJO的匹配方式,對(duì)于非8種基本類(lèi)型的方法形參,只有將List實(shí)例化作為成員變量封裝在POJO類(lèi)中,并將這個(gè)類(lèi)作為形參才能正確接收數(shù)據(jù)。
-
代碼
**// POJO類(lèi)** public class UsersDTO { private List<User> users = new ArrayList<>(); public List<User> getUsers() { return users; } public void setUsers(List<User> users) { this.users = users; } } **//Controller類(lèi)** @RequestMapping("param7") public String param7(UsersDTO usersDTO) { List<User> users = usersDTO.getUsers(); for (User user : users) { System.out.println("user = " + user); } return "param1"; } **//JSP頁(yè)** <form method="post" action="${pageContext.request.contextPath}/param/param7"> UserName <input type="text" name="users[0].name"><br> Password <input type="text" name="users[0].password"><br> Age <input type="text" name="users[0].age"><br> <hr> UserName <input type="text" name="users[1].name"><br> Password <input type="text" name="users[1].password"><br> Age <input type="text" name="users[1].age"><br> <input type="submit" value="submit"> </form>
3.3 接收Client請(qǐng)求參數(shù)的總結(jié)
3.4@RequestParam注解
作用:用于修飾控制器方法的形參
@RequestMapping("param2")
public String param2(@RequestParam String name,@RequestParam String password)
3.4.1 @RequestParam注解詳解
-
解決請(qǐng)求參數(shù)與方法形參名字不一致的問(wèn)題
Http請(qǐng)求:http://localhost:8989/param/param1/param1?n=jack&p=1234 @RequestMapping("/param1") public String param1(@RequestParam("n") String name, @RequestParam("p") String password) { System.out.println("name = " + name); System.out.println("password = " + password); return "param1"; }
-
注意
-
@RequestParam注解簡(jiǎn)寫(xiě)形式:不書(shū)寫(xiě)value書(shū)寫(xiě)的內(nèi)容,@RequestParam默認(rèn)會(huì)把對(duì)應(yīng)形參名作為value屬性的值
-
使用了@RequestParam注解的形參,客戶(hù)端必須傳遞數(shù)據(jù),不能省略,否則報(bào)錯(cuò)。
-
POJO類(lèi)型的形參,不能與@RequestParam注解聯(lián)用。會(huì)報(bào)400錯(cuò)誤
-
典型的應(yīng)用場(chǎng)景
htpp請(qǐng)求:http://localhost:8989/param/paramController/param1?id≤10 @RequestMapping("/param1") public String param1(@RequestParam("id<") Integer id) { } **當(dāng)提交的數(shù)據(jù)參數(shù)名不符合java的變量命名規(guī)則時(shí),可以采用這種方式**
-
-
@RequestParam的required屬性
required = true時(shí):@RequestParam修飾的控制器方法參數(shù),客戶(hù)端必須提交數(shù)據(jù),否則報(bào)錯(cuò),默認(rèn)值
required = false時(shí):@RequestParam修飾的控制器方法參數(shù),客戶(hù)端可以不提交數(shù)據(jù),不會(huì)報(bào)錯(cuò)
解決了使用@RequestParam注解時(shí),客戶(hù)端必須傳遞數(shù)據(jù)的問(wèn)題。
-
@RequestParam的defaultValue屬性
-
客戶(hù)端沒(méi)有提交數(shù)據(jù)的時(shí)候,給對(duì)應(yīng)的形參提供默認(rèn)值
http://localhost:8989/param/paramController/param1?name=jack @RequestMapping("/param4") public String param4(@RequestParam String name, @RequestParam(defaultValue="9999") String password) { System.out.println("name = " + name); System.out.println("password = " + password); return "param1"; } 注意:如果使用了defaultValue,則required屬性也默認(rèn)設(shè)置成了false
-
解決控制器方法形參,使用包裝器的問(wèn)題
@RequestMapping("param6") public String param6(@RequestParam(defaultValue = "0") int age) { System.out.println("age = " + age); return "param1"; }
-
defaultValue典型的使用場(chǎng)景
默認(rèn)值操作,一個(gè)典型的應(yīng)用場(chǎng)景是:分頁(yè)首頁(yè)查詢(xún),不傳頁(yè)號(hào)的設(shè)計(jì)
http://localhost:8989/param/page/findall http://localhost:8989/param/page/findall?pageNum=2 @RequestMapping("findall") public String findall(@RequestParam(defaultValue = "0") int pageNum) { }
-
3.5 中文請(qǐng)求參數(shù)的亂碼問(wèn)題
3.5.1 回顧JavaWeb開(kāi)發(fā)中 中文亂碼的解決方案
- GET請(qǐng)求亂碼的解決方案
- POST請(qǐng)求亂碼的解決方案
3.5.2 SpringMVC解決中文字符集亂碼
-
GET請(qǐng)求的中文亂碼
UTF-8字符集,Tomcat8已經(jīng)內(nèi)部處理,無(wú)需我們處理。GBK字符集或者Tomcat8以前版本,需要配置server.xml
-
POST請(qǐng)求的中文亂碼,SpringMVC提供了過(guò)濾器解決
org.springframework.web.filter.CharacterEncodingFilter
-
web.xml配置(通過(guò)alt+insert插入)
<filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
3.6 SpringMVC的類(lèi)型轉(zhuǎn)換器
3.6.1 SpringMVC中的內(nèi)置類(lèi)型轉(zhuǎn)換器
- 分析
-
內(nèi)置類(lèi)型轉(zhuǎn)換器的概念
-
SpringMVC中提供了內(nèi)置類(lèi)型轉(zhuǎn)換器,把客戶(hù)端提交的字符串類(lèi)型的請(qǐng)求參數(shù),轉(zhuǎn)換承控制器方法參數(shù)需要的數(shù)據(jù)類(lèi)型
-
SpringMVC并不是對(duì)于所有的類(lèi)型,都提供了內(nèi)置的類(lèi)型轉(zhuǎn)換器,他只是提供了常見(jiàn)類(lèi)型的轉(zhuǎn)換器
比如:8種基本類(lèi)型,常見(jiàn)的集合類(lèi)型等
-
-
原理分析
3.6.2 SpringMVC中自定義類(lèi)型轉(zhuǎn)換器
SpringMVC在接收客戶(hù)端提交請(qǐng)求參數(shù)時(shí),如果請(qǐng)求參數(shù)對(duì)應(yīng)的控制器方法形參,是非常規(guī)數(shù)據(jù)類(lèi)型,SpringMVC默認(rèn)情況下無(wú)法進(jìn)行類(lèi)型轉(zhuǎn)換。會(huì)拋出異常,程序員可以通過(guò)自定義類(lèi)型轉(zhuǎn)換器解決上述問(wèn)題。例如:日期類(lèi)型
- 開(kāi)發(fā)思路
-
編碼
**// 實(shí)現(xiàn)Converter<S,T>接口** public class DateConverter implements Converter<String, Date> { @Override public Date convert(String source) { Date date = null; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); try { date = sdf.parse(source); } catch (ParseException e) { e.printStackTrace(); } return date; } } // **配置類(lèi)型轉(zhuǎn)換器,讓Spring進(jìn)行對(duì)象的創(chuàng)建** <bean id="dateConverter" class="com.baizhi.DateConverter"/> // **進(jìn)行類(lèi)型轉(zhuǎn)換器注冊(cè),讓SpringMVC能夠識(shí)別日期類(lèi)型轉(zhuǎn)換的類(lèi)型轉(zhuǎn)換器-->** <bean id="serviceFactoryBean" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <set> <ref bean="dateConverter"/> </set> </property> </bean> // **最后一步** <mvc:annotation-driven conversion-service="serviceFactoryBean"/> // **上述第一步 第二步可以合二為一** <bean id="formattingConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <set> <bean id="converter" class="com.baizhi.DateConverter"/> </set> </property> </bean>
3.7 接收其他請(qǐng)求數(shù)據(jù)
3.7.1 動(dòng)態(tài)參數(shù)收集
-
單值動(dòng)態(tài)參數(shù)收集(一個(gè)key對(duì)應(yīng)一個(gè)請(qǐng)求數(shù)據(jù))
http://localhost:8989/param/param2/param1?name=suns http://localhost:8989/param/param2/param1?age=10 @RequestMapping("/param1") public String param1(@RequestParam Map<String, String> params) { Set<String> keys = params.keySet(); for (String key : keys) { System.out.println("key = " + key+",value = "+params.get(key)); } return "param1"; } **注意:如果需要接收動(dòng)態(tài)參數(shù),必須保證Map的形參前面加入@RequestParam注解,否則接收不到數(shù)據(jù)**
-
多值動(dòng)態(tài)參數(shù)收集(一個(gè)key對(duì)應(yīng)多個(gè)請(qǐng)求數(shù)據(jù))
http://localhost:8989/param/param2/param1?id=2&id=3&id=4 **第一種解決思路:通過(guò)數(shù)組形參接收請(qǐng)求參數(shù)** @RequestMapping("param5") public String param5(Integer[] ids) { for (Integer id : ids) { System.out.println("id = " + id); } return "param1"; } 存在的問(wèn)題:請(qǐng)求參數(shù)的key發(fā)生改變就接收不到請(qǐng)求數(shù)據(jù) 第二種解決思路:通過(guò)MultiValueMap<K,V> 接收請(qǐng)求參數(shù) @RequestMapping("/param2") public String param2(@RequestParam MultiValueMap<String, String> params) { Set<String> keys = params.keySet(); for (String key : keys) { List<String> values = params.get(key); System.out.println("key = " + key); for (String value : values) { System.out.println("value = " + value); } } return "param1"; }
-
典型應(yīng)用場(chǎng)景
3.7.2 接收cookie數(shù)據(jù)
- 回顧Servlet中獲取的方式
-
SpringMVC獲取Cookie的方式
測(cè)試Cookie 通過(guò)postman測(cè)試 @RequestMapping("/param4") public String param4(@CookieValue("name") String value) { System.out.println("value = " + value); return "param1"; } 推薦使用@CookieValue獲取cookie @RequestMapping("/param3") public String param3(HttpServletRequest request) { Cookie[] cookies = request.getCookies(); for (Cookie cookie : cookies) { if ("name".equals(cookie.getName())) { System.out.println("cookie.getValue() = " + cookie.getValue()); } } return "param1"; } 這種方式基于Servlet API存在耦合,不推薦使用。
3.7.3 接收請(qǐng)求頭數(shù)據(jù)
- 什么是請(qǐng)求頭
- 獲取請(qǐng)求頭的方式
-
Servlet中的獲取方式
核心代碼 String value = request.getHeader("key");
-
SpringMVC中的獲取方式文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-747313.html
@RequestMapping("/param6") public String param6(@RequestHeader("Host") String host) { System.out.println("host = " + host); return "param1"; } 推薦使用@RequestHeader的方式獲取請(qǐng)求頭 @RequestMapping("/param5") public String param5(HttpServletRequest request) { String host = request.getHeader("Host"); System.out.println("host = " + host); return "param1"; } 這種方式存在與Servlet API的耦合問(wèn)題,不建議后續(xù)使用
-
下一章:Spring MVC學(xué)習(xí)隨筆-控制器(Controller)開(kāi)發(fā)詳解:調(diào)用業(yè)務(wù)對(duì)象、父子工廠拆分(applicationContext.xml、dispatcher.xml)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-747313.html
到了這里,關(guān)于Spring MVC學(xué)習(xí)隨筆-控制器(Controller)開(kāi)發(fā)詳解:接受客戶(hù)端(Client)請(qǐng)求參數(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!