目錄
一、@RequestMapping是什么?
二、@RequestMapping 的使用演示
? ? ? ? 1.@RequestMapping在方法上的使用:
? ? ? ? 2.@RequestMapping同時在類和方法上使用:
? ? ? ? 3.@RequestMapping指定請求參數:
? ? ? ? 4.@RequestMapping使用Ant風格URL:
? ? ? ? 5.@RequestMapping 配合 @PathVariable映射:
三、@RequestMapping的使用細節
四、@RequestMapping延伸——SpringMVC中,如何通過注解實現POJO類直接作為Controller,而不依賴Servlet或接口?
五、總結
一、@RequestMapping是什么?
? ? ? ? (1) @RequestMapping注解 用于將瀏覽器發來的 HTTP 請求映射到具體的 Controller類 或者 某個方法上。
? ? ? ? (2) @RequestMapping 定義了請求的 URL 路徑、請求使用的 HTTP 方法(GET, POST 等)、請求的參數、請求頭等匹配條件。
? ? ? ? (3)?@RequestMapping 既可以在類級別使用,定義指定類的所有方法共享的基礎路徑;也可以在方法級別使用,定義具體處理請求的路徑;還可以同時在類和方法級別上使用,并且,當同時修飾類和方法時,請求的 url 就是它們的組合—— /類請求值/方法請求值,具體應該為——http://IP[域名]:port/WEB工程路徑/類請求值/方法請求值。
二、@RequestMapping 的使用演示
? ? ? ? 1.@RequestMapping在方法上的使用:
? ? ? ? ? ? ? ? 我們在 “SpringMVC 執行流程分析” 一文中已經演示過 @RequestMapping 在方法上的使用了,具體請見鏈接文章的 “快速入門” 部分。如下圖所示:
? ? ? ? 2.@RequestMapping同時在類和方法上使用:
????????????????我們在 “SpringMVC 執行流程分析” 一文中已經配置過 applicationContext-mvc.xml 和 web.xml。
? ? ? ? ? ? ? ? 這里以 “購買商品并提示購買成功” 的小demo進行演示:先來準備一個 Controller 或者說是 Handler,OrderHandler代碼如下:
package com.cyan.web;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;/*** @author : Cyan_RA9* @version : 22.0*/
@RequestMapping(value = "/order")
@Controller
public class OrderHandler {/*** 1. method=RequestMethod.POST: 表示請求 purchase 目標方法的請求方式必須是 post* 2. SpringMVC 控制器默認支持 GET 和 POST 兩種方式,(如果不指定默認就是這兩個)*/@RequestMapping(value = "/purchase", method = RequestMethod.POST)public String purchase() {System.out.println("make a purchase of goods~~~");return "purchase_OK";}
}
? ? ? ? ? ? ? ? 可以看到,OrderHandler 和 purchase() 方法上面都用了 @RequestMapping 進行修飾,如果想訪問 purcahse方法,正確的 URL 就應該是 http://localhost:8080/SpringMVC/order/purchase。
? ? ? ? ? ? ? ? 注意,此處我們將?@RequestMapping?的method屬性指定為了 POST,其實一共有八種類型(常用的有GET,POST,PUT,DELETE,HEAD這些),如下圖所示:
? ? ? ? ? ? ? ? 通過一個 form 表單來訪問這個URL,并且指定為 post 類型,testPurchase.jsp代碼如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>BUY_GOODS</title><style>/* 給表格和所有單元格設置邊框 */table, th, td {border: 1px solid black;}table {border-collapse: collapse;padding: 2px;}th {font-weight: bold;border: 2px solid blue;}</style>
</head>
<body>
<form action="order/purchase" method="post"> <!-- order前面不帶/ --><table class="my-table"><tr><th colspan="2">Buy Goods</th></tr><tr><td>buyerName: </td><td><input type="text" name="buyerName"/></td></tr><tr><td>amount: </td><td><input type="text" name="amount"/></td></tr><tr><td colspan="2"><input type="submit" value="Purchase"/></td></tr></table>
</form>
</body>
</html>
? ? ? ? ? ? ? ? 表單效果圖如下:
? ? ? ? ? ? ? ? 再來一個?purchase_OK 頁面,對應 OrderHandler 的purchase()方法的 return "purchase_OK"。purchase_OK.jsp代碼如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Successfully</title>
</head>
<body><h3>Purchase Successfully!</h3>
</body>
</html>
????????????????purchase_OK 頁面效果圖如下:
? ? ? ? ? ? ? ? 最后進行運行測試,運行結果如下GIF圖所示:
? ? ? ? ? ? ? ? 注意,由于我們在OrderHandler中指定了請求方式為 POST類型,所以如果我們將 form表單 的method屬性改為 get,如下圖所示:
? ? ? ? ? ? ? ? 此時form表單的請求類型和要訪問的purchase()方法指定的請求類型不一致,將會報錯405,如下圖所示:
? ? ? ? 3.@RequestMapping指定請求參數:
? ? ? ? ? ? ? ? @RequestMapping 中的 params 屬性可以用于指定請求參數,如下圖所示:
? ? ? ? ? ? ? ? params?具體的使用方式有下面幾種——
? ? ? ? ? ? ? ? ①?params = "param1_name" : 表示請求必須包含名稱是 "param1_name" 的請求參數。
? ? ? ? ? ? ? ? ② params = "param1_name!=value1":表示請求必須包含名稱是 "param1_name" 的請求參數 并且 它的值不可以是 value1(手動指定)。
? ? ? ? ? ? ? ? ③ params = "!=param1_name":表示請求必須 不包含 參數名稱為 "param1_name" 的請求參數。
? ? ? ? ? ? ? ? ④ params = { "param1_name=value1", "param2_name" } :表示請求必須同時包含名稱為 "param1_name" 和 "param2_name" 的請求參數 并且 param1_name 參數的值必須是指定的 value1。
? ? ? ? ? ? ? ? 以 “保存訂單” 的demo來測試 params 的具體用法。在OrderHandler中新增一個saveOrder 方法,OrderHandler類代碼如下:
package com.cyan.web;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;/*** @author : Cyan_RA9* @version : 22.0*/
@RequestMapping(value = "/order")
@Controller
public class OrderHandler {/*** 1. method=RequestMethod.POST: 表示請求 purchase 目標方法的請求方式必須是 post* 2. SpringMVC 控制器默認支持 GET 和 POST 兩種方式,(如果不指定默認就是這兩個)*/@RequestMapping(value = "/purchase", method = RequestMethod.POST)public String purchase() {System.out.println("make a purchase of goods~~~");return "purchase_OK";}@RequestMapping(value = "/save", params = "orderId!=0", method = RequestMethod.GET)public String saveOrder(String orderId) {// 傳入的參數會傳遞到方法的形參列表System.out.println("orderId = " + orderId);return "order_OK";}
}
? ? ? ? ? ? ? ? 對應的order_OK.jsp代碼如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>SuccessfullyEX</title>
</head>
<body>
<h3 style="color: cornflowerblue">Order Successfully!</h3>
</body>
</html>
? ? ? ? ? ? ? ? 再來一個用于測試 /order/save 的form表單,testOrder.jsp代碼如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>SAVE_ORDERS</title><style>/* 給表格和所有單元格設置邊框 */table, th, td {border: 1px solid black;}table {border-collapse: collapse;padding: 2px;}th {font-weight: bold;border: 2px solid blue;}</style>
</head>
<body>
<form action="order/save" method="get"><table class="my-table"><tr><th colspan="2">Make an Order</th></tr><tr><td>orderId: </td><td><input type="text" name="orderId"/></td></tr><tr><td>orderType: </td><td><input type="text" name="orderType"/></td></tr><tr><td colspan="2"><input type="submit" value="ORDER"/></td></tr></table>
</form>
</body>
</html>
? ? ? ? ? ? ? ? 頁面效果如下圖所示:
? ? ? ? ? ? ? ? 我們先輸入符合規則的orderId,測試效果如下GIF圖所示:
? ? ? ? ? ? ? ? 但是,如果我們將 orderId 改成 0,就會報錯400,如下GIF圖所示:
? ? ? ? 4.@RequestMapping使用Ant風格URL:
? ? ? ? ? ? ? ? @RequestMapping 支持下面三種 Ant 風格 URL——
? ? ? ? ? ? ? ? ① "?" :匹配文件名中的任意一個字符;
? ? ? ? ? ? ? ? ② "*" :匹配文件名中的任意1到多個字符(不能匹配空字符串);
? ? ? ? ? ? ? ? ③ "**":匹配多層路徑(0到多個路徑段)。
? ? ? ? ? ? ? ? 這里up在之前用過的UserSerlvet上做做手腳,來測試 Ant風格 URL,UserServlet代碼如下:
package com.cyan.web;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;@Controller //@Controller注解,標識當前類是一個控制器,有時也稱為Handler(處理器)
public class UserServlet {@RequestMapping(value = "/user/?/login") //此處的value可以省略public String login() {System.out.println("This is login!");return "login_OK";}@RequestMapping(value = "/user/*/sign") //此處的value可以省略public String sign() {System.out.println("This is sign~~~");return "login_OK";}@RequestMapping(value = "/user/**/register") //此處的value可以省略public String register() {System.out.println("This is register+++");return "login_OK";}
}
? ? ? ? ? ? ? ? 再來一個 testAnt.jsp 用于測試URL的匹配情況,testAnt.jsp代碼如下——
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>testAnt</title>
</head>
<body><a href="user/1/login">login_test1</a> <br/><a href="user/2/login">login_test2</a> <br/><a href="user/3/login">login_test3</a> <br/> <br/><a href="user/abc/sign">sign_test1</a> <br/><a href="user/fff/sign">sign_test2</a> <br/><a href="user/Cyan-RA9/sign">sign_test3</a> <br/> <br/><a href="user/register">register_test1</a> <br/><a href="user/Pro/register">register_test2</a> <br/><a href="user/Pro/Max/Ultra/Plus/register">register_test3</a>
</body>
</html>
? ? ? ? ? ? ? ? 最后進行運行測試,測試情況如下?GIF圖?所示:
? ? ? ? ? ? ? ? IDEA 后臺的輸出結果如下圖所示:
? ? ? ? ? ? ? ? 正好對應了 UserServlet 中三個方法的輸出語句,符合預期。
? ? ? ? 5.@RequestMapping 配合 @PathVariable映射:
? ? ? ? ? ? ? ? 一般情況下,URL的參數形式是——action 屬性[+?+請求參數]。其中,請求參數的格式是:name=value&name=value。
? ? ? ? ? ? ? ? 但是,借助 @PathVariable 可以省略參數名,簡化URL.
? ? ? ? ? ? ? ? 新建一個 UserHandler 用于演示,UserHandler類代碼如下:
package com.cyan.web;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;/*** @author : Cyan_RA9* @version : 22.0*/
@Controller
@RequestMapping(value = "/user")
public class UserHandler {/*1. @RequestMapping 中定義的參數名和 @PathVariable 中指定的參數名 必須保持一致。2. 使用了 @PathVariable 的方法的形參名,可以與上面兩者不一致,形參名無所謂。*/@RequestMapping(value = "/sign/up/{username}/{userid}")public String sign_up(@PathVariable("username") String name, @PathVariable("userid") String id) {System.out.println(("Parameters Received : " + "username = " + name + ", userid = " + id));return "login_OK";}
}
? ? ? ? ? ? ? ? 再來一個 testPathVariable 頁面,用于測試 URL 的簡化效果,testPathVariable.jsp 代碼如下——
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>@PathVariable Test</title>
</head>
<body><h3>Click the reference to take a test</h3><a href="user/sign/up/Cyan_RA9/141">點我就完事兒!</a>
</body>
</html>
? ? ? ? ? ? ? ? 測試結果如下GIF圖所示:
三、@RequestMapping的使用細節
????????1. @RequestMapping(及其派生注解)映射的 URL 不能重復,即同一個項目中不能有兩個方法去匹配完全相同的 URL,這時候 Tomcat 啟動時會報錯,如下圖所示:
? ? ? ? 2.@RequestMapping(value = "/xxx",method = RequestMethod.POST) 就等價于 @PostMapping(value = "/xxx")?。類似的寫法還有: @GetMapping,@PutMapping,@DeleteMapping。
? ? ? ? 3.如果已經確定 某個表單 或者 超鏈接 會提交字段數據, 那么要求提交的參數名 和 目標方法的參數名保持一致.(也就是我們在上面演示3 和 演示5中做的那樣.)
四、@RequestMapping延伸——SpringMVC中,如何通過注解實現POJO類直接作為Controller,而不依賴Servlet或接口?
????????????????我們可以使用 @Controller 來把一個 POJO類 標記為SpringMVC的 控制器,@Controller 本身可以看作是 @Component 的一個特例,所以被 @Controller 標記的類也會被 Spring 容器作為組件進行管理。除了 @Controller 之外,我們還需要另一個核心注解——@RequestMapping(或者它的派生注解),這個注解可以把瀏覽器發來的 HTTP 請求映射到具體的 Controller 類 或者 某個方法上面;@RequestMapping 直接定義了 HTTP 請求的一些屬性,例如請求的URL,請求的方法類型,請求的參數等等。
????????????????那么上面說的這兩個注解,就是我們自己 能操作的部分,但是真正要想實現對 Servlet API 的解耦,背后靠的是 前端控制器(DispatcherServlet),處理器映射器(HandlerMapping),處理器適配器(HandlerAdapter) 這三大組件的協同工作,尤其是 HandlerAdapter(因為它直接實現了 適配器模式)。DispatcherServlet 拿到 HandlerMapping 找到的處理器(即 我們標記的 POJO Controller)后,并不會直接調用它。而是將處理器交給 HandlerAdapter,讓它去調用。HandlerAdapter 會從 HttpServletRequest 中提取信息(即參數解析),然后把提取到的有用信息 適配為 POJO 方法的參數,那么我們標記為控制器的 POJO,根本就不需要直接接觸 HttpServletRequest 或 HttpServletResponse。而且 HandlerAdapter 通過反射直接檢查 POJO 方法簽名,只要方法簽名符合 Spring MVC 的約定,就可以被調用,所以也不需要依賴接口。
? ? ? ? ? ? ? ? SpringMVC的執行流程回顧——如下圖所示:
五、總結
- 🆗,以上就是 SpringMVC --- @RequestMapping 的全部內容了😀。
- 這篇文章沒什么難度,主要就是演示了一下 @RequestMapping 的各種使用方式和技巧,大家只要知道 @RequestMapping 在整個 Spring MVC 中很重要并且把它用熟練就可以了。