2015-03-31 103 views
36

我是Spring MVC的新手。請幫我解開文檔。Spring MVC:請解釋@RequestParam和@ModelAttribute之間的區別

文檔

Spring MVC Documentation狀態(重點煤礦):

  • @ModelAttribute上的方法參數指示參數應該從模型中檢索。如果模型中不存在,則應首先實例化參數,然後將其添加到模型中。一旦出現在模型中,參數的字段應該從具有匹配名稱的所有請求參數填充。 WebDataBinder類將請求參數名稱(包括查詢字符串參數和表單字段)與名稱建模屬性字段相匹配。

  • @RequestParam將請求參數綁定到控制器中的方法參數

免責聲明/澄清

我知道@ModelAttribute@RequestParam是不一樣的東西,並不是相互排斥的,不執行相同的作用,並能同時使用,如this question - 的確,@RequestParam可以用於填充@ModelAttribute的字段。我的問題更多地針對他們內部工作之間的差異。

問:

是什麼@ModelAttribute之間的差異,@RequestParam(在方法的參數,而不是方法使用)?具體做法是:

  • 來源:待辦事項@RequestParam@ModelAttribute具有 信息/人口,在URL即請求參數相同的源,其可以被供給作爲一種形式/模型,這是POST版的要素是什麼?
  • 用法:@RequestParam檢索到的變量是否被丟棄(除非傳入模型中),而使用@ModelAttribute檢索的變量是否被自動送入要返回的模型?

或者在非常基本的編碼示例中,這兩個示例之間的真實工作區別是什麼?

實施例1:@RequestParam

// foo and bar are thrown away, and are just used (e.g.) to control flow? 
@RequestMapping(method = RequestMethod.POST) 
public String testFooBar(@RequestParam("foo") String foo, 
@RequestParam("bar") String bar, ModelMap model) { 
    try { 
    doStuff(foo, bar); 
    } 
    // other code 
    } 

實施例2:@ModelAttribute

// FOOBAR CLASS 
// Fields could of course be explicitly populated from parameters by @RequestParam 
public class FooBar{ 
    private String foo; 
    private String bar; 
    // plus set() and get() methods 
} 

// CONTROLLER 
// Foo and Bar become part of the model to be returned for the next view? 
@RequestMapping(method = RequestMethod.POST) 
public String setupForm(@ModelAttribute("fooBar") FooBar foobar) { 
    String foo = fooBar.getFoo(); 
    String bar = fooBar.getBar(); 
    try { 
     doStuff(foo, bar); 
    } 
    // other code 
} 

我的當前理解:

@ModelAttribute@RequestParam博個詢問請求參數的信息,但他們不同的方式使用這些信息:

  • @RequestParam只是填充獨立變量(當然這可能是一個@ModelAttribute類字段)。這些變量在控制器完成時將被丟棄,除非它們已被饋入模型中。

  • @ModelAttribute填充一個類的字段,然後填充模型的屬性將被傳遞迴視圖

這是正確的嗎?

回答

27

@RequestParam只是填充獨立變量(當然這可能是@ModelAttribute類中的字段)。這些變量在控制器完成時將被丟棄,除非它們已被饋入模型中。

不要混淆「模型」一詞與會話。 http會話通常是:HTTP.GET,服務器響應,然後是HTTP.POST。當你使用@ModelAttribute註解時,你總是構建一個你已經註解的實例,這就是你認爲「向模型提供東西」可能會使變量停滯不前。這是不正確的,一旦HttpServletRequest完成這些變量不應該再次成爲瀏覽器/服務器對話的一部分,除非它們已經保存在會話中。

@ModelAttribute填充類,然後填充模型的屬性的字段被傳遞迴視圖

是的!爲了正確,@ModelAttribute告訴Spring使用其默認Web數據綁定器來填充來自HttpServletRequest的數據的某個實例。選擇將這些數據傳回給視圖取決於程序員。當你有一個註解爲@ModelAttribute的方法時,每次代碼訪問該servlet時都會調用它。當你有@ModelAttribute作爲方法的參數之一時,我們正在討論傳入的Http表單數據綁定。

打電話@RequestParam是說request.getParameter("foo");在底層,Java的HttpServletRequest可讓您通過執行鍵值查找來從請求對象獲取值。返回的值是Object類型。如果你在你的web應用程序中沒有使用Spring,那麼你會輸入很多東西。

然後,當您開始使用@ModelAttribute時,Spring會將此抽象更進一步。這個註釋採用了數據綁定的概念。數據綁定的目標是控制器中的代碼不必爲每個表單元素調用request.getParameter("foo1")。想象一下你有一個5字段的網頁表單。沒有數據綁定,程序員必須手動檢索並驗證每個字段。程序員必須確保請求包含屬性,屬性的值存在,並且該屬性的值是每個字段預期的類型。使用@ModelAttribute告訴Spring爲你做這個工作。

