1吨艇、SpringMVC的概述:
? Spring 為展現(xiàn)層提供的基于 MVC 設(shè)計(jì)理念的優(yōu)秀的Web 框架杯缺,是目前最主流的 MVC 框架之一
? Spring3.0 后全面超越 Struts2,成為最優(yōu)秀的 MVC 框架
? Spring MVC 通過一套 MVC 注解哨免,讓 POJO 成為處理請(qǐng)求的控制器,而無須實(shí)現(xiàn)任何接口。
? 支持 REST 風(fēng)格的 URL 請(qǐng)求
? 采用了松散耦合可插拔組件結(jié)構(gòu)犀被,比其他 MVC 框架更具擴(kuò)展性和靈活性
2、第一個(gè)Hellow
1外冀、步驟:
– 加入 jar 包 – 在 web.xml 中配置 DispatcherServlet
– 加入 Spring MVC 的配置文件
– 編寫處理請(qǐng)求的處理器寡键,并標(biāo)識(shí)為處理器
– 編寫視圖
1.1、jar包:
1.2锥惋、配置 web.xml昌腰,spring-mvc.xml:
1.2.1、配置 DispatcherServlet(web.xml) :
DispatcherServlet 默認(rèn)加載 /WEB-INF/<servletName-servlet>.xml 的 Spring 配置文件, 啟動(dòng) WEB 層 的 Spring 容器膀跌≡馍蹋可以通過 contextConfigLocation 初始化參數(shù)自定義配置文件的位置和名稱
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置文件方法二:使用默認(rèn)配置地址
默認(rèn)的配置文件為: /WEB-INF/<servlet-name>-servlet.xml
-->
<!--配置文件方法一:指定地址檢索,
contextConfigLocation 來配置 SpringMVC 的配置文件
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-mvc.xml</param-value>
</init-param>-->
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
配置詳解:
1.2.2捅伤、配置自動(dòng)掃描的包(spring-mvc.xml):
<!--配置自定義掃描包-->
<context:component-scan base-package="com.kk"/>
名稱空間補(bǔ)充:
1.2.3劫流、配置視圖解析器:
視圖名稱解析器:將視圖邏輯名解析為: /WEB-INF/pages/<viewName>.jsp
<!--配置視圖解析器: 如果把 handler 方法返回值解析為實(shí)際的物理視圖-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/><!--前置目錄-->
<property name="suffix" value=".jsp"/><!--后綴-->
</bean>
1.3、創(chuàng)建請(qǐng)求處理器類:
@Controller//此注解將類標(biāo)記為控制層
public class HelloWorld {
@RequestMapping("/hello")//此注解可映射方法或者類為url
public String hello() {
System.out.println ("helloworld...");
return "success";
}
}
對(duì)應(yīng)的view:
1.4、手繪流程圖:
3祠汇、@RequestMapping 映射請(qǐng)求
1.1仍秤、概述:
1、 Spring MVC 使用 @RequestMapping 注解為控制器指定可以處理哪些 URL 請(qǐng)求
2可很、 在控制器的類定義及方法定義處都可標(biāo)注 :
@RequestMapping
– 類定義處:提供初步的請(qǐng)求映射信息诗力。相對(duì)于 WEB 應(yīng)用的根目錄
– 方法處:提供進(jìn)一步的細(xì)分映射信息。相對(duì)于類定義處的 URL我抠。
若類定義處未標(biāo)注 @RequestMapping苇本,則方法處標(biāo)記的 URL 相對(duì)于WEB 應(yīng)用的根目錄
3、 DispatcherServlet 截獲請(qǐng)求后菜拓,就通過控制器上
@RequestMapping 提供的映射信息確定請(qǐng)求所對(duì)應(yīng)的處理方法瓣窄。
2、使用@RequestMappiing示例:
@Controller//此注解將類標(biāo)記為控制層
@RequestMapping("/hello")//限定所有請(qǐng)求纳鼎,部署的根路徑
public class HelloWorld {
@RequestMapping("/SpringMVC")//可定義多個(gè)方法俺夕,加上注解來處理
public String hello() {
System.out.println ("helloworld...");
return "success";
}
}
3、映射請(qǐng)求參數(shù)贱鄙、請(qǐng)求方法或請(qǐng)求頭:
3.1劝贸、標(biāo)準(zhǔn)的請(qǐng)求頭:
3.2、@RequestMapping 除了可以使用請(qǐng)求 URL 映射請(qǐng)求外贰逾,還可以使用請(qǐng)求方法悬荣、請(qǐng)求參數(shù)及請(qǐng)求頭映射請(qǐng)求
3.3、@RequestMapping 的 value疙剑、method氯迂、params 及 heads 分別表示請(qǐng)求 URL、請(qǐng)求方法言缤、請(qǐng)求參數(shù)及請(qǐng)求頭的映射條件嚼蚀,他們之間是與的關(guān)系,聯(lián)合使用多個(gè)條件可讓請(qǐng)求映射更加精確化管挟。
3.4轿曙、params 和 headers支持簡單的表達(dá)式:
能進(jìn)入的訪問地址:http://localhost:8081/mvc/testParamsAndHeaders?username&age=1 (請(qǐng)求頭Accept-Language=en-US,zh;q=0.8)
@RequestMapping(value = "testParamsAndHeaders", params = { "username",
"age!=10" }, headers = { "Accept-Language=en-US,zh;q=0.8" })
public String testParamsAndHeaders() {
System.out.println("testParamsAndHeaders");
return SUCCESS;
}
4、@RequestMapping 映射請(qǐng)求支持的風(fēng)格:
案例:
訪問地址:http://localhost:8081/mvc/testAntPath/xxxxxsa/abc
@RequestMapping(value = "testAntPath/*/abc")
public String testAntPath()
{
System.out.println ("testAntPath " );
return SUCCESS;
}
5僻孝、@PathVariable 映射 URL 綁定的占位符
概述:
1导帝、 帶占位符的 URL 是 Spring3.0 新增的功能,該功能在SpringMVC 向 REST 目標(biāo)挺進(jìn)發(fā)展過程中具有里程碑的意義
2穿铆、 通過 @PathVariable 可以將 URL 中占位符參數(shù)綁定到控制器處理方法的入?yún)⒅校篣RL 中的 {xxx} 占位符可以通過 @PathVariable("xxx") 綁定到操作方法的入?yún)⒅小?/p>
訪問地址:http://localhost:8081/mvc/testPathVariable/16
@RequestMapping("/testPathVariable/{id}")
public String testPathVariable(@PathVariable("id") Integer id) {
System.out.println("testPathVariable: " + id);
return SUCCESS;
}
6您单、Rest風(fēng)格:
案例:
@RequestMapping(value = "testParamsAndHeaders", params = { "username",
"age!=10" }, headers = { "Accept-Language=en-US,zh;q=0.8" })
public String testParamsAndHeaders() {
System.out.println("testParamsAndHeaders");
return SUCCESS;
}
正確訪問地址:
RestTest.java
@Controller
@RequestMapping("springmvc")
public class RestTest {
@RequestMapping(value = "testRest", method = RequestMethod.POST)
public String hello1() {
System.out.println ("當(dāng)前是添加操作");
return "success";
}
@RequestMapping(value = "testRest/{id}", method = RequestMethod.DELETE)
public String hello2(@PathVariable Integer id) {
System.out.println ("當(dāng)前是刪除操作,得到的id:"+id);
return "success";
}
@RequestMapping(value = "testRest/{id}", method = RequestMethod.PUT)
public String hello3(@PathVariable Integer id) {
System.out.println ("當(dāng)前是更新操作荞雏,得到的id:"+id);
return "success";
}
@RequestMapping(value = "testRest/{id}", method = RequestMethod.GET)
public String hello4(@PathVariable Integer id) {
System.out.println ("當(dāng)前是查詢操作虐秦,得到的id:"+id);
return "success";
}
}
index.jsp
<%--注: .action 是配置了后綴攔截--%>
<form action="springmvc/testRest.action" method="post">
<input type="submit" value="添加操作">
</form><br>
<form action="springmvc/testRest/1.action" method="post">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="刪除操作">
</form><br>
<form action="springmvc/testRest/1.action" method="post">
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="更新操作">
</form><br>
<a href="springmvc/testRest/1.action">查詢操作</a>
前提:在web.xml上配置Rest請(qǐng)求轉(zhuǎn)換:
<!--
配置 org.springframework.web.filter.HiddenHttpMethodFilter: 可以把 POST 請(qǐng)求轉(zhuǎn)為 DELETE 或 POST 請(qǐng)求
-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注意:此處可能出現(xiàn)jsp不支持post平酿,請(qǐng)求頭加上isErrorPage="true",默認(rèn)為false
4悦陋、映射請(qǐng)求參數(shù) & 請(qǐng)求頭
1蜈彼、概述:
2、@RequestParam 綁定請(qǐng)求參數(shù)值
? 在處理方法入?yún)⑻幨褂?@RequestParam 可以把請(qǐng)求參數(shù)傳遞給請(qǐng)求方法
– value:參數(shù)名
– required:是否必須俺驶。默認(rèn)為 true, 表示請(qǐng)求參數(shù)中必須包含對(duì)應(yīng)的參數(shù)幸逆,若不存在,將拋出異常
測試地址:http://localhost:8081/mvc/testRequestParam?username=大根
@RequestMapping("testRequestParam")
public String testRequestParam(@RequestParam(value = "username") String name,
@RequestParam(value = "age",required = false,defaultValue = "0") int age){
System.out.println ("第一個(gè)參數(shù)值:"+name+",第二個(gè)無傳入痒钝,默認(rèn)值:"+age );
return SUCCESS;
}
3秉颗、@RequestHeader 綁定請(qǐng)求報(bào)頭的屬性值
請(qǐng)求頭包含了若干個(gè)屬性,服務(wù)器可據(jù)此獲知客戶端的信息送矩,通過 @RequestHeader 即可將請(qǐng)求頭中的屬性值綁定到處理方法的入?yún)⒅?/p>
測試地址:http://localhost:8081/mvc/testRequestHeader
@RequestMapping("testRequestHeader")
public String testRequestHeader(
@RequestHeader("Accept-Language") String al )
{
System.out.println ("請(qǐng)求頭中Accept-Language值為:"+al );
return SUCCESS;
}
4、@CookieValue 綁定請(qǐng)求中的 Cookie 值
@CookieValue 可讓處理方法入?yún)⒔壎硞€(gè) Cookie 值
測試地址:http://localhost:8081/mvc/testCookieValue
@RequestMapping("testCookieValue")
public String testCookieValue(
@CookieValue("JSESSIONID") String sessionId )
{
System.out.println ("Cookie中Session的 ID:"+sessionId );
return SUCCESS;
}
5哪替、POJO 對(duì)象綁定請(qǐng)求參數(shù)值
Spring MVC 會(huì)按請(qǐng)求參數(shù)名和 POJO 屬性名進(jìn)行自動(dòng)匹配栋荸,自動(dòng)為該對(duì)象填充屬性值。支持級(jí)聯(lián)屬性凭舶。
如:dept.deptId晌块、dept.address.tel 等
測試地址:http://localhost:8081/mvc/testPojo?uid=2&uname=%E5%A4%A7%E6%A0%B9&age=11
@RequestMapping("testPojo")
public String testPojo(User user)
{
System.out.println ("用戶的對(duì)象的屬性值:"+user );
return SUCCESS;
}
6、Servlet API 作為入?yún)?/p>
測試地址:http://localhost:8081/mvc/testServletApi
/**
* HttpServletRequest
* HttpServletResponse
* HttpSession
* java.security.Principal
* Locale InputStream
* OutputStream
* Reader
* Writer
*
* @return
*/
@RequestMapping("testServletApi")
public void testServletApi(HttpServletRequest req, HttpServletResponse resp, Writer out)
throws IOException {
System.out.println ("testServletApi:"+req+resp);
out.write ("hello kk");
//return SUCCESS;
}
5帅霜、處理模型數(shù)據(jù)
概:
Spring MVC 提供了以下幾種途徑輸出模型數(shù)據(jù):
– ModelAndView: 處理方法返回值類型為 ModelAndView時(shí), 方法體即可通過該對(duì)象添加模型數(shù)據(jù)
– Map 及 Model: 入?yún)椋簅rg.springframework.ui.Model匆背、org.springframework.ui.ModelMap 或 java.uti.Map 時(shí),處理方法返回時(shí)身冀,Map 中的數(shù)據(jù)會(huì)自動(dòng)添加到模型中钝尸。
– @SessionAttributes: 將模型中的某個(gè)屬性暫存到HttpSession 中,以便多個(gè)請(qǐng)求之間可以共享這個(gè)屬性
– @ModelAttribute: 方法入?yún)?biāo)注該注解后, 入?yún)⒌膶?duì)象就會(huì)放到數(shù)據(jù)模型中
1搂根、ModelAndView:
1.1珍促、 控制器處理方法的返回值如果為 ModelAndView, 則其既包含視圖信息,也包含模型數(shù)據(jù)信息剩愧。
1.2猪叙、 添加模型數(shù)據(jù):
– MoelAndView addObject(String attributeName, Object attributeValue)
– ModelAndView addAllObject(Map<String, ?> modelMap)
1.3、 設(shè)置視圖: – void setView(View view) – void setViewName(String viewName)j
@RequestMapping("testModelAndView")
public ModelAndView testModelAndView() {
String viewName = SUCCESS;
ModelAndView modelAndView = new ModelAndView (viewName);
modelAndView.addObject ("time",new Date ());
return modelAndView;
}
----------------------------------------------------------------------------------------------------------------------
jsp頁面:
<body>
Time: ${requestScope.time}<br>
map: ${requestScope.names}<br>
</body>
2仁卷、Map及Model
概:
@RequestMapping("testMap")
public String testMap(Map<String,Object> map) {
//實(shí)際上也可以是Model類型或者M(jìn)odelMap
//org.springframework.validation.support.BindingAwareModelMap
System.out.println (map.getClass ().getName () );
map.put ("names", Arrays.asList ("Tom","kk","mike"));
System.out.println (map );
return SUCCESS;
}
----------------------------------------------------------------------------------------------------------------------
jsp頁面:
<body>
Time: ${requestScope.time}<br>
map: ${requestScope.names}<br>
</body>
BindingAwareModelMap繼承圖:
因?yàn)閭魅氲膍ap 實(shí)際上是BindingAwareModelMap(MVC處理的)
3穴翩、@SessionAttributes
@Controller
//value內(nèi)可以指定多個(gè);存入session域中锦积,并且也存入request域一份
//types如果類型是String芒帕,map.put(key,value)中的value是字符串的話也會(huì)存入Session中,如果不是只會(huì)存到request
@SessionAttributes(value = {"user"},types = {String.class})//該注解只能放類上
public class RestTest {
public static final String SUCCESS = "success";
@RequestMapping("testSessionAtt")
public String testSessionAtt(Map<String,Object> map)
{
User user = new User (1, "kk", 27);
map.put ("user",user);
map.put ("sex",1);
map.put ("age","18");
return SUCCESS;
}
-----------------------------------------jsp頁面-------------------------------------------------------------------------------------------
user--request: ${requestScope.user}<br>
user--session: ${sessionScope.user}<br>
sex--request: ${requestScope.sex}<br>
sex--session: ${sessionScope.sex}<br>//這個(gè)沒有值,其他都有
age--request: ${requestScope.age}<br>
age--session: ${sessionScope.age}<br>
4充包、@ModelAttribute(重點(diǎn))
1副签、概要:
2遥椿、案例流程:
3、@ModelAttribute詳解淆储,說明
/**
* 1. 有 @ModelAttribute 標(biāo)記的方法, 會(huì)在每個(gè)目標(biāo)方法執(zhí)行之前被 SpringMVC 調(diào)用!
* 2. @ModelAttribute 注解也可以來修飾目標(biāo)方法 POJO 類型的入?yún)? 其 value 屬性值有如下的作用:
* 1). SpringMVC 會(huì)使用 value 屬性值在 implicitModel 中查找對(duì)應(yīng)的對(duì)象, 若存在則會(huì)直接傳入到目標(biāo)方法的入?yún)⒅?
* 2). SpringMVC 會(huì)一 value 為 key, POJO 類型的對(duì)象為 value, 存入到 request 中.
*/
/**
* 運(yùn)行流程:
* 1. 執(zhí)行 @ModelAttribute 注解修飾的方法: 從數(shù)據(jù)庫中取出對(duì)象, 把對(duì)象放入到了 Map 中. 鍵為: user
* 2. SpringMVC 從 Map 中取出 User 對(duì)象, 并把表單的請(qǐng)求參數(shù)賦給該 User 對(duì)象的對(duì)應(yīng)屬性.
* 3. SpringMVC 把上述對(duì)象傳入目標(biāo)方法的參數(shù).
*
* 注意: 在 @ModelAttribute 修飾的方法中, 放入到 Map 時(shí)的鍵需要和目標(biāo)方法入?yún)㈩愋偷牡谝粋€(gè)字母小寫的字符串一致!
*
* SpringMVC 確定目標(biāo)方法 POJO 類型入?yún)⒌倪^程
* 1. 確定一個(gè) key:
* 1). 若目標(biāo)方法的 POJO 類型的參數(shù)木有使用 @ModelAttribute 作為修飾, 則 key 為 POJO 類名第一個(gè)字母的小寫
* 2). 若使用了 @ModelAttribute 來修飾, 則 key 為 @ModelAttribute 注解的 value 屬性值.
* 2. 在 implicitModel 中查找 key 對(duì)應(yīng)的對(duì)象, 若存在, 則作為入?yún)魅? * 1). 若在 @ModelAttribute 標(biāo)記的方法中在 Map 中保存過, 且 key 和 1 確定的 key 一致, 則會(huì)獲取到.
* 3. 若 implicitModel 中不存在 key 對(duì)應(yīng)的對(duì)象, 則檢查當(dāng)前的 Handler 是否使用 @SessionAttributes 注解修飾,
* 若使用了該注解, 且 @SessionAttributes 注解的 value 屬性值中包含了 key, 則會(huì)從 HttpSession 中來獲取 key 所
* 對(duì)應(yīng)的 value 值, 若存在則直接傳入到目標(biāo)方法的入?yún)⒅? 若不存在則將拋出異常.
* 4. 若 Handler 沒有標(biāo)識(shí) @SessionAttributes 注解或 @SessionAttributes 注解的 value 值中不包含 key, 則
* 會(huì)通過反射來創(chuàng)建 POJO 類型的參數(shù), 傳入為目標(biāo)方法的參數(shù)
* 5. SpringMVC 會(huì)把 key 和 POJO 類型的對(duì)象保存到 implicitModel 中, 進(jìn)而會(huì)保存到 request 中.
*
* 源代碼分析的流程
* 1. 調(diào)用 @ModelAttribute 注解修飾的方法. 實(shí)際上把 @ModelAttribute 方法中 Map 中的數(shù)據(jù)放在了 implicitModel 中.
* 2. 解析請(qǐng)求處理器的目標(biāo)參數(shù), 實(shí)際上該目標(biāo)參數(shù)來自于 WebDataBinder 對(duì)象的 target 屬性
* 1). 創(chuàng)建 WebDataBinder 對(duì)象:
* ①. 確定 objectName 屬性: 若傳入的 attrName 屬性值為 "", 則 objectName 為類名第一個(gè)字母小寫.
* *注意: attrName. 若目標(biāo)方法的 POJO 屬性使用了 @ModelAttribute 來修飾, 則 attrName 值即為 @ModelAttribute
* 的 value 屬性值
*
* ②. 確定 target 屬性:
* > 在 implicitModel 中查找 attrName 對(duì)應(yīng)的屬性值. 若存在, ok
* > *若不存在: 則驗(yàn)證當(dāng)前 Handler 是否使用了 @SessionAttributes 進(jìn)行修飾, 若使用了, 則嘗試從 Session 中
* 獲取 attrName 所對(duì)應(yīng)的屬性值. 若 session 中沒有對(duì)應(yīng)的屬性值, 則拋出了異常.
* > 若 Handler 沒有使用 @SessionAttributes 進(jìn)行修飾, 或 @SessionAttributes 中沒有使用 value 值指定的 key
* 和 attrName 相匹配, 則通過反射創(chuàng)建了 POJO 對(duì)象
*
* 2). SpringMVC 把表單的請(qǐng)求參數(shù)賦給了 WebDataBinder 的 target 對(duì)應(yīng)的屬性.
* 3). *SpringMVC 會(huì)把 WebDataBinder 的 attrName 和 target 給到 implicitModel.
* 近而傳到 request 域?qū)ο笾?
* 4). 把 WebDataBinder 的 target 作為參數(shù)傳遞給目標(biāo)方法的入?yún)?
*/
5冠场、@SessionAttributes引發(fā)的異常:
講人話,就是類上面上的@SessionAttributes( value="xxx"),xxx找不到本砰,所有必須有碴裙,或者注釋掉這個(gè)注解
解決方法:
6、視圖和視圖解析器
概述:
案例:
@RequestMapping("show")
public String test() {
return SUCCESS;
}
@RequestMapping("testRedirect")
public String testRedirect() {
System.out.println ("重定向");
return "redirect:/index.jsp";
}