SpringMVC常用注解(轉(zhuǎn))

1条摸、@Controller

  1. 在SpringMVC 中缅糟,控制器Controller 負(fù)責(zé)處理由DispatcherServlet 分發(fā)的請(qǐng)求,它把用戶請(qǐng)求的數(shù)據(jù)經(jīng)過(guò)業(yè)務(wù)處理層處理之后封裝成一個(gè)Model 捕犬,然后再把該Model 返回給對(duì)應(yīng)的View 進(jìn)行展示爱只。
  2. 在SpringMVC 中提供了一個(gè)非常簡(jiǎn)便的定義Controller 的方法,你無(wú)需繼承特定的類或?qū)崿F(xiàn)特定的接口凰兑,只需使用@Controller 標(biāo)記一個(gè)類是Controller 妥粟,然后使用@RequestMapping 和@RequestParam 等一些注解用以定義URL 請(qǐng)求和Controller 方法之間的映射审丘,這樣的Controller 就能被外界訪問(wèn)到吏够。此外Controller 不會(huì)直接依賴于HttpServletRequest 和HttpServletResponse 等HttpServlet 對(duì)象,它們可以通過(guò)Controller 的方法參數(shù)靈活的獲取到滩报。
  3. @Controller 用于標(biāo)記在一個(gè)類上锅知,使用它標(biāo)記的類就是一個(gè)SpringMVC Controller 對(duì)象。分發(fā)處理器將會(huì)掃描使用了該注解的類的方法脓钾,并檢測(cè)該方法是否使用了@RequestMapping 注解售睹。@Controller 只是定義了一個(gè)控制器類,而使用@RequestMapping 注解的方法才是真正處理請(qǐng)求的處理器可训。單單使用@Controller 標(biāo)記在一個(gè)類上還不能真正意義上的說(shuō)它就是SpringMVC 的一個(gè)控制器類昌妹,因?yàn)檫@個(gè)時(shí)候Spring 還不認(rèn)識(shí)它。那么要如何做Spring 才能認(rèn)識(shí)它呢握截?這個(gè)時(shí)候就需要我們把這個(gè)控制器類交給Spring 來(lái)管理飞崖。有兩種方式:
  • 在SpringMVC 的配置文件中定義MyController 的bean 對(duì)象。
  • 在SpringMVC 的配置文件中告訴Spring 該到哪里去找標(biāo)記為@Controller 的Controller 控制器谨胞。
<!--方式一-->
<bean class="com.host.app.web.controller.MyController"/>
<!--方式二-->
< context:component-scan base-package = "com.host.app.web" />//路徑寫到controller的上一層(掃描包詳解見(jiàn)下面淺析)

2固歪、@RequestMapping

RequestMapping是一個(gè)用來(lái)處理請(qǐng)求地址映射的注解,可用于類或方法上胯努。用于類上牢裳,表示類中的所有響應(yīng)請(qǐng)求的方法都是以該地址作為父路徑逢防。
RequestMapping注解有六個(gè)屬性,下面我們把她分成三類進(jìn)行說(shuō)明(下面有相應(yīng)示例)蒲讯。

1. value忘朝, method
  • value: 指定請(qǐng)求的實(shí)際地址,指定的地址可以是URI Template 模式(后面將會(huì)說(shuō)明)伶椿;
  • method: 指定請(qǐng)求的method類型辜伟, GET、POST脊另、PUT导狡、DELETE等;
2. consumes偎痛,produces
  • consumes: 指定處理請(qǐng)求的提交內(nèi)容類型(Content-Type)旱捧,例如application/json, text/html;
  • produces: 指定返回的內(nèi)容類型,僅當(dāng)request請(qǐng)求頭中的(Accept)類型中包含該指定類型才返回踩麦;
3. params枚赡,headers
  • params: 指定request中必須包含某些參數(shù)值是,才讓該方法處理谓谦。
  • headers: 指定request中必須包含某些指定的header值贫橙,才能讓該方法處理請(qǐng)求。

3反粥、@Resource和@Autowired

@Resource和@Autowired都是做bean的注入時(shí)使用卢肃,其實(shí)@Resource并不是Spring的注解,它的包是javax.annotation.Resource才顿,需要導(dǎo)入莫湘,但是Spring支持該注解的注入。

共同點(diǎn)

兩者都可以寫在字段和setter方法上郑气。兩者如果都寫在字段上幅垮,那么就不需要再寫setter方法。

不同點(diǎn)

(1)@Autowired

@Autowired為Spring提供的注解尾组,需要導(dǎo)入包org.springframework.beans.factory.annotation.Autowired;只按照byType注入忙芒。

public class TestServiceImpl {
   // 下面兩種@Autowired只要使用一種即可
   @Autowired
   private UserDao userDao; // 用于字段上

   @Autowired
   public void setUserDao(UserDao userDao) { // 用于屬性的方法上
       this.userDao = userDao;
   }
}

