spring mvc:注解@ModelAttribute妙用


在Spring mvc中,注解@ModelAttribute是一個非常常用的注解,其功能主要在兩方面:

  1. 運用在參數上,會將客戶端傳遞過來的參數按名稱注入到指定對象中,並且會將這個對象自動加入ModelMap中,便於View層使用;
  2. 運用在方法上,會在每一個@RequestMapping標注的方法前執行,如果有返回值,則自動將該返回值加入到ModelMap中;

一般開發中,第一種用法居多,本次我將使用第二種用法以期節省controller層的一些代碼:

目前使用spring mvc開發的controller層方法一般類似於:

1  @RequestMapping("/{encodeId}/detail")
2  public String detail(ModelMap model, @PathVariable String encodeId) {
3     .....
4  }

幾乎在每一個@RequestMapping標注的方法的參數中都會有 ModelMap model的參數,既然這是一個大概率事件,為什么不可以像注入request那樣,直接在類的開始使用@Resource進行自動注入呢?

另外一個,就是response,response也不能像request那樣進行自動注入。

類似的可能還有很多,既然這些都是controller層常用的代碼,如果能將其在一個basecontroller層自動注入,然后controller層繼承這個basecontroller,那樣就沒有必要再@RequestMapping標注的方法中寫上這些參數,使得參數個數減少,清晰。

我的思路正是使用@ModelAttribute注解,編寫一個basecontroller類,預定義一些項目中controller層常用的對象,如下:

1     @Resource
2     protected HttpServletRequest request;
3 
4     protected ModelMap model;
5 
6     protected HttpServletResponse response;

request不用解釋,可以直接使用@Resource直接注入,response和model的注入方式如下:

 1     /**
 2      * 設置response
 3      * 
 4      * @param response
 5      */
 6     @ModelAttribute
 7     private final void initResponse(HttpServletResponse response) {
 8         this.response = response;
 9     }
10 
11     /**
12      * 設置model
13      * 
14      * @param model
15      */
16     @ModelAttribute
17     private final void initModelMap(ModelMap model) {
18         this.model = model;
19     }

spring在執行@RequestMapping前會執行上述方法,spring會和平常一樣,每次請求重新生成一個model和response,然后注入到方法的參數中,這樣就變相在繼承了這個basecontroller的controller中自動注入了response和model,在這個controller層中再也不必每次寫ModelMap和response參數,整體代碼整潔了不少。

我在項目中這樣使用暫無問題,如果哪位高手知道這種做法會有弊端或者有更好的方法,求指正!


 

修正: 

  非常感謝eBusinessMan的提醒,確實有可能在spring mvc單例模式下會出現訪問對象不一致的情況,為了防止該問題,而又能保持這種代碼的簡潔性以及確保使用spring mvc性能問題不太嚴重,我決定使用ThreadLocal來處理。(后期驗證是否會出現該問題在本文進行補充

驗證結果:request采用spring的自動注入方式是線程安全的,response、model是不安全的,采用ThreadLocal可以解決該問題)

request對象不再使用注解自動注入(也可以繼續使用注解方式注入),而使用同response和model初始化的方式,取消request、response、model三個類變量,具體如下:

 1   private static final ThreadLocal<HttpServletRequest> requestContainer = new ThreadLocal<HttpServletRequest>();
 2 
 3   private static final ThreadLocal<HttpServletResponse> responseContainer = new ThreadLocal<HttpServletResponse>();
 4 
 5   private static final ThreadLocal<ModelMap> modelContainer = new ThreadLocal<ModelMap>();
 6 
 7     /**
 8      * 初始化response
 9      * 
10      * @param response
11      */
12     @ModelAttribute
13     private final void initResponse(HttpServletResponse response) {
14         responseContainer.set(response);
15     }
16 
17     /**
18      * 獲取當前線程的response對象
19      * 
20      * @return
21      */
22     protected final HttpServletResponse getResponse() {
23         return responseContainer.get();
24     }
25 
26     /**
27      * 初始化request
28      * 
29      * @param request
30      */
31     @ModelAttribute
32     private final void initRequest(HttpServletRequest request) {
33         requestContainer.set(request);
34     }
35 
36     /**
37      * 獲取當前線程的request對象
38      * 
39      * @return
40      */
41     protected final HttpServletRequest getRequest() {
42         return requestContainer.get();
43     }
44 
45     /**
46      * 設置model
47      * 
48      * @param model
49      */
50     @ModelAttribute
51     private final void initModelMap(ModelMap model) {
52         modelContainer.set(model);
53     }
54 
55     /**
56      * 獲取當前線程的modelMap對象
57      * 
58      * @return
59      */
60     protected final ModelMap getModelMap() {
61         return modelContainer.get();
62     }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM