Spring、SpringMVC中常用註解含義及用法
1、@Controller
在SpringMVC中只需要使用這個標記一個類是Controller,然後使用@RequestMapping和@RequestParam等一些註解用以定義URL請求和Controller方法之間的映射,這樣的Controller就能被外界訪問到。此外,Controller不會直接依賴於HttpServletRequest 和HttpServletResponse 等HttpServlet 對象,他們可以通過Controller的方法參數靈活的獲取到。
舉個例子:
- @Controller
- public class TestController {
- @RequestMapping ( "/showView" )
- public ModelAndView showView() {
- ModelAndView modelAndView = new ModelAndView();
- modelAndView.setViewName( "viewName" );
- modelAndView.addObject( " 需要放到 model 中的屬性名稱 " , " 對應的屬性值,它是一個對象 " );
- return modelAndView;
- }
- }
在上面的例子中,@Controller是標記在類TestController上面的, 所以類TestController就是一個SpringMVC Controller對象。分發處理器會掃描使用了該註解的類的方法,並檢測該方法是否調用了@RequestMapping註解。@Controller只是定義了一個控制器類,而使用@RequestMapping註解的方法纔是真正處理請求的處理器。然後使用@RequestMapping ( "/showView" )標記在Controller方法上,表示當請求/showView.do 的時候訪問的是TestController 的showView 方法,該方法返回了一個包括Model 和View 的ModelAndView 對象。
單單使用@Controller 標記在一個類上還不能真正意義上的說它就是SpringMVC 的一個控制器類,因爲這個時候Spring 還不認識它。那麼要如何做Spring 才能認識它呢?這個時候就需要把這個控制器類交給Spring 來管理。
第一種方式是在SpringMVC 的配置文件中定義MyController 的bean 對象。
第二種方式是在SpringMVC 的配置文件中告訴Spring 該到哪裏去找標記爲@Controller 的Controller 控制器。
- < context:component-scan base-package = "com.host.app.web.controller" >
- < context:exclude-filter type = "annotation"
- expression = "org.springframework.stereotype.Service" />
- context:component-scan >
注:上面 context:exclude-filter 標註的是不掃描 @Service 標註的類
2、@RequestMapping
使用 @RequestMapping 來映射 Request 請求與處理器,通過這個註解可以定義不同的處理器映射規則,即爲控制器指定可以處理哪些URL請求。
用@RequestMapping 來映射URL 到控制器類,或者是到Controller 控制器的處理方法上。當@RequestMapping 標記在Controller 類上的時候,裏面使用@RequestMapping 標記的方法的請求地址都是相對於類上的@RequestMapping 而言的;當Controller 類上沒有標記@RequestMapping 註解時,方法上的@RequestMapping 都是絕對路徑。這種絕對路徑和相對路徑所組合成的最終路徑都是相對於根路徑“/ ”而言的。
在上面那個例子中:
這個控制器裏因爲TestController 沒有被@RequestMapping 標記,所以當需要訪問到裏面使用了@RequestMapping 標記的showView 方法時,就是使用的絕對路徑/showView.do 請求就可以了。
如果改成這樣:
- @Controller
- @RequestMapping ( "/test" )
- public class TestController {
- @RequestMapping ( "/showView" )
- public ModelAndView showView() {
- ModelAndView modelAndView = new ModelAndView();
- modelAndView.setViewName( "viewName" );
- modelAndView.addObject( " 需要放到 model 中的屬性名稱 " , " 對應的屬性值,它是一個對象 " );
- return modelAndView;
- }
- }
這種情況下是在控制器上加了@RequestMapping 註解,所以當需要訪問到裏面使用了@RequestMapping 標記的方法showView() 的時候就需要使用showView 方法上@RequestMapping 相對於控制器TestController上@RequestMapping 的地址,即/test/showView.do 。
URL路徑映射:@RequestMapping("/hello"),可以將多個url映射到同一個方法上。
窄化請求映射:
(1)在class上面添加@RequestMapping(url)指定通用請求前綴,限制此類下的所有方法請求url必須以請求前綴開頭,通過此方法來分類管理url;
(2)在方法名上面再設置請求映射url,即添加@RequestMapping註解在方法名上。return “/WEB-INF/jsp/login.jsp” 調用這個方法,重定向的到指定的jsp頁面或制定的@RequestMapping的請求路徑;
(3)在瀏覽器上輸入相應地址,完成訪問。
3、@RequestBody
用於讀取http請求的內容(字符串),通過springMVC提供的HttpMessageConverter接口將讀取到的內容轉換爲json、xml等格式的數據,再轉換爲java對象綁定到Controller類方法的參數上。
簡單點來說,就是把json格式的數據轉換爲java對象,就舉個例子來說明:
編寫一個jsp頁面來向後臺傳遞json格式的數據(切記是json格式的):
- jsonData();
- function jsonData()
- {
- $.ajax({
- url:"/user/jsonTest.do",
- contentType:'application/json;charset=utf-8',//設置json格式
- data:'{"username":"張三":"address":"福州"}',
- type:'post',
- success:function(data){
- alert(data);
- },error:function(error){
- alert(error);
- }
- })
- }
然後在後臺接收一下:
- @RequestMapping("/jsonTest.do")
- public void jsonTest(@RequestBody User user) throws Exception
- {
- System.out.println(user.toString());
- }
這樣的話,前臺的兩個json數據就會自動匹配到User這個對象的屬性中了,當然屬性名稱要一樣的。
查看一下結果:
可以看到User這個對象中的username和address都已經自動賦值好了,這個就是json格式的數據轉java對象了,可以省去我們在後臺將json轉成java對象。不過在使用的時候,要注意兩邊的名稱要相同,前臺的username要對應java對象中的username這樣才能成功。否則得到如下:
4、@ResponseBody
含義:
@Responsebody 註解表示該方法的返回的結果直接寫入 HTTP 響應正文(ResponseBody)中,一般在異步獲取數據時使用,通常是在使用 @RequestMapping 後,返回值通常解析爲跳轉路徑,加上 @Responsebody 後返回結果不會被解析爲跳轉路徑,而是直接寫入HTTP 響應正文中。
作用:
用於將Controller中方法返回的對象通過適當的HttpMessageConverter轉換爲指定格式的數據,如:json、xml等,然後寫入到response對象的body區,通過Response響應給客戶端。需要注意的是,在使用此註解之後不會再走試圖處理器,而是直接將數據寫入到輸入流中,他的效果等同於通過response對象輸出指定格式的數據。
使用時機:
返回的數據不是html標籤的頁面,而是其他某種格式的數據時(如json、xml等)使用;
舉個例子:
- @RequestMapping("/login")
- @ResponseBody
- public User login(User user){
- return user;
- }
User字段是:userName pwd
那麼在前臺接收到的數據爲:'{"userName":"xxx","pwd":"xxx"}'
效果等同於如下代碼:
- @RequestMapping("/login")
- public void login(User user, HttpServletResponse response){
- response.getWriter.write(JSONObject.fromObject(user).toString());
- }
5、@ModelAttribute
在方法定義上使用該註解: SpringMVC在調用目標處理方法前, 會先逐個調用在方法級上標註了@ModelAttribute的方法;
在方法的入參前使用該註解:可以從隱含對象中獲取隱含的模型數據中獲取對象,再將請求參數 –綁定到對象中,再傳入入參將方法入參對象添加到模型中。
6、@RequestParam
處理簡單類型的綁定,用 @RequestParam 綁定 HttpServletRequest 請求參數到控制器方法參數,即在處理方法入參處使用該註解,可以把請求參數傳遞給請求方法。
- @RequestMapping ( "requestParam" )
- public String testRequestParam( @RequestParam(required=false) String name, @RequestParam ( "age" ) int age) {
- return "requestParam" ;
- }
在上面代碼中利用@RequestParam 從HttpServletRequest 中綁定了參數name 到控制器方法參數name ,綁定了參數age 到控制器方法參數age 。當沒有明確指定從request 中取哪個參數時,Spring 在代碼是debug 編譯的情況下會默認取跟方法參數同名的參數,如果不是debug 編譯的就會報錯。此外,當需要從request 中綁定的參數和方法的參數名不相同的時候,也需要在@RequestParam 中明確指出是要綁定哪個參數。在上面的代碼中如果訪問 /requestParam.do?name=hello&age=1 則Spring 將會把request請求參數name的值hello賦給對應的處理方法參數name ,把參數age 的值1 賦給對應的處理方法參數age 。
在@RequestParam 中除了指定綁定哪個參數的屬性value之外,還有一個屬性required,它表示所指定的參數是否必須在request 屬性中存在,默認是true,表示必須存在,當不存在時就會報錯。在上面代碼中我們指定了參數name的required的屬性爲false ,而沒有指定age 的required 屬性,這時候如果我們訪問/requestParam.do而沒有傳遞參數的時候,系統就會拋出異常,因爲age 參數是必須存在的,而我們沒有指定。而如果我們訪問 /requestParam.do?age=1 的時候就可以正常訪問,因爲我們傳遞了必須的參數age ,而參數name是非必須的,不傳遞也可以。
『
value:參數名,即入參的請求參數名字
如:value="id",表示將請求的參數區的名字爲id的參數的值等待傳入;
require:是否必需,默認是true,表示請求中一定要有相應的參數,否則會報400錯誤。且在每個參數定義前設置。
defaultValue:默認值,表示如果請求中沒有同名參數時的默認值。
通過 require=true 限定參數id必須傳遞,如果不傳遞會報400錯誤;
可以使用defaultValue設置默認值,即使 require=true 也可以不傳遞id參數。
』
7、@PathVariable 綁定URL佔位符到入參。
8、@ExceptionHandler 註解到方法上, 出現異常時會執行該方法。
9、@ControllerAdvice 使一個Controller成爲全局的異常處理類, 類中用ExceptinHandler方法註解的方法可以處理所有Controller發生的異常。
10、@Autowired
它可以對類成員變量、方法以及構造函數進行標註,完成自動裝配的工作。通過@Autowired 的使用來消除代碼Java代碼裏面的getter/setter與bean屬性中的property。當然,getter看個人需求,如果私有屬性需要對外提供的話,應當予以保留。
@Autowired 和 @Service("")的配合使用:
實例:
- @Controller
- @RequestMapping("/test")
- public class StudentController {
- @Autowired
- private StudentService studentService;
- @RequestMapping("getInfo")
- @ResponseBody
- public int getInfo(Student student){
- return studentService.insertStu(student);
- }
- }
在Controller中對私有變量用@Autowired標註,因爲studentService這個變量是service層接口,所以要找到他的實現類StudentServiceImpl,並在實現類上添加@Service("")的註釋。
- @Service("StudentService")
- public class StudentServiceImpl implements StudentService {
- @Autowired
- private StudentDao studentDao;
- public int insertStu(Student student){
- return studentDao.insertInfo(student);
- }
- }
如果不添加@Service("")註釋,會報如下錯誤。因爲@Autowired 將尋找與之匹配的bean來創建(類名)bena,但因爲刪除接口實現類上@Service("")註解,找不到服務對象,@Autowired自然也就找不到實例bean了。
11、@Override
@Override是僞代碼,表示重寫(當然不寫也可以),不過也有好處:
(1)可以當註釋用,方便閱讀;
(2)編譯器可以給你驗證@Override下面的方法名是否是你父類中所有的,如果沒有則報錯。
例如,你如果沒寫@Override,而你下面的方法名又寫錯了,這時你的編譯器是可以編譯通過的,因爲編譯器以爲這個方法是你的子類中自己增加的方法。
舉例:在重寫父類的onCreate時,在方法前面加上@Override 系統可以幫你檢查方法的正確性。
@Override
public void onCreate(Bundle savedInstanceState)
{…….}
這種寫法是正確的,如果你寫成:
@Override
public void oncreate(Bundle savedInstanceState)
{…….}
編譯器會報如下錯誤:
The method oncreate(Bundle) of type HelloWorld must override or implement a supertype method,以確保你正確重寫onCreate方法(因爲oncreate應該爲onCreate)。
而如果你不加@Override,則編譯器將不會檢測出錯誤,而是會認爲你爲子類定義了一個新方法:oncreate
12、@Transactional
使用時機:
對數據庫的數據進行批量或連表操作時,爲了保證數據的一致性和正確性,則需要添加事務管理機制進行管理;
當對數據庫的數據操作失敗時,事務管理可以很好保證所有的數據 回滾 到原來的數據,如果操作成功,則保證所有的需要更新的數據持久化。
『
回滾(Rollback)指的是程序或數據處理錯誤,將程序或數據恢復到上一次正確狀態的行爲。
回滾包括程序回滾和數據回滾等類型。
刪除由一個或多個部分完成的事務執行的更新。爲保證應用程序、數據庫或系統錯誤後還原數據庫的完整性,需要使用回滾。
回滾泛指程序更新失敗, 返回上一次正確狀態的行爲。
回滾與恢復有本質的區別。
升級回滾:是指因升級中所發生的意外而自動回滾。
』
使用優點:
(1)開發團隊達成一致約定,明確標註事務方法的編程風格;
(2)保證事務方法的執行時間儘可能短,不要穿插其他網絡操作,RPC/HTTP請求或者剝離到事務方法外部;
(3)不是所有的方法都需要事務,如果只有一條修改操作、只讀操作不需要事務控制。
13、@Param
mybatis提供了一個使用註解來參入多個參數的方法,這種方法需要在接口的參數上添加@Param註解。
舉個例子:
- /**
- * 更新學生信息
- * @param student
- * @return
- */
- int updateInfo(@Param("student") Student student);
在這個updateInfo的方法中需要傳入多個參數,那麼在進行mybatis配置的時候,沒有辦法同事配置多個參數,所以需要@Param這個註解來綁定參數對象。student這個參數中包含了三個對象,用@Param來綁定參數並命名爲"student"。並且在mapper.xml文件中調用時,對逐個參數在調用時,要加上 student. 的前綴。如下所示:
- UPDATE test_student SET name=#{student.name},age=#{student.age} WHERE id=#{student.id}
注意事項:在使用@Param來註解時,如果使用#{ } 或者 ${ } 的方式都可以,但如果不是用@Param註解時,則必須使用#{ }方式。
@RequestParam和@RequestBody的區別
@RequestParam
A) 常用來處理簡單類型的綁定,通過Request.getParameter() 獲取的String可直接轉換爲簡單類型的情況( 由String到 簡單類型的轉換操作由ConversionService配置的轉換器來完成);因爲使用request.getParameter()方式獲取參數,所以可以處理get 方式中queryString的值,也可以處理post方式中 body data的值。
B)用來處理Content-Type: 爲 application/x-www-form-urlencoded編碼的內容,提交方式GET、POST。(不設置這個屬性,好像這就是默認值)
C) 該註解有兩個屬性: value、required; value用來指定要傳入值的id名稱,required用來指示參數是否必須綁定。
在方法參數裏面如是:
- public WebResponse findReleventPolicyPage(@RequestParam("pageSize") Integer pageSize,
- @RequestParam("pageNum") Integer pageNum,
- @RequestParam("type") Integer type){}
@RequestBody
處理HttpEntity傳遞過來的數據,一般用來處理非Content-Type: application/x-www-form-urlencoded編碼格式的數據。
GET請求中,因爲沒有HttpEntity,所以@RequestBody並不適用。
POST請求中,通過HttpEntity傳遞的參數,必須要在請求頭中聲明數據的類型Content-Type,SpringMVC通過使用HandlerAdapter 配置的HttpMessageConverters來解析HttpEntity中的數據,然後綁定到相應的bean上。
用於將Controller中方法返回的對象,通過適當的HttpMessageConverter轉換爲指定格式的數據,如:json、xml等,然後通過Response響應給客戶端。
在方法參數裏面如是:
- @RequestMapping("/json_test")
- // 響應json數據,把pojo對象轉換成json數據並響應
- @ResponseBody
- public Items jsonTest (@RequestBody Items items){ // 接受json數據並轉換成pojo對象
- return items;
- }
總結
在GET請求中,不能使用@RequestBody。
在POST請求,可以使用@RequestBody和@RequestParam,但是如果使用@RequestBody,對於參數轉化的配置必須統一。
舉個例子,在SpringMVC配置了HttpMessageConverters處理棧中,指定json轉化的格式,如Date轉成‘yyyy-MM-dd’,則參數接收對象包含的字段如果是Date類型,就只能讓客戶端傳遞年月日的格式,不能傳時分秒。因爲不同的接口,它的參數可能對時間參數有不同的格式要求,所以這樣做會讓客戶端調用同事對參數的格式有點困惑,所以說擴展性不高。
如果使用@RequestParam來接受參數,可以在接受參數的model中設置@DateFormat指定所需要接受時間參數的格式。
另外,使用@RequestBody接受的參數是不會被Servlet轉化統一放在request對象的Param參數集中,@RequestParam是可以的。
綜上所述,一般情況下,推薦使用@RequestParam註解來接受Http請求參數。