1、@Controller
在SpringMVC中只需要使用這個標記一個類是Controller,然後使用@RequestMapping和@RequestParam等一些註解用以定義URL請求和Controller方法之間的對映,這樣的Controller就能被外界訪問到。此外,Controller不會直接依賴於HttpServletRequest 和HttpServletResponse 等HttpServlet 物件,他們可以通過Controller的方法引數靈活的獲取到。
舉個例子:
@Controllerpublic 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 物件。
<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格式的):
<script>jsonData();function jsonData(){$.ajax({url:"<%=path%>/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);}})}</script>
然後在後臺接收一下:
@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")@ResponseBodypublic 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 {@Autowiredprivate StudentService studentService;@RequestMapping("getInfo")@ResponseBodypublic int getInfo(Student student){return studentService.insertStu(student);}}
在Controller中對私有變數用@Autowired標註,因為studentService這個變數是service層介面,所以要找到他的實現類StudentServiceImpl,並在實現類上新增@Service("")的註釋。
@Service("StudentService")public class StudentServiceImpl implements StudentService {@Autowiredprivate 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>UPDATE test_student SET name=#{student.name},age=#{student.age} WHERE id=#{student.id}</update>
注意事項:在使用@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資料並響應@ResponseBodypublic 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請求引數。