spring MVC和spring的註解

概述
註釋配置相對於 XML 配置具備不少的優點:
它能夠充分利用 Java 的反射機制獲取類結構信息,這些信息能夠有效減小配置的工做。如使用 JPA 註釋配置 ORM 映射時,咱們就不須要指定 PO 的屬性名、類型等信息,若是關係表字段和 PO 屬性名、類型都一致,您甚至無需編寫任務屬性映射信息——由於這些信息均可以經過 Java 反射機制獲取。
註釋和 Java 代碼位於一個文件中,而 XML 配置採用獨立的配置文件,大多數配置信息在程序開發完成後都不會調整,若是配置信息和 Java 代碼放在一塊兒,有助於加強程序的內聚性。而採用獨立的 XML 配置文件,程序員在編寫一個功能時,每每須要在程序文件和配置文件中不停切換,這種思惟上的不連貫會下降開發效率。javascript

springmvc和struts是一個層次的概念,均屬java web mvc框架,只是ssh中第2個s的技術。html

ssh通常意義上是指 struts,spring framework以及hibernate。這三個框架做用是不同的。
hibernate主要是用於持久層,struts主要是用於mvc,而spring主要用於aop和ioc。前端

spring mvc經常使用的註解: @Controller 、 @RequestMapping 、 @PathVariable 、 @ModelAttribute 、 @ResponseBody 、 @RequestParam 、 @SessionAttributes 、@CookieValue 、@RequestHeader 九個

@Controller
@Controller 負責註冊一個bean 到spring 上下文中,bean 的ID 默認爲

類名稱開頭字母小寫,你也能夠本身指定,以下
方法一:
@Controller
public class TestController {}
 
方法二:           
@Controller("tmpController")
public class TestController {}java

@RequestMapping
 
1.@RequestMapping用來定義訪問的URL,你能夠爲整個類定義一個@RequestMapping,或者爲每一個方法指定一個。
把@RequestMapping放在類級別上,這可令它與方法級別上的@RequestMapping註解協同工做,取得縮小選擇範圍的效果。
例如:
@RequestMapping("/test")
public class TestController {}
則該類下的全部訪問路徑都在/test之下。程序員

2.將@RequestMapping用於整個類不是必須的,若是沒有配置,全部的方法的訪問路徑配置將是徹底獨立的,沒有任何關聯。web

3.完整的參數項爲:@RequestMapping(value="",method ={"",""},headers={},params={"",""}),各參數說明以下:
value :String[] 設置訪問地址
method: RequestMethod[]設置訪問方式,字符數組,查看RequestMethod類,包括GET, HEAD, POST, PUT, DELETE, OPTIONS, TRACE,經常使用RequestMethod.GET,RequestMethod.POST。
headers:String[] headers通常結合method = RequestMethod.POST使用
params: String[] 訪問參數設置,字符數組 例如:userId=idajax

4.value的配置還能夠採用模版變量的形式 ,例如:@RequestMapping

(value="/owners/{ownerId}", method=RequestMethod.GET),這點將在介

紹@PathVariable中詳細說明。spring

5.@RequestMapping params的補充說明,你能夠經過設置參數條件來限制

訪問地址,例如params="myParam=myValue"表達式,訪問地址中參數只有

包含了該規定的值"myParam=myValue"才能匹配得上,相似"myParam"之類

的表達式也是支持的,表示當前請求的地址必須有該參數(參數的值能夠是

任意),"!myParam"之類的表達式代表當前請求的地址不能包含具體指定的

參數"myParam"。後端

6.有一點須要注意的,若是爲類定義了訪問地址爲*.do,*.html之類的,則

在方法級的@RequestMapping,不能再定義value值,不然會報錯,例如
Java代碼 
@RequestMapping("/bbs.do") 
public class BbsController { 
    @RequestMapping(params = "method=getList") 
    public String getList() { 
     return "list"; 
    } 
@RequestMapping(value= "/spList") 
public String getSpecialList() { 
     return "splist"; 
    } 

 
如上例:/bbs.do?method=getList 能夠訪問到方法getList() ;而訪

問/bbs.do/spList則會報錯.數組

@PathVariable
1.@PathVariable用於方法中的參數,表示方法參數綁定到地址URL的模板

變量。
例如:
Java代碼 
@RequestMapping(value="/owners/{ownerId}",

method=RequestMethod.GET) 
public String findOwner(@PathVariable String ownerId, Model

model) { 
  Owner owner = ownerService.findOwner(ownerId);   
  model.addAttribute("owner", owner);   
  return "displayOwner"; 

2.@PathVariable用於地址欄使用{xxx}模版變量時使用。
若是@RequestMapping沒有定義相似"/{ownerId}" ,這種變量,則使用在

方法中@PathVariable會報錯。

@ModelAttribute
1.應用於方法參數,參數能夠在頁面直接獲取,至關於request.setAttribute(,)
2.應用於方法,將任何一個擁有返回值的方法標註上 @ModelAttribute,使其返回值將會進入到模型對象的屬性列表中.
3.應用於方法參數時@ModelAttribute("xx"),須關聯到Object的數據類型,基本數據類型 如:int,String不起做用。

例如:
Java代碼 
@ModelAttribute("items")//<——①向模型對象中添加一個名爲items的屬性 
public List populateItems() { 
        List lists = new ArrayList(); 
        lists.add("item1"); 
        lists.add("item2"); 
        return lists; 

@RequestMapping(params = "method=listAllBoard") 
public String listAllBoard(@ModelAttribute("currUser")User user,ModelMap model) { 
        bbtForumService.getAllBoard(); 
        //<——②在此訪問模型中的items屬性 
        System.out.println("model.items:" + ((List)

model.get("items")).size()); 
        return "listBoard"; 

在 ① 處,經過使用 @ModelAttribute 註解,populateItem() 方法將在任何請求處理方法執行前調用,Spring MVC 會將該方法返回值以「items」爲名放入到隱含的模型對象屬性列表中。
因此在 ② 處,咱們就能夠經過 ModelMap 入參訪問到 items 屬性,當執行 listAllBoard() 請求處理方法時,② 處將在控制檯打印出「model.items:2」的信息。固然咱們也能夠在請求的視圖中訪問到模型對象中的 items 屬性。

 

@ResponseBody
這個註解能夠直接放在方法上,表示返回類型將會直接做爲HTTP響應字節流輸出(不被放置在Model,也不被攔截爲視圖頁面名稱)。能夠用於ajax。
 
@RequestParam
@RequestParam是一個可選參數,例如:@RequestParam("id") 註解,因此它將和URL所帶參數 id進行綁定,若是入參是基本數據類型(如 int、long、float 等),URL 請求參數中
必定要有對應的參數,不然將拋出org.springframework.web.util.NestedServletException 異常,提示沒法將 null 轉換爲基本數據類型.
 
@RequestParam包含3個配置 @RequestParam(required = ,value="",

defaultValue = "")
required :參數是否必須,boolean類型,可選項,默認爲true
value: 傳遞的參數名稱,String類型,可選項,若是有值,對應到設置方法的參數
defaultValue:String類型,參數沒有傳遞時爲參數指定默認的值。

如:

package com.happyBKs.springmvc.handlers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@RequestMapping("class")
@Controller
public class RPTestHandler {
    
    String page="successrm";
    
    @RequestMapping("student")
    public String handle(@RequestParam(value="username") String un, @RequestParam(value="age",required=false, defaultValue="0") int age)
    {
        System.out.println("a student's request has come. username: "+un+", age: "+age);
        return page;
    }
    
    

}

1、基本使用,獲取提交的參數
後端代碼:

Java代碼

 收藏代碼

  1. @RequestMapping("testRequestParam")    
  2.    public String filesUpload(@RequestParam String inputStr, HttpServletRequest request) {    
  3.     System.out.println(inputStr);  
  4.       
  5.     int inputInt = Integer.valueOf(request.getParameter("inputInt"));  
  6.     System.out.println(inputInt);  
  7.       
  8.     // ......省略  
  9.     return "index";  
  10.    }     



前端代碼:

Html代碼

 收藏代碼

  1. <form action="/gadget/testRequestParam" method="post">    
  2.      參數inputStr:<input type="text" name="inputStr">    
  3.      參數intputInt:<input type="text" name="inputInt">    
  4. </form>  



前端界面:


執行結果:
test1
123

能夠看到spring會自動根據參數名字封裝進入,咱們能夠直接拿這個參數名來用

2、各類異常狀況處理
一、能夠對傳入參數指定參數名

Java代碼

 收藏代碼

  1. @RequestParam String inputStr  
  2. // 下面的對傳入參數指定爲aa,若是前端不傳aa參數名,會報錯  
  3. @RequestParam(value="aa") String inputStr  


錯誤信息:
HTTP Status 400 - Required String parameter 'aa' is not present

二、能夠經過required=false或者true來要求@RequestParam配置的前端參數是否必定要傳

Java代碼

 收藏代碼

  1. // required=false表示不傳的話,會給參數賦值爲null,required=true就是必需要有  
  2. @RequestMapping("testRequestParam")    
  3.     public String filesUpload(@RequestParam(value="aa", required=true) String inputStr, HttpServletRequest request)  



三、若是用@ RequestParam 註解的參數是int基本類型,可是required=false,這時若是不傳參數值會報錯,由於不傳值,會賦值爲null給int,這個不能夠

Java代碼

 收藏代碼

  1. @RequestMapping("testRequestParam")    
  2.    public String filesUpload(@RequestParam(value="aa", required=true) String inputStr,   
  3.         @RequestParam(value="inputInt", required=false) int inputInt  
  4.         ,HttpServletRequest request) {    
  5.       
  6.     // ......省略  
  7.     return "index";  
  8.    }  



解決方法:
    「Consider declaring it as object wrapper for the corresponding primitive type.」建議使用包裝類型代替基本類型,如使用「Integer」代替「int」


 
@SessionAttributes

session管理,Spring 容許咱們有選擇地指定 ModelMap 中的哪些屬性須要轉存到session 中,以便下一個請求屬對應的 ModelMap 的屬性列表中還能訪問到這些屬性。這一功能是經過類定義處標註 @SessionAttributes 註解來實現的。@SessionAttributes 只能聲明在類上,而不能聲明在方法上。
 在 默認狀況下,ModelMap 中的屬性做用域是 request 級別是,也就是說,當本次請求結束後,ModelMap 中的屬性將銷燬。若是但願在 多個請求中共享 ModelMap 中的屬性,必須將其屬性轉存到 session 中,這樣ModelMap 的屬性才能夠被跨請求訪問。 Spring 容許咱們有選擇地指定 ModelMap 中的哪些屬性須要轉存到 session 中,以便下一個請求屬對應的ModelMap 的屬性 列表中還能訪問到這些屬性。這一功能是經過類定義處標註 @SessionAttributes 註解來實現的。

代碼:

使模型對象的特定屬性具備 Session 範圍的做用域

 

 

Java代碼  收藏代碼

  1. package com.baobaotao.web;  
  2.   
  3. …  
  4. import org.springframework.ui.ModelMap;  
  5. import org.springframework.web.bind.annotation.SessionAttributes;  
  6.   
  7. @Controller  
  8. @RequestMapping("/bbtForum.do")  
  9. @SessionAttributes("currUser"//①將ModelMap中屬性名爲currUser的屬性  
  10. //放到Session屬性列表中,以便這個屬性能夠跨請求訪問 
  11. public class BbtForumController {  
  12. …  
  13.     @RequestMapping(params = "method=listBoardTopic")  
  14.     public String listBoardTopic(@RequestParam("id")int topicId, User user,  
  15. ModelMap model) {  
  16.         bbtForumService.getBoardTopics(topicId);  
  17.         System.out.println("topicId:" + topicId);  
  18.         System.out.println("user:" + user);  
  19.         model.addAttribute("currUser",user); //②向ModelMap中添加一個屬性
  20.         return "listTopic";  
  21.     }  
  22.   
  23. }  

    咱們在 ② 處添加了一個 ModelMap 屬性,其屬性名爲 currUser,而 ① 處經過 @SessionAttributes 註解將ModelMap 中名爲 currUser 的屬性放置到 Session 中, 因此咱們不但能夠在 listBoardTopic() 請求所對應的 JSP視圖頁面中通 過 request.getAttribute(「currUser」) 和 session.getAttribute(「currUser」) 獲 取 user 對象,還能夠在下一個請求所對應的 JSP 視圖頁面中通 過 session.getAttribute(「currUser」) 或 ModelMap#get(「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」})。

 

2、@ModelAttribute

 

     咱們能夠在 須要訪問 Session 屬性的 controller 上加上 @SessionAttributes,而後在 action 須要的 User 參數上加上 @ModelAttribute,並保證二者的屬性名稱一致。SpringMVC 就會自動將 @SessionAttributes 定義的屬性注入到 ModelMap 對象,在 setup action 的參數列表時,去
ModelMap 中取到這樣的對象,再添加到參數列表。只要咱們不去調用 SessionStatus 的 setComplete() 方法,這個對象就會一直保留在 Session 中,從而實現 Session 信息的共享。

Java代碼  

  1. @Controller  
  2. @SessionAttributes("currentUser")
  3. public class GreetingController{  
  4. @RequestMapping  
  5. public void hello(@ModelAttribute("currentUser")
    User user){  
  6.   //user.sayHello()  
  7. }  
  8. }  

Spring MVC 對於@ModelAttribute 、@SessionAttributes 的詳細處理流程

1)Spring MVC 在調用處理方法以前,在請求線程中自動的建立一個隱含的模型對象。

2)調用全部方法級的 標註了 @ModelAttribute 的方法,並將方法返回值添加到隱含的模型對象中。

3)若是方法所在的控制器 (標記 @Controller的類)沒有標記 @SessionAttributes("sessionXXX") 註釋,則該處理步驟可跳過。

查看Session 中是否存在 sessionXXX 屬性,若是有,將其添加到隱含的模型對象中。若是隱含的模型對象中已經存在了sessionXXX屬性,則其值將會被覆蓋

 

如下的步驟是針對 標記@ModelAttribute("xxx") 方法入參 的

4)若是隱含的模型對象已經存在xxx屬性,則將其賦值給入參,並將用戶的請求消息 賦值給入參的相應屬性 (PS:支持級聯屬性),並返回,如下的處理步驟再也不進行。

5)若是 方法所在的控制器、標記了 @SessionAttributes("xxx") 註釋,則繼續進行該處理步驟,不然直接進入步驟6。

查找 Session,若是沒有找到 xxx 屬性,則拋出異常 HttpSessionRequiredException 。

若是找到則將其賦值給入參,並將用戶的請求消息 賦值給入參的相應屬性 (PS:支持級聯屬性),並返回,如下的處理步驟再也不進行。

6)建立入參實例,並將其賦值給入參,並將用戶的請求消息 賦值給入參的相應屬性 (PS:支持級聯屬性)。至此,處理完畢。


最後
@CookieValue 獲取cookie信息
@RequestHeader 獲取請求的頭部信息

Spring的註解:

@Service用於標註業務層組件

@Controller用於標註控制層組件(如struts中的action)

@Repository用於標註數據訪問組件,即DAO組件

@Component泛指組件,當組件很差歸類的時候,咱們可使用這個註解進行標註。

[java] view plain copy

 

  1. @Service  
  2. public class VentorServiceImpl implements iVentorService {     
  3. }  
  4. @Repository  
  5. public class VentorDaoImpl implements iVentorDao {   
  6. }  

component-scan標籤默認狀況下自動掃描指定路徑下的包(含全部子包),將帶有@Component、@Repository、 @Service、@Controller標籤的類自動註冊到spring容器。對標記了 Spring's @Required、@Autowired、JSR250's @PostConstruct、@PreDestroy、@Resource、JAX-WS's @WebServiceRef、EJB3's @EJB、JPA's @PersistenceContext、@PersistenceUnit等註解的類進行對應的操做使註解生效(包含了annotation- config標籤的做用)。