@Autowired注解是按照類型(byType)裝配依賴對(duì)象,默認(rèn)情況下它要求依賴對(duì)象必須存在讳侨,如果允許null值呵萨,可以設(shè)置它的required屬性為false。如果我們想使用按照名稱(byName)來(lái)裝配爷耀,可以結(jié)合@Qualifier注解一起使用甘桑。如下:

public class TestServiceImpl {
   @Autowired
   @Qualifier("userDao")
   private UserDao userDao; 
}

(2)@Resource

@Resource默認(rèn)按照ByName自動(dòng)注入,由J2EE提供,需要導(dǎo)入包javax.annotation.Resource跑杭。@Resource有兩個(gè)重要的屬性:name和type铆帽,而Spring將@Resource注解的name屬性解析為bean的名字,而type屬性則解析為bean的類型德谅。所以爹橱,如果使用name屬性,則使用byName的自動(dòng)注入策略窄做,而使用type屬性時(shí)則使用byType自動(dòng)注入策略愧驱。如果既不制定name也不制定type屬性,這時(shí)將通過(guò)反射機(jī)制使用byName自動(dòng)注入策略椭盏。

public class TestServiceImpl {
   // 下面兩種@Resource只要使用一種即可
   @Resource(name="userDao")
   private UserDao userDao; // 用于字段上

   @Resource(name="userDao")
   public void setUserDao(UserDao userDao) { // 用于屬性的setter方法上
       this.userDao = userDao;
   }
}

注:最好是將@Resource放在setter方法上组砚,因?yàn)檫@樣更符合面向?qū)ο蟮乃枷耄ㄟ^(guò)set掏颊、get去操作屬性糟红,而不是直接去操作屬性。

@Resource裝配順序:

  1. 如果同時(shí)指定了name和type乌叶,則從Spring上下文中找到唯一匹配的bean進(jìn)行裝配盆偿,找不到則拋出異常。
  2. 如果指定了name准浴,則從上下文中查找名稱(id)匹配的bean進(jìn)行裝配事扭,找不到則拋出異常。
  3. 如果指定了type乐横,則從上下文中找到類似匹配的唯一bean進(jìn)行裝配求橄,找不到或是找到多個(gè),都會(huì)拋出異常晰奖。
  4. 如果既沒(méi)有指定name谈撒,又沒(méi)有指定type腥泥,則自動(dòng)按照byName方式進(jìn)行裝配匾南;如果沒(méi)有匹配,則回退為一個(gè)原始類型進(jìn)行匹配蛔外,如果匹配則自動(dòng)裝配蛆楞。

@Resource的作用相當(dāng)于@Autowired,只不過(guò)@Autowired按照byType自動(dòng)注入夹厌。

4豹爹、@ModelAttribute和 @SessionAttributes

代表的是:

  1. 該Controller的所有方法在調(diào)用前,先執(zhí)行此@ModelAttribute方法矛纹,可用于注解和方法參數(shù)中臂聋,可以把這個(gè)@ModelAttribute特性,應(yīng)用在BaseController當(dāng)中,所有的Controller繼承BaseController孩等,即可實(shí)現(xiàn)在調(diào)用Controller時(shí)艾君,先執(zhí)行@ModelAttribute方法。
  2. @SessionAttributes即將值放到session作用域中肄方,寫在class上面冰垄。

具體示例參見(jiàn)下面:使用 @ModelAttribute 和 @SessionAttributes 傳遞和保存數(shù)據(jù)

5、@PathVariable

用于將請(qǐng)求URL中的模板變量映射到功能處理方法的參數(shù)上权她,即取出uri模板中的變量作為參數(shù)虹茶。如:

@Controller  
public class TestController {  
    @RequestMapping(value="/user/{userId}/roles/{roleId}",method = RequestMethod.GET)  
    public String getLogin(@PathVariable("userId") String userId,  
        @PathVariable("roleId") String roleId){  
        System.out.println("User Id : " + userId);  
        System.out.println("Role Id : " + roleId);  
        return "hello";  
    }  
    @RequestMapping(value="/product/{productId}",method = RequestMethod.GET)  
    public String getProduct(@PathVariable("productId") String productId){  
          System.out.println("Product Id : " + productId);  
          return "hello";  
    }  
    @RequestMapping(value="/javabeat/{regexp1:[a-z-]+}",  
          method = RequestMethod.GET)  
    public String getRegExp(@PathVariable("regexp1") String regexp1){  
          System.out.println("URI Part 1 : " + regexp1);  
          return "hello";  
    }  
}

6、@requestParam

@requestParam主要用于在SpringMVC后臺(tái)控制層獲取參數(shù)隅要,類似一種是request.getParameter("name")蝴罪,它有三個(gè)常用參數(shù):defaultValue = "0", required = false, value = "isApp";defaultValue 表示設(shè)置默認(rèn)值步清,required 銅過(guò)boolean設(shè)置是否是必須要傳入的參數(shù)洲炊,value 值表示接受的傳入的參數(shù)類型。

7尼啡、@ResponseBody

作用: 該注解用于將Controller的方法返回的對(duì)象暂衡,通過(guò)適當(dāng)?shù)腍ttpMessageConverter轉(zhuǎn)換為指定格式后,寫入到Response對(duì)象的body數(shù)據(jù)區(qū)崖瞭。

