引用自:https://www.cnblogs.com/xiaoxi/p/5718894.html
1、@RequestMapping
@RequestMapping
RequestMapping是一個用來處理請求地址映射的注解(將請求映射到對應的控制器方法中),可用於類或方法上。用於類上,表示類中的所有響應請求的方法都是以該地址作為父路徑。
RequestMapping請求路徑映射,如果標注在某個controller的類級別上,則表明訪問此類路徑下的方法都要加上其配置的路徑;最常用是標注在方法上,表明哪個具體的方法來接受處理某次請求。
@Controller @RequestMapping(value="/book") public class BookController { @RequestMapping(value="/title") public String getTitle(){ return "title"; } @RequestMapping(value="/content") public String getContent(){ return "content"; } }
由於BookController類加了value="/book"的@RequestMapping的注解,所以相關路徑都要加上"/book",即請求的url分別為:
(1)http://localhost:8080/book/title
(2)http://localhost:8080/book/content
"@RequestMapping"的value值前后是否有“/”對請求的路徑沒有影響,即value="book" 、"/book"、"/book/"其效果是一樣的。
RequestMapping的屬性
value:指定請求的實際url
(1)普通的具體值。如前面的value="/book"。
(2)含某變量的一類值。
@RequestMapping(value="/get/{bookId}") public String getBookById(@PathVariable String bookId,Model model){ model.addAttribute("bookId", bookId); return "book"; }
路徑中的bookId可以當變量,@PathVariable注解即提取路徑中的變量值。
(3)ant風格
@RequestMapping(value="/get/id?"):可匹配“/get/id1”或“/get/ida”,但不匹配“/get/id”或“/get/idaa”;
@RequestMapping(value="/get/id*"):可匹配“/get/idabc”或“/get/id”,但不匹配“/get/idabc/abc”;
@RequestMapping(value="/get/id/*"):可匹配“/get/id/abc”,但不匹配“/get/idabc”;
@RequestMapping(value="/get/id/**/{id}"):可匹配“/get/id/abc/abc/123”或“/get/id/123”,也就是Ant風格和URI模板變量風格可混用。
(4)含正則表達式的一類值
@RequestMapping(value="/get/{idPre:\\d+}-{idNum:\\d+}"):可以匹配“/get/123-1”,但不能匹配“/get/abc-1”,這樣可以設計更加嚴格的規則。
可以通過@PathVariable 注解提取路徑中的變量(idPre,idNum)
(5)或關系
@RequestMapping(value={"/get","/fetch"} )即 /get或/fetch都會映射到該方法上。
method:指定請求的method類型, GET、POST、PUT、DELETE等;
@RequestMapping(value="/get/{bookid}",method={RequestMethod.GET,RequestMethod.POST})
params:指定request中必須包含某些參數值是,才讓該方法處理。
@RequestMapping(params="action=del"),請求參數包含“action=del”,如:http://localhost:8080/book?action=del
@Controller @RequestMapping("/owners/{ownerId}") public class RelativePathUriTemplateController { @RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, params="myParam=myValue") public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) { // implementation omitted } }
僅處理請求中包含了名為“myParam”,值為“myValue”的請求。
headers:指定request中必須包含某些指定的header值,才能讓該方法處理請求。
@RequestMapping(value="/header/id", headers = "Accept=application/json"):表示請求的URL必須為“/header/id 且請求頭中必須有“Accept =application/json”參數即可匹配。
@Controller @RequestMapping("/owners/{ownerId}") public class RelativePathUriTemplateController { @RequestMapping(value = "/pets", method = RequestMethod.GET, headers="Referer=http://www.ifeng.com/") public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) { // implementation omitted } }
僅處理request的header中包含了指定“Refer”請求頭和對應值為“http://www.ifeng.com/
”的請求。
consumes:指定處理請求的提交內容類型(Content-Type),例如application/json, text/html。
@Controller @RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json") public void addPet(@RequestBody Pet pet, Model model) { // implementation omitted }
方法僅處理request Content-Type為“application/json”類型的請求。
produces: 指定返回的內容類型,僅當request請求頭中的(Accept)類型中包含該指定類型才返回。
@Controller @RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, produces="application/json") @ResponseBody public Pet getPet(@PathVariable String petId, Model model) { // implementation omitted }
方法僅處理request請求中Accept頭中包含了"application/json"的請求,同時暗示了返回的內容類型為application/json;
2、@RequestParam綁定單個請求參數值
@RequestParam用於將請求參數區數據映射到功能處理方法的參數上。
public String requestparam1(@RequestParam String username)
請求中包含username參數(如/requestparam1?username=zhang),則自動傳入。
@RequestParam有以下三個參數:
value:參數名字,即入參的請求參數名字,如username表示請求的參數區中的名字為username的參數的值將傳入;
required:是否必須,默認是true,表示請求中一定要有相應的參數,否則將拋出異常;
defaultValue:默認值,表示如果請求中沒有同名參數時的默認值,設置該參數時,自動將required設為false。
public String requestparam4(@RequestParam(value="username",required=false) String username)
表示請求中可以沒有名字為username的參數,如果沒有默認為null,此處需要注意如下幾點:
原子類型:必須有值,否則拋出異常,如果允許空值請使用包裝類代替。
Boolean包裝類型:默認Boolean.FALSE,其他引用類型默認為null。
如果請求中有多個同名的應該如何接收呢?如給用戶授權時,可能授予多個權限,首先看下如下代碼:
public String requestparam7(@RequestParam(value="role") String roleList)
如果請求參數類似於url?role=admin&rule=user,則實際roleList參數入參的數據為“admin,user”,即多個數據之間使用“,”分割;我們應該使用如下方式來接收多個請求參數:
public String requestparam7(@RequestParam(value="role") String[] roleList)
或者
public String requestparam8(@RequestParam(value="list") List<String> list)
3、@PathVariable綁定URI模板變量值
@PathVariable用於將請求URL中的模板變量映射到功能處理方法的參數上。
@RequestMapping(value="/users/{userId}/topics/{topicId}") public String test( @PathVariable(value="userId") int userId, @PathVariable(value="topicId") int topicId)
如請求的URL為“控制器URL/users/123/topics/456”,則自動將URL中模板變量{userId}和{topicId}綁定到通過@PathVariable注解的同名參數上,即入參后userId=123、topicId=456。
4、@ModelAttribute
ModelAttribute可以應用在方法參數上或方法上,他的作用主要是當注解在方法參數上時會將注解的參數對象添加到Model中;當注解在請求處理方法Action上時會將該方法變成一個非請求處理的方法,但其它Action被調用時會首先調用該方法。
4.1 @ModelAttribute注釋一個方法
被@ModelAttribute注釋的方法表示這個方法的目的是增加一個或多個模型(model)屬性。這個方法和被@RequestMapping注釋的方法一樣也支持@RequestParam參數,但是它不能直接被請求映射。實際上,控制器中的@ModelAttribute方法是在同一控制器中的@RequestMapping方法被調用之前調用的。
被@ModelAttribute注釋的方法用於填充model屬性,例如,為下拉菜單填充內容,或檢索一個command對象(如,Account),用它來表示一個HTML表單中的數據。
一個控制器可以有任意數量的@ModelAttribute方法。所有這些方法都在@RequestMapping方法被調用之前調用。
有兩種類型的@ModelAttribute方法。一種是:只加入一個屬性,用方法的返回類型隱含表示。另一種是:方法接受一個Model類型的參數,這個model可以加入任意多個model屬性。
(1)@ModelAttribute注釋void返回值的方法
@Controller @RequestMapping(value="/test") public class TestController { /** * 1.@ModelAttribute注釋void返回值的方法 * @param abc * @param model */ @ModelAttribute public void populateModel(@RequestParam String abc, Model model) { model.addAttribute("attributeName", abc); } @RequestMapping(value = "/helloWorld") public String helloWorld() { return "test/helloWorld"; } }
這個例子,在獲得請求/helloWorld 后,populateModel方法在helloWorld方法之前先被調用,它把請求參數(/helloWorld?abc=text)加入到一個名為attributeName的model屬性中,在它執行后helloWorld被調用,返回視圖名helloWorld和model已由@ModelAttribute方法生產好了。
這個例子中model屬性名稱和model屬性對象由model.addAttribute()實現,不過前提是要在方法中加入一個Model類型的參數。
(2)@ModelAttribute注釋返回具體類的方法
/** * 2.@ModelAttribute注釋返回具體類的方法 * @param id * @return */ @ModelAttribute public User getUserInfo(String id){ if(id!=null && !id.equals("")){ return userService.getUserInfo(id); } return null; }
這種情況,model屬性的名稱沒有指定,它由返回類型隱含表示,如這個方法返回User類型,那么這個model屬性的名稱是user。
這個例子中model屬性名稱有返回對象類型隱含表示,model屬性對象就是方法的返回值。它無須要特定的參數。
(3)@ModelAttribute(value="")注釋返回具體類的方法
@Controller @RequestMapping(value="/test") public class TestController { /** * 3.@ModelAttribute(value="")注釋返回具體類的方法 * @param abc * @return */ @ModelAttribute("str") public String getParam(@RequestParam String param) { return param; } @RequestMapping(value = "/helloWorld") public String helloWorld() { return "test/helloWorld"; } }
這個例子中使用@ModelAttribute注釋的value屬性,來指定model屬性的名稱。model屬性對象就是方法的返回值。它無須要特定的參數。
完整的代碼:
package demo.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import demo.model.User; import demo.service.IUserService; @Controller @RequestMapping(value="/test") public class TestController { @Autowired private IUserService userService; /** * 1.@ModelAttribute注釋void返回值的方法 * @param abc * @param model */ @ModelAttribute public void populateModel(@RequestParam String abc, Model model) { model.addAttribute("attributeName", abc); } /** * 2.@ModelAttribute注釋返回具體類的方法 * @param id * @return */ @ModelAttribute public User getUserInfo(String id){ if(id!=null && !id.equals("")){ return userService.getUserInfo(id); } return null; } /** * 3.@ModelAttribute(value="")注釋返回具體類的方法 * @param abc * @return */ @ModelAttribute("str") public String getParam(@RequestParam String param) { return param; } @RequestMapping(value = "/helloWorld") public String helloWorld() { return "test/helloWorld"; } }
Jsp前台取值:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>helloWorld</title> </head> <body> 1.The attributeValue is: ${attributeName} <br/><br/> 2.用戶信息:<br/> 姓名:${user.user_name}<br/> 年齡:${user.user_age}<br/> 郵箱:${user.user_email}<br/><br/> 3.The param is: ${str} </body> </html>
頁面效果圖:
URL格式:http://localhost/SSMDemo/test/helloWorld?abc=text&id=1¶m=aaa 注:當url或者post中不包含參數abc和參數param時,會報錯。
(4)@ModelAttribute和@RequestMapping同時注釋一個方法
@Controller @RequestMapping(value="/test") public class TestController { @RequestMapping(value = "/helloWorld") @ModelAttribute("attributeName") public String helloWorld() { return "hi"; } }
這時這個方法的返回值並不是表示一個視圖名稱,而是model屬性的值,視圖名稱由RequestToViewNameTranslator根據請求"/helloWorld"轉換為helloWorld。Model屬性名稱由@ModelAttribute(value=””)指定,相當於在request中封裝了key=attributeName,value=hi。
Jsp頁面:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>helloWorld</title> </head> <body> The attributeValue is: ${attributeName} </body> </html>
4.2 @ModelAttribute注釋一個方法的參數
@ModelAttribute注釋方法的一個參數表示應從模型model中取得。若在model中未找到,那么這個參數將先被實例化后加入到model中。若在model中找到,則請求參數名稱和model屬性字段若相匹配就會自動填充。這個機制對於表單提交數據綁定到對象屬性上很有效。
當@ModelAttribute注解用於方法參數時,它有了雙重功能,即“存/取”。首先,它從模型中取出數據並賦予對應的參數,如果模型中尚不存在,則實例化一個,並存放於模型中;其次,一旦模型中已存在此數據對象,接下來一個很重要的步驟便是將請求參數綁定到此對象上(請求參數名映射對象屬性名),這是Spring MVC提供的一個非常便利的機制--數據綁定。
@RequestMapping(value = "/login.htm", method = RequestMethod.GET) public String doLogin(@ModelAttribute("baseMember") BaseMember member) { member.setLoginName("loginName"); return "home"; }
上述代碼中,如果模型中尚不存在鍵名為“baseMember”的數據,則首先會調用BaseMember類的默認構造器創建一個對象,如果不存在默認構造器會拋出異常。因此,給實體類提供一個默認構造器是一個好的編程習慣。當請求路徑的請求參數或提交的表單與BaseMember的屬性名匹配時,將自動將其值綁定到baseMember對象中,非常的便利!這可能是我們使用@ModelAttribute最主要的原因之一。比如:請求路徑為http://localhost:8080/spring-web/login.htm?loginName=myLoginName,baseMember對象中的loginName屬性的值將被設置為myLoginName。
4.3 @ModelAttribute注解的使用場景
當@ModelAttribute注解用於方法時,與其處於同一個處理類的所有請求方法執行前都會執行一次此方法,這可能並不是我們想要的,因此,我們使用更多的是將其應用在請求方法的參數上,而它的一部分功能與@RequestParam注解是一致的,只不過@RequestParam用於綁定單個參數值,而@ModelAttribute注解可以綁定所有名稱匹配的,此外它自動將綁定后的數據添加到模型中,無形中也給我們提供了便利,這也可能是它命名為ModelAttribute的原因。
5、SessionAttributes
在默認情況下,ModelMap中的屬性作用域是request級別,也就是說,當本次請求結束后,ModelMap 中的屬性將銷毀。如果希望在多個請求中共享ModelMap中的屬性,必須將其屬性轉存到session 中,這樣 ModelMap 的屬性才可以被跨請求訪問。
Spring 允許我們有選擇地指定 ModelMap 中的哪些屬性需要轉存到 session 中,以便下一個請求屬對應的 ModelMap 的屬性列表中還能訪問到這些屬性。這一功能是通過類定義處標注 @SessionAttributes 注解來實現的。
package demo.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.SessionAttributes; import demo.model.User; @Controller @RequestMapping(value="/demo1") //(1)將ModelMap中屬性名為currUser的屬性放到Session屬性列表中,以便這個屬性可以跨請求訪問 @SessionAttributes("currUser") public class Demo1Controller { @RequestMapping(value="/getUser") public String getUser(ModelMap model){ User user=new User(); user.setUser_name("zhangsan"); user.setUser_age(25); user.setUser_email("zhangsan@sina.com"); //(2)向ModelMap中添加一個屬性 model.addAttribute("currUser",user); return "/demo/user"; } @RequestMapping(value="/getUser1") public String getUser1(ModelMap model){ User user=(User)model.get("currUser"); System.out.println(user.getUser_name()); System.out.println(user.getUser_age()); System.out.println(user.getUser_email()); return "demo/user1"; } }
我們在(2)處添加了一個 ModelMap 屬性,其屬性名為 currUser,而(1)處通過 @SessionAttributes 注解將 ModelMap 中名為 currUser 的屬性放置到 Session 中,所以我們不但可以在 getUser() 請求所對應的 JSP 視圖頁面中通過 request.getAttribute(“currUser”) 和 session.getAttribute(“currUser”) 獲取 user 對象,還可以在下一個請求(getUser1())所對應的 JSP 視圖頁面中通過 session.getAttribute(“currUser”) 或 session.getAttribute(“currUser”)訪問到這個屬性。
這里我們僅將一個 ModelMap 的屬性放入 Session 中,其實 @SessionAttributes 允許指定多個屬性。你可以通過字符串數組的方式指定多個屬性,如 @SessionAttributes({“attr1”,"attr2”})。此外,@SessionAttributes 還可以通過屬性類型指定要 session 化的 ModelMap 屬性,如 @SessionAttributes(types = User.class),當然也可以指定多個類,如 @SessionAttributes(types = {User.class,Dept.class}),還可以聯合使用屬性名和屬性類型指定:@SessionAttributes(types = {User.class,Dept.class},value={“attr1”,"attr2”})。
user.jsp頁面:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <%@ page import="demo.model.User" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> </head> <body><br> <%User user=(User)session.getAttribute("currUser");%> 用戶名:<%=user.getUser_name() %><br/> 年齡:<%=user.getUser_age() %><br/> 郵箱:<%=user.getUser_email() %><br/><br/> <a href="<%=path %>/demo1/getUser1">跳轉</a> </body> </html>
通過@ModelAttribute綁定
@SessionAttributes 是用來在 controller 內部共享 model 屬性的。我們可以在需要訪問 Session 屬性的 controller 上加上 @SessionAttributes,然后在 action 需要的 User 參數上加上 @ModelAttribute,並保證兩者的屬性名稱一致。SpringMVC 就會自動將 @SessionAttributes 定義的屬性注入到 ModelMap 對象,在 setup action 的參數列表時,去 ModelMap 中取到這樣的對象,再添加到參數列表。只要我們不去調用 SessionStatus 的 setComplete() 方法,這個對象就會一直保留在 Session 中,從而實現 Session 信息的共享。
@Controller @SessionAttributes("currentUser") public class GreetingController{ @RequestMapping public void hello(@ModelAttribute("currentUser") User user){ //user.sayHello() } }
@SessionAttributes清除
@SessionAttributes需要清除時,使用SessionStatus.setComplete();來清除。注意,它只清除@SessionAttributes的session,不會清除HttpSession的數據。故如用戶身份驗證對象的session一般不用它來實現,還是用session.setAttribute等傳統的方式實現。
6、@Responsebody與@RequestBody
@Responsebody表示該方法的返回結果直接寫入HTTP response body中。一般在異步獲取數據時使用,在使用@RequestMapping后,返回值通常解析為跳轉路徑,加上@Responsebody后返回結果不會被解析為跳轉路徑,而是直接寫入HTTP response body中。比如異步獲取json數據,加上@Responsebody后,會直接返回json數據。
@RequestBody將HTTP請求正文插入方法中,使用適合的HttpMessageConverter將請求體寫入某個對象。
$("#btn2").click(function(){ var url='<%=request.getContextPath()%>/User/addUserInfo'; var data={"user_name":$("#userName").val(),"user_sex":$("#userSex").val(),"user_age":$("#userAge").val(), "user_email":$("#userEmail").val(),"user_telephone":$("#userTelephone").val(),"user_education":$("#userEducation").val(), "user_title":$("#userTitle").val()}; $.ajax({ type:'POST', contentType : 'application/json', url:url, dataType:"json", data:JSON.stringify(data), async:false, success:function(data){ alert("新增成功!"); }, error: function(XMLHttpRequest, textStatus, errorThrown){ alert(XMLHttpRequest.status); alert(XMLHttpRequest.readyState); alert(textStatus); } }) })
@RequestMapping(value="/addUserInfo",method=RequestMethod.POST) @ResponseBody //將請求中的data寫入UserModel對象中 public String addUserInfo(@RequestBody UserModel user){ System.out.println("user_name--------"+user.getUser_name()); System.out.println("user_sex--------"+user.getUser_sex()); System.out.println("user_age--------"+user.getUser_age()); System.out.println("user_email--------"+user.getUser_email()); System.out.println("user_title--------"+user.getUser_title()); System.out.println("user_education--------"+user.getUser_education()); System.out.println("user_telephone--------"+user.getUser_telephone()); //不會被解析為跳轉路徑,而是直接寫入HTTP response body中 return "{}"; }
@RequestBody 將HTTP請求正文轉換為適合的HttpMessageConverter對象。
@ResponseBody 將內容或對象作為 HTTP 響應正文返回,並調用適合HttpMessageConverter的Adapter轉換對象,寫入輸出流。
@RequestBody
作用:
i) 該注解用於讀取Request請求的body部分數據,使用系統默認配置的HttpMessageConverter進行解析,然后把相應的數據綁定到要返回的對象上;
ii) 再把HttpMessageConverter返回的對象數據綁定到 controller中方法的參數上。
使用時機:
A) GET、POST方式提時, 根據request header Content-Type的值來判斷:
application/x-www-form-urlencoded, 可選(即非必須,因為這種情況的數據@RequestParam, @ModelAttribute也可以處理,當然@RequestBody也能處理);
multipart/form-data, 不能處理(即使用@RequestBody不能處理這種格式的數據);
其他格式, 必須(其他格式包括application/json, application/xml等。這些格式的數據,必須使用@RequestBody來處理);
B) PUT方式提交時, 根據request header Content-Type的值來判斷:
application/x-www-form-urlencoded, 必須;
multipart/form-data, 不能處理;
其他格式, 必須;
說明:request的body部分的數據編碼格式由header部分的Content-Type指定;
@ResponseBody
作用:
該注解用於將Controller的方法返回的對象,通過適當的HttpMessageConverter轉換為指定格式后,寫入到Response對象的body數據區。
使用時機:
返回的數據不是html標簽的頁面,而是其他某種格式的數據時(如json、xml等)使用;