@Autowired 註釋,它能夠對類成員變量、方法及構造函數進行標註,完成自動裝配的工做

Spring 經過一個 BeanPostProcessor 對 @Autowired 進行解析,因此要讓@Autowired 起做用必須事先在 Spring 容器中聲明AutowiredAnnotationBeanPostProcessor Bean。

@Resource

@Resource 的做用至關於 @Autowired,只不過 @Autowired 按 byType 自動注入,面@Resource 默認按 byName 自動注入罷了。@Resource 有兩個屬性是比較重要的,分別是 name 和 type,Spring 將@Resource 註釋的 name 屬性解析爲 Bean 的名字,而 type 屬性則解析爲 Bean 的類型。因此若是使用 name 屬性,則使用 byName 的自動注入策略,而使用 type 屬性時則使用 byType 自動注入策略。若是既不指定 name 也不指定 type 屬性,這時將經過反射機制使用 byName 自動注入策略。

Resource 註釋類位於 Spring 發佈包的 lib/j2ee/common-annotations.jar 類包中,所以在使用以前必須將其加入到項目的類庫中。來看一個使用@Resource的例子:

JSR-250 爲初始化以後/銷燬以前方法的指定定義了兩個註釋類,分別是 @PostConstruct 和 @PreDestroy,這兩個註釋只能應用於方法上。標註了 @PostConstruct 註釋的方法將在類實例化後調用,而標註了 @PreDestroy 的方法將在類銷燬以前調用。