使用時(shí)機(jī):返回的數(shù)據(jù)不是html標(biāo)簽的頁(yè)面狂巢,而是其他某種格式的數(shù)據(jù)時(shí)(如json、xml等)使用书聚;

8唧领、@Component

相當(dāng)于通用的注解,當(dāng)不知道一些類歸到哪個(gè)層時(shí)使用雌续,但是不建議斩个。

9、@Repository

用于注解dao層驯杜,在daoImpl類上面注解受啥。

注:

1、使用 @RequestMapping 來(lái)映射 Request 請(qǐng)求與處理器

方式一鸽心、通過(guò)常見(jiàn)的類路徑和方法路徑結(jié)合訪問(wèn)controller方法

方式二滚局、使用uri模板

@Controller
@RequestMapping ( "/test/{variable1}" )
public class MyController {

   @RequestMapping ( "/showView/{variable2}" )
   public ModelAndView showView( @PathVariable String variable1, @PathVariable ( "variable2" ) int variable2) {
      ModelAndView modelAndView = new ModelAndView();
      modelAndView.setViewName( "viewName" );
      modelAndView.addObject( " 需要放到 model 中的屬性名稱 " , " 對(duì)應(yīng)的屬性值,它是一個(gè)對(duì)象 " );
      return modelAndView;
   }
}

URI 模板就是在URI 中給定一個(gè)變量顽频,然后在映射的時(shí)候動(dòng)態(tài)的給該變量賦值藤肢。如URI 模板http://localhost/app/{variable1}/index.html ,這個(gè)模板里面包含一個(gè)變量variable1 糯景,那么當(dāng)我們請(qǐng)求http://localhost/app/hello/index.html 的時(shí)候嘁圈,該URL 就跟模板相匹配省骂,只是把模板中的variable1 用hello 來(lái)取代。這個(gè)變量在SpringMVC 中是使用@PathVariable 來(lái)標(biāo)記的最住。在SpringMVC 中冀宴,我們可以使用@PathVariable 來(lái)標(biāo)記一個(gè)Controller 的處理方法參數(shù),表示該參數(shù)的值將使用URI 模板中對(duì)應(yīng)的變量的值來(lái)賦值温学。

代碼中我們定義了兩個(gè)URI 變量略贮,一個(gè)是控制器類上的variable1 ,一個(gè)是showView 方法上的variable2 仗岖,然后在showView 方法的參數(shù)里面使用@PathVariable 標(biāo)記使用了這兩個(gè)變量逃延。所以當(dāng)我們使用/test/hello/showView/2.do 來(lái)請(qǐng)求的時(shí)候就可以訪問(wèn)到MyController 的showView 方法,這個(gè)時(shí)候variable1 就被賦予值hello 轧拄,variable2 就被賦予值2 揽祥,然后我們?cè)趕howView 方法參數(shù)里面標(biāo)注了參數(shù)variable1 和variable2 是來(lái)自訪問(wèn)路徑的path 變量,這樣方法參數(shù)variable1 和variable2 就被分別賦予hello 和2 檩电。方法參數(shù)variable1 是定義為String 類型拄丰,variable2 是定義為int 類型,像這種簡(jiǎn)單類型在進(jìn)行賦值的時(shí)候Spring 是會(huì)幫我們自動(dòng)轉(zhuǎn)換的俐末。

在上面的代碼中我們可以看到在標(biāo)記variable1 為path 變量的時(shí)候我們使用的是@PathVariable 料按,而在標(biāo)記variable2 的時(shí)候使用的是@PathVariable(“variable2”) 。這兩者有什么區(qū)別呢卓箫?第一種情況就默認(rèn)去URI 模板中找跟參數(shù)名相同的變量载矿,但是這種情況只有在使用debug 模式進(jìn)行編譯的時(shí)候才可以,而第二種情況是明確規(guī)定使用的就是URI 模板中的variable2 變量烹卒。當(dāng)不是使用debug 模式進(jìn)行編譯闷盔,或者是所需要使用的變量名跟參數(shù)名不相同的時(shí)候,就要使用第二種方式明確指出使用的是URI 模板中的哪個(gè)變量旅急。

除了在請(qǐng)求路徑中使用URI 模板逢勾,定義變量之外,@RequestMapping 中還支持通配符"*"藐吮。如下面的代碼我就可以使用/myTest/whatever/wildcard.do 訪問(wèn)到Controller 的testWildcard 方法溺拱。如:

@Controller
@RequestMapping ( "/myTest" )
public class MyController {
   @RequestMapping ( "*/wildcard" )
   public String testWildcard() {
      System. out .println( "wildcard------------" );
      return "wildcard" ;
   }  
}

當(dāng)@RequestParam中沒(méi)有指定參數(shù)名稱時(shí),Spring 在代碼是debug 編譯的情況下會(huì)默認(rèn)取更方法參數(shù)同名的參數(shù)炎码,如果不是debug 編譯的就會(huì)報(bào)錯(cuò)盟迟。

2秋泳、使用 @RequestMapping 的一些高級(jí)用法

(1)params屬性

@RequestMapping (value= "testParams" , params={ "param1=value1" , "param2" , "!param3" })
   public String testParams() {
      System. out .println( "test Params..........." );
      return "testParams" ;
   }

用@RequestMapping 的params 屬性指定了三個(gè)參數(shù)潦闲,這些參數(shù)都是針對(duì)請(qǐng)求參數(shù)而言的,它們分別表示參數(shù)param1 的值必須等于value1 迫皱,參數(shù)param2 必須存在歉闰,值無(wú)所謂辖众,參數(shù)param3 必須不存在,只有當(dāng)請(qǐng)求/testParams.do 并且滿足指定的三個(gè)參數(shù)條件的時(shí)候才能訪問(wèn)到該方法和敬。所以當(dāng)請(qǐng)求/testParams.do?param1=value1&param2=value2 的時(shí)候能夠正確訪問(wèn)到該testParams 方法凹炸,當(dāng)請(qǐng)求/testParams.do?param1=value1&param2=value2&param3=value3 的時(shí)候就不能夠正常的訪問(wèn)到該方法,因?yàn)樵贎RequestMapping 的params 參數(shù)里面指定了參數(shù)param3 是不能存在的昼弟。

(2)method屬性

@RequestMapping (value= "testMethod" , method={RequestMethod. GET , RequestMethod. DELETE })
   public String testMethod() {
      return "method" ;
   }

在上面的代碼中就使用method 參數(shù)限制了以GET 或DELETE 方法請(qǐng)求/testMethod 的時(shí)候才能訪問(wèn)到該Controller 的testMethod 方法啤它。

(3)headers屬性

@RequestMapping (value= "testHeaders" , headers={ "host=localhost" , "Accept" })
   public String testHeaders() {
      return "headers" ;
   }

headers 屬性的用法和功能與params 屬性相似。在上面的代碼中當(dāng)請(qǐng)求/testHeaders.do 的時(shí)候只有當(dāng)請(qǐng)求頭包含Accept 信息舱痘,且請(qǐng)求的host 為localhost 的時(shí)候才能正確的訪問(wèn)到testHeaders 方法变骡。

3、 @RequestMapping 標(biāo)記的處理器方法支持的方法參數(shù)和返回類型

支持的方法參數(shù)類型:

(1 )HttpServlet 對(duì)象芭逝,主要包括HttpServletRequest 塌碌、HttpServletResponse 和HttpSession 對(duì)象。 這些參數(shù)Spring 在調(diào)用處理器方法的時(shí)候會(huì)自動(dòng)給它們賦值旬盯,所以當(dāng)在處理器方法中需要使用到這些對(duì)象的時(shí)候台妆,可以直接在方法上給定一個(gè)方法參數(shù)的申明,然后在方法體里面直接用就可以了胖翰。但是有一點(diǎn)需要注意的是在使用HttpSession 對(duì)象的時(shí)候接剩,如果此時(shí)HttpSession 對(duì)象還沒(méi)有建立起來(lái)的話就會(huì)有問(wèn)題。

(2 )Spring 自己的WebRequest 對(duì)象萨咳。 使用該對(duì)象可以訪問(wèn)到存放在HttpServletRequest 和HttpSession 中的屬性值搂漠。

(3 )InputStream 、OutputStream 某弦、Reader 和Writer 桐汤。 InputStream 和Reader 是針對(duì)HttpServletRequest 而言的,可以從里面取數(shù)據(jù)靶壮;OutputStream 和Writer 是針對(duì)HttpServletResponse 而言的怔毛,可以往里面寫數(shù)據(jù)。

(4 )使用@PathVariable 腾降、@RequestParam 拣度、@CookieValue 和@RequestHeader 標(biāo)記的參數(shù)。

(5 )使用@ModelAttribute 標(biāo)記的參數(shù)螃壤。

(6 )java.util.Map 抗果、Spring 封裝的Model 和ModelMap 。 這些都可以用來(lái)封裝模型數(shù)據(jù)奸晴,用來(lái)給視圖做展示冤馏。

(7 )實(shí)體類。 可以用來(lái)接收上傳的參數(shù)寄啼。

(8 )Spring 封裝的MultipartFile 逮光。 用來(lái)接收上傳文件的代箭。

(9 )Spring 封裝的Errors 和BindingResult 對(duì)象。 這兩個(gè)對(duì)象參數(shù)必須緊接在需要驗(yàn)證的實(shí)體對(duì)象參數(shù)之后涕刚,它里面包含了實(shí)體對(duì)象的驗(yàn)證結(jié)果嗡综。

支持的返回類型

(1 )一個(gè)包含模型和視圖的ModelAndView 對(duì)象。

(2 )一個(gè)模型對(duì)象杜漠,這主要包括Spring 封裝好的Model 和ModelMap 极景,以及java.util.Map ,當(dāng)沒(méi)有視圖返回的時(shí)候視圖名稱將由RequestToViewNameTranslator 來(lái)決定驾茴。

