1. 程式人生 > 其它 >3.@Controller和@RequestMapping註解

3.@Controller和@RequestMapping註解

Spring 2.5 版本新增了 Spring MVC 註解功能,用於替換傳統的基於 XML 的 Spring MVC 配置。

傳統風格的控制器不僅需要在配置檔案中部署對映,而且只能編寫一個處理方法,不夠靈活。

使用基於註解的控制器具有以下 2 個優點:

  1. 在基於註解的控制器類中可以編寫多個處理方法,進而可以處理多個請求(動作),這就允許將相關的操作編寫在同一個控制器類中,從而減少控制器類的數量,方便以後維護。
  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 中新增以下程式碼:

  1. <!-- 使用掃描機制掃描控制器類,控制器類都在net.biancheng.controller包及其子包下 -->
  2. <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 配置檔案程式碼如下。

  1. <?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,程式碼如下。

  1. 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 檢視。