雖然咱們能夠經過 @Autowired 或 @Resource 在 Bean 類中使用自動注入功能,可是 Bean 仍是在 XML 文件中經過 <bean> 進行定義 —— 也就是說,在 XML 配置文件中定義 Bean,經過@Autowired 或 @Resource 爲 Bean 的成員變量、方法入參或構造函數入參提供自動注入的功能。可否也經過註釋定義 Bean,從 XML 配置文件中徹底移除 Bean 定義的配置呢?那是確定的,咱們經過 Spring 2.5 提供的@Component 註釋就能夠達到這個目標了。

爲何 @Repository 只能標註在 DAO 類上呢?這是由於該註解的做用不僅是將類識別爲 Bean,同時它還能將所標註的類中拋出的數據訪問異常封裝爲 Spring 的數據訪問異常類型。 Spring 自己提供了一個豐富的而且是與具體的數據訪問技術無關的數據訪問異常結構,用於封裝不一樣的持久層框架拋出的異常,使得異常獨立於底層的框架。

Spring 2.5 在 @Repository 的基礎上增長了功能相似的額外三個註解:@Component、@Service、@Constroller,它們分別用於軟件系統的不一樣層次:

@Component 是一個泛化的概念,僅僅表示一個組件 (Bean) ,能夠做用在任何層次。
    @Service 一般做用在業務層,可是目前該功能與 @Component 相同。
    @Constroller 一般做用在控制層,可是目前該功能與 @Component 相同。

經過在類上使用 @Repository、@Component、@Service 和 @Constroller 註解,Spring 會自動建立相應的 BeanDefinition 對象,並註冊到 ApplicationContext 中。這些類就成了 Spring 受管組件。這三個註解除了做用於不一樣軟件層次的類,其使用方式與 @Repository 是徹底相同的。

@Component 有一個可選的入參,用於指定 Bean 的名稱,在 Boss 中,咱們就將 Bean 名稱定義爲「boss」。通常狀況下,Bean 都是 singleton 的,須要注入 Bean 的地方僅須要經過 byType 策略就能夠自動注入了,因此大可沒必要指定 Bean 的名稱。

在使用 @Component 註釋後,Spring 容器必須啓用類掃描機制以啓用註釋驅動 Bean 定義和註釋驅動 Bean 自動注入的策略。
@Scope

spring中bean的scope屬性,有以下5種類型:

    singleton 表示在spring容器中的單例,經過spring容器得到該bean時老是返回惟一的實例
    prototype表示每次得到bean都會生成一個新的對象
    request表示在一次http請求內有效(只適用於web應用)
    session表示在一個用戶會話內有效(只適用於web應用)
    globalSession表示在全局會話內有效(只適用於web應用)

在多數狀況,咱們只會使用singleton和prototype兩種scope,若是在spring配置文件內未指定scope屬性,默認爲singleton。 scope是prototype的狀況下,同一個bean定義會返回不一樣的對象。


是否有了這些 IOC 註釋,咱們就能夠徹底摒除原來 XML 配置的方式呢?NO。有如下幾點緣由:

    註釋配置不必定在先天上優於 XML 配置。若是 Bean 的依賴關係是固定的,(如 Service 使用了哪幾個 DAO 類),這種配置信息不會在部署時發生調整,那麼註釋配置優於 XML 配置;反之若是這種依賴關係會在部署時發生調整,XML 配置顯然又優於註釋配置,由於註釋是對 Java 源代碼的調整,您須要從新改寫源代碼並從新編譯才能夠實施調整。
    若是 Bean 不是本身編寫的類(如 JdbcTemplate、SessionFactoryBean 等),註釋配置將沒法實施,此時 XML 配置是惟一可用的方式。
    註釋配置每每是類級別的,而 XML 配置則能夠表現得更加靈活。好比相比於 @Transaction 事務註釋,使用 aop/tx 命名空間的事務配置更加靈活和簡單。

因此在實現應用中,咱們每每須要同時使用註釋配置和 XML 配置,對於類級別且不會發生變更的配置能夠優先考慮註釋配置;而對於那些第三方類以及容易發生調整的配置則應優先考慮使用 XML 配置。Spring 會在具體實施 Bean 建立和 Bean 注入以前將這兩種配置方式的元信息融合在一塊兒。

相關文章
相關標籤/搜索