(3 )一個(gè)View 對(duì)象戴陡。這個(gè)時(shí)候如果在渲染視圖的過(guò)程中模型的話就可以給處理器方法定義一個(gè)模型參數(shù),然后在方法體里面往模型中添加值沟涨。

(4 )一個(gè)String 字符串恤批。這往往代表的是一個(gè)視圖名稱。這個(gè)時(shí)候如果需要在渲染視圖的過(guò)程中需要模型的話就可以給處理器方法一個(gè)模型參數(shù)裹赴,然后在方法體里面往模型中添加值就可以了喜庞。

(5 )返回值是void 。這種情況一般是我們直接把返回結(jié)果寫到HttpServletResponse 中了棋返,如果沒(méi)有寫的話延都,那么Spring 將會(huì)利用RequestToViewNameTranslator 來(lái)返回一個(gè)對(duì)應(yīng)的視圖名稱。如果視圖中需要模型的話睛竣,處理方法與返回字符串的情況相同晰房。

(6 )如果處理器方法被注解@ResponseBody 標(biāo)記的話,那么處理器方法的任何返回類型都會(huì)通過(guò)HttpMessageConverters 轉(zhuǎn)換之后寫到HttpServletResponse 中射沟,而不會(huì)像上面的那些情況一樣當(dāng)做視圖或者模型來(lái)處理殊者。

(7 )除以上幾種情況之外的其他任何返回類型都會(huì)被當(dāng)做模型中的一個(gè)屬性來(lái)處理,而返回的視圖還是由RequestToViewNameTranslator 來(lái)決定验夯,添加到模型中的屬性名稱可以在該方法上用@ModelAttribute(“attributeName”) 來(lái)定義猖吴,否則將使用返回類型的類名稱的首字母小寫形式來(lái)表示。使用@ModelAttribute 標(biāo)記的方法會(huì)在@RequestMapping 標(biāo)記的方法執(zhí)行之前執(zhí)行挥转。

4海蔽、使用 @ModelAttribute 和 @SessionAttributes 傳遞和保存數(shù)據(jù)

SpringMVC 支持使用 @ModelAttribute 和 @SessionAttributes 在不同的模型(model)和控制器之間共享數(shù)據(jù)。 **@ModelAttribute **主要有兩種使用方式绑谣,一種是標(biāo)注在方法上党窜,一種是標(biāo)注在 Controller 方法參數(shù)上。

當(dāng) @ModelAttribute 標(biāo)記在方法上的時(shí)候借宵,該方法將在處理器方法執(zhí)行之前執(zhí)行幌衣,然后把返回的對(duì)象存放在 session 或模型屬性中,屬性名稱可以使用 @ModelAttribute(“attributeName”) 在標(biāo)記方法的時(shí)候指定暇务,若未指定泼掠,則使用返回類型的類名稱(首字母小寫)作為屬性名稱怔软。關(guān)于 @ModelAttribute 標(biāo)記在方法上時(shí)對(duì)應(yīng)的屬性是存放在 session 中還是存放在模型中垦细,我們來(lái)做一個(gè)實(shí)驗(yàn)择镇,看下面一段代碼。

@Controller
@RequestMapping ( "/myTest" )
public class MyController {

   @ModelAttribute ( "hello" )
   public String getModel() {
      System. out .println( "-------------Hello---------" );
      return "world" ;
   }

   @ModelAttribute ( "intValue" )
   public int getInteger() {
      System. out .println( "-------------intValue---------------" );
      return 10;
   }

   @RequestMapping ( "sayHello" )
   public void sayHello( @ModelAttribute ( "hello" ) String hello, @ModelAttribute ( "intValue" ) int num, @ModelAttribute ( "user2" ) User user, Writer writer, HttpSession session) throws IOException {
      writer.write( "Hello " + hello + " , Hello " + user.getUsername() + num);
      writer.write( "\r" );
      Enumeration enume = session.getAttributeNames();
      while (enume.hasMoreElements())
          writer.write(enume.nextElement() + "\r" );
   }

   @ModelAttribute ( "user2" )
   public User getUser(){
      System. out .println( "---------getUser-------------" );
      return new User(3, "user2" );
   }
}

當(dāng)我們請(qǐng)求 /myTest/sayHello.do 的時(shí)候使用 @ModelAttribute 標(biāo)記的方法會(huì)先執(zhí)行括改,然后把它們返回的對(duì)象存放到模型中腻豌。最終訪問(wèn)到 sayHello 方法的時(shí)候,使用 @ModelAttribute 標(biāo)記的方法參數(shù)都能被正確的注入值嘱能。執(zhí)行結(jié)果如下所示:

  • Hello world,Hello user210*

由執(zhí)行結(jié)果我們可以看出來(lái)吝梅,此時(shí) session 中沒(méi)有包含任何屬性,也就是說(shuō)上面的那些對(duì)象都是存放在模型屬性中惹骂,而不是存放在 session 屬性中苏携。那要如何才能存放在 session 屬性中呢?這個(gè)時(shí)候我們先引入一個(gè)新的概念 @SessionAttributes 对粪,它的用法會(huì)在講完 @ModelAttribute 之后介紹右冻,這里我們就先拿來(lái)用一下。我們?cè)?MyController 類上加上 @SessionAttributes 屬性標(biāo)記哪些是需要存放到 session 中的著拭。看下面的代碼:

