3.@Controller和@RequestMapping註解
Spring 2.5 版本新增了 Spring MVC 註解功能,用於替換傳統的基於 XML 的 Spring MVC 配置。
傳統風格的控制器不僅需要在配置檔案中部署對映,而且只能編寫一個處理方法,不夠靈活。
使用基於註解的控制器具有以下 2 個優點:
- 在基於註解的控制器類中可以編寫多個處理方法,進而可以處理多個請求(動作),這就允許將相關的操作編寫在同一個控制器類中,從而減少控制器類的數量,方便以後維護。
- 基於註解的控制器不需要在配置檔案中部署對映,僅需要使用 @RequestMapping 註解一個方法進行請求處理即可。
下面介紹在 Spring MVC 中最重要的兩個註解型別:@Controller 和 @RequestMapping。
一、Controller註解
@Controller 註解用於宣告某類的例項是一個控制器。例如,在 net.biancheng.controller 包中建立控制器類 IndexController,示例程式碼如下。
package net.biancheng.controller;
import org.springframework.stereotype.Controller;
@Controller
public class IndexController {
// 處理請求的方法
}
Spring MVC 使用掃描機制找到應用中所有基於註解的控制器類,所以,為了讓控制器類被 Spring MVC 框架掃描到,需要在配置檔案中宣告 spring-context,並使用<context:component-scan/>
例如,在 springmvcDemo 應用的配置檔案 springmvc-servlet.xml 中新增以下程式碼:
- <!-- 使用掃描機制掃描控制器類,控制器類都在net.biancheng.controller包及其子包下 -->
- <context:component-scan base-package="net.biancheng.controller" />
二、RequestMapping註解
一個控制器內有多個處理請求的方法,如 UserController 裡通常有增加使用者、修改使用者資訊、刪除指定使用者、根據條件獲取使用者列表等。每個方法負責不同的請求操作,而 @RequestMapping 就負責將請求對映到對應的控制器方法上。
在基於註解的控制器類中可以為每個請求編寫對應的處理方法。使用 @RequestMapping 註解將請求與處理方法一 一對應即可。
@RequestMapping 註解可用於類或方法上。用於類上,表示類中的所有響應請求的方法都以該地址作為父路徑。
@RequestMapping 註解常用屬性如下。
1. value 屬性
value 屬性是 @RequestMapping 註解的預設屬性,因此如果只有 value 屬性時,可以省略該屬性名,如果有其它屬性,則必須寫上 value 屬性名稱。如下。
- @RequestMapping(value="toUser")
- @RequestMapping("toUser")
value 屬性支援萬用字元匹配,如 @RequestMapping(value="toUser/*") 表示 http://localhost:8080/toUser/1 或 http://localhost:8080/toUser/hahaha 都能夠正常訪問。
2. path屬性
path 屬性和 value 屬性都用來作為對映使用。即@RequestMapping(value="toUser") 和 @RequestMapping(path="toUser") 都能訪問 toUser() 方法。
path 屬性支援萬用字元匹配,如 @RequestMapping(path="toUser/*") 表示 http://localhost:8080/toUser/1 或 http://localhost:8080/toUser/hahaha 都能夠正常訪問。
3. name屬性
name屬性相當於方法的註釋,使方法更易理解。如@RequestMapping(value = "toUser",name = "獲取使用者資訊")。
4. method屬性
method 屬性用於表示該方法支援哪些 HTTP 請求。如果省略 method 屬性,則說明該方法支援全部的 HTTP 請求。
@RequestMapping(value = "toUser",method = RequestMethod.GET) 表示該方法只支援 GET 請求。也可指定多個 HTTP 請求,如 @RequestMapping(value = "toUser",method = {RequestMethod.GET,RequestMethod.POST}),說明該方法同時支援 GET 和 POST 請求。
5. params屬性
params 屬性用於指定請求中規定的引數,程式碼如下。
@RequestMapping(value = "toUser",params = "type")
public String toUser() {
return "showUser";
}
以上程式碼表示請求中必須包含 type 引數時才能執行該請求。即 http://localhost:8080/toUser?type=xxx 能夠正常訪問 toUser() 方法,而http://localhost:8080/toUser 則不能正常訪問 toUser() 方法。
@RequestMapping(value = "toUser",params = "type=1")
public String toUser() {
return "showUser";
}
以上程式碼表示請求中必須包含 type 引數,且 type 引數為 1 時才能夠執行該請求。即http://localhost:8080/toUser?type=1 能夠正常訪問 toUser() 方法,而 http://localhost:8080/toUser?type=2 則不能正常訪問 toUser() 方法。
6. header屬性
header 屬性表示請求中必須包含某些指定的 header 值。
@RequestMapping(value = "toUser",headers = "Referer=http://www.xxx.com") 表示請求的 header 中必須包含了指定的“Referer”請求頭,以及值為“http://www.xxx.com”時,才能執行該請求。
7.consumers屬性
consumers 屬性用於指定處理請求的提交內容型別(Content-Type),例如:application/json、text/html。如
@RequestMapping(value = "toUser",consumes = "application/json")。
8. produces屬性
produces 屬性用於指定返回的內容型別,返回的內容型別必須是 request 請求頭(Accept)中所包含的型別。如@RequestMapping(value = "toUser",produces = "application/json")。
除此之外,produces 屬性還可以指定返回值的編碼。如@RequestMapping(value = "toUser",produces = "application/json,charset=utf-8"),表示返回 utf-8 編碼。
使用 @RequestMapping 來完成對映,具體包括 4 個方面的資訊項:請求 URL、請求引數、請求方法和請求頭。
通過請求URL進行對映
1)方法級別註解
方法級別註解的示例程式碼如下。
package net.biancheng.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class IndexController {
@RequestMapping(value = "/index/login")
public String login() {
return "login";
}
@RequestMapping(value = "/index/register")
public String register() {
return "register";
}
}
上述示例中有兩個 RequestMapping 註解語句,它們都作用在處理方法上。在整個 Web 專案中,@RequestMapping 對映的請求資訊必須保證全域性唯一。
使用者可以使用如下 URL 訪問 login 方法(請求處理方法),在訪問 login 方法之前需要事先在 /WEB-INF/jsp/ 目錄下建立 login.jsp。
http://localhost:8080/springmvcDemo/index/login
2)類級別註解
類級別註解的示例程式碼如下:
package net.biancheng.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/index")
public class IndexController {
@RequestMapping("/login")
public String login() {
return "login";
}
@RequestMapping("/register")
public String register() {
return "register";
}
}
在類級別註解的情況下,控制器類中的所有方法都將對映為類級別的請求。使用者可以使用如下 URL 訪問 login 方法。
http://localhost:8080/springmvcDemo/index/login
為了方便維護程式,建議開發者採用類級別註解,將相關處理放在同一個控制器類中。例如,對使用者的增、刪、改、查等處理方法都可以放在 UserController 控制類中。
通過請求引數、請求方法進行對映
@RequestMapping 除了可以使用請求 URL 對映請求之外,還可以使用請求引數、請求方法來對映請求,通過多個條件可以讓請求對映更加精確。
package net.biancheng.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class IndexController {
@RequestMapping(value = "/index/success" method=RequestMethod.GET, Params="username")
public String success(@RequestParam String username) {
return "index";
}
上述程式碼中,@RequestMapping 的 value 表示請求的 URL;method 表示請求方法,此處設定為 GET 請求,若是 POST 請求,則無法進入 success 這個處理方法中。params 表示請求引數,此處引數名為 username。
三、編寫請求處理方法
在控制類中每個請求處理方法可以有多個不同型別的引數,以及一個多種型別的返回結果。
1)請求處理方法中常出現的引數型別
如果需要在請求處理方法中使用 Servlet API 型別,那麼可以將這些型別作為請求處理方法的引數型別。Servlet API 引數型別的示例程式碼如下:
package net.biancheng.controller;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/index")
public class IndexController {
@RequestMapping("/login")
public String login(HttpSession session,HttpServletRequest request) {
session.setAttribute("skey", "session範圍的值");
session.setAttribute("rkey", "request範圍的值");
return "login";
}
}
除了 Servlet API 引數型別以外,還有輸入輸出流、表單實體類、註解型別、與 Spring 框架相關的型別等,這些型別在後續章節中使用時再詳細介紹。
其中特別重要的型別是 org.springframework.ui.Model 型別,該型別是一個包含 Map 的 Spring MVC型別。在每次呼叫請求處理方法時 Spring MVC 都將建立 org.springframework.ui.Model 物件。Model 引數型別的示例程式碼如下:
package net.biancheng.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/index")
public class IndexController {
@RequestMapping("/register")
public String register(Model model) {
/*在檢視中可以使用EL表示式${success}取出model中的值*/
model.addAttribute("success", "註冊成功");
return "register";
}
}
2)請求處理方法常見的返回型別
請求處理方法可以返回如下型別的物件:
- ModelAndView
- Model
- 包含模型屬性的 Map
- View
- 代表邏輯檢視名的 String
- void
- 其它任意Java型別
最常見的返回型別就是代表邏輯檢視名稱的 String 型別,例如前面幾節中的請求處理方法。
四、示例
建立 Web 應用 springmvcDemo2,匯入相應的 JAR 包(可參考《第一個Spring MVC程式》一節匯入的 JAR 包)。
springmvcDemo2 應用目錄結構如下。
springmvcDemo2目錄結構
web.xml 程式碼如下。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>springMVC</display-name>
<!-- 部署 DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springmvc-servlet.xml</param-value>
</init-param>
<!-- 表示容器再啟動時立即載入servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- 處理所有URL -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
springmvc-servlet.xml 配置檔案程式碼如下。
-
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:component-scan base-package="net.biancheng.controller" /> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--字首 --> <property name="prefix" value="/WEB-INF/jsp/" /> <!--字尾 --> <property name="suffix" value=".jsp" /> </bean> </beans>
建立 User 實體類,程式碼如下。如前面所說,使用 Controller 註解的一個優點在於一個控制類可以包含多個請求處理方法。建立 UserController,程式碼如下。
-
package net.biancheng.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import net.biancheng.po.User; @Controller @RequestMapping("/user") public class UserController { @RequestMapping("/login") public String getLogin(Model model) { User us = new User(); us.setName("程式設計幫"); model.addAttribute("user", us); return "login"; } @RequestMapping("/register") public String getRegister() { return "register"; } }
index.jsp 檔案頁面程式碼如下。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
未註冊的使用者,請
<a href="${pageContext.request.contextPath }/user/register"> 註冊</a>!
<br /> 已註冊的使用者,去
<a href="${pageContext.request.contextPath }/user/login"> 登入</a>!
</body>
</html>
login.jsp 程式碼如下。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
登入頁面! 歡迎 ${user.name} 登入
</body>
</html>
register.jsp 程式碼如下。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
註冊頁面!
</body>
</html>
執行結果如下。
index.jsp頁面
register.jsp頁面
login.jsp頁面
在上圖所示的頁面中,當用戶單擊“註冊”超連結時,控制器會將該請求轉發給 UserController 的 getLogin 方法處理,處理後跳轉到 /WEB-INF/jsp 下的 register.jsp 檢視。同理,當單擊“登入”超連結時,控制器處理後轉到 /WEB-INF/jsp下的 login.jsp 檢視。