如果註釋在你的控制器的方法與@ModelAttribute("fooBar") FooBar fooBarFooBar實例將總是可以由Spring構建,並提供給您的方法。數據綁定起作用的地方是在Method的參數中使用了這個註釋的時候; Spring查看HttpServletRequest的實例,並查看它是否可以將請求中的數據與FooBar的實例上的正確屬性相匹配。這是基於java的屬性約定,你有一個字段,如foo和公共getter和setter叫getFoosetFoo。這看起來很神奇,但如果你打破約定,你的Spring數據綁定將停止工作,因爲它無法知道,其中綁定你的數據HttpServletRequest你仍然會得到一個FooBar的實例,但屬性不會被設置爲來自請求的任何值。

2

@ModelAttribute註釋參數由註冊ServletModelAttributeMethodProcessor(或ModelAttributeMethodProcessor)和@RequestParam註釋參數處理由註冊RequestParamMethodArgumentResolverRequestParamMapMethodArgumentResolver根據參數類型處理。

這裏是Spring是如何使用這些HandlerMethodArgumentResolvers解決論據處理程序方法的解釋:

在這兩種情況下,@ModelAttribute@RequestParam,以約束從被檢索的值ServletRequest parameters

你可以看看上面提到的類型的源代碼,但這裏是簡單的細節。

對於@ModelAttribute,Spring將創建一個參數類型的實例。它將檢查該實例的字段並嘗試根據由名稱和字段名稱組成的命名/別名策略將參數值綁定到它們。它通常使用一組Converter實例將String(參數值始終爲String值)轉換爲目標字段類型IntegerDate等等。您還可以註冊自己的Converter類型以進行自定義轉換。你也可以嵌套POJO類型。

對於@RequestParam,Spring將使用相同的Converter實例將參數值直接轉換爲帶註釋的參數類型。

請注意,參數值不會「丟棄」。它們在容器的請求處理週期期間被存儲在HttpServletRequest中。您可以隨時通過appropriate methods訪問它們。

0

@ModelAttribute(參數)@SessionAttributes或從@ModelAttribute(方法)加載一個模型屬性。

你不需要它只是綁定來自請求的值,但它會從@SessionAttributes加載後做到這一點。

@RequestParam將請求參數綁定到對象。

0
  • 在方法級別

當註釋在方法級別使用它表示方法的目的是爲了增加一個或多個模型屬性。這些方法支持與@RequestMapping方法相同的參數類型,但不能直接映射到請求。

@ModelAttribute 
public void addAttributes(Model model) { 
    model.addAttribute("msg", "Welcome to the Netherlands!"); 
} 

將名爲msg的屬性添加到控制器類中定義的所有模型的方法。

在調用任何請求處理程序方法之前,Spring-MVC將始終首先調用該方法。 也就是說,在用@RequestMapping註解的控制器方法被調用之前調用@ModelAttribute方法。序列背後的邏輯是,在控制器方法內的任何處理開始之前,必須創建模型對象。

將相應的類註釋爲@ControllerAdvice也很重要。因此,您可以在模型中添加將被識別爲全局的值。這實際上意味着對於響應部分中的每個方法,每個請求都存在默認值。

  • 作爲方法的參數

當作爲方法的參數使用,指示的參數應該從模型中檢索。如果不存在,它應該首先實例化,然後添加到模型中,一旦出現在模型中,參數字段應該從具有匹配名稱的所有請求參數中填充。

在用戶模型屬性後面的代碼片段中填充了提交給addUser端點的表單中的數據。 Spring MVC在調用提交方法之前在幕後執行此操作:

**@RequestMapping**(value = "/addUser", method = RequestMethod.POST) 
public String submit(@ModelAttribute("user") User user) { 
    return "userView"; 
} 

因此,它將表單數據與bean綁定。使用@RequestMapping註解的控制器可以具有用@ModelAttribute註釋的自定義類參數。

這就是通常所說的Spring-MVC中的數據綁定,這是一種常見的機制,不需要單獨解析每個表單字段。

1

@ModelAttribute:綁定整個Java對象(如Employee)。支持多個請求參數

@RequestParam:結合一個單一的請求參數(像的firstName)

一般而言,
@RequestParam是最適合讀出一小則params的。

@ModelAttribute用於具有大量字段的表單。

@ModelAttribute爲您提供了額外的功能,如數據綁定,驗證和形式預先填充。

相關問題