@Controller
@RequestMapping ( "/myTest" )
@SessionAttributes (value={ "intValue" , "stringValue" }, types={User. class })
public class MyController {

   @ModelAttribute ( "hello" )
   public String getModel() {
      System. out .println( "-------------Hello---------" );
      return "world" ;
   }

   @ModelAttribute ( "intValue" )
   public int getInteger() {
      System. out .println( "-------------intValue---------------" );
      return 10;
   }

   @RequestMapping ( "sayHello" )
   public void sayHello(Map<String, Object> map, @ModelAttribute ( "hello" ) String hello, @ModelAttribute ( "intValue" ) int num, @ModelAttribute ( "user2" ) User user, Writer writer, HttpServletRequest request) throws IOException {
      map.put( "stringValue" , "String" );
      writer.write( "Hello " + hello + " , Hello " + user.getUsername() + num);
      writer.write( "\r" );
      HttpSession session = request.getSession();
      Enumeration enume = session.getAttributeNames();
      while (enume.hasMoreElements())
          writer.write(enume.nextElement() + "\r" );
      System. out .println(session);
   }

   @ModelAttribute ( "user2" )
   public User getUser() {
      System. out .println( "---------getUser-------------" );
      return new User(3, "user2" );
   }
}

在上面代碼中我們指定了屬性為 intValue 或 stringValue 或者類型為 User 的都會(huì)放到 Session中,利用上面的代碼當(dāng)我們?cè)L問(wèn) /myTest/sayHello.do 的時(shí)候伍伤,結(jié)果如下:

  • Hello world,Hello user210*

仍然沒(méi)有打印出任何 session 屬性抛杨,這是怎么回事呢?怎么定義了把模型中屬性名為 intValue 的對(duì)象和類型為 User 的對(duì)象存到 session 中鄙币,而實(shí)際上沒(méi)有加進(jìn)去呢肃叶?難道我們錯(cuò)啦?我們當(dāng)然沒(méi)有錯(cuò)十嘿,只是在第一次訪問(wèn) /myTest/sayHello.do 的時(shí)候 @SessionAttributes 定義了需要存放到 session 中的屬性被环,而且這個(gè)模型中也有對(duì)應(yīng)的屬性,但是這個(gè)時(shí)候還沒(méi)有加到 session 中详幽,所以 session 中不會(huì)有任何屬性筛欢,等處理器方法執(zhí)行完成后 Spring 才會(huì)把模型中對(duì)應(yīng)的屬性添加到 session 中。所以當(dāng)請(qǐng)求第二次的時(shí)候就會(huì)出現(xiàn)如下結(jié)果:

  • Hello world,Hello user210*

user2

intValue

stringValue

當(dāng) @ModelAttribute 標(biāo)記在處理器方法參數(shù)上的時(shí)候唇聘,表示該參數(shù)的值將從模型或者 Session 中取對(duì)應(yīng)名稱的屬性值版姑,該名稱可以通過(guò) @ModelAttribute(“attributeName”) 來(lái)指定,若未指定迟郎,則使用參數(shù)類型的類名稱(首字母小寫)作為屬性名稱剥险。

5、@PathVariable和@RequestParam的區(qū)別

請(qǐng)求路徑上有個(gè)id的變量值宪肖,可以通過(guò)@PathVariable來(lái)獲取 @RequestMapping(value = "/page/{id}", method = RequestMethod.GET)
@RequestParam用來(lái)獲得靜態(tài)的URL請(qǐng)求入?yún)? spring注解時(shí)action里用到表制。

簡(jiǎn)介:

handler method 參數(shù)綁定常用的注解,我們根據(jù)他們處理的Request的不同內(nèi)容部分分為四類:(主要講解常用類型)

A健爬、處理**requet uri **部分(這里指uri template中variable,不含queryString部分)的注解: @PathVariable;

B么介、處理request header部分的注解: @RequestHeader, @CookieValue;

C娜遵、處理request body部分的注解:@RequestParam, @RequestBody;

D、處理attribute類型是注解: @SessionAttributes, @ModelAttribute;

(1)壤短、@PathVariable

當(dāng)使用@RequestMapping URI template 樣式映射時(shí)设拟, 即 someUrl/{paramId}, 這時(shí)的paramId可通過(guò) @Pathvariable注解綁定它傳過(guò)來(lái)的值到方法的參數(shù)上。

示例代碼:

@Controller  
@RequestMapping("/owners/{ownerId}")  
public class RelativePathUriTemplateController {  

 @RequestMapping("/pets/{petId}")  
 public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {      
   // implementation omitted   
 }  
}

上面代碼把URI template 中變量 ownerId的值和petId的值久脯,綁定到方法的參數(shù)上纳胧。若方法參數(shù)名稱和需要綁定的uri template中變量名稱不一致,需要在@PathVariable("name")指定uri template中的名稱帘撰。

(2)跑慕、 @RequestHeader、@CookieValue

@RequestHeader 注解摧找,可以把Request請(qǐng)求header部分的值綁定到方法的參數(shù)上核行。

示例代碼:

這是一個(gè)Request 的header部分:

Host                    localhost:8080  
Accept                  text/html,application/xhtml+xml,application/xml;q=0.9  
Accept-Language         fr,en-gb;q=0.7,en;q=0.3  
Accept-Encoding         gzip,deflate  
Accept-Charset          ISO-8859-1,utf-8;q=0.7,*;q=0.7  
Keep-Alive              300  
@RequestMapping("/displayHeaderInfo.do")  

public void displayHeaderInfo(@RequestHeader("Accept-Encoding") String encoding,  
                              @RequestHeader("Keep-Alive") long keepAlive)  {  
}

上面的代碼,把request header部分的 Accept-Encoding的值慰于,綁定到參數(shù)encoding上了钮科, Keep-Alive header的值綁定到參數(shù)keepAlive上。

@CookieValue 可以把Request header中關(guān)于cookie的值綁定到方法的參數(shù)上婆赠。

例如有如下Cookie值:

JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84

@RequestMapping("/displayHeaderInfo.do")  
public void displayHeaderInfo(@CookieValue("JSESSIONID") String cookie)  {  
}

即把JSESSIONID的值綁定到參數(shù)cookie上绵脯。

(3)、@RequestParam, @RequestBody

@RequestParam

A) 常用來(lái)處理簡(jiǎn)單類型的綁定休里,通過(guò)Request.getParameter() 獲取的String可直接轉(zhuǎn)換為簡(jiǎn)單類型的情況( String--> 簡(jiǎn)單類型的轉(zhuǎn)換操作由ConversionService配置的轉(zhuǎn)換器來(lái)完成)蛆挫;因?yàn)槭褂胷equest.getParameter()方式獲取參數(shù),所以可以處理get 方式中queryString的值妙黍,也可以處理post方式中 body data的值悴侵;

B)用來(lái)處理Content-Type: 為 application/x-www-form-urlencoded編碼的內(nèi)容,提交方式GET拭嫁、POST可免;

C) 該注解有兩個(gè)屬性: value、required做粤; value用來(lái)指定要傳入值的id名稱浇借,required用來(lái)指示參數(shù)是否必須綁定;

示例代碼:

@Controller  
@RequestMapping("/pets")  
@SessionAttributes("pet")  
public class EditPetForm {  
   @RequestMapping(method = RequestMethod.GET)  
public String setupForm(@RequestParam("petId") int petId, ModelMap model) {  
      Pet pet = this.clinic.loadPet(petId);  
  model.addAttribute("pet", pet);  
  return "petForm";  
  }
}

@RequestBody

該注解常用來(lái)處理Content-Type: 不是application/x-www-form-urlencoded編碼的內(nèi)容怕品,例如application/json, application/xml等妇垢;

它是通過(guò)使用HandlerAdapter 配置的HttpMessageConverters來(lái)解析post data body,然后綁定到相應(yīng)的bean上的。

因?yàn)榕渲糜蠪ormHttpMessageConverter闯估,所以也可以用來(lái)處理 application/x-www-form-urlencoded的內(nèi)容灼舍,處理完的結(jié)果放在一個(gè)MultiValueMap<String, String>里,這種情況在某些特殊需求下使用涨薪,詳情查看FormHttpMessageConverter api;

示例代碼:

@RequestMapping(value = "/something", method = RequestMethod.PUT)  
public void handle(@RequestBody String body, Writer writer) throws IOException {  
 writer.write(body);  
}

(4)骑素、@SessionAttributes, @ModelAttribute

@SessionAttributes:

該注解用來(lái)綁定HttpSession中的attribute對(duì)象的值,便于在方法中的參數(shù)里使用尤辱。

該注解有value砂豌、types兩個(gè)屬性厢岂,可以通過(guò)名字和類型指定要使用的attribute 對(duì)象光督;

示例代碼:

@Controller  
@RequestMapping("/editPet.do")  
@SessionAttributes("pet")  
public class EditPetForm {  
   // ...   
}

@ModelAttribute

該注解有兩個(gè)用法,一個(gè)是用于方法上塔粒,一個(gè)是用于參數(shù)上结借;

用于方法上時(shí): 通常用來(lái)在處理@RequestMapping之前,為請(qǐng)求綁定需要從后臺(tái)查詢的model卒茬;

用于參數(shù)上時(shí): 用來(lái)通過(guò)名稱對(duì)應(yīng)船老,把相應(yīng)名稱的值綁定到注解的參數(shù)bean上;要綁定的值來(lái)源于:

A) @SessionAttributes 啟用的attribute 對(duì)象上圃酵;

B) @ModelAttribute 用于方法上時(shí)指定的model對(duì)象柳畔;

C) 上述兩種情況都沒(méi)有時(shí),new一個(gè)需要綁定的bean對(duì)象郭赐,然后把request中按名稱對(duì)應(yīng)的方式把值綁定到bean中薪韩。

用到方法上@ModelAttribute的示例代碼:

@ModelAttribute  
public Account addAccount(@RequestParam String number) {  
   return accountManager.findAccount(number);  
}

這種方式實(shí)際的效果就是在調(diào)用@RequestMapping的方法之前,為request對(duì)象的model里put(“account”捌锭, Account)俘陷。

用在參數(shù)上的@ModelAttribute示例代碼:

@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)  
public String processSubmit(@ModelAttribute Pet pet) {  

}

首先查詢 @SessionAttributes有無(wú)綁定的Pet對(duì)象,若沒(méi)有則查詢@ModelAttribute方法層面上是否綁定了Pet對(duì)象观谦,若沒(méi)有則將URI template中的值按對(duì)應(yīng)的名稱綁定到Pet對(duì)象的各屬性上拉盾。

6、< context:component-scan base-package = "" />淺析

component-scan 默認(rèn)掃描的注解類型是 @Component豁状,不過(guò)捉偏,在 @Component 語(yǔ)義基礎(chǔ)上細(xì)化后的 @Repository, @Service 和 @Controller 也同樣可以獲得 component-scan 的青睞

有了<context:component-scan>,另一個(gè)<context:annotation-config/>標(biāo)簽根本可以移除掉泻红,因?yàn)橐呀?jīng)被包含進(jìn)去了

另外<context:annotation-config/>還提供了兩個(gè)子標(biāo)簽

1. <context:include-filter> //指定掃描的路徑

2. <context:exclude-filter> //排除掃描的路徑

<context:component-scan>有一個(gè)use-default-filters屬性夭禽,屬性默認(rèn)為true,表示會(huì)掃描指定包下的全部的標(biāo)有@Component的類,并注冊(cè)成bean.也就是@Component的子注解@Service,@Reposity等承桥。

這種掃描的粒度有點(diǎn)太大驻粟,如果你只想掃描指定包下面的Controller或其他內(nèi)容則設(shè)置use-default-filters屬性為false,表示不再按照scan指定的包掃描,而是按照<context:include-filter>指定的包掃描蜀撑,示例:

<context:component-scan base-package="com.tan" use-default-filters="false">
       <context:include-filter type="regex" expression="com.tan.*"/>//注意后面要寫.*
</context:component-scan>

當(dāng)沒(méi)有設(shè)置use-default-filters屬性或者屬性為true時(shí)挤巡,表示基于base-packge包下指定掃描的具體路徑

<context:component-scan base-package="com.tan" >
       <context:include-filter type="regex" expression=".controller.*"/>
       <context:include-filter type="regex" expression=".service.*"/>
       <context:include-filter type="regex" expression=".dao.*"/>
</context:component-scan>

效果相當(dāng)于:

<context:component-scan base-package="com.tan" >
       <context:exclude-filter type="regex" expression=".model.*"/>
</context:component-scan>

注意:本人嘗試時(shí)無(wú)論哪種情況<context:include-filter>和<context:exclude-filter>都不能同時(shí)存在

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市酷麦,隨后出現(xiàn)的幾起案子矿卑,更是在濱河造成了極大的恐慌,老刑警劉巖沃饶,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件母廷,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡糊肤,警方通過(guò)查閱死者的電腦和手機(jī)琴昆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)馆揉,“玉大人业舍,你說(shuō)我怎么就攤上這事∩ǎ” “怎么了舷暮?”我有些...
    開(kāi)封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)噩茄。 經(jīng)常有香客問(wèn)我下面,道長(zhǎng),這世上最難降的妖魔是什么绩聘? 我笑而不...
    開(kāi)封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任沥割,我火速辦了婚禮,結(jié)果婚禮上君纫,老公的妹妹穿的比我還像新娘驯遇。我一直安慰自己,他們只是感情好蓄髓,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布叉庐。 她就那樣靜靜地躺著,像睡著了一般会喝。 火紅的嫁衣襯著肌膚如雪陡叠。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天肢执,我揣著相機(jī)與錄音枉阵,去河邊找鬼。 笑死预茄,一個(gè)胖子當(dāng)著我的面吹牛兴溜,可吹牛的內(nèi)容都是我干的侦厚。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼拙徽,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼刨沦!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起膘怕,我...
    開(kāi)封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤想诅,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后岛心,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體来破,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年忘古,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了徘禁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡存皂,死狀恐怖晌坤,靈堂內(nèi)的尸體忽然破棺而出逢艘,到底是詐尸還是另有隱情旦袋,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布它改,位于F島的核電站疤孕,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏央拖。R本人自食惡果不足惜祭阀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鲜戒。 院中可真熱鬧专控,春花似錦、人聲如沸遏餐。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)失都。三九已至柏蘑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間粹庞,已是汗流浹背咳焚。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留庞溜,地道東北人革半。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親又官。 傳聞我的和親對(duì)象是個(gè)殘疾皇子